3bb22a3d33c93f4da03e9e1da0b360b05133c394
[platform/core/uifw/libscl-core.git] / src / sclcoreui-efl.cpp
1 /*
2  * Copyright (c) 2014 - 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
18 #include "sclcoreui-efl.h"
19 #include "sclcoreimpl.h"
20 #include <Elementary.h>
21 #include <dlog.h>
22 #include <appcore-efl.h>
23
24 #include <vconf.h>
25 #include <vconf-keys.h>
26
27 #include <glib.h>
28 #include <malloc.h>
29 #ifdef WAYLAND
30 #define EFL_BETA_API_SUPPORT
31 #include <Ecore_Wl2.h>
32 #include <input-method-client-protocol.h>
33 #else
34 #include <Ecore_X.h>
35 #include <X11/Xlib.h>
36 #include <X11/Xatom.h>
37 #endif
38
39 #ifdef WEBSOCKET
40  /* This websocket agent is for supporting Tizen 2.X legacy web IMEs that uses websocket */
41 CWebHelperAgentWebSocket g_websocket;
42 #endif
43
44 static struct appcore_ops ops;
45
46 #ifdef WAYLAND
47 struct WaylandKeyboard
48 {
49     Ecore_Evas *ee;
50     Ecore_Wl2_Window *wl_win;
51
52     struct wl_surface *surface;
53     struct wl_input_panel *ip;
54     struct wl_output *output;
55     struct wl_input_panel_surface *ips;
56 };
57
58 struct WaylandKeyboard wlkb = {0};
59
60 #define RENDER_PRE_TIMEOUT 1.0f
61 static Ecore_Timer *_render_pre_timer = NULL;
62 static void delete_render_pre_timer()
63 {
64     if (_render_pre_timer) {
65         ecore_timer_del(_render_pre_timer);
66         _render_pre_timer = NULL;
67     }
68 }
69 #endif
70
71 using namespace scl;
72
73 CSCLCoreUIEFL::CSCLCoreUIEFL()
74 {
75     m_initialized = FALSE;
76
77     m_backend_identifier = "EFL";
78
79     m_rotation_degree = 0;
80     m_main_window = SCLWINDOW_INVALID;
81     m_appid = NULL;
82     m_display = NULL;
83     m_portrait_size.width = 0;
84     m_portrait_size.height = 0;
85     m_landscape_size.width = 0;
86     m_landscape_size.height = 0;
87
88     memset(m_option_window_info, 0x00, sizeof(m_option_window_info));
89 }
90
91 CSCLCoreUIEFL::~CSCLCoreUIEFL()
92 {
93 }
94
95 sclboolean CSCLCoreUIEFL::init()
96 {
97     m_initialized = TRUE;
98     m_rotation_degree = -1;
99
100     for (int loop = 0;loop < OPTION_WINDOW_TYPE_MAX;loop++) {
101         m_option_window_info[loop].window = SCLWINDOW_INVALID;
102     }
103
104 #ifdef WEBSOCKET
105     g_websocket.init();
106 #endif
107
108     return TRUE;
109 }
110
111 void CSCLCoreUIEFL::fini()
112 {
113     m_initialized = FALSE;
114
115 #ifdef WEBSOCKET
116     g_websocket.exit();
117 #endif
118 }
119
120 sclwindow CSCLCoreUIEFL::get_main_window()
121 {
122     if (m_initialized) {
123         return m_main_window;
124     } else {
125         return NULL;
126     }
127 }
128
129 void CSCLCoreUIEFL::set_keyboard_size_hints(SclSize portrait, SclSize landscape)
130 {
131     Evas_Object *main_window = NATIVE_WINDOW_CAST(m_main_window);
132
133 #ifdef WAYLAND
134     Ecore_Wl2_Window *wl_window = (Ecore_Wl2_Window *)elm_win_wl_window_get(main_window);
135     ecore_wl2_window_rotation_geometry_set(wl_window,   0, 0, 0, portrait.width, portrait.height);
136     ecore_wl2_window_rotation_geometry_set(wl_window,  90, 0, 0, landscape.height, landscape.width);
137     ecore_wl2_window_rotation_geometry_set(wl_window, 180, 0, 0, portrait.width, portrait.height);
138     ecore_wl2_window_rotation_geometry_set(wl_window, 270, 0, 0, landscape.height, landscape.width);
139 #else
140     /*
141     ecore_x_e_window_rotation_geometry_set(elm_win_xwindow_get(main_window),   0, 0, 0, portrait.width, portrait.height);
142     ecore_x_e_window_rotation_geometry_set(elm_win_xwindow_get(main_window),  90, 0, 0, landscape.height, landscape.width);
143     ecore_x_e_window_rotation_geometry_set(elm_win_xwindow_get(main_window), 180, 0, 0, portrait.width, portrait.height);
144     ecore_x_e_window_rotation_geometry_set(elm_win_xwindow_get(main_window), 270, 0, 0, landscape.height, landscape.width);
145     */
146 #endif
147     LOGD("%d %d %d %d", portrait.width, portrait.height, landscape.width, landscape.height);
148
149     m_portrait_size = portrait;
150     m_landscape_size = landscape;
151 }
152
153 void CSCLCoreUIEFL::set_floating_mode(sclboolean floating_mode)
154 {
155     if (wlkb.ips)
156         wl_input_panel_surface_set_floating_panel(wlkb.ips, floating_mode);
157 }
158
159 void CSCLCoreUIEFL::set_floating_drag_enabled(sclboolean enabled)
160 {
161     if (wlkb.ips)
162         wl_input_panel_surface_set_floating_drag_enabled(wlkb.ips, enabled);
163 }
164
165 void CSCLCoreUIEFL::update_keyboard_geometry(SclSize portrait, SclSize landscape)
166 {
167     Evas_Object *main_window = NATIVE_WINDOW_CAST(m_main_window);
168     Evas_Coord win_w = 0, win_h = 0;
169     elm_win_screen_size_get(main_window, NULL, NULL, &win_w, &win_h);
170     int degree = m_rotation_degree;
171     LOGD("rotation : %d", degree);
172     char geometry[128];
173
174     snprintf(geometry, sizeof(geometry), "%d,%d,%d,%d", (win_w - portrait.width) / 2, win_h - portrait.height, portrait.width, portrait.height);
175     vconf_set_str(VCONFKEY_ISF_INPUT_PANEL_PORT_GEOMETRY, geometry);
176     snprintf(geometry, sizeof(geometry), "%d,%d,%d,%d", (win_h - landscape.width) / 2, win_w - landscape.height, landscape.width, landscape.height);
177     vconf_set_str(VCONFKEY_ISF_INPUT_PANEL_LAND_GEOMETRY, geometry);
178
179     CSCLCoreImpl *impl = CSCLCoreImpl::get_instance();
180     if (impl) {
181         if (degree == 0 || degree == 180)
182             impl->update_geometry((win_w - portrait.width) / 2, win_h - portrait.height, portrait.width, portrait.height);
183         else
184             impl->update_geometry((win_h - landscape.width) / 2, win_w - landscape.height, landscape.width, landscape.height);
185     }
186 }
187
188 void CSCLCoreUIEFL::get_keyboard_size(SclSize *portrait, SclSize *landscape)
189 {
190     *portrait = m_portrait_size;
191     *landscape = m_landscape_size;
192 }
193
194 #ifdef WAYLAND
195 static int language_changed_cb(void *event_info, void* data)
196 {
197     char clang[_POSIX_PATH_MAX] = {0};
198     char *vconf_str = vconf_get_str(VCONFKEY_LANGSET);
199     if (vconf_str) {
200         snprintf(clang, sizeof(clang), "%s", vconf_str);
201         free(vconf_str);
202     }
203     LOGD("current language is %s\n", clang);
204
205     setenv("LC_ALL", clang, 1);
206     char *r = setlocale(LC_ALL, "");
207     if (r == NULL) {
208         setlocale(LC_ALL, "en_US.UTF-8");
209     }
210
211     CSCLCoreImpl *impl = CSCLCoreImpl::get_instance();
212     if (impl) {
213         ISCLCoreEventCallback *callback = impl->get_core_event_callback();
214         if (callback) {
215             callback->on_set_display_language(clang);
216         }
217     }
218
219     return 0;
220 }
221
222 static void accessibility_changed_cb(keynode_t *key, void* data)
223 {
224     int vconf_value = 0;
225     if (vconf_get_bool(VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, &vconf_value) == 0) {
226         LOGD("accessibility state : %d\n", vconf_value);
227
228         CSCLCoreImpl *impl = CSCLCoreImpl::get_instance();
229         if (impl) {
230             ISCLCoreEventCallback *callback = impl->get_core_event_callback();
231             if (callback) {
232                 callback->on_set_accessibility_state(vconf_value);
233             }
234         }
235     }
236 }
237
238 static void win_rotation_changed_cb(void *data, Evas_Object *obj, void *event)
239 {
240     int degree = elm_win_rotation_get(obj);
241     LOGD("elm_win_rotation_get angle : %d\n", degree);
242
243     CSCLCoreUIEFL *coreui = static_cast<CSCLCoreUIEFL*>(data);
244     if (coreui) {
245         coreui->set_screen_rotation_degree(degree);
246     }
247 }
248 #else
249 static Eina_Bool _client_message_cb(void *data, int type, void *event)
250 {
251     Ecore_X_Event_Client_Message *ev = (Ecore_X_Event_Client_Message *)event;
252
253     ISCLCoreEventCallback *callback = NULL;
254     CSCLCoreImpl *impl = CSCLCoreImpl::get_instance();
255     Evas_Object *main_window = NULL;
256     if (impl) {
257         callback = impl->get_core_event_callback();
258         main_window = NATIVE_WINDOW_CAST(impl->get_main_window());
259     }
260
261 #ifndef APPLY_WINDOW_MANAGER_CHANGE
262 #else
263     if (ev->message_type == ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE) {
264         LOGD("ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE , %d %d\n", ev->data.l[0], gFHiddenState);
265         angle = ev->data.l[0];
266         ise_set_screen_direction(angle);
267         if (!gFHiddenState) {
268             ise_show(gLastIC);
269         }
270     } else if (ev->message_type == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE) {
271         LOGD("ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE , %d\n", ev->data.l[0]);
272         elm_win_keyboard_mode_set(main_window, (Elm_Win_Keyboard_Mode)(ev->data.l[0]));
273         gFHiddenState = !(ev->data.l[0]);
274     }
275 #endif
276
277     if (ev->message_type == ECORE_X_ATOM_E_WINDOW_ROTATION_CHANGE_REQUEST) {
278         if (ev->win == elm_win_xwindow_get(main_window)) {
279             int degree = ev->data.l[1];
280             CSCLCoreUIEFL *coreui = static_cast<CSCLCoreUIEFL*>(data);
281             if (coreui) {
282                 coreui->set_screen_rotation_degree(degree);
283             }
284             LOGD("_ECORE_X_ATOM_E_WINDOW_ROTATION_REQUEST, %d\n", degree);
285             if (callback) {
286                 callback->on_set_rotation_degree(degree);
287             }
288             Ecore_X_Window control_window = 0;
289             Ecore_X_Atom atom = ecore_x_atom_get("_ISF_CONTROL_WINDOW");
290             Ecore_X_Window root = ecore_x_window_root_first_get();
291             if (ecore_x_window_prop_xid_get(root, atom, ECORE_X_ATOM_WINDOW, &control_window, 1) == 1) {
292                 ecore_x_client_message32_send(control_window, ECORE_X_ATOM_E_WINDOW_ROTATION_CHANGE_REQUEST,
293                     ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
294                     ev->data.l[0], ev->data.l[1], ev->data.l[2], ev->data.l[3], ev->data.l[4]);
295             }
296         }
297     }
298
299     return ECORE_CALLBACK_RENEW;
300 }
301 #endif
302
303 int CSCLCoreUIEFL::get_screen_rotation_degree()
304 {
305     int angle = 0;
306
307 #ifdef WAYLAND
308     if (m_rotation_degree == -1) {
309         m_rotation_degree = elm_win_rotation_get(NATIVE_WINDOW_CAST(m_main_window));
310     }
311     LOGD("m_rotation_degree : %d", m_rotation_degree);
312     angle = m_rotation_degree;
313 #else
314     if (m_rotation_degree == -1) {
315         int  ret = 0;
316         Atom type_return;
317         int  format_return;
318         unsigned long    nitems_return;
319         unsigned long    bytes_after_return;
320         unsigned char   *data_window = NULL;
321         unsigned char   *data_angle = NULL;
322
323         Ecore_X_Window app_window = 0;
324
325         Evas_Object *keypad_win = NATIVE_WINDOW_CAST(m_main_window);
326
327         LOGD("Trying to get app window degree for %p\n", keypad_win);
328         Ecore_X_Window win = elm_win_xwindow_get(NATIVE_WINDOW_CAST(keypad_win));
329         ret = XGetWindowProperty((Display *)ecore_x_display_get(),
330             ecore_x_window_root_get(win),
331             ecore_x_atom_get("_ISF_ACTIVE_WINDOW"),
332             0, G_MAXLONG, False, XA_WINDOW, &type_return,
333             &format_return, &nitems_return, &bytes_after_return,
334             &data_window);
335
336         if (ret == Success) {
337             if ((type_return == XA_WINDOW) && (format_return == 32) && (data_window)) {
338                 app_window = *(Window *)data_window;
339
340                 ret = XGetWindowProperty((Display *)ecore_x_display_get(), app_window,
341                     ecore_x_atom_get("_E_ILLUME_ROTATE_WINDOW_ANGLE"),
342                     0, G_MAXLONG, False, XA_CARDINAL, &type_return,
343                     &format_return, &nitems_return, &bytes_after_return,
344                     &data_angle);
345
346                 LOGD("app_window : %p, ret %d, %d, %p\n", app_window, ret, type_return, data_angle);
347                 if (ret == Success) {
348                     if (data_angle) {
349                         if (type_return == XA_CARDINAL) {
350                             angle = *(unsigned int*)data_angle;
351                             LOGD("current rotation angle is %p %d\n", app_window, angle);
352                         }
353                         XFree(data_angle);
354                     }
355                 }
356             }
357             if (data_window)
358                 XFree(data_window);
359         }
360     } else {
361         angle = m_rotation_degree;
362     }
363 #endif
364
365     return angle;
366 }
367
368 static void signal_handler(int sig) {
369     elm_exit();
370 }
371
372 #ifdef WAYLAND
373 static bool
374 _wayland_setup(struct WaylandKeyboard *wlkb, Evas_Object *main_window)
375 {
376     Eina_Iterator *globals;
377     struct wl_registry *registry;
378     Ecore_Wl2_Global *global;
379     Ecore_Wl2_Display *ewd;
380
381     if (!(ewd = ecore_wl2_connected_display_get(NULL)))
382         return false;
383
384     if (!(registry = ecore_wl2_display_registry_get(ewd)))
385         return false;
386
387     if (!(globals = ecore_wl2_display_globals_get(ewd)))
388         return false;
389
390     EINA_ITERATOR_FOREACH(globals, global)
391     {
392         if (strcmp(global->interface, "wl_input_panel") == 0)
393             wlkb->ip = (wl_input_panel *)wl_registry_bind(registry, global->id, &wl_input_panel_interface, 1);
394         else if (strcmp(global->interface, "wl_output") == 0)
395             wlkb->output = (wl_output *)wl_registry_bind(registry, global->id, &wl_output_interface, 1);
396     }
397
398     if (!wlkb->ip) {
399         LOGW("Can't get wayland input panel interface\n");
400         return false;
401     }
402
403     if (!wlkb->output) {
404         LOGW("Can't get wayland output interface\n");
405         return false;
406     }
407
408     wlkb->ee = ecore_evas_ecore_evas_get(evas_object_evas_get(main_window));
409     if (!wlkb->ee) {
410         LOGW("ERROR: Unable to create Ecore_Evas object\n");
411         return false;
412     }
413
414     /* Set input panel surface */
415     LOGD("Setting up input panel\n");
416     wlkb->wl_win = ecore_evas_wayland2_window_get(wlkb->ee);
417     if (!wlkb->wl_win) {
418         LOGW("Couldn't get wayland window\n");
419         return false;
420     }
421
422     ecore_wl2_window_type_set(wlkb->wl_win, ECORE_WL2_WINDOW_TYPE_NONE);
423     Ecore_Wl2_Surface *surface = ecore_wl2_surface_create(wlkb->wl_win, EINA_TRUE);
424     if (!surface) {
425         LOGW("Couldn't create surface\n");
426         return false;
427     }
428
429     wlkb->surface = ecore_wl2_window_surface_get(wlkb->wl_win);
430     if (!wlkb->surface) {
431         LOGW("Couldn't get surface\n");
432         return false;
433     }
434
435     wlkb->ips = wl_input_panel_get_input_panel_surface(wlkb->ip, wlkb->surface);
436     if (!wlkb->ips) {
437         LOGW("Couldn't get input panel surface\n");
438         return false;
439     }
440
441     wl_input_panel_surface_set_toplevel(wlkb->ips, wlkb->output, WL_INPUT_PANEL_SURFACE_POSITION_CENTER_BOTTOM);
442
443     return true;
444 }
445 #endif
446
447 sclboolean CSCLCoreUIEFL::create_main_window()
448 {
449     elm_config_accel_preference_set("3d");
450     elm_policy_set(ELM_POLICY_THROTTLE, ELM_POLICY_THROTTLE_NEVER);
451
452     Evas_Object *main_window = elm_win_add(NULL, m_appid, ELM_WIN_UTILITY);
453     if (!main_window) {
454         LOGE("Failed to create main window\n");
455         return FALSE;
456     }
457
458     m_main_window = SCL_WINDOW_CAST(main_window);
459
460 #ifdef WAYLAND
461     if (!_wayland_setup(&wlkb, main_window)) {
462         LOGW("ERROR: Unable to setup input panel.\n");
463         return FALSE;
464     }
465 #endif
466
467     elm_win_borderless_set(main_window, EINA_TRUE);
468     elm_win_keyboard_win_set(main_window, EINA_TRUE);
469     elm_win_autodel_set(main_window, EINA_TRUE);
470     elm_win_title_set(main_window, m_appid);
471     elm_atspi_accessible_name_set(main_window, "Keyboard");
472     elm_atspi_accessible_role_set(main_window, ELM_ATSPI_ROLE_INPUT_METHOD_WINDOW);
473     elm_win_prop_focus_skip_set(main_window, EINA_TRUE);
474     int rots[] = { 0, 90, 180, 270 };
475     elm_win_wm_rotation_available_rotations_set(main_window, rots, (sizeof(rots) / sizeof(int)));
476
477 #ifndef WAYLAND
478     unsigned int set = 1;
479     ecore_x_window_prop_card32_set(elm_win_xwindow_get(main_window),
480         ECORE_X_ATOM_E_WINDOW_ROTATION_SUPPORTED,
481         &set, 1);
482
483     ecore_x_icccm_name_class_set(elm_win_xwindow_get(main_window), "Virtual Keyboard", "ISF");
484 #else
485     evas_object_show(main_window);
486 #endif
487
488     Evas_Coord win_w = 0, win_h = 0;
489     elm_win_screen_size_get(main_window, NULL, NULL, &win_w, &win_h);
490     SclSize portrait;
491     portrait.width = win_w;
492     portrait.height = win_h / 3;
493     SclSize landscape;
494     landscape.width = win_h;
495     landscape.height = win_w / 3;
496     set_keyboard_size_hints(portrait, landscape);
497
498 #ifdef WAYLAND
499     appcore_set_event_callback(APPCORE_EVENT_LANG_CHANGE, language_changed_cb, NULL);
500
501     vconf_notify_key_changed(VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, accessibility_changed_cb, NULL);
502
503     evas_object_smart_callback_add(main_window, "wm,rotation,changed", win_rotation_changed_cb, this);
504     evas_object_show(main_window);
505 #else
506     Ecore_Event_Handler *XClientMsgHandler =
507         ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE, _client_message_cb, this);
508 #endif
509     return TRUE;
510 }
511
512 int CSCLCoreUIEFL::create(void *data)
513 {
514     LOGD("");
515
516     CSCLCoreImpl *impl = CSCLCoreImpl::get_instance();
517     if (impl) {
518         if (!impl->prepare()) {
519             appcore_efl_fini();
520             return -1;
521         }
522     }
523
524     /* Should we call these callback functions here? */
525     language_changed_cb(NULL, NULL);
526     accessibility_changed_cb(NULL, NULL);
527
528     signal(SIGQUIT, signal_handler);
529     signal(SIGTERM, signal_handler);
530     signal(SIGINT,  signal_handler);
531     signal(SIGHUP,  signal_handler);
532
533     return 0;
534 }
535
536 int CSCLCoreUIEFL::terminate(void *data)
537 {
538     CSCLCoreImpl *impl = CSCLCoreImpl::get_instance();
539     if (impl)
540         impl->fini();
541
542 #ifndef WAYLAND
543     if (XClientMsgHandler) {
544         ecore_event_handler_del(XClientMsgHandler);
545         XClientMsgHandler = NULL;
546     }
547 #endif
548
549     return 0;
550 }
551
552 static int app_create_cb(void *data)
553 {
554     LOGD("app_create_cb() is called");
555     CSCLCoreUIEFL *sclui = static_cast<CSCLCoreUIEFL *>(data);
556     if (sclui) {
557         int ret = sclui->create(data);
558         elm_cache_all_flush();
559         malloc_trim(0);
560         return ret;
561     }
562
563     return -1;
564 }
565
566 static int app_terminate_cb(void *data)
567 {
568     CSCLCoreUIEFL *sclui = static_cast<CSCLCoreUIEFL *>(data);
569     if (sclui)
570         return sclui->terminate(data);
571
572     return -1;
573 }
574
575 void CSCLCoreUIEFL::run(const sclchar *display)
576 {
577     char **argv = new char*[4];
578     int argc = 3;
579     const sclchar *appid = NULL;
580
581     ops.create = app_create_cb;
582     ops.terminate = app_terminate_cb;
583     ops.resume = NULL;
584     ops.pause = NULL;
585     ops.reset = NULL;
586     ops.data = this;
587
588     CSCLCoreImpl *impl = CSCLCoreImpl::get_instance();
589     if (impl) {
590         appid = impl->get_uuid();
591     }
592
593     if (!appid)
594         appid = "";
595
596     m_appid = appid;
597     m_display = display;
598
599     argv[0] = const_cast<char *> (appid);
600     argv[1] = (char *)"--display";
601     argv[2] = const_cast<char *> (display);
602     argv[3] = 0;
603
604     LOGD("name : %s\n", appid);
605
606 #ifdef WEBSOCKET
607     if (g_websocket.initialized()) {
608         g_websocket.run();
609     }
610 #endif
611
612     appcore_efl_main(appid, &argc, (char ***)&argv, &ops);
613
614     delete [] argv;
615 }
616
617 static void focus_out_cb(void *data, Evas *e, void *event)
618 {
619     OptionWindowInfo *info = static_cast<OptionWindowInfo*>(data);
620     if (info) {
621         if (info->window) {
622             CSCLCoreImpl *impl = CSCLCoreImpl::get_instance();
623             if (impl) {
624                 ISCLCoreEventCallback *callback = impl->get_core_event_callback();
625                 if (callback) {
626                     callback->on_destroy_option_window(info->window);
627                 }
628             }
629
630             evas_object_hide(NATIVE_WINDOW_CAST(info->window));
631             evas_object_del(NATIVE_WINDOW_CAST(info->window));
632             info->window = NULL;
633         }
634     }
635 }
636
637 static void
638 set_transient_for_app_window(Evas_Object *window)
639 {
640     /* Set a transient window for window stack */
641     /* Gets the current XID of the active window into the root window property  */
642 #ifndef WAYLAND
643     Atom type_return;
644     unsigned long nitems_return;
645     unsigned long bytes_after_return;
646     int format_return;
647     unsigned char *data = NULL;
648     Ecore_X_Window xAppWindow;
649     Ecore_X_Window xWindow = elm_win_xwindow_get(window);
650     gint ret = 0;
651
652     ret = XGetWindowProperty((Display *)ecore_x_display_get(), ecore_x_window_root_get(xWindow),
653         ecore_x_atom_get("_ISF_ACTIVE_WINDOW"),
654         0, G_MAXLONG, False, XA_WINDOW, &type_return,
655         &format_return, &nitems_return, &bytes_after_return,
656         &data);
657
658     if (ret == Success) {
659         if (data) {
660             if (type_return == XA_WINDOW) {
661                 xAppWindow = *(Window *)data;
662                 LOGD("TRANSIENT_FOR SET : %x , %x\n", xAppWindow, xWindow);
663                 ecore_x_icccm_transient_for_set(xWindow, xAppWindow);
664             }
665             XFree(data);
666         }
667     }
668 #endif
669 }
670
671 static void
672 set_transient_for_isf_setting_window(Evas_Object *window)
673 {
674     /* Set a transient window for window stack */
675     /* Gets the current XID of the active window into the root window property  */
676 #ifndef WAYLAND
677     Atom type_return;
678     unsigned long nitems_return;
679     unsigned long bytes_after_return;
680     int format_return;
681     unsigned char *data = NULL;
682     Ecore_X_Window xControlWindow, xSettingWindow;
683     Ecore_X_Window xWindow = elm_win_xwindow_get(window);
684     gint ret = 0;
685
686     ret = XGetWindowProperty((Display *)ecore_x_display_get(), ecore_x_window_root_get(xWindow),
687         ecore_x_atom_get("_ISF_CONTROL_WINDOW"),
688         0, G_MAXLONG, False, XA_WINDOW, &type_return,
689         &format_return, &nitems_return, &bytes_after_return,
690         &data);
691
692     if (ret == Success) {
693         if (data) {
694             if (type_return == XA_WINDOW) {
695                 xControlWindow = *(Window *)data;
696
697                 ecore_x_window_prop_xid_get(xControlWindow, ecore_x_atom_get("ISF Setting window"),
698                     ECORE_X_ATOM_WINDOW, &xSettingWindow, 1);
699
700                 LOGD("TRANSIENT_FOR SET : %x , %x\n", xSettingWindow, xWindow);
701                 ecore_x_icccm_transient_for_set(xWindow, xSettingWindow);
702             }
703             XFree(data);
704         }
705     }
706 #endif
707 }
708
709 sclwindow CSCLCoreUIEFL::create_option_window(SCLOptionWindowType type)
710 {
711     if (type >= OPTION_WINDOW_TYPE_MAX) {
712         return SCLWINDOW_INVALID;
713     }
714
715     ISCLCoreEventCallback *callback = NULL;
716     CSCLCoreImpl *impl = CSCLCoreImpl::get_instance();
717     if (impl) {
718         callback = impl->get_core_event_callback();
719         if (callback) {
720             sclboolean ret = false;
721             callback->on_check_option_window_availability(&ret);
722             if (ret == false) {
723                 LOGW("option_window not available\n");
724                 return SCLWINDOW_INVALID;
725             }
726         } else {
727             return SCLWINDOW_INVALID;
728         }
729     }
730
731     /* Just in case the previous option window for setting application exists */
732     if (type == OPTION_WINDOW_TYPE_SETTING_APPLICATION) {
733         if (m_option_window_info[type].window != SCLWINDOW_INVALID) {
734             destroy_option_window(m_option_window_info[type].window);
735         }
736     }
737
738     Evas_Object *window, *bg;
739
740     window = elm_win_add(NATIVE_WINDOW_CAST(m_main_window), "Option window", ELM_WIN_BASIC);
741     if (!window) return NULL;
742
743     elm_win_title_set(window, "Option window");
744     bg = elm_bg_add(window);
745     if (!bg) {
746         evas_object_del(window);
747         return NULL;
748     }
749
750     evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
751     elm_win_resize_object_add(window, bg);
752     evas_object_show(bg);
753
754 #ifndef WAYLAND
755     Evas_Coord win_w = 0, win_h = 0;
756     elm_win_screen_size_get(window, NULL, NULL, &win_w, &win_h);
757     int degree = get_screen_rotation_degree();
758     if (degree == 90 || degree == 270) {
759         evas_object_resize(window, win_h, win_w);
760     } else {
761         evas_object_resize(window, win_w, win_h);
762     }
763 #endif
764
765     int rots[] = { 0, 90, 180, 270 };
766     elm_win_wm_rotation_available_rotations_set(window, rots, (sizeof(rots) / sizeof(int)));
767
768     elm_win_indicator_mode_set(window, ELM_WIN_INDICATOR_SHOW);
769
770     if (callback) {
771         callback->on_create_option_window(window, type);
772     }
773
774     if (type == OPTION_WINDOW_TYPE_NORMAL) {
775         Evas *evas = evas_object_evas_get(window);
776         evas_event_callback_add(evas, EVAS_CALLBACK_CANVAS_FOCUS_OUT, focus_out_cb, &m_option_window_info[type]);
777         set_transient_for_app_window(window);
778     } else if (type == OPTION_WINDOW_TYPE_SETTING_APPLICATION) {
779         set_transient_for_isf_setting_window(window);
780     }
781
782     m_option_window_info[type].window = window;
783
784     return window;
785 }
786
787 bool CSCLCoreUIEFL::show_option_window(SCLOptionWindowType type)
788 {
789     if (type >= OPTION_WINDOW_TYPE_MAX) {
790         return SCLWINDOW_INVALID;
791     }
792
793     ISCLCoreEventCallback *callback = NULL;
794     CSCLCoreImpl *impl = CSCLCoreImpl::get_instance();
795     if (impl) {
796         callback = impl->get_core_event_callback();
797         if (callback) {
798             sclboolean ret = false;
799             callback->on_check_option_window_availability(&ret);
800             if (ret == false) {
801                 LOGW("option_window not available\n");
802                 return false;
803             }
804         } else {
805             return false;
806         }
807     }
808
809     if (m_option_window_info[type].window != SCLWINDOW_INVALID) {
810         evas_object_show(static_cast<Evas_Object*>(m_option_window_info[type].window));
811         elm_win_raise(static_cast<Evas_Object*>(m_option_window_info[type].window));
812         return true;
813     }
814
815     return false;
816 }
817
818 void CSCLCoreUIEFL::destroy_option_window(sclwindow window)
819 {
820     CSCLCoreImpl *impl = CSCLCoreImpl::get_instance();
821     if (impl) {
822         ISCLCoreEventCallback *callback = impl->get_core_event_callback();
823         if (callback) {
824             callback->on_destroy_option_window(window);
825         }
826     }
827
828     for (int loop = 0;loop < OPTION_WINDOW_TYPE_MAX;loop++) {
829         if (m_option_window_info[loop].window == window) {
830             evas_object_del(NATIVE_WINDOW_CAST(window));
831             m_option_window_info[loop].window = SCLWINDOW_INVALID;
832         }
833     }
834 }
835
836 void CSCLCoreUIEFL::set_screen_rotation_degree(int degree)
837 {
838     m_rotation_degree = degree;
839
840     ISCLCoreEventCallback *callback = NULL;
841     CSCLCoreImpl *impl = CSCLCoreImpl::get_instance();
842     if (impl) {
843         callback = impl->get_core_event_callback();
844     }
845     if (callback) {
846         callback->on_set_rotation_degree(degree);
847     }
848
849     LOGD("rotation value set : %d", degree);
850 }
851
852 #ifdef WAYLAND
853 static void _render_pre_cb(void *data, Evas *e, void *event_info)
854 {
855     LOGD("_render_pre_cb() called, now invoking wl_input_panel_surface_set_ready()");
856
857     wl_input_panel_surface_set_ready(wlkb.ips, 1);
858
859     Evas_Object *main_window = NATIVE_WINDOW_CAST(data);
860     evas_event_callback_del_full(evas_object_evas_get(main_window),
861         EVAS_CALLBACK_RENDER_PRE, _render_pre_cb, main_window);
862
863     delete_render_pre_timer();
864 }
865
866 static Eina_Bool _render_pre_timeout(void *data)
867 {
868     LOGD("_render_pre_timer expired, forcing to call _render_pre_cb() callback");
869
870     _render_pre_cb(data, NULL, NULL);
871
872     return ECORE_CALLBACK_CANCEL;
873 }
874 #endif
875
876 void CSCLCoreUIEFL::process_keyboard_ui_state_change(KEYBOARD_UI_STATE state)
877 {
878 #ifdef WAYLAND
879     if (state == KEYBOARD_UI_STATE_WILL_SHOW) {
880         evas_event_callback_add(evas_object_evas_get(NATIVE_WINDOW_CAST(m_main_window)),
881             EVAS_CALLBACK_RENDER_PRE, _render_pre_cb, (void*)m_main_window);
882         _render_pre_timer = ecore_timer_add(RENDER_PRE_TIMEOUT, _render_pre_timeout, (void*)m_main_window);
883         LOGD("Registered RENDER_PRE callback, _render_pre_cb() and a timer callback");
884     } else if (state == KEYBOARD_UI_STATE_DID_SHOW) {
885         LOGD("Forcing keyboard window to render");
886         evas_render(evas_object_evas_get(NATIVE_WINDOW_CAST(m_main_window)));
887     }
888 #endif
889 }