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