2 * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include "sclcoreui-efl.h"
19 #include "sclcoreimpl.h"
20 #include <Elementary.h>
24 #include <vconf-keys.h>
28 #include <Ecore_Wayland.h>
29 #include <input-method-client-protocol.h>
33 #include <X11/Xatom.h>
37 struct WaylandKeyboard
40 Ecore_Wl_Window *wl_win;
41 const char *ee_engine;
43 struct wl_surface *surface;
44 struct wl_input_panel *ip;
45 struct wl_output *output;
48 struct WaylandKeyboard wlkb = {0};
54 CSCLCoreUIEFL::CSCLCoreUIEFL()
56 m_initialized = FALSE;
58 m_backend_identifier = "EFL";
61 CSCLCoreUIEFL::~CSCLCoreUIEFL()
65 sclboolean CSCLCoreUIEFL::init()
68 m_rotation_degree = -1;
70 for (int loop = 0;loop < OPTION_WINDOW_TYPE_MAX;loop++) {
71 m_option_window_info[loop].window = SCLWINDOW_INVALID;
72 m_option_window_info[loop].handler = NULL;
78 void CSCLCoreUIEFL::fini()
80 m_initialized = FALSE;
83 sclwindow CSCLCoreUIEFL::get_main_window()
92 void CSCLCoreUIEFL::set_keyboard_size_hints(SclSize portrait, SclSize landscape)
94 Evas_Object *main_window = NATIVE_WINDOW_CAST(m_main_window);
97 ecore_wl_window_rotation_geometry_set(elm_win_wl_window_get(main_window), 0, 0, 0, portrait.width, portrait.height);
98 ecore_wl_window_rotation_geometry_set(elm_win_wl_window_get(main_window), 90, 0, 0, landscape.height, landscape.width);
99 ecore_wl_window_rotation_geometry_set(elm_win_wl_window_get(main_window), 180, 0, 0, portrait.width, portrait.height);
100 ecore_wl_window_rotation_geometry_set(elm_win_wl_window_get(main_window), 270, 0, 0, landscape.height, landscape.width);
103 ecore_x_e_window_rotation_geometry_set(elm_win_xwindow_get(main_window), 0, 0, 0, portrait.width, portrait.height);
104 ecore_x_e_window_rotation_geometry_set(elm_win_xwindow_get(main_window), 90, 0, 0, landscape.height, landscape.width);
105 ecore_x_e_window_rotation_geometry_set(elm_win_xwindow_get(main_window), 180, 0, 0, portrait.width, portrait.height);
106 ecore_x_e_window_rotation_geometry_set(elm_win_xwindow_get(main_window), 270, 0, 0, landscape.height, landscape.width);
111 const char * extract_themename_from_theme_file_path(const char *filepath) {
112 static char themename[_POSIX_PATH_MAX] = {0};
113 memset(themename, 0x00, sizeof(themename));
116 /* There could be more than 1 theme filepath, separated by : */
117 char pathstr[_POSIX_PATH_MAX] = {0};
118 strncpy(pathstr, filepath, _POSIX_PATH_MAX - 1);
119 for (int loop = 0;loop < _POSIX_PATH_MAX;loop++) {
120 if (pathstr[loop] == ':') {
121 /* FIXME : Let's consider the 1st theme filepath only for now */
122 pathstr[loop] = '\0';
127 const char *filename = ecore_file_file_get(pathstr);
129 char *stripname = ecore_file_strip_ext(filename);
131 strncpy(themename, stripname, _POSIX_PATH_MAX - 1);
141 static void language_changed_cb(keynode_t *key, void* data)
143 char clang[_POSIX_PATH_MAX] = {0};
144 char *vconf_str = vconf_get_str(VCONFKEY_LANGSET);
146 snprintf(clang, sizeof(clang), "%s", vconf_str);
149 LOGD("current language is %s\n", clang);
151 CSCLCoreImpl *impl = CSCLCoreImpl::get_instance();
153 ISCLCoreEventCallback *callback = impl->get_core_event_callback();
155 callback->on_set_display_language(clang);
160 static void accessibility_changed_cb(keynode_t *key, void* data)
163 if (vconf_get_bool(VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, &vconf_value) == 0) {
164 LOGD("accessibility state : %d\n", vconf_value);
166 CSCLCoreImpl *impl = CSCLCoreImpl::get_instance();
168 ISCLCoreEventCallback *callback = impl->get_core_event_callback();
170 callback->on_set_accessibility_state(vconf_value);
177 static void win_rotation_changed_cb(void *data, Evas_Object *obj, void *event)
179 int degree = elm_win_rotation_get(obj);
180 LOGD("rotation angle : %d\n", degree);
182 ISCLCoreEventCallback *callback = NULL;
183 CSCLCoreImpl *impl = CSCLCoreImpl::get_instance();
185 callback = impl->get_core_event_callback();
188 CSCLCoreUIEFL *coreui = static_cast<CSCLCoreUIEFL*>(data);
190 coreui->set_screen_rotation_degree(degree);
193 callback->on_set_rotation_degree(degree);
197 static Eina_Bool _client_message_cb(void *data, int type, void *event)
199 Ecore_X_Event_Client_Message *ev = (Ecore_X_Event_Client_Message *)event;
201 ISCLCoreEventCallback *callback = NULL;
202 CSCLCoreImpl *impl = CSCLCoreImpl::get_instance();
203 Evas_Object *main_window = NULL;
205 callback = impl->get_core_event_callback();
206 main_window = NATIVE_WINDOW_CAST(impl->get_main_window());
209 #ifndef APPLY_WINDOW_MANAGER_CHANGE
211 if (ev->message_type == ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE) {
212 LOGD("ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE , %d %d\n", ev->data.l[0], gFHiddenState);
213 angle = ev->data.l[0];
214 ise_set_screen_direction(angle);
215 if (!gFHiddenState) {
218 } else if (ev->message_type == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE) {
219 LOGD("ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE , %d\n", ev->data.l[0]);
220 elm_win_keyboard_mode_set(main_window, (Elm_Win_Keyboard_Mode)(ev->data.l[0]));
221 gFHiddenState = !(ev->data.l[0]);
225 if (ev->message_type == ECORE_X_ATOM_E_WINDOW_ROTATION_CHANGE_REQUEST) {
226 if (ev->win == elm_win_xwindow_get(main_window)) {
227 int degree = ev->data.l[1];
228 CSCLCoreUIEFL *coreui = static_cast<CSCLCoreUIEFL*>(data);
230 coreui->set_screen_rotation_degree(degree);
232 LOGD("_ECORE_X_ATOM_E_WINDOW_ROTATION_REQUEST, %d\n", degree);
234 callback->on_set_rotation_degree(degree);
236 Ecore_X_Window control_window = 0;
237 Ecore_X_Atom atom = ecore_x_atom_get("_ISF_CONTROL_WINDOW");
238 Ecore_X_Window root = ecore_x_window_root_first_get();
239 if (ecore_x_window_prop_xid_get(root, atom, ECORE_X_ATOM_WINDOW, &control_window, 1) == 1) {
240 ecore_x_client_message32_send(control_window, ECORE_X_ATOM_E_WINDOW_ROTATION_CHANGE_REQUEST,
241 ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
242 ev->data.l[0], ev->data.l[1], ev->data.l[2], ev->data.l[3], ev->data.l[4]);
247 return ECORE_CALLBACK_RENEW;
251 int CSCLCoreUIEFL::get_screen_rotation_degree()
256 angle = elm_win_rotation_get(NATIVE_WINDOW_CAST(m_main_window));
258 if (m_rotation_degree == -1) {
262 unsigned long nitems_return;
263 unsigned long bytes_after_return;
264 unsigned char *data_window = NULL;
265 unsigned char *data_angle = NULL;
267 Ecore_X_Window app_window = 0;
269 Evas_Object *keypad_win = NATIVE_WINDOW_CAST(m_main_window);
271 LOGD("Trying to get app window degree for %p\n", keypad_win);
272 Ecore_X_Window win = elm_win_xwindow_get(NATIVE_WINDOW_CAST(keypad_win));
273 ret = XGetWindowProperty((Display *)ecore_x_display_get(),
274 ecore_x_window_root_get(win),
275 ecore_x_atom_get("_ISF_ACTIVE_WINDOW"),
276 0, G_MAXLONG, False, XA_WINDOW, &type_return,
277 &format_return, &nitems_return, &bytes_after_return,
280 if (ret == Success) {
281 if ((type_return == XA_WINDOW) && (format_return == 32) && (data_window)) {
282 app_window = *(Window *)data_window;
284 ret = XGetWindowProperty((Display *)ecore_x_display_get(), app_window,
285 ecore_x_atom_get("_E_ILLUME_ROTATE_WINDOW_ANGLE"),
286 0, G_MAXLONG, False, XA_CARDINAL, &type_return,
287 &format_return, &nitems_return, &bytes_after_return,
290 LOGD("app_window : %p, ret %d, %d, %p\n", app_window, ret, type_return, data_angle);
291 if (ret == Success) {
293 if (type_return == XA_CARDINAL) {
294 angle = *(unsigned int*)data_angle;
295 LOGD("current rotation angle is %p %d\n", app_window, angle);
305 angle = m_rotation_degree;
312 void signal_handler(int sig) {
318 _wayland_setup(struct WaylandKeyboard *wlkb, Evas_Object *main_window)
320 Eina_Inlist *globals;
321 struct wl_registry *registry;
322 Ecore_Wl_Global *global;
323 struct wl_input_panel_surface *ips;
325 if (!(registry = ecore_wl_registry_get()))
328 if (!(globals = ecore_wl_globals_get()))
331 EINA_INLIST_FOREACH(globals, global)
333 if (strcmp(global->interface, "wl_input_panel") == 0)
334 wlkb->ip = (wl_input_panel *)wl_registry_bind(registry, global->id, &wl_input_panel_interface, 1);
335 else if (strcmp(global->interface, "wl_output") == 0)
336 wlkb->output = (wl_output *)wl_registry_bind(registry, global->id, &wl_output_interface, 1);
340 LOGW("Can't get wayland input panel interface\n");
345 LOGW("Can't get wayland output interface\n");
349 wlkb->ee = ecore_evas_ecore_evas_get(evas_object_evas_get(main_window));
351 LOGW("ERROR: Unable to create Ecore_Evas object");
355 /* Set input panel surface */
356 LOGD("Setting up input panel\n");
357 wlkb->wl_win = ecore_evas_wayland_window_get(wlkb->ee);
359 LOGW("Couldn't get wayland window\n");
363 ecore_wl_window_type_set(wlkb->wl_win, ECORE_WL_WINDOW_TYPE_NONE);
364 wlkb->surface = ecore_wl_window_surface_create(wlkb->wl_win);
365 if (!wlkb->surface) {
366 LOGW("Couldn't create surface\n");
370 ips = wl_input_panel_get_input_panel_surface(wlkb->ip, wlkb->surface);
372 LOGW("Couldn't get input panel surface\n");
376 wl_input_panel_surface_set_toplevel(ips, wlkb->output, WL_INPUT_PANEL_SURFACE_POSITION_CENTER_BOTTOM);
382 check_evas_engine(struct WaylandKeyboard *wlkb)
384 Eina_Bool ret = EINA_FALSE;
385 const char *env = getenv("ECORE_EVAS_ENGINE");
388 if (ecore_evas_engine_type_supported_get(ECORE_EVAS_ENGINE_WAYLAND_SHM))
390 else if (ecore_evas_engine_type_supported_get(ECORE_EVAS_ENGINE_WAYLAND_EGL))
393 LOGW("ERROR: Ecore_Evas does must be compiled with support for Wayland engines\n");
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");
402 wlkb->ee_engine = env;
410 void CSCLCoreUIEFL::run(const sclchar *display)
415 CSCLCoreImpl *impl = CSCLCoreImpl::get_instance();
417 const sclchar *uuid = impl->get_uuid();
421 argv[0] = const_cast<char *> (uuid);
422 argv[1] = (char *)"--display";
423 argv[2] = const_cast<char *> (display);
426 elm_init(argc, argv);
429 if (!check_evas_engine(&wlkb)) {
430 LOGW("_wlkb_check_evas_engine error!\n");
434 LOGD("Selected engine: '%s'\n", wlkb.ee_engine);
437 elm_config_accel_preference_set("3d");
438 elm_policy_set(ELM_POLICY_THROTTLE, ELM_POLICY_THROTTLE_NEVER);
440 Evas_Object *main_window = elm_win_add(NULL, uuid, ELM_WIN_UTILITY);
442 LOGE("Failed to create main window\n");
446 m_main_window = SCL_WINDOW_CAST(main_window);
449 if (!_wayland_setup(&wlkb, main_window)) {
450 LOGW("ERROR: Unable to setup input panel.\n");
456 elm_win_borderless_set(main_window, EINA_TRUE);
457 elm_win_keyboard_win_set(main_window, EINA_TRUE);
458 elm_win_autodel_set(main_window, EINA_TRUE);
459 elm_win_title_set(main_window, uuid);
460 elm_win_prop_focus_skip_set(main_window, EINA_TRUE);
461 int rots[] = { 0, 90, 180, 270 };
462 elm_win_wm_rotation_available_rotations_set(main_window, rots, (sizeof(rots) / sizeof(int)));
465 unsigned int set = 1;
466 ecore_x_window_prop_card32_set(elm_win_xwindow_get(main_window),
467 ECORE_X_ATOM_E_WINDOW_ROTATION_SUPPORTED,
470 ecore_x_icccm_name_class_set(elm_win_xwindow_get(main_window), "Virtual Keyboard", "ISF");
473 vconf_notify_key_changed(VCONFKEY_LANGSET, language_changed_cb, NULL);
474 vconf_notify_key_changed(VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, accessibility_changed_cb, NULL);
476 /* Should we call these callback functions here? */
477 language_changed_cb(NULL, NULL);
478 accessibility_changed_cb(NULL, NULL);
483 evas_object_smart_callback_add(main_window, "wm,rotation,changed", win_rotation_changed_cb, this);
485 Ecore_Event_Handler *XClientMsgHandler =
486 ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE, _client_message_cb, this);
489 signal(SIGQUIT, signal_handler);
490 signal(SIGTERM, signal_handler);
491 signal(SIGINT, signal_handler);
492 signal(SIGHUP, signal_handler);
495 evas_object_show(main_window);
502 vconf_ignore_key_changed(VCONFKEY_LANGSET, language_changed_cb);
503 vconf_ignore_key_changed(VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, accessibility_changed_cb);
506 if (XClientMsgHandler) {
507 ecore_event_handler_del(XClientMsgHandler);
508 XClientMsgHandler = NULL;
516 static Eina_Bool focus_out_cb(void *data, int type, void *event)
518 OptionWindowInfo *info = static_cast<OptionWindowInfo*>(data);
521 CSCLCoreImpl *impl = CSCLCoreImpl::get_instance();
523 ISCLCoreEventCallback *callback = impl->get_core_event_callback();
525 callback->on_destroy_option_window(info->window);
529 evas_object_hide(NATIVE_WINDOW_CAST(info->window));
530 evas_object_del(NATIVE_WINDOW_CAST(info->window));
534 ecore_event_handler_del(info->handler);
535 info->handler = NULL;
539 return ECORE_CALLBACK_CANCEL;
543 set_transient_for_app_window(Evas_Object *window)
545 /* Set a transient window for window stack */
546 /* Gets the current XID of the active window into the root window property */
549 unsigned long nitems_return;
550 unsigned long bytes_after_return;
552 unsigned char *data = NULL;
553 Ecore_X_Window xAppWindow;
554 Ecore_X_Window xWindow = elm_win_xwindow_get(window);
557 ret = XGetWindowProperty((Display *)ecore_x_display_get(), ecore_x_window_root_get(xWindow),
558 ecore_x_atom_get("_ISF_ACTIVE_WINDOW"),
559 0, G_MAXLONG, False, XA_WINDOW, &type_return,
560 &format_return, &nitems_return, &bytes_after_return,
563 if (ret == Success) {
565 if (type_return == XA_WINDOW) {
566 xAppWindow = *(Window *)data;
567 LOGD("TRANSIENT_FOR SET : %x , %x", xAppWindow, xWindow);
568 ecore_x_icccm_transient_for_set(xWindow, xAppWindow);
577 set_transient_for_isf_setting_window(Evas_Object *window)
579 /* Set a transient window for window stack */
580 /* Gets the current XID of the active window into the root window property */
583 unsigned long nitems_return;
584 unsigned long bytes_after_return;
586 unsigned char *data = NULL;
587 Ecore_X_Window xControlWindow, xSettingWindow;
588 Ecore_X_Window xWindow = elm_win_xwindow_get(window);
591 ret = XGetWindowProperty((Display *)ecore_x_display_get(), ecore_x_window_root_get(xWindow),
592 ecore_x_atom_get("_ISF_CONTROL_WINDOW"),
593 0, G_MAXLONG, False, XA_WINDOW, &type_return,
594 &format_return, &nitems_return, &bytes_after_return,
597 if (ret == Success) {
599 if (type_return == XA_WINDOW) {
600 xControlWindow = *(Window *)data;
602 ecore_x_window_prop_xid_get(xControlWindow, ecore_x_atom_get("ISF Setting window"),
603 ECORE_X_ATOM_WINDOW, &xSettingWindow, 1);
605 LOGD("TRANSIENT_FOR SET : %x , %x", xSettingWindow, xWindow);
606 ecore_x_icccm_transient_for_set(xWindow, xSettingWindow);
614 sclwindow CSCLCoreUIEFL::create_option_window(SCLOptionWindowType type)
616 if (type < 0 || type >= OPTION_WINDOW_TYPE_MAX) {
617 return SCLWINDOW_INVALID;
620 ISCLCoreEventCallback *callback = NULL;
621 CSCLCoreImpl *impl = CSCLCoreImpl::get_instance();
623 callback = impl->get_core_event_callback();
625 sclboolean ret = false;
626 callback->on_check_option_window_availability(&ret);
628 LOGW("on_create_option_window() is not available");
629 return SCLWINDOW_INVALID;
633 return SCLWINDOW_INVALID;
636 /* Just in case the previous option window for setting application exists */
637 if (type == OPTION_WINDOW_TYPE_SETTING_APPLICATION) {
638 if (m_option_window_info[type].window != SCLWINDOW_INVALID) {
639 destroy_option_window(m_option_window_info[type].window);
643 Evas_Object *window = elm_win_util_standard_add("Option window", "Option window");
645 elm_win_borderless_set(window, EINA_TRUE);
647 Evas_Coord win_w = 0, win_h = 0;
648 elm_win_screen_size_get(window, NULL, NULL, &win_w, &win_h);
649 int degree = get_screen_rotation_degree();
650 if (degree == 90 || degree == 270) {
651 evas_object_resize(window, win_h, win_w);
653 evas_object_resize(window, win_w, win_h);
656 int rots[] = { 0, 90, 180, 270 };
657 elm_win_wm_rotation_available_rotations_set(window, rots, (sizeof(rots) / sizeof(int)));
659 elm_win_indicator_mode_set(window, ELM_WIN_INDICATOR_SHOW);
662 callback->on_create_option_window(window, type);
665 Ecore_Event_Handler *handler = NULL;
666 if (type == OPTION_WINDOW_TYPE_NORMAL) {
668 handler = ecore_event_handler_add(ECORE_WL_EVENT_FOCUS_OUT, focus_out_cb, &m_option_window_info[type]);
670 handler = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_FOCUS_OUT, focus_out_cb, &m_option_window_info[type]);
672 set_transient_for_app_window(window);
673 } else if (type == OPTION_WINDOW_TYPE_SETTING_APPLICATION) {
674 set_transient_for_isf_setting_window(window);
675 evas_object_show(window);
678 m_option_window_info[type].window = window;
679 m_option_window_info[type].handler = handler;
684 void CSCLCoreUIEFL::destroy_option_window(sclwindow window)
686 CSCLCoreImpl *impl = CSCLCoreImpl::get_instance();
688 ISCLCoreEventCallback *callback = impl->get_core_event_callback();
690 callback->on_destroy_option_window(window);
694 for (int loop = 0;loop < OPTION_WINDOW_TYPE_MAX;loop++) {
695 if (m_option_window_info[loop].window == window) {
696 evas_object_del(NATIVE_WINDOW_CAST(window));
697 m_option_window_info[loop].window = SCLWINDOW_INVALID;
698 if (m_option_window_info[loop].handler) {
699 ecore_event_handler_del(m_option_window_info[loop].handler);
700 m_option_window_info[loop].handler = NULL;
706 void CSCLCoreUIEFL::set_screen_rotation_degree(int degree)
708 m_rotation_degree = degree;