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