Merge pull request #25 from myroot/fix-widget-size-issue
[platform/framework/web/crosswalk-tizen.git] / runtime / browser / native_window.cc
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16
17 #include "runtime/browser/native_window.h"
18
19 #if defined(HAVE_X11)
20 #include <Ecore_X.h>
21 #elif defined(HAVE_WAYLAND)
22 #include <Ecore_Wayland.h>
23 #endif
24
25 #include <cstdint>
26
27 #include "common/logger.h"
28
29 namespace runtime {
30
31 namespace {
32   const char* kEdjePath = "/usr/share/edje/xwalk/xwalk_tizen.edj";
33   const char* kWinowRotationEventKey = "wm,rotation,changed";
34   const char* kWinowFocusedEventKey = "focused";
35   const char* kWinowUnfocusedEventKey = "unfocused";
36 }  // namespace
37
38
39 NativeWindow::NativeWindow()
40     : initialized_(false),
41       window_(NULL),
42       focus_(NULL),
43       content_(NULL),
44       rotation_(0),
45       handler_id_(0) {
46 }
47
48 NativeWindow::~NativeWindow() {
49 }
50
51 void NativeWindow::Initialize() {
52   // window
53   window_ = CreateWindowInternal();
54   elm_win_conformant_set(window_, EINA_TRUE);
55   int w, h;
56 #if defined(HAVE_X11)
57   uint16_t pid = getpid();
58   ecore_x_window_prop_property_set(
59     elm_win_xwindow_get(window_),
60     ECORE_X_ATOM_NET_WM_PID,
61     ECORE_X_ATOM_CARDINAL, 32, &pid, 1);
62   ecore_x_vsync_animator_tick_source_set(elm_win_xwindow_get(window_));
63   ecore_x_window_size_get(ecore_x_window_root_first_get(), &w, &h);
64 #elif defined(HAVE_WAYLAND)
65   ecore_wl_screen_size_get(&w, &h);
66 #endif
67   evas_object_resize(window_, w, h);
68   elm_win_autodel_set(window_, EINA_TRUE);
69   evas_object_smart_callback_add(window_, "delete,request",
70                                  DidDeleteRequested, this);
71   evas_object_smart_callback_add(window_, "profile,changed",
72                                  DidProfileChanged, this);
73
74   #define EVAS_SIZE_EXPAND_FILL(obj) \
75     evas_object_size_hint_weight_set(obj, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); \
76     evas_object_size_hint_align_set(obj, EVAS_HINT_FILL, EVAS_HINT_FILL);
77
78   // background
79   Evas_Object* bg = evas_object_rectangle_add(evas_object_evas_get(window_));
80   evas_object_color_set(bg, 0, 0, 0, 255);
81   EVAS_SIZE_EXPAND_FILL(bg);
82   elm_win_resize_object_add(window_, bg);
83   evas_object_render_op_set(bg, EVAS_RENDER_BLEND);
84   evas_object_show(bg);
85
86   // conformant
87   Evas_Object* conformant = elm_conformant_add(window_);
88   EVAS_SIZE_EXPAND_FILL(conformant);
89   elm_win_resize_object_add(window_, conformant);
90   evas_object_show(conformant);
91
92   // top layout
93   Evas_Object* top_layout = elm_layout_add(conformant);
94   elm_layout_file_set(top_layout, kEdjePath, "web-application");
95   EVAS_SIZE_EXPAND_FILL(top_layout);
96   elm_object_content_set(conformant, top_layout);
97   evas_object_show(top_layout);
98
99   // focus
100   Evas_Object* focus = elm_button_add(top_layout);
101   elm_theme_extension_add(NULL, kEdjePath);
102   elm_object_style_set(focus, "wrt");
103   elm_object_part_content_set(top_layout, "elm.swallow.content", focus);
104   EVAS_SIZE_EXPAND_FILL(focus);
105   elm_access_object_unregister(focus);
106   evas_object_show(focus);
107   focus_ = focus;
108
109   // focus callback
110   auto focus_callback = [](void* user_data,
111                            Evas_Object*,
112                            void*) -> void {
113     NativeWindow* window = static_cast<NativeWindow*>(user_data);
114     window->DidFocusChanged(true);
115   };
116   auto unfocus_callback = [](void* user_data,
117                              Evas_Object*,
118                              void*) -> void {
119     NativeWindow* window = static_cast<NativeWindow*>(user_data);
120     window->DidFocusChanged(false);
121   };
122
123   evas_object_smart_callback_add(focus,
124                                  kWinowFocusedEventKey,
125                                  focus_callback,
126                                  this);
127   evas_object_smart_callback_add(focus,
128                                  kWinowUnfocusedEventKey,
129                                  unfocus_callback,
130                                  this);
131
132   // Rotation
133   auto rotation_callback = [](void* user_data,
134                               Evas_Object* obj,
135                               void*) -> void {
136       NativeWindow* window = static_cast<NativeWindow*>(user_data);
137       int degree = elm_win_rotation_get(obj);
138       window->DidRotation(degree);
139   };
140   evas_object_smart_callback_add(window_,
141                                  kWinowRotationEventKey,
142                                  rotation_callback,
143                                  this);
144
145   if (w > h) {
146     natural_orientation_ = ScreenOrientation::LANDSCAPE_PRIMARY;
147   } else {
148     natural_orientation_ = ScreenOrientation::PORTRAIT_PRIMARY;
149   }
150
151   initialized_ = true;
152 }
153
154 void NativeWindow::DidDeleteRequested(void* /*data*/,
155     Evas_Object* /*obj*/, void* /*event_info*/) {
156   LOGGER(DEBUG) << "didDeleteRequested";
157   elm_exit();
158 }
159
160 void NativeWindow::DidProfileChanged(void* /*data*/,
161     Evas_Object* /*obj*/, void* /*event_info*/) {
162   LOGGER(DEBUG) << "didProfileChanged";
163 }
164
165 Evas_Object* NativeWindow::evas_object() const {
166   return window_;
167 }
168
169 void NativeWindow::SetContent(Evas_Object* content) {
170   // Remarks
171   // If any object was already set as a content object in the same part,
172   // the previous object will be deleted automatically with this call.
173   // If the content is NULL, this call will just delete the previous object.
174   // If the If you wish to preserve it,
175   // issue elm_object_part_content_unset() on it first.
176   evas_object_show(content);
177   elm_object_part_content_unset(focus_, "elm.swallow.content");
178   elm_object_part_content_set(focus_, "elm.swallow.content", content);
179   elm_object_focus_set(focus_, EINA_TRUE);
180   content_ = content;
181
182   // attached webview was resized by evas_norender API
183   evas_norender(evas_object_evas_get(window_));
184 }
185
186 void NativeWindow::DidRotation(int degree) {
187   rotation_ = degree;
188   auto it = handler_table_.begin();
189   for ( ; it != handler_table_.end(); ++it) {
190     it->second(degree);
191   }
192 }
193
194 void NativeWindow::DidFocusChanged(bool got) {
195   if (content_ != NULL) {
196     elm_object_focus_set(content_, got ? EINA_TRUE : EINA_FALSE);
197   }
198 }
199
200 int NativeWindow::AddRotationHandler(RotationHandler handler) {
201   int id = handler_id_++;
202   handler_table_[id] = handler;
203   return id;
204 }
205
206 void NativeWindow::RemoveRotationHandler(int id) {
207   handler_table_.erase(id);
208 }
209
210 void NativeWindow::SetRotationLock(int degree) {
211   if (degree != -1)
212     rotation_ = degree % 360;
213   elm_win_wm_rotation_preferred_rotation_set(window_, rotation_);
214 }
215
216 void NativeWindow::SetRotationLock(ScreenOrientation orientation) {
217   int portrait_natural_angle[] = {
218     0,  // PORTRAIT_PRIMARY
219     180,  // PORTRAIT_SECONDARY
220     270,  // LANDSCAPE_PRIMARY
221     90,  // LANDSCAPE_SECONDARY
222     0,  // NATURAL
223     -1  // ANY
224   };
225   int landscape_natural_angle[] = {
226     270,  // PORTRAIT_PRIMARY
227     90,  // PORTRAIT_SECONDARY
228     0,  // LANDSCAPE_PRIMARY
229     180,  // LANDSCAPE_SECONDARY
230     0,  // NATURAL
231     -1,  // ANY
232   };
233   auto& convert_table =
234       natural_orientation_ == ScreenOrientation::PORTRAIT_PRIMARY ?
235           portrait_natural_angle :
236           landscape_natural_angle;
237   SetRotationLock(convert_table[static_cast<int>(orientation)]);
238 }
239
240
241 void NativeWindow::SetAutoRotation() {
242   elm_win_wm_rotation_preferred_rotation_set(window_, -1);
243   if (elm_win_wm_rotation_supported_get(window_)) {
244     const int rotation[4] = {0, 90, 180, 270};
245     elm_win_wm_rotation_available_rotations_set(window_, rotation, 4);
246   }
247   rotation_ = elm_win_rotation_get(window_);
248 }
249
250 void NativeWindow::Show() {
251   evas_object_show(window_);
252 }
253
254 void NativeWindow::Active() {
255   elm_win_activate(window_);
256 }
257
258 void NativeWindow::InActive() {
259   elm_win_lower(window_);
260 }
261
262 void NativeWindow::FullScreen(bool enable) {
263   elm_win_indicator_opacity_set(window_,
264       enable ? ELM_WIN_INDICATOR_TRANSPARENT : ELM_WIN_INDICATOR_OPAQUE);
265 }
266
267 }  // namespace runtime