Merge pull request #132 from JongHeonChoi/fx_xwalk_capability
[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 #include <Ecore_Wayland.h>
20 #include <ewk_chromium.h>
21 #include <cstdint>
22
23 #include "common/arraysize.h"
24 #include "common/logger.h"
25
26 namespace runtime {
27
28 namespace {
29 const char* kEdjePath = "/usr/share/edje/xwalk/xwalk_tizen.edj";
30 const char* kWinowRotationEventKey = "wm,rotation,changed";
31 const char* kWinowFocusedEventKey = "focused";
32 const char* kWinowUnfocusedEventKey = "unfocused";
33
34 const int kPortraitNaturalAngle[] = {
35   0,  // PORTRAIT_PRIMARY
36   180,  // PORTRAIT_SECONDARY
37   270,  // LANDSCAPE_PRIMARY
38   90,  // LANDSCAPE_SECONDARY
39   0,  // NATURAL
40   -1  // ANY
41 };
42 const int kLandscapeNaturalAngle[] = {
43   270,  // PORTRAIT_PRIMARY
44   90,  // PORTRAIT_SECONDARY
45   0,  // LANDSCAPE_PRIMARY
46   180,  // LANDSCAPE_SECONDARY
47   0,  // NATURAL
48   -1,  // ANY
49 };
50
51 NativeWindow::ScreenOrientation NativeAngleToOrientation(
52     int angle, NativeWindow::ScreenOrientation natural_orientation) {
53   auto& convert_table =
54       natural_orientation == NativeWindow::ScreenOrientation::PORTRAIT_PRIMARY ?
55           kPortraitNaturalAngle :
56           kLandscapeNaturalAngle;
57   unsigned index = ARRAYSIZE(convert_table) - 1;
58   for (unsigned i = 0; i < ARRAYSIZE(convert_table); ++i) {
59     if (convert_table[i] == angle) {
60       index = i;
61       break;
62     }
63   }
64   return static_cast<NativeWindow::ScreenOrientation>(index);
65 }
66
67 }  // namespace
68
69
70 NativeWindow::NativeWindow()
71     : window_(NULL),
72       window_type_(Type::NORMAL),
73       initialized_(false),
74       focus_(NULL),
75       content_(NULL),
76       rotation_(0),
77       handler_id_(0) {
78 }
79
80 NativeWindow::~NativeWindow() {
81   if (window_)
82     evas_object_del(window_);
83 }
84
85 void NativeWindow::Initialize() {
86   if (initialized_) {
87     LOGGER(DEBUG) << "already initialized";
88     return;
89   }
90   // window
91   window_ = CreateWindowInternal();
92   elm_win_conformant_set(window_, EINA_TRUE);
93   int w, h;
94   ecore_wl_screen_size_get(&w, &h);
95   evas_object_resize(window_, w, h);
96   elm_win_size_base_set(window_, w, h);
97   elm_win_autodel_set(window_, EINA_TRUE);
98   evas_object_smart_callback_add(window_, "delete,request",
99                                  DidDeleteRequested, this);
100   evas_object_smart_callback_add(window_, "profile,changed",
101                                  DidProfileChanged, this);
102
103   #define EVAS_SIZE_EXPAND_FILL(obj) \
104     evas_object_size_hint_weight_set(obj, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); \
105     evas_object_size_hint_align_set(obj, EVAS_HINT_FILL, EVAS_HINT_FILL);
106
107   // background
108   Evas_Object* bg = evas_object_rectangle_add(evas_object_evas_get(window_));
109   evas_object_color_set(bg, 0, 0, 0, 255);
110   EVAS_SIZE_EXPAND_FILL(bg);
111   elm_win_resize_object_add(window_, bg);
112   evas_object_render_op_set(bg, EVAS_RENDER_BLEND);
113   evas_object_show(bg);
114
115   // conformant
116   Evas_Object* conformant = elm_conformant_add(window_);
117   EVAS_SIZE_EXPAND_FILL(conformant);
118   elm_win_resize_object_add(window_, conformant);
119   evas_object_show(conformant);
120
121   // top layout
122   Evas_Object* top_layout = elm_layout_add(conformant);
123   elm_layout_file_set(top_layout, kEdjePath, "web-application");
124   EVAS_SIZE_EXPAND_FILL(top_layout);
125   elm_object_content_set(conformant, top_layout);
126   evas_object_show(top_layout);
127
128   // focus
129   Evas_Object* focus = elm_bg_add(top_layout);
130   evas_object_size_hint_align_set(focus, EVAS_HINT_FILL, EVAS_HINT_FILL);
131   evas_object_size_hint_weight_set(focus, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
132   elm_object_focus_allow_set(focus, EINA_TRUE);
133   elm_object_part_content_set(top_layout, "elm.swallow.content", focus);
134   EVAS_SIZE_EXPAND_FILL(focus);
135   elm_access_object_unregister(focus);
136   evas_object_show(focus);
137   focus_ = focus;
138
139   // focus callback
140   auto focus_callback = [](void* user_data,
141                            Evas_Object*,
142                            void*) -> void {
143     NativeWindow* window = static_cast<NativeWindow*>(user_data);
144     window->DidFocusChanged(true);
145   };
146   auto unfocus_callback = [](void* user_data,
147                              Evas_Object*,
148                              void*) -> void {
149     NativeWindow* window = static_cast<NativeWindow*>(user_data);
150     window->DidFocusChanged(false);
151   };
152
153   evas_object_smart_callback_add(focus,
154                                  kWinowFocusedEventKey,
155                                  focus_callback,
156                                  this);
157   evas_object_smart_callback_add(focus,
158                                  kWinowUnfocusedEventKey,
159                                  unfocus_callback,
160                                  this);
161
162   // Rotation
163   auto rotation_callback = [](void* user_data,
164                               Evas_Object* obj,
165                               void*) -> void {
166       NativeWindow* window = static_cast<NativeWindow*>(user_data);
167       int degree = elm_win_rotation_get(obj);
168       window->DidRotation(degree);
169   };
170   evas_object_smart_callback_add(window_,
171                                  kWinowRotationEventKey,
172                                  rotation_callback,
173                                  this);
174
175   if (w > h) {
176     natural_orientation_ = ScreenOrientation::LANDSCAPE_PRIMARY;
177   } else {
178     natural_orientation_ = ScreenOrientation::PORTRAIT_PRIMARY;
179   }
180
181   initialized_ = true;
182 }
183
184 void NativeWindow::DidDeleteRequested(void* /*data*/,
185     Evas_Object* /*obj*/, void* /*event_info*/) {
186   LOGGER(DEBUG) << "didDeleteRequested";
187   elm_exit();
188 }
189
190 void NativeWindow::DidProfileChanged(void* /*data*/,
191     Evas_Object* /*obj*/, void* /*event_info*/) {
192   LOGGER(DEBUG) << "didProfileChanged";
193 }
194
195 Evas_Object* NativeWindow::evas_object() const {
196   return window_;
197 }
198
199 void NativeWindow::SetContent(Evas_Object* content) {
200   // Remarks
201   // If any object was already set as a content object in the same part,
202   // the previous object will be deleted automatically with this call.
203   // If the content is NULL, this call will just delete the previous object.
204   // If the If you wish to preserve it,
205   // issue elm_object_part_content_unset() on it first.
206
207   evas_object_show(content);
208   evas_object_hide(
209     elm_object_part_content_unset(focus_, "elm.swallow.content"));
210   elm_object_part_content_set(focus_, "elm.swallow.content", content);
211   elm_object_focus_set(focus_, EINA_TRUE);
212   content_ = content;
213
214   // attached webview was resized by evas_norender API
215   evas_norender(evas_object_evas_get(window_));
216 }
217
218 void NativeWindow::DidRotation(int degree) {
219   rotation_ = degree;
220   auto it = handler_table_.begin();
221   for ( ; it != handler_table_.end(); ++it) {
222     it->second(degree);
223   }
224 }
225
226 void NativeWindow::DidFocusChanged(bool got) {
227   if (content_ != NULL) {
228     ewk_view_focus_set(content_, got ? EINA_TRUE : EINA_FALSE);
229   }
230 }
231
232 int NativeWindow::AddRotationHandler(RotationHandler handler) {
233   int id = handler_id_++;
234   handler_table_[id] = handler;
235   return id;
236 }
237
238 void NativeWindow::RemoveRotationHandler(int id) {
239   handler_table_.erase(id);
240 }
241
242 NativeWindow::ScreenOrientation NativeWindow::orientation() const {
243   return NativeAngleToOrientation(rotation_, natural_orientation_);
244 }
245
246 void NativeWindow::SetRotationLock(int degree) {
247   if (degree != -1)
248     rotation_ = degree % 360;
249   elm_win_wm_rotation_preferred_rotation_set(window_, rotation_);
250 }
251
252 void NativeWindow::SetRotationLock(ScreenOrientation orientation) {
253   auto& convert_table =
254       natural_orientation_ == ScreenOrientation::PORTRAIT_PRIMARY ?
255           kPortraitNaturalAngle :
256           kLandscapeNaturalAngle;
257   SetRotationLock(convert_table[static_cast<int>(orientation)]);
258 }
259
260
261 void NativeWindow::SetAutoRotation() {
262   elm_win_wm_rotation_preferred_rotation_set(window_, -1);
263   if (elm_win_wm_rotation_supported_get(window_)) {
264     const int rotation[4] = {0, 90, 180, 270};
265     elm_win_wm_rotation_available_rotations_set(window_, rotation, 4);
266   }
267   rotation_ = elm_win_rotation_get(window_);
268 }
269
270 void NativeWindow::Show() {
271   evas_object_show(window_);
272 }
273
274 void NativeWindow::Active() {
275   elm_win_activate(window_);
276 }
277
278 void NativeWindow::InActive() {
279   elm_win_lower(window_);
280 }
281
282 void NativeWindow::FullScreen(bool enable) {
283   elm_win_indicator_opacity_set(window_,
284       enable ? ELM_WIN_INDICATOR_TRANSPARENT : ELM_WIN_INDICATOR_OPAQUE);
285 }
286
287 #ifdef MANUAL_ROTATE_FEATURE_SUPPORT
288 void NativeWindow::EnableManualRotation(bool enable) {
289   LOGGER(DEBUG) << "set manual rotation : " << (enable ? "enabled" : "disabled");
290   elm_win_wm_rotation_manual_rotation_done_set(window_, enable ? EINA_TRUE : EINA_FALSE);
291 }
292
293 void NativeWindow::ManualRotationDone() {
294   if (EINA_TRUE == elm_win_wm_rotation_manual_rotation_done_get(window_)) {
295     elm_win_wm_rotation_manual_rotation_done(window_);
296   }
297 }
298 #endif  // MANUAL_ROTATE_FEATURE_SUPPORT
299
300 }  // namespace runtime