2 * ISF(Input Service Framework)
4 * ISF is based on SCIM 1.4.7 and extended for supporting more mobile fitable.
5 * Copyright (c) 2012-2015 Samsung Electronics Co., Ltd.
7 * Contact: Haifeng Deng <haifeng.deng@samsung.com>, Jihoon Kim <jihoon48.kim@samsung.com>
9 * This library is free software; you can redistribute it and/or modify it under
10 * the terms of the GNU Lesser General Public License as published by the
11 * Free Software Foundation; either version 2.1 of the License, or (at your option)
14 * This library is distributed in the hope that it will be useful, but WITHOUT ANY
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17 * License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software Foundation, Inc., 51
21 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 #define Uses_SCIM_CONFIG_PATH
26 #define Uses_SCIM_HELPER_MODULE
27 #define Uses_SCIM_PANEL_AGENT
28 #define Uses_SCIM_COMPOSE_KEY
29 #define Uses_SCIM_IMENGINE_MODULE
33 #include <sys/types.h>
35 #include <sys/times.h>
42 #include <Ecore_File.h>
44 #include "scim_private.h"
46 #include "scim_stl_map.h"
47 #if ISF_BUILD_CANDIDATE_UI
49 #include <Elementary.h>
52 #include <Ecore_Wayland.h>
53 #endif /* HAVE_ECOREWL */
56 #endif /* HAVE_ECOREX */
59 #include <X11/Xatom.h>
66 #endif /* HAVE_FEEDBACK */
67 #endif /* CANDIDATE */
70 #include <vconf-keys.h>
73 #ifdef HAVE_NOTIFICATION
74 #include <notification.h>
75 #include <notification_internal.h>
81 #include <bluetooth.h>
83 #ifdef HAVE_PKGMGR_INFO
84 #include <package_manager.h>
85 #include <pkgmgr-info.h>
87 #include <app_control.h>
90 #include "isf_panel_efl.h"
91 #include "isf_panel_utility.h"
92 #include "isf_query_utility.h"
94 #include "privilege_checker.h"
95 #include "remote_input.h"
96 #include "tizen_profile.h"
101 /////////////////////////////////////////////////////////////////////////////
102 // Declaration of macro.
103 /////////////////////////////////////////////////////////////////////////////
104 #define EFL_CANDIDATE_THEME1 (SCIM_DATADIR "/isf_candidate_theme1.edj")
106 #define ISF_CANDIDATE_TABLE 0
108 #define ISF_EFL_AUX 1
109 #define ISF_EFL_CANDIDATE_0 2
110 #define ISF_EFL_CANDIDATE_ITEMS 3
112 #define ISE_DEFAULT_HEIGHT_PORTRAIT 444
113 #define ISE_DEFAULT_HEIGHT_LANDSCAPE 316
115 #define ISF_CANDIDATE_DESTROY_DELAY 3
116 #define ISF_ISE_HIDE_DELAY 0.15
118 #define ISF_PREEDIT_BORDER 16
119 #define ISE_LAUNCH_TIMEOUT 2.0
121 #define ISF_POP_PLAY_ICON_FILE (SCIM_ICONDIR "/pop_play.png")
122 #define ISF_KEYBOARD_ICON_FILE (SCIM_ICONDIR "/noti_keyboard_connected.png")
123 #define ISF_ISE_SELECTOR_ICON_FILE "/noti_keyboard.png"
125 #define HOST_BUS_NAME "org.tizen.usb.host"
126 #define HOST_OBJECT_PATH "/Org/Tizen/Usb/Host"
127 #define HOST_INTERFACE_NAME "org.tizen.usb.host"
128 #define HOST_KEYBOARD_SIGNAL "usbkeyboard"
129 #define HOST_ADDED "added"
130 #define HOST_REMOVED "removed"
132 #define E_PROP_DEVICEMGR_INPUTWIN "DeviceMgr Input Window"
135 /////////////////////////////////////////////////////////////////////////////
136 // Declaration of external variables.
137 /////////////////////////////////////////////////////////////////////////////
138 extern MapStringVectorSizeT _groups;
139 extern std::vector<ImeInfoDB> _ime_info;
141 CommonLookupTable g_isf_candidate_table;
144 /////////////////////////////////////////////////////////////////////////////
145 // Declaration of internal data types.
146 /////////////////////////////////////////////////////////////////////////////
147 typedef enum _WINDOW_STATE {
148 WINDOW_STATE_HIDE = 0,
149 WINDOW_STATE_WILL_HIDE,
150 WINDOW_STATE_WILL_SHOW,
155 typedef struct NotiData
164 typedef std::vector < std::pair <String, uint32> > VectorPairStringUint32;
166 /////////////////////////////////////////////////////////////////////////////
167 // Declaration of internal functions.
168 /////////////////////////////////////////////////////////////////////////////
169 #if ISF_BUILD_CANDIDATE_UI
170 static Evas_Object *efl_create_window (const char *strWinName, const char *strEffect);
171 #endif /* CANDIDATE */
174 static void efl_set_transient_for_app_window (Ecore_X_Window window);
176 #if ISF_BUILD_CANDIDATE_UI
177 static int efl_get_app_window_angle (void);
178 #endif /* CANDIDATE */
179 static int efl_get_ise_window_angle (void);
180 #if ISF_BUILD_CANDIDATE_UI
182 static int efl_get_quickpanel_window_angle (void);
183 #endif /* HAVE_ECOREX */
185 static int ui_candidate_get_valid_height (void);
186 static void ui_candidate_hide (bool bForce, bool bSetVirtualKbd = true, bool will_hide = false);
187 static void ui_destroy_candidate_window (void);
188 static void ui_settle_candidate_window (void);
189 static void ui_candidate_show (bool bSetVirtualKbd = true);
190 static void ui_create_candidate_window (void);
191 static void update_table (int table_type, const LookupTable &table);
192 static void ui_candidate_window_close_button_cb (void *data, Evas *e, Evas_Object *button, void *event_info);
193 #endif /* CANDIDATE */
194 static void set_soft_candidate_geometry (int x, int y, int width, int height);
195 #if ISF_BUILD_CANDIDATE_UI
196 static void set_highlight_color (Evas_Object *item, uint32 nForeGround, uint32 nBackGround, bool bSetBack);
197 static void ui_tts_focus_rect_hide (void);
198 #endif /* CANDIDATE */
200 #if ISF_BUILD_CANDIDATE_UI
201 static Evas_Object *get_candidate (const String& str, Evas_Object *parent, int *total_width, uint32 ForeGround, uint32 BackGround, bool HighLight, bool SetBack, int item_num, int item);
202 static bool tokenize_tag (const String& str, struct image *image_data);
203 #endif /* CANDIDATE */
205 static void launch_default_soft_keyboard (keynode_t *key = NULL, void* data = NULL);
207 /* PanelAgent related functions */
208 static bool initialize_panel_agent (const ConfigPointer& config, const String &display, bool resident);
210 static void slot_focus_in (void);
211 static void slot_focus_out (void);
212 static void slot_expand_candidate (void);
213 static void slot_contract_candidate (void);
214 static void slot_set_candidate_style (int portrait_line, int mode);
215 static void slot_update_input_context (int type, int value);
216 static void slot_update_ise_geometry (int x, int y, int width, int height);
217 static void slot_update_spot_location (int x, int y, int top_y);
218 static void slot_update_factory_info (const PanelFactoryInfo &info);
219 static void slot_show_preedit_string (void);
220 static void slot_show_aux_string (void);
221 static void slot_show_candidate_table (void);
222 static void slot_hide_preedit_string (void);
223 static void slot_hide_aux_string (void);
224 static void slot_hide_candidate_table (void);
225 static void slot_update_preedit_string (const String &str, const AttributeList &attrs, int caret);
226 static void slot_update_preedit_caret (int caret);
227 static void slot_update_aux_string (const String &str, const AttributeList &attrs);
228 static void slot_update_candidate_table (const LookupTable &table);
229 static void slot_select_candidate (int index);
230 static void slot_set_active_ise (const String &uuid, bool changeDefault);
231 static bool slot_get_ise_list (std::vector<String> &list);
232 static bool slot_get_all_helper_ise_info (HELPER_ISE_INFO &info);
233 static void slot_set_has_option_helper_ise_info (const String &appid, bool has_option);
234 static void slot_set_enable_helper_ise_info (const String &appid, bool is_enabled);
235 static void slot_show_helper_ise_list (void);
236 static void slot_show_helper_ise_selector (void);
237 static bool slot_is_helper_ise_enabled (String appid, int &enabled);
238 static bool slot_get_ise_information (String uuid, String &name, String &language, int &type, int &option, String &module_name);
239 static bool slot_get_keyboard_ise_list (std::vector<String> &name_list);
240 static void slot_get_language_list (std::vector<String> &name);
241 static void slot_get_all_language (std::vector<String> &lang);
242 static void slot_get_ise_language (char *name, std::vector<String> &list);
243 static bool slot_get_ise_info (const String &uuid, ISE_INFO &info);
244 static void slot_get_candidate_geometry (struct rectinfo &info);
245 static void slot_get_input_panel_geometry (struct rectinfo &info);
246 static void slot_get_recent_ise_geometry (int angle, struct rectinfo &info);
247 static bool slot_check_privilege_by_sockfd (int client_id, String privilege);
248 static void slot_set_keyboard_ise (const String &uuid);
249 static void slot_get_keyboard_ise (String &ise_name, String &ise_uuid);
250 static void slot_accept_connection (int fd);
251 static void slot_close_connection (int fd);
252 static void slot_exit (void);
254 static void slot_register_helper (int id, const HelperInfo& info);
255 static void slot_register_helper_properties (int id, const PropertyList &props);
256 static void slot_show_ise (void);
257 static void slot_hide_ise (void);
259 static void slot_will_hide_ack (void);
260 static void slot_candidate_will_hide_ack (void);
262 static void slot_set_keyboard_mode (int mode);
263 static void slot_get_ise_state (int &state);
264 static void slot_start_default_ise (void);
265 static void slot_stop_default_ise (bool is_exist);
266 static void slot_run_helper (const String &uuid, const String &config, const String &display);
267 static bool slot_launch_option_application (String ime_appid);
269 #if ENABLE_REMOTE_INPUT
270 static void slot_send_remote_input_message (const String &msg, bool len);
271 static void slot_recv_remote_surrounding_text (int cursor, const String &text);
275 static Eina_Bool efl_create_control_window (void);
276 static Ecore_X_Window efl_get_app_window (void);
277 static Ecore_X_Window efl_get_quickpanel_window (void);
278 static Ecore_X_Window efl_get_global_navigation_window (void);
281 static void change_keyboard_mode (TOOLBAR_MODE_T mode);
282 static unsigned int get_ise_index (const String uuid);
283 static bool set_active_ise (const String &uuid, bool launch_ise);
284 static bool update_ise_list (std::vector<String> &list);
285 static void update_ise_locale (const char *lang = NULL);
286 #ifdef HAVE_NOTIFICATION
287 static void delete_notification (NotificationData *noti_data);
288 static void create_notification (NotificationData *noti_data);
289 static void show_ime_selector_notification (void);
291 static void set_language_and_locale (const char *lang_str);
292 static bool app_control_launch (const char *app_id);
293 static void terminate_active_ise (const String uuid);
295 /////////////////////////////////////////////////////////////////////////////
296 // Declaration of internal variables.
297 /////////////////////////////////////////////////////////////////////////////
298 #if ISF_BUILD_CANDIDATE_UI
299 static Evas_Object *_candidate_window = 0;
300 static Evas_Object *_candidate_area_1 = 0;
301 static Evas_Object *_candidate_area_2 = 0;
302 static Evas_Object *_candidate_bg = 0;
303 static Evas_Object *_candidate_0_scroll = 0;
304 static Evas_Object *_candidate_scroll = 0;
305 static Evas_Object *_scroller_bg = 0;
306 static Evas_Object *_candidate_0_table = 0;
307 static Evas_Object *_candidate_table = 0;
308 static Evas_Object *_candidate_0 [SCIM_LOOKUP_TABLE_MAX_PAGESIZE];
309 static Evas_Object *_candidate_text [SCIM_LOOKUP_TABLE_MAX_PAGESIZE];
310 static Evas_Object *_candidate_image [SCIM_LOOKUP_TABLE_MAX_PAGESIZE];
311 static Evas_Object *_candidate_pop_image [SCIM_LOOKUP_TABLE_MAX_PAGESIZE];
312 static Evas_Object *_seperate_0 [SCIM_LOOKUP_TABLE_MAX_PAGESIZE];
313 static Evas_Object *_seperate_items [SCIM_LOOKUP_TABLE_MAX_PAGESIZE];
314 static Evas_Object *_line_0 [SCIM_LOOKUP_TABLE_MAX_PAGESIZE];
315 static Evas_Object *_line_items [SCIM_LOOKUP_TABLE_MAX_PAGESIZE];
316 static Evas_Object *_more_btn = 0;
317 static Evas_Object *_close_btn = 0;
318 static bool _candidate_show_requested = false;
319 #endif /* CANDIDATE */
320 static bool _updated_hide_state_geometry = false;
321 #if ISF_BUILD_CANDIDATE_UI
322 static int _candidate_x = 0;
323 static int _candidate_y = 0;
324 static int _candidate_width = 0;
325 static int _candidate_height = 0;
326 #endif /* CANDIDATE */
327 static int _soft_candidate_width = 0;
328 static int _soft_candidate_height = 0;
329 #if ISF_BUILD_CANDIDATE_UI
330 static int _candidate_valid_height = 0;
332 static bool _candidate_area_1_visible = false;
333 static bool _candidate_area_2_visible = false;
334 static bool _aux_area_visible = false;
335 #endif /* CANDIDATE */
337 static ISF_CANDIDATE_MODE_T _candidate_mode = SOFT_CANDIDATE_WINDOW;
338 static ISF_CANDIDATE_PORTRAIT_LINE_T _candidate_port_line = ONE_LINE_CANDIDATE;
340 #if ISF_BUILD_CANDIDATE_UI
341 static int _candidate_port_width = 480;
342 static int _candidate_port_height_min = 76;
343 static int _candidate_port_height_min_2 = 150;
344 static int _candidate_port_height_max = 286;
345 static int _candidate_port_height_max_2 = 350;
346 static int _candidate_land_width = 784;
347 static int _candidate_land_height_min = 84;
348 static int _candidate_land_height_min_2 = 168;
349 static int _candidate_land_height_max = 150;
350 static int _candidate_land_height_max_2 = 214;
351 static int _candidate_area_1_pos [2] = {0, 2};
352 static int _more_btn_pos [4] = {369, 11, 689, 11};
353 static int _close_btn_pos [4] = {362, 211, 682, 75};
354 static int _more_btn_width = 80;
355 static int _more_btn_height = 64;
357 static int _h_padding = 4;
358 static int _v_padding = 2;
359 static int _item_min_width = 99;
360 static int _item_min_height = 82;
362 static int _candidate_scroll_0_width_min = 350;
363 static int _candidate_scroll_0_width_max = 670;
365 static int _candidate_scroll_width = 453;
366 static int _candidate_scroll_width_min = 453;
367 static int _candidate_scroll_width_max = 663;
368 static int _candidate_scroll_height_min = 124;
369 static int _candidate_scroll_height_max = 190;
371 const int MORE_BUTTON_INDEX = -1;
372 const int CLOSE_BUTTON_INDEX = -2;
373 const int INVALID_TTS_FOCUS_INDEX = -100;
374 static int _candidate_tts_focus_index = INVALID_TTS_FOCUS_INDEX;
375 static uint32 _candidate_display_number = 0;
376 static std::vector<uint32> _candidate_row_items;
377 static Evas_Object *_tts_focus_rect = 0;
378 static bool _wait_stop_event = false;
380 static Evas_Object *_preedit_window = 0;
381 static Evas_Object *_preedit_text = 0;
382 static int _preedit_width = 100;
383 static int _preedit_height = 54;
385 static Evas_Object *_aux_area = 0;
386 static Evas_Object *_aux_line = 0;
387 static Evas_Object *_aux_table = 0;
388 static int _aux_height = 0;
389 static int _aux_port_width = 444;
390 static int _aux_land_width = 764;
391 static std::vector<Evas_Object *> _aux_items;
392 static std::vector<Evas_Object *> _aux_seperates;
394 static Evas_Object *_tmp_preedit_text = 0;
395 static Evas_Object *_tmp_aux_text = 0;
396 static Evas_Object *_tmp_candidate_text = 0;
398 static int _spot_location_x = -1;
399 static int _spot_location_y = -1;
400 static int _spot_location_top_y = -1;
401 static int _candidate_angle = 0;
402 #endif /* CANDIDATE */
404 static int _ise_angle = -1;
405 static int _ise_x = 0;
406 static int _ise_y = 0;
407 static int _ise_width = 0;
408 static int _ise_height = 0;
409 static WINDOW_STATE _ise_state = WINDOW_STATE_HIDE;
410 static WINDOW_STATE _candidate_state = WINDOW_STATE_HIDE;
412 #if ISF_BUILD_CANDIDATE_UI
413 static int _indicator_height = 0;//24;
414 static int _screen_width = 720;
415 static int _screen_height = 1280;
416 static float _width_rate = 1.0;
417 static float _height_rate = 1.0;
418 static int _blank_width = 30;
420 static String _candidate_name = String ("candidate");
421 static String _candidate_edje_file = String (EFL_CANDIDATE_THEME1);
423 static String _candidate_font_name = String ("Tizen");
424 static int _candidate_font_size = 38;
425 static int _aux_font_size = 38;
426 static int _click_object = 0;
427 static int _click_down_pos [2] = {0, 0};
428 static int _click_up_pos [2] = {0, 0};
429 static bool _is_click = true;
430 #endif /* CANDIDATE */
431 static String _initial_ise_uuid = String ("");
432 static String _locale_string = String ("");
433 static ConfigPointer _config;
434 static Connection _config_connection;
436 static InfoManager *_info_manager = 0;
438 static clock_t _clock_start;
440 #if ISF_BUILD_CANDIDATE_UI
441 static Ecore_Timer *_check_size_timer = NULL;
442 static Ecore_Timer *_longpress_timer = NULL;
443 static Ecore_Timer *_destroy_timer = NULL;
444 #endif /* CANDIDATE */
446 static Ecore_Timer *_off_prepare_done_timer = NULL;
448 #if ISF_BUILD_CANDIDATE_UI
449 static Ecore_Timer *_candidate_hide_timer = NULL;
450 #endif /* CANDIDATE */
451 static Ecore_Timer *_ise_hide_timer = NULL;
454 static Ecore_X_Window _ise_window = 0;
455 static Ecore_X_Window _app_window = 0;
456 static Ecore_X_Window _control_window = 0;
457 static Ecore_X_Window _input_win = 0;
460 #ifdef HAVE_PKGMGR_INFO
461 static package_manager_h pkgmgr = NULL;
462 static VectorPairStringUint32 g_pkgids_to_be_uninstalled;
463 static Ecore_Timer *g_release_uninstalled_ime_info_timer = NULL;
464 static String g_stopped_helper_pkgid = "";
465 static Ecore_Timer *g_start_default_helper_timer = NULL;
466 static VectorPairStringUint32 g_pkgids_to_be_updated_and_installed;
467 static String g_updated_helper_pkgid = "";
470 static bool _launch_ise_on_request = false;
471 static bool _auto_destroy_ise = false;
472 static bool _soft_keyboard_launched = false;
473 static bool _focus_in = false;
475 #if ISF_BUILD_CANDIDATE_UI
476 static bool candidate_expanded = false;
477 static int _candidate_image_count = 0;
478 static int _candidate_text_count = 0;
479 static int _candidate_pop_image_count = 0;
480 static int candidate_image_height = 38;
481 static int candidate_play_image_width_height = 19;
483 static const int CANDIDATE_TEXT_OFFSET = 2;
485 static double _app_scale = 1.0;
486 static double _system_scale = 1.0;
487 #endif /* CANDIDATE */
489 #ifdef HAVE_NOTIFICATION
490 static NotificationData hwkbd_module_noti = {"Input detected from hardware keyboard", "Tap to use virtual keyboard", ISF_KEYBOARD_ICON_FILE, "", 0};
491 static NotificationData ise_selector_module_noti = {"Select input method", "", "", "", 0};
494 #if ISF_BUILD_CANDIDATE_UI
496 static tts_h _tts = NULL;
500 static bool feedback_initialized = false;
502 #endif /* CANDIDATE */
505 static E_DBus_Connection *edbus_conn;
506 static E_DBus_Signal_Handler *edbus_handler;
509 #if ENABLE_REMOTE_INPUT
510 static Remote_Input* remote_input_impl = NULL;
511 static bool launch_remote_input = false;
514 #if ISF_BUILD_CANDIDATE_UI
516 static Ecore_Event_Handler *_candidate_show_handler = NULL;
518 #endif /* CANDIDATE */
520 static String ime_selector_app = "";
521 static String ime_list_app = "";
523 static Ecore_Timer *_ise_check_pid_alive_timer = NULL;
524 static const double _ise_check_pid_alive_time = 3.0f;
525 static String _ise_check_pid_alive_uuid;
527 static Ecore_Timer *g_monitor_user_data_path_timer = NULL;
530 EMOJI_IMAGE_WIDTH = 0,
533 EMOJI_IMAGE_TAG_FLAG,
534 EMOJI_IMAGE_POP_FLAG,
541 int emoji_option[EMOJI_IMAGE_END];
544 /* This structure stores the geometry information reported by ISE */
547 bool valid; /* Whether this information is currently valid */
548 int angle; /* For which angle this information is useful */
549 struct rectinfo geometry; /* Geometry information */
552 static struct GeometryCache _ise_reported_geometry = {0, 0, {0, 0, 0, 0}};
553 static struct GeometryCache _portrait_recent_ise_geometry = {0, 0, {0, 0, 0, 0}};
554 static struct GeometryCache _landscape_recent_ise_geometry = {0, 0, {0, 0, 0, 0}};
557 static void get_input_window (void)
560 Ecore_X_Atom atom = 0;
562 if (_input_win == 0) {
563 atom = ecore_x_atom_get (E_PROP_DEVICEMGR_INPUTWIN);
564 win_ret = ecore_x_window_prop_window_get (ecore_x_window_root_first_get (), atom, &_input_win, 1);
565 if (_input_win == 0 || win_ret < 1) {
566 LOGW ("Input window is NULL!");
568 ecore_x_event_mask_set (_input_win, ECORE_X_EVENT_MASK_WINDOW_PROPERTY);
574 static int pkgmgr_get_appinfo (const char *appid, pkgmgrinfo_appinfo_h *handle)
577 /* Try to get in global packages */
578 ret = pkgmgrinfo_appinfo_get_appinfo (appid, handle);
579 if (ret != PMINFO_R_OK) {
580 LOGW ("[pkgmgrinfo_appinfo_get_appinfo] appid : '%s', ret : %d, uid : %d", appid, ret, getuid ());
581 /* Try to get in user packages */
582 ret = pkgmgrinfo_appinfo_get_usr_appinfo (appid, getuid (), handle);
583 if (ret != PMINFO_R_OK)
584 LOGW ("[pkgmgrinfo_appinfo_get_usr_appinfo] appid : '%s', ret : %d", appid, ret);
591 static void usb_keyboard_signal_cb (void *data, DBusMessage *msg)
601 if (dbus_message_is_signal (msg, HOST_INTERFACE_NAME, HOST_KEYBOARD_SIGNAL) == 0) {
602 LOGW ("HOST_KEYBOARD_SIGNAL");
606 dbus_error_init (&err);
608 if (dbus_message_get_args (msg, &err, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID) == 0) {
609 LOGW ("DBUS_TYPE_INVALID");
615 if (!strncmp (str, HOST_ADDED, strlen (HOST_ADDED))) {
620 if (!strncmp (str, HOST_REMOVED, strlen (HOST_REMOVED))) {
621 LOGD ("HOST_REMOVED");
622 if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) {
623 change_keyboard_mode (TOOLBAR_HELPER_MODE);
628 LOGW ("ERROR: msg (%s) is improper", str);
631 static void unregister_edbus_signal_handler (void)
634 LOGD ("unregister signal handler for keyboard");
636 e_dbus_signal_handler_del (edbus_conn, edbus_handler);
637 edbus_handler = NULL;
639 e_dbus_connection_close (edbus_conn);
645 static int register_edbus_signal_handler (void)
650 while (e_dbus_init () == 0) {
657 edbus_conn = e_dbus_bus_get (DBUS_BUS_SYSTEM);
659 LOGW ("edbus connection fail");
663 edbus_handler = e_dbus_signal_handler_add (edbus_conn, NULL, HOST_OBJECT_PATH, HOST_INTERFACE_NAME, HOST_KEYBOARD_SIGNAL, usb_keyboard_signal_cb, NULL);
664 if (!edbus_handler) {
665 LOGW ("cannot register signal");
669 LOGD ("Success edbus register");
675 #ifdef HAVE_NOTIFICATION
676 static void delete_notification (NotificationData *noti_data)
678 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
680 if (!_MOBILE) return;
682 if (noti_data->noti_id != 0) {
683 notification_delete_by_priv_id ("isf-panel-efl", NOTIFICATION_TYPE_ONGOING, noti_data->noti_id);
684 LOGD ("deleted notification : %s", noti_data->launch_app.c_str ());
685 noti_data->noti_id = 0;
689 static void create_notification (NotificationData *noti_data)
691 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
693 notification_h notification = NULL;
696 if (!_MOBILE) return;
698 if (noti_data->noti_id != 0) {
699 notification_delete_by_priv_id ("isf-panel-efl", NOTIFICATION_TYPE_ONGOING, noti_data->noti_id);
700 noti_data->noti_id = 0;
703 notification = notification_create (NOTIFICATION_TYPE_ONGOING);
704 if (notification != NULL) {
705 notification_set_pkgname (notification, "isf-panel-efl");
706 notification_set_layout (notification, NOTIFICATION_LY_ONGOING_EVENT);
707 notification_set_image (notification, NOTIFICATION_IMAGE_TYPE_ICON, noti_data->icon.c_str());
708 notification_set_text (notification, NOTIFICATION_TEXT_TYPE_TITLE, _(noti_data->title.c_str()), NULL, NOTIFICATION_VARIABLE_TYPE_NONE);
709 notification_set_text (notification, NOTIFICATION_TEXT_TYPE_CONTENT, _(noti_data->content.c_str ()), NULL, NOTIFICATION_VARIABLE_TYPE_NONE);
710 notification_set_display_applist (notification, NOTIFICATION_DISPLAY_APP_NOTIFICATION_TRAY);
712 app_control_h service = NULL;
713 if (app_control_create (&service) == APP_CONTROL_ERROR_NONE) {
714 app_control_set_operation (service, APP_CONTROL_OPERATION_DEFAULT);
715 app_control_set_app_id (service, noti_data->launch_app.c_str ());
717 notification_set_launch_option (notification, NOTIFICATION_LAUNCH_OPTION_APP_CONTROL, (void *)service);
718 ret = notification_insert (notification, ¬i_data->noti_id);
719 if (ret != NOTIFICATION_ERROR_NONE) {
720 LOGW ("Failed to insert notification. error code : %d", ret);
722 app_control_destroy (service);
725 LOGW ("Failed to create appcontrol");
727 notification_free (notification);
730 LOGW ("Failed to create notification");
733 #endif /* HAVE_NOTIFICATION */
735 #if ISF_BUILD_CANDIDATE_UI
736 static bool tokenize_tag (const String& str, struct image *image_token)
738 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " str=" << str << ", length=" << str.length () << "\n";
739 if (str.length () <= 0) {
740 LOGW ("str is empty!!!");
744 char **tag_str = NULL;
746 tag_str = eina_str_split (str.c_str (), "\u3013", 0);
751 for (i = 0; tag_str [i]; i++) {
753 if (str.length () == strlen (tag_str[i])) {
763 image_token->path = String (tag_str[i]);
765 if (i - 1 < EMOJI_IMAGE_END)
766 image_token->emoji_option [i - 1] = atoi (tag_str[i]);
768 LOGW ("emoji option is more than EMOJI_IMAGE_END!!!");
780 static Evas_Object* get_candidate (const String& str, Evas_Object *parent, int *total_width, uint32 ForeGround, uint32 BackGround, bool HighLight, bool SetBack, int item_num, int item_index)
782 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " str=" << str << ", length=" << str.length () << "\n";
784 struct image image_data;
785 int object_width = 0, text_width = 0, image_width = 0, image_height = 0, max_width = 0, button_width = 0;
787 int image_get_width = 0, image_get_height = 0;
788 char image_key [10] = {0, };
789 char **splited_string = NULL;
790 char **sub_splited_string = NULL;
791 double image_rate = 0.0;
792 bool tokenize_result = false;
793 bool candidate_is_long = false;
795 Evas_Object *candidate_object_table = NULL;
796 Evas_Object *candidate_object_table_bg_rect = NULL;
797 Evas_Object *candidate_left_padding = NULL;
799 candidate_object_table = elm_table_add (parent);
801 candidate_left_padding = evas_object_rectangle_add (evas_object_evas_get (parent));
802 evas_object_size_hint_weight_set (candidate_left_padding, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
803 evas_object_size_hint_align_set (candidate_left_padding, EVAS_HINT_FILL, EVAS_HINT_FILL);
804 evas_object_size_hint_min_set (candidate_left_padding, _blank_width, 1);
805 evas_object_color_set (candidate_left_padding, 0, 0, 0, 0);
806 elm_table_pack (candidate_object_table, candidate_left_padding, 0, 0, _blank_width, 1);
807 evas_object_show (candidate_left_padding);
809 object_width += _blank_width;
810 if (item_num > 1 && item_index == 0)
811 button_width = 92 * _width_rate;
815 splited_string = eina_str_split (str.c_str (), "\uE000", 0);
816 if (splited_string) {
817 for (i = 0; splited_string [i]; i++) {
818 if (candidate_is_long)
820 sub_splited_string = eina_str_split (splited_string [i], "\uE001", 0);
821 if (sub_splited_string) {
822 for (j = 0; sub_splited_string [j]; j++) {
823 if (candidate_is_long)
825 tokenize_result = tokenize_tag (sub_splited_string [j], &image_data);
826 if (tokenize_result && _candidate_image_count < SCIM_LOOKUP_TABLE_MAX_PAGESIZE && _candidate_text_count < SCIM_LOOKUP_TABLE_MAX_PAGESIZE) {
827 _candidate_image [_candidate_image_count] = elm_image_add (parent);
828 snprintf (image_key, sizeof (image_key), "%d", _candidate_image_count);
829 elm_image_file_set (_candidate_image [_candidate_image_count], image_data.path.c_str (), image_key);
830 elm_image_animated_set (_candidate_image [_candidate_image_count], EINA_TRUE);
831 elm_image_animated_play_set (_candidate_image [_candidate_image_count], EINA_TRUE);
832 elm_image_object_size_get (_candidate_image [_candidate_image_count], &image_get_width, &image_get_height);
833 LOGD ("image_path=%s, key=%s", image_data.path.c_str (), image_key);
835 if (image_get_height > image_get_width)
836 image_rate = ((double)candidate_image_height / (double)image_get_width);
838 image_rate = ((double)candidate_image_height / (double)image_get_height);
840 image_width = (int)((double)image_get_width * image_rate);
841 image_height = candidate_image_height;
843 if (_candidate_angle == 90 || _candidate_angle == 270)
844 max_width = _candidate_land_width - (_blank_width + object_width + button_width + (2 * CANDIDATE_TEXT_OFFSET));
846 max_width = _candidate_port_width - (_blank_width + object_width + button_width + (2 * CANDIDATE_TEXT_OFFSET));
848 if (image_width > max_width) {
849 Evas_Object *candidate_end = edje_object_add (evas_object_evas_get (parent));
850 edje_object_file_set (candidate_end, _candidate_edje_file.c_str (), _candidate_name.c_str ());
851 evas_object_show (candidate_end);
852 edje_object_part_text_set (candidate_end, "candidate", "...");
853 edje_object_scale_set (_candidate_text [_candidate_text_count], _height_rate);
855 text_width = max_width;
856 evas_object_size_hint_min_set (candidate_end, text_width + (2 * CANDIDATE_TEXT_OFFSET), _item_min_height);
857 if (HighLight || SetBack) {
858 set_highlight_color (candidate_end, ForeGround, BackGround, SetBack);
860 elm_table_pack (candidate_object_table, candidate_end, object_width, 0, text_width + (2 * CANDIDATE_TEXT_OFFSET), _candidate_font_size);
861 object_width += (text_width + (2 * CANDIDATE_TEXT_OFFSET));
863 if (_candidate_image [_candidate_image_count]) {
864 evas_object_del (_candidate_image [_candidate_image_count]);
865 _candidate_image [_candidate_image_count] = NULL;
867 candidate_is_long = true;
871 evas_object_resize (_candidate_image [_candidate_image_count], image_width, image_height);
872 evas_object_show (_candidate_image [_candidate_image_count]);
873 evas_object_size_hint_min_set (_candidate_image [_candidate_image_count], image_width, image_height);
875 elm_table_pack (candidate_object_table, _candidate_image [_candidate_image_count], object_width, 1, image_width, image_height);
876 object_width += image_width;
877 _candidate_image_count++;
879 if (image_data.emoji_option [EMOJI_IMAGE_POP_FLAG] == 1 && image_width > 0 && _candidate_pop_image_count < SCIM_LOOKUP_TABLE_MAX_PAGESIZE) {
880 _candidate_pop_image [_candidate_pop_image_count] = elm_image_add (parent);
881 elm_image_file_set (_candidate_pop_image [_candidate_pop_image_count], ISF_POP_PLAY_ICON_FILE, image_key);
882 evas_object_resize (_candidate_pop_image [_candidate_pop_image_count], candidate_play_image_width_height, candidate_play_image_width_height);
883 evas_object_show (_candidate_pop_image [_candidate_pop_image_count]);
884 evas_object_size_hint_min_set (_candidate_pop_image [_candidate_pop_image_count], candidate_play_image_width_height, candidate_play_image_width_height);
886 elm_table_pack (candidate_object_table, _candidate_pop_image [_candidate_pop_image_count],
887 object_width - candidate_play_image_width_height, image_height - candidate_play_image_width_height - 2,
888 candidate_play_image_width_height, candidate_play_image_width_height);
890 _candidate_pop_image_count++;
893 } else if (strlen (sub_splited_string [j]) > 0 && _candidate_text_count < SCIM_LOOKUP_TABLE_MAX_PAGESIZE) {
894 _candidate_text [_candidate_text_count] = edje_object_add (evas_object_evas_get (parent));
895 edje_object_file_set (_candidate_text [_candidate_text_count], _candidate_edje_file.c_str (), _candidate_name.c_str ());
896 evas_object_show (_candidate_text [_candidate_text_count]);
897 edje_object_part_text_set (_candidate_text [_candidate_text_count], "candidate", sub_splited_string [j]);
898 edje_object_text_class_set (_candidate_text [_candidate_text_count], "tizen",
899 _candidate_font_name.c_str (), _candidate_font_size);
900 evas_object_text_text_set (_tmp_candidate_text, sub_splited_string [j]);
901 evas_object_geometry_get (_tmp_candidate_text, NULL, NULL, &text_width, NULL);
903 if (_candidate_angle == 90 || _candidate_angle == 270)
904 max_width = _candidate_land_width - (_blank_width + object_width + button_width + (2 * CANDIDATE_TEXT_OFFSET));
906 max_width = _candidate_port_width - (_blank_width + object_width + button_width + (2 * CANDIDATE_TEXT_OFFSET));
908 if (text_width > max_width) {
909 candidate_is_long = true;
910 /* In order to avoid overlap issue, calculate show_string */
911 String show_string = String (sub_splited_string [j]);
912 int show_length = text_width;
913 while (show_length > max_width && show_string.length () > 1) {
914 show_string = show_string.substr (0, show_string.length () - 1);
915 evas_object_text_text_set (_tmp_candidate_text, (show_string + String ("...")).c_str ());
916 evas_object_geometry_get (_tmp_candidate_text, NULL, NULL, &show_length, NULL);
918 edje_object_part_text_set (_candidate_text [_candidate_text_count], "candidate", (show_string + String ("...")).c_str ());
919 text_width = max_width;
922 evas_object_size_hint_min_set (_candidate_text [_candidate_text_count], text_width + (2 * CANDIDATE_TEXT_OFFSET), _item_min_height);
923 if (HighLight || SetBack) {
924 set_highlight_color (_candidate_text [_candidate_text_count], ForeGround, BackGround, SetBack);
926 elm_table_pack (candidate_object_table, _candidate_text [_candidate_text_count], object_width, 0, text_width + (2 * CANDIDATE_TEXT_OFFSET), _candidate_font_size);
927 object_width += (text_width + (2 * CANDIDATE_TEXT_OFFSET));
928 _candidate_text_count++;
934 if (splited_string [0])
935 free (splited_string [0]);
937 free (splited_string);
940 if (sub_splited_string) {
941 if (sub_splited_string [0])
942 free (sub_splited_string [0]);
944 free (sub_splited_string);
947 *total_width = object_width + _blank_width;
949 candidate_object_table_bg_rect = edje_object_add (evas_object_evas_get (parent));
950 edje_object_file_set (candidate_object_table_bg_rect, _candidate_edje_file.c_str (), "candidate_object_table");
951 evas_object_size_hint_weight_set (candidate_object_table_bg_rect, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
952 evas_object_size_hint_align_set (candidate_object_table_bg_rect, EVAS_HINT_FILL, EVAS_HINT_FILL);
953 evas_object_size_hint_min_set (candidate_object_table_bg_rect, *total_width, _item_min_height);
954 elm_table_pack (candidate_object_table, candidate_object_table_bg_rect, 0, 0, *total_width, _item_min_height);
955 evas_object_show (candidate_object_table_bg_rect);
957 evas_object_size_hint_align_set (candidate_object_table, EVAS_HINT_FILL, EVAS_HINT_FILL);
958 evas_object_size_hint_weight_set (candidate_object_table, EVAS_HINT_EXPAND, 0.0);
960 return candidate_object_table;
962 #endif /* CANDIDATE */
964 /////////////////////////////////////////////////////////////////////////////
965 // Implementation of internal functions.
966 /////////////////////////////////////////////////////////////////////////////
968 * @brief Print system time point for panel performance.
970 * @param strInfo The output information.
972 static void check_time (const char *strInfo)
974 gettime (_clock_start, strInfo);
975 ISF_LOG ("%s ppid=%d pid=%d\n", strInfo, getppid (), getpid ());
979 * @brief Flush memory for elm.
983 static void flush_memory (void)
985 #if ISF_BUILD_CANDIDATE_UI
986 elm_cache_all_flush ();
991 #if ISF_BUILD_CANDIDATE_UI
993 * @brief Get ISE geometry information.
994 * Returns the "expected" ISE geometry when kbd_state is ON, otherwise w/h set to 0
996 * @param info The data is used to store ISE position and size.
997 * @param kbd_state The keyboard state.
999 static struct rectinfo get_ise_geometry ()
1001 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
1003 struct rectinfo info = {0, 0, 0, 0};
1007 Ecore_X_Window gnb_win = efl_get_global_navigation_window ();
1009 ecore_x_window_size_get (gnb_win, &w, &h);
1012 int win_w = _screen_width, win_h = _screen_height;
1013 int angle = (_ise_angle == -1) ? efl_get_app_window_angle () : _ise_angle;
1016 /* The height of global navigation bar */
1019 if (angle == 90 || angle == 270) {
1020 win_w = _screen_height;
1021 win_h = _screen_width;
1026 /* If we have geometry reported by ISE, use the geometry information */
1027 if (_ise_reported_geometry.valid && _ise_reported_geometry.angle == angle) {
1028 info = _ise_reported_geometry.geometry;
1029 /* But still, if the current ISE is not in SHOW state, set w/h to 0 */
1030 if (_ise_state != WINDOW_STATE_SHOW) {
1031 info.pos_y = (win_h > win_w) ? win_h : win_w;
1036 /* READ ISE's SIZE HINT HERE */
1039 int pos_x, pos_y, width, height;
1040 if (ecore_x_e_window_rotation_geometry_get (_ise_window, angle,
1041 &pos_x, &pos_y, &width, &height)) {
1045 if (angle == 90 || angle == 270) {
1046 info.width = height;
1047 info.height = width;
1050 info.height = height;
1053 info.pos_x = (int)info.width > win_w ? 0 : (win_w - info.width) / 2;
1054 if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) {
1056 info.pos_y = (win_h > win_w) ? win_h : win_w;
1060 if (_ise_state == WINDOW_STATE_SHOW) {
1061 info.pos_y = win_h - info.height - gnb_height;
1063 info.pos_y = (win_h > win_w) ? win_h : win_w;
1069 LOGD ("angle : %d, w_angle : %d, mode : %d, Geometry : %d %d %d %d",
1071 _info_manager->get_current_toolbar_mode (),
1072 info.pos_x, info.pos_y, info.width, info.height);
1081 // FIXME: Get the ISE's SIZE.
1089 _ise_width = info.width;
1090 _ise_height = info.height;
1094 #endif /* CANDIDATE */
1098 * @brief Set keyboard geometry for autoscroll.
1099 * This includes the ISE geometry together with candidate window
1101 * @param kbd_state The keyboard state.
1103 static void set_keyboard_geometry_atom_info (Ecore_X_Window window, struct rectinfo ise_rect)
1105 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
1107 if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) {
1110 if (_candidate_mode == FIXED_CANDIDATE_WINDOW) {
1111 if (_candidate_window && _candidate_state == WINDOW_STATE_SHOW) {
1112 ise_rect.width = _candidate_width;
1113 ise_rect.height = _candidate_height;
1115 } else if (_candidate_mode == SOFT_CANDIDATE_WINDOW) {
1116 ise_rect.width = _soft_candidate_width;
1117 ise_rect.height = _soft_candidate_height;
1120 int angle = efl_get_app_window_angle ();
1121 if (angle == 90 || angle == 270)
1122 ise_rect.pos_y = _screen_width - ise_rect.height;
1124 ise_rect.pos_y = _screen_height - ise_rect.height;
1126 if (_candidate_mode == FIXED_CANDIDATE_WINDOW) {
1127 if (_candidate_window && _candidate_state == WINDOW_STATE_SHOW) {
1128 _candidate_valid_height = ui_candidate_get_valid_height ();
1129 if ((_candidate_height - _candidate_valid_height) > _ise_height) {
1130 _candidate_valid_height = _candidate_height;
1131 ise_rect.pos_y = ise_rect.pos_y + ise_rect.height - _candidate_height;
1132 ise_rect.height = _candidate_height;
1134 ise_rect.pos_y -= _candidate_valid_height;
1135 ise_rect.height += _candidate_valid_height;
1141 ecore_x_e_illume_keyboard_geometry_set (window, ise_rect.pos_x, ise_rect.pos_y, ise_rect.width, ise_rect.height);
1142 LOGD ("KEYBOARD_GEOMETRY_SET : %d %d %d %d", ise_rect.pos_x, ise_rect.pos_y, ise_rect.width, ise_rect.height);
1143 SCIM_DEBUG_MAIN (3) << " KEYBOARD_GEOMETRY x=" << ise_rect.pos_x << " y=" << ise_rect.pos_y
1144 << " width=" << ise_rect.width << " height=" << ise_rect.height << "\n";
1146 /* even the kbd_state is OFF, consider the keyboard is still ON if we have candidate opened */
1147 if (ise_rect.width == 0 && ise_rect.height == 0) {
1148 ecore_x_e_virtual_keyboard_state_set (window, ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF);
1150 ecore_x_e_virtual_keyboard_state_set (window, ECORE_X_VIRTUAL_KEYBOARD_STATE_ON);
1152 if (_ise_angle == 0 || _ise_angle == 180) {
1153 _portrait_recent_ise_geometry.valid = true;
1154 _portrait_recent_ise_geometry.geometry = ise_rect;
1157 _landscape_recent_ise_geometry.valid = true;
1158 _landscape_recent_ise_geometry.geometry = ise_rect;
1165 * @brief Get ISE index according to uuid.
1167 * @param uuid The ISE uuid.
1169 * @return The ISE index
1171 static unsigned int get_ise_index (const String uuid)
1173 unsigned int index = 0;
1174 if (uuid.length () > 0) {
1175 for (unsigned int i = 0; i < _ime_info.size (); i++) {
1176 if (uuid == _ime_info[i].appid) {
1186 static void set_keyboard_engine (String active_uuid)
1188 String IMENGINE_KEY = String (SCIM_CONFIG_DEFAULT_IMENGINE_FACTORY) + String ("/") + String ("~other");
1189 String keyboard_uuid = _config->read (IMENGINE_KEY, String (""));
1190 if (active_uuid != keyboard_uuid) {
1191 _info_manager->change_factory (active_uuid);
1192 _config->write (IMENGINE_KEY, active_uuid);
1197 static void _update_ime_info(void)
1199 std::vector<String> ise_langs;
1202 isf_pkg_select_all_ime_info_db(_ime_info);
1204 /* Update _groups */
1206 for (size_t i = 0; i < _ime_info.size (); ++i) {
1207 scim_split_string_list(ise_langs, _ime_info[i].languages);
1208 for (size_t j = 0; j < ise_langs.size (); j++) {
1209 if (std::find (_groups[ise_langs[j]].begin (), _groups[ise_langs[j]].end (), i) == _groups[ise_langs[j]].end ())
1210 _groups[ise_langs[j]].push_back (i);
1216 static void _initialize_ime_info (void)
1218 std::vector<ImeInfoDB>::iterator iter;
1219 VectorPairStringUint32 ime_on_off;
1220 // Store is_enabled values of each keyboard
1221 for (iter = _ime_info.begin (); iter != _ime_info.end (); iter++) {
1222 if (iter->mode == TOOLBAR_HELPER_MODE) {
1223 ime_on_off.push_back (std::make_pair (iter->appid, iter->is_enabled));
1226 // Delete the whole ime_info DB and reload
1227 isf_db_delete_ime_info ();
1228 _update_ime_info ();
1229 // Restore is_enabled value to valid keyboards
1230 for (iter = _ime_info.begin (); iter != _ime_info.end (); iter++) {
1231 if (iter->mode == TOOLBAR_HELPER_MODE) {
1232 for (VectorPairStringUint32::iterator it = ime_on_off.begin (); it != ime_on_off.end (); it++) {
1233 if (it->first.compare (iter->appid) == 0) {
1234 if (it->second != iter->is_enabled) {
1235 iter->is_enabled = it->second;
1236 isf_db_update_is_enabled_by_appid (iter->appid.c_str (), static_cast<bool>(iter->is_enabled));
1238 ime_on_off.erase (it);
1246 #ifdef HAVE_PKGMGR_INFO
1248 * @brief Insert or update ime_info data with pkgid.
1250 * @param pkgid pkgid to insert/update ime_info table.
1252 * @return 1 on successful insert, 2 on successful update, -1 if pkgid is not IME package, otherwise return 0.
1254 static int _isf_insert_ime_info_by_pkgid(const char *pkgid)
1257 pkgmgrinfo_pkginfo_h handle = NULL;
1258 int result = 0; // 0: not IME, 1: Inserted, 2: Updated (because of the same appid)
1259 uid_t uid = getuid ();
1263 LOGW ("pkgid is null.");
1267 /* Try to get in global packages */
1268 ret = pkgmgrinfo_pkginfo_get_pkginfo (pkgid, &handle);
1269 if (ret != PMINFO_R_OK) {
1270 /* Try to get in user packages */
1271 ret = pkgmgrinfo_pkginfo_get_usr_pkginfo (pkgid, uid, &handle);
1272 if (ret != PMINFO_R_OK) {
1273 LOGW ("Failed to call pkgmgrinfo_pkginfo_get_pkginfo & get_usr_pkginfo(\"%s\",~) returned %d, uid : %d", pkgid, ret, getuid ());
1282 /* Try to get in user packages */
1283 ret = pkgmgrinfo_appinfo_get_usr_list (handle, PMINFO_UI_APP, isf_pkg_ime_app_list_cb, (void *)&result, uid);
1286 /* Try to get in global packages */
1287 ret = pkgmgrinfo_appinfo_get_list (handle, PMINFO_UI_APP, isf_pkg_ime_app_list_cb, (void *)&result);
1290 if (ret != PMINFO_R_OK) {
1291 LOGW ("Failed to call %s failed(%d)", user ? "pkgmgrinfo_appinfo_get_usr_list" : "pkgmgrinfo_appinfo_get_list", ret);
1298 pkgmgrinfo_pkginfo_destroy_pkginfo (handle);
1304 * @brief Timer to start initial Helper ISE if the active (selected) 3rd party keyboard is uninstalled.
1306 * @param data User data
1308 * @return If it returns ECORE_CALLBACK_RENEW, it will be called again at the next tick, or if it returns
1309 * ECORE_CALLBACK_CANCEL it will be deleted automatically making any references/handles for it invalid.
1311 static Eina_Bool _start_default_helper_timer(void *data)
1313 std::vector<String> total_appids;
1314 std::vector<ImeInfoDB>::iterator it;
1315 VectorPairStringUint32::iterator iter;
1317 /* Let panel know that ISE is deleted... */
1318 for (it = _ime_info.begin(); it != _ime_info.end(); it++) {
1319 total_appids.push_back(it->appid);
1321 if (total_appids.size() > 0)
1322 _info_manager->update_ise_list (total_appids);
1324 LOGD ("Try to start the initial helper");
1325 set_active_ise(_initial_ise_uuid, true);
1327 for (iter = g_pkgids_to_be_uninstalled.begin (); iter != g_pkgids_to_be_uninstalled.end (); iter++) {
1328 if (iter->first.compare(g_stopped_helper_pkgid) == 0) {
1329 g_pkgids_to_be_uninstalled.erase (iter);
1333 g_stopped_helper_pkgid = "";
1335 g_start_default_helper_timer = NULL;
1336 return ECORE_CALLBACK_CANCEL;
1340 * @brief Timer to release uninstalled IME related info; g_pkgids_to_be_uninstalled has appid and is_enabled.
1342 * @param data User data
1344 * @return If it returns ECORE_CALLBACK_RENEW, it will be called again at the next tick, or if it returns
1345 * ECORE_CALLBACK_CANCEL it will be deleted automatically making any references/handles for it invalid.
1347 static Eina_Bool _release_uninstalled_pkginfo_timer(void *data)
1349 g_pkgids_to_be_uninstalled.clear ();
1350 g_release_uninstalled_ime_info_timer = NULL;
1351 return ECORE_CALLBACK_CANCEL;
1355 * @brief Called when the package is installed, uninstalled or updated, and the progress of the request to the package manager changes.
1357 * @param[in] type The type of the package to be installed, uninstalled or updated
1358 * @param[in] package The name of the package to be installed, uninstalled or updated
1359 * @param[in] event_type The type of the request to the package manager
1360 * @param[in] event_state The current state of the request to the package manager
1361 * @param[in] progress The progress for the request that is being processed by the package manager \n
1362 * The range of progress is from 0 to 100
1363 * @param[in] error The error code when the package manager failed to process the request
1364 * @param[in] user_data The user data passed from package_manager_set_event_cb()
1365 * @see package_manager_set_event_cb()
1366 * @see package_manager_unset_event_cb()
1368 INFO: Package install/update/uninstall scenario
1369 Install and Uninstall are obviously simple.
1370 Install: just INSTALL
1371 Uninstall: just UNINSTALL
1372 Update package (change the source codes in IME project and Run As again), there are four scenarios:
1375 2. UNINSTALL -> INSTALL
1376 This happens when Tizen IDE Property > Tizen SDK > Rapid Development Support > Check "Enable Project specific settings"
1377 and change Application ID in tizen-manifest.xml file and Run As.
1378 3. UPDATE -> INSTALL
1379 This happens when Tizen IDE Property > Tizen SDK > Rapid Development Support > Uncheck "Enable Project specific settings"
1380 and change Application ID in tizen-manifest.xml file and Run As.
1381 At UPDATE event, pkgid (package parameter) is invalid...
1383 Exceptionally, only UPDATE can be called when Application ID in tizen-manifest.xml file is changed.
1384 At UPDATE event, pkgid (package parameter) is valid, and only appid is changed; the previous appid is invalid.
1386 If multiple packages (including non-IME pkgs) are uninstalled and installed; Z300H UPS (ultra power saving) mode scenario.
1387 For example, A and B packages are uninstalled and installed, the package manager works in this order: A UNINSTALL -> B UNINSTALL -> A INSTALL -> B INSTALL
1389 Assuming IMEngine won't be changed through this. IMEngine might have multiple appids for one pkgid.
1390 Assuming preinstalled IME won't be changed through this.
1392 static void _package_manager_event_cb (const char *type, const char *package, package_manager_event_type_e event_type, package_manager_event_state_e event_state, int progress, package_manager_error_e error, void *user_data)
1394 String current_ime_appid; // now appid is uuid.
1395 std::vector<String> appids;
1396 std::vector<String> total_appids;
1397 std::vector<ImeInfoDB>::iterator it;
1398 std::vector<String>::iterator it2;
1399 VectorPairStringUint32::iterator it3;
1402 if (!package || !type)
1405 if (event_type == PACKAGE_MANAGER_EVENT_TYPE_UPDATE) {
1406 if (event_state == PACKAGE_MANAGER_EVENT_STATE_COMPLETED) {
1407 LOGD ("type=%s package=%s event_type=UPDATE event_state=COMPLETED progress=%d error=%d", type, package, progress, error);
1409 ret = _isf_insert_ime_info_by_pkgid (package); // If package is not IME, -1 would be returned.
1410 if (ret == 1) { // In case the package is updated with the changed appid. In this case, there will be two IMEs
1411 ret = isf_db_select_appids_by_pkgid (package, appids);
1413 if (_ime_info.size () > 0 && _ime_info [get_ise_index (appids.front ())].is_enabled)
1414 isf_db_update_is_enabled_by_appid (appids.back ().c_str (), true);
1415 isf_db_delete_ime_info_by_appid (appids.front ().c_str ());
1418 _update_ime_info ();
1420 /* Let panel know that ise list is changed... */
1421 for (it = _ime_info.begin(); it != _ime_info.end(); it++) {
1422 total_appids.push_back(it->appid);
1424 if (total_appids.size() > 0)
1425 _info_manager->update_ise_list (total_appids);
1427 if (ret > 1 && _soft_keyboard_launched) { // If the previous appid of pkgid is the current IME, restart it with new appid.
1428 current_ime_appid = scim_global_config_read(String(SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), _initial_ise_uuid);
1429 if (current_ime_appid.compare (appids.front ()) == 0) {
1430 LOGD ("Stop IME(%s)", current_ime_appid.c_str ());
1431 _info_manager->hide_helper (current_ime_appid);
1432 _info_manager->stop_helper (current_ime_appid);
1433 LOGD ("Start IME(%s)", appids.back ().c_str ());
1434 scim_global_config_write (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), appids.back ());
1435 set_keyboard_engine (String (SCIM_COMPOSE_KEY_FACTORY_UUID));
1436 _info_manager->start_helper (appids.back ());
1440 else if (ret == 2) { // In case IME package is just updated...
1441 _update_ime_info ();
1443 if (_soft_keyboard_launched) { // If package is the current IME, restart it.
1444 current_ime_appid = scim_global_config_read(String(SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), _initial_ise_uuid);
1445 if (isf_db_select_appids_by_pkgid(package, appids)) {
1446 if (std::find(appids.begin(), appids.end(), current_ime_appid) != appids.end()) { // If the current ISE package is updated, restart it.
1447 for (it = _ime_info.begin (); it != _ime_info.end (); it++) {
1448 if (it->mode == TOOLBAR_HELPER_MODE && it->appid.compare(current_ime_appid) == 0) { // Make sure it's Helper ISE...
1449 LOGD ("Restart IME(%s)", current_ime_appid.c_str ());
1450 _info_manager->hide_helper (current_ime_appid);
1451 _info_manager->stop_helper (current_ime_appid);
1452 _info_manager->start_helper (current_ime_appid);
1460 else if (ret == 0) { // For example, this happens if appid is changed in IME project and Run As again. Assuming only Helper (3rd party) might be updated and there is one appid per each pkgid...
1461 if (isf_db_select_appids_by_pkgid(package, appids) == 1) {
1462 for (it = _ime_info.begin (); it != _ime_info.end (); it++) {
1463 if (it->pkgid.compare(package) == 0) {
1464 g_pkgids_to_be_updated_and_installed.push_back (std::make_pair (it->pkgid, it->is_enabled));
1468 if (it == _ime_info.end ()) // Probably not going to happen.
1469 g_pkgids_to_be_updated_and_installed.push_back(std::make_pair (String(package), 0));
1471 current_ime_appid = scim_global_config_read(String(SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), _initial_ise_uuid);
1472 if (_soft_keyboard_launched && std::find(appids.begin(), appids.end(), current_ime_appid) != appids.end()) { // If the updated IME is the current ISE...
1473 for (it = _ime_info.begin (); it != _ime_info.end (); it++) {
1474 if (it->appid.compare(current_ime_appid) == 0 && it->mode == TOOLBAR_HELPER_MODE) { // Make sure it's Helper ISE...
1475 LOGD ("Stop IME(%s)", current_ime_appid.c_str ());
1476 _info_manager->hide_helper (current_ime_appid);
1477 _info_manager->stop_helper (current_ime_appid);
1478 _soft_keyboard_launched = false;
1479 g_updated_helper_pkgid = package;
1485 if (appids.size () > 0) // Probably appids size is 1.
1486 LOGD ("Delete IME(%s)", appids[0].c_str ());
1487 if (isf_db_delete_ime_info_by_pkgid(package)) { // Delete package from ime_info db.
1490 /* Let panel know that ise is deleted... */
1491 for (it = _ime_info.begin(); it != _ime_info.end(); it++) {
1492 total_appids.push_back(it->appid);
1494 if (total_appids.size() > 0)
1495 _info_manager->update_ise_list (total_appids);
1499 LOGW ("isf_db_select_appids_by_pkgid returned %d.", ret);
1504 else if (event_type == PACKAGE_MANAGER_EVENT_TYPE_INSTALL) {
1505 if (event_state == PACKAGE_MANAGER_EVENT_STATE_COMPLETED) {
1506 LOGD ("type=%s package=%s event_type=INSTALL event_state=COMPLETED progress=%d error=%d", type, package, progress, error);
1508 ///////////////// UNINSTALL -> INSTALL and if the uninstalled IME is reinstalled /////////////////
1509 if (g_stopped_helper_pkgid.compare(package) == 0 && g_start_default_helper_timer) {
1510 LOGD ("Cancel timer to start the default IME");
1511 ecore_timer_del(g_start_default_helper_timer);
1512 g_start_default_helper_timer = NULL;
1513 g_stopped_helper_pkgid = "";
1515 ret = _isf_insert_ime_info_by_pkgid(package);
1517 /* Find appid by pkgid. There might be multiple appid, but assume Helper always has one appid.
1518 And appid can be changed, but pkgid won't be changed. */
1519 ret = isf_db_select_appids_by_pkgid(package, appids);
1520 if (ret == 1 && appids.size () == 1) {
1521 for (it3 = g_pkgids_to_be_uninstalled.begin (); it3 != g_pkgids_to_be_uninstalled.end (); it3++) {
1522 if (it3->first.compare(package) == 0) {
1524 isf_db_update_is_enabled_by_appid(appids[0].c_str (), (bool)it3->second);
1528 /* Let panel know that ise is added... */
1529 for (it = _ime_info.begin(); it != _ime_info.end(); it++) {
1530 total_appids.push_back(it->appid);
1532 if (total_appids.size() > 0)
1533 _info_manager->update_ise_list (total_appids);
1535 LOGD ("Restart IME(%s)", appids[0].c_str ());
1536 scim_global_config_write (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), appids[0]);
1537 set_keyboard_engine (String (SCIM_COMPOSE_KEY_FACTORY_UUID));
1538 _info_manager->start_helper (appids[0]);
1539 _soft_keyboard_launched = true;
1541 g_pkgids_to_be_uninstalled.erase (it3);
1547 LOGW ("isf_db_select_appids_by_pkgid returned %d.", ret);
1551 /* Let panel know that ise is added... */
1552 for (it = _ime_info.begin(); it != _ime_info.end(); it++) {
1553 total_appids.push_back(it->appid);
1555 if (total_appids.size() > 0)
1556 _info_manager->update_ise_list (total_appids);
1560 LOGW ("_isf_insert_ime_info_by_pkgid returned %d.", ret);
1563 else { // If new package is installed...
1564 ret = _isf_insert_ime_info_by_pkgid(package); // If package is not IME, -1 would be returned.
1565 if (ret > 0) { // In case package is IME...
1566 ///////////////// INSTALL /////////////////
1569 /* Let panel know that ise is added... */
1570 for (it = _ime_info.begin(); it != _ime_info.end(); it++) {
1571 total_appids.push_back(it->appid);
1573 if (total_appids.size() > 0)
1574 _info_manager->update_ise_list (total_appids);
1575 ///////////////// END /////////////////
1577 /* For example, the following happens if appid is changed in IME project and Run As again. The appid would be changed this time.
1578 Assuming only Helper (3rd party) might be installed after update or uninstall and there is one appid per each pkgid...*/
1580 ///////////////// UPDATE -> INSTALL /////////////////
1581 for (it3 = g_pkgids_to_be_updated_and_installed.begin (); it3 != g_pkgids_to_be_updated_and_installed.end (); it3++) {
1582 if (it3->first.compare(package) == 0) {
1584 for (it = _ime_info.begin(); it != _ime_info.end(); it++) {
1585 if (it->pkgid.compare(package) == 0) {
1586 it->is_enabled = it3->second;
1587 isf_db_update_is_enabled_by_appid(it->appid.c_str (), (bool)it->is_enabled);
1592 g_pkgids_to_be_updated_and_installed.erase (it3);
1596 if (g_updated_helper_pkgid.compare(package) == 0) {
1597 for (it = _ime_info.begin(); it != _ime_info.end(); it++) {
1598 if (it->mode == TOOLBAR_HELPER_MODE && it->pkgid.compare(package) == 0) {
1599 LOGD ("Start IME(%s)", it->appid.c_str ());
1600 scim_global_config_write (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), it->appid);
1601 set_keyboard_engine (String (SCIM_COMPOSE_KEY_FACTORY_UUID));
1602 _info_manager->start_helper (it->appid);
1603 _soft_keyboard_launched = true;
1607 g_updated_helper_pkgid = "";
1610 ///////////////// END /////////////////
1612 ///////////////// UNINSTALL -> INSTALL /////////////////
1613 for (it3 = g_pkgids_to_be_uninstalled.begin (); it3 != g_pkgids_to_be_uninstalled.end (); it3++) {
1614 if (it3->first.compare(package) == 0) {
1616 for (it = _ime_info.begin(); it != _ime_info.end(); it++) {
1617 if (it->pkgid.compare(package) == 0) {
1618 it->is_enabled = it3->second;
1619 isf_db_update_is_enabled_by_appid(it->appid.c_str (), (bool)it->is_enabled);
1624 g_pkgids_to_be_uninstalled.erase (it3);
1628 ///////////////// END /////////////////
1630 else if (ret == 0) {
1631 LOGW ("_isf_insert_ime_info_by_pkgid returned %d.", ret);
1636 else if (event_type == PACKAGE_MANAGER_EVENT_TYPE_UNINSTALL) {
1637 switch (event_state) {
1638 case PACKAGE_MANAGER_EVENT_STATE_STARTED:
1639 LOGD ("type=%s package=%s event_type=UNINSTALL event_state=STARTED progress=%d error=%d", type, package, progress, error);
1641 // Need to check if there is "http://tizen.org/category/ime" category; it can be done by comparing pkgid with ime_info db.
1643 if (_ime_info.size() == 0)
1646 for (it = _ime_info.begin (); it != _ime_info.end (); it++) {
1647 if (it->pkgid.compare(package) == 0 && it->is_preinstalled == 0) { // Ignore if it's preinstalled IME and IMEngine.
1654 // There might be more than one appid for one pkgid, but let's assume Helper always has one appid per a pkgid. Stop Helper ISE, but not delete it from ime_info db.
1655 LOGD ("%s for pkgid(\"%s\") is about to be deleted", it->appid.c_str (), package);
1656 g_pkgids_to_be_uninstalled.push_back(std::make_pair (String(package), it->is_enabled));
1658 if (_soft_keyboard_launched && isf_db_select_appids_by_pkgid(package, appids)) {
1659 current_ime_appid = scim_global_config_read(String(SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), _initial_ise_uuid);
1660 if (std::find(appids.begin(), appids.end(), current_ime_appid) != appids.end()) { // If the uninstalled IME is the current ISE... appids size is probably 1.
1661 for (it = _ime_info.begin (); it != _ime_info.end (); it++) {
1662 if (it->appid.compare(current_ime_appid) == 0 && it->mode == TOOLBAR_HELPER_MODE) { // Make sure it's Helper ISE...
1663 LOGD ("Stop IME(%s)", current_ime_appid.c_str ());
1664 _info_manager->hide_helper (current_ime_appid);
1665 _info_manager->stop_helper (current_ime_appid);
1666 _soft_keyboard_launched = false;
1667 g_stopped_helper_pkgid = package;
1677 case PACKAGE_MANAGER_EVENT_STATE_COMPLETED:
1678 LOGD ("type=%s package=%s event_type=UNINSTALL event_state=COMPLETED progress=%d error=%d", type, package, progress, error);
1680 for (it3 = g_pkgids_to_be_uninstalled.begin (); it3 != g_pkgids_to_be_uninstalled.end (); it3++) {
1681 if (it3->first.compare(package) == 0) {
1682 if (isf_db_delete_ime_info_by_pkgid(package)) { // Delete package from ime_info db.
1686 if (g_stopped_helper_pkgid.compare(package) == 0) { // If the uninstalled ISE is the current ISE, start the initial helper ISE by timer.
1687 if (g_start_default_helper_timer)
1688 ecore_timer_del(g_start_default_helper_timer);
1689 LOGD ("Add timer to start the default IME");
1690 g_start_default_helper_timer = ecore_timer_add(3.0, _start_default_helper_timer, NULL);
1692 else { // Need to clean up g_pkgids_to_be_uninstalled info unless the same package is installed again; e.g., UNINSTALL -> INSTALL case.
1693 if (g_release_uninstalled_ime_info_timer)
1694 ecore_timer_del(g_release_uninstalled_ime_info_timer);
1695 LOGD ("Add timer to release uninstalled IME pkg info");
1696 g_release_uninstalled_ime_info_timer = ecore_timer_add(7.0, _release_uninstalled_pkginfo_timer, NULL);
1699 /* Let panel know that ise is deleted... */
1700 for (it = _ime_info.begin(); it != _ime_info.end(); it++) {
1701 total_appids.push_back(it->appid);
1703 if (total_appids.size() > 0)
1704 _info_manager->update_ise_list (total_appids);
1711 case PACKAGE_MANAGER_EVENT_STATE_FAILED:
1712 LOGD ("type=%s package=%s event_type=UNINSTALL event_state=FAILED progress=%d error=%d", type, package, progress, error);
1714 for (it3 = g_pkgids_to_be_uninstalled.begin (); it3 != g_pkgids_to_be_uninstalled.end (); it3++) {
1715 if (it3->first.compare(package) == 0) {
1716 // Update _ime_info for sure...
1719 if (g_stopped_helper_pkgid.compare(package) == 0) {
1720 ret = isf_db_select_appids_by_pkgid(package, appids);
1721 if (ret == 1 && appids.size () == 1) {
1722 for (it = _ime_info.begin (); it != _ime_info.end (); it++) {
1723 if (it->appid.compare(appids[0]) == 0 && it->mode == TOOLBAR_HELPER_MODE) { // Make sure it's Helper ISE...
1724 LOGD ("Restart IME(%s)", appids[0].c_str ());
1725 set_keyboard_engine (String (SCIM_COMPOSE_KEY_FACTORY_UUID));
1726 _info_manager->start_helper (appids[0]);
1727 _soft_keyboard_launched = true;
1733 LOGW ("isf_db_select_appids_by_pkgid returned %d.", ret);
1735 g_stopped_helper_pkgid = "";
1738 g_pkgids_to_be_uninstalled.erase (it3);
1752 * @brief Set keyboard ISE.
1754 * @param uuid The keyboard ISE's uuid.
1756 * @return false if keyboard ISE change is failed, otherwise return true.
1758 static bool set_keyboard_ise (const String &uuid)
1760 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
1762 TOOLBAR_MODE_T mode = _info_manager->get_current_toolbar_mode ();
1764 if (TOOLBAR_HELPER_MODE == mode) {
1765 String pre_uuid = _info_manager->get_current_helper_uuid ();
1766 _info_manager->hide_helper (pre_uuid);
1767 _info_manager->stop_helper (pre_uuid);
1768 _soft_keyboard_launched = false;
1769 } else if (TOOLBAR_KEYBOARD_MODE == mode) {
1770 uint32 kbd_option = 0;
1771 String kbd_uuid, kbd_name;
1772 isf_get_keyboard_ise (_config, kbd_uuid, kbd_name, kbd_option);
1773 if (kbd_uuid == uuid)
1777 _info_manager->change_factory (uuid);
1779 String language = String ("~other");/*scim_get_locale_language (scim_get_current_locale ());*/
1780 _config->write (String (SCIM_CONFIG_DEFAULT_IMENGINE_FACTORY) + String ("/") + language, uuid);
1786 * @brief Set helper ISE.
1788 * @param uuid The helper ISE's uuid.
1789 * @param launch_ise The flag for launching helper ISE.
1791 * @return false if helper ISE change is failed, otherwise return true.
1793 static bool set_helper_ise (const String &uuid, bool launch_ise)
1795 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
1797 TOOLBAR_MODE_T mode = _info_manager->get_current_toolbar_mode ();
1798 String pre_uuid = _info_manager->get_current_helper_uuid ();
1799 LOGD ("pre_appid=%s, appid=%s, launch_ise=%d, %d", pre_uuid.c_str(), uuid.c_str(), launch_ise, _soft_keyboard_launched);
1800 if (pre_uuid == uuid && _soft_keyboard_launched)
1803 if (TOOLBAR_HELPER_MODE == mode && pre_uuid.length () > 0 && _soft_keyboard_launched) {
1804 _info_manager->hide_helper (pre_uuid);
1805 _info_manager->stop_helper (pre_uuid);
1806 _soft_keyboard_launched = false;
1807 LOGD ("stop helper : %s", pre_uuid.c_str ());
1811 LOGD ("Start helper (%s)", uuid.c_str ());
1813 set_keyboard_engine (String (SCIM_COMPOSE_KEY_FACTORY_UUID));
1814 if (_info_manager->start_helper (uuid))
1815 _soft_keyboard_launched = true;
1817 _config->write (String (SCIM_CONFIG_DEFAULT_HELPER_ISE), uuid);
1822 #ifdef HAVE_PKGMGR_INFO
1823 int get_ime_app_list_cb (const pkgmgrinfo_appinfo_h handle, void *user_data)
1826 char *appid = NULL, *pkgid = NULL, *pkgtype = NULL, *exec = NULL, *label = NULL, *path = NULL;
1827 pkgmgrinfo_pkginfo_h pkginfo_handle = NULL;
1829 int *result = static_cast<int*>(user_data);
1831 if (result) /* in this case, need to check category */ {
1833 ret = pkgmgrinfo_appinfo_is_category_exist (handle, "http://tizen.org/category/ime", &exist);
1834 if (ret != PMINFO_R_OK || !exist) {
1840 ret = pkgmgrinfo_appinfo_get_appid (handle, &appid);
1841 if (ret == PMINFO_R_OK)
1842 ime_db.appid = String (appid ? appid : "");
1844 LOGE ("pkgmgrinfo_appinfo_get_appid failed! error code=%d", ret);
1848 ime_db.iconpath = "";
1851 ret = pkgmgrinfo_appinfo_get_pkgid (handle, &pkgid);
1852 if (ret == PMINFO_R_OK)
1853 ime_db.pkgid = String (pkgid ? pkgid : "");
1855 LOGE ("pkgmgrinfo_appinfo_get_pkgid failed! error code=%d", ret);
1860 ret = pkgmgrinfo_appinfo_get_exec (handle, &exec);
1861 if (ret == PMINFO_R_OK)
1862 ime_db.exec = String (exec ? exec : "");
1864 LOGE ("pkgmgrinfo_appinfo_get_exec failed! error code=%d", ret);
1869 ret = pkgmgrinfo_appinfo_get_label (handle, &label);
1870 if (ret == PMINFO_R_OK)
1871 ime_db.label = String (label ? label : "");
1873 /* get pkgmgrinfo_pkginfo_h */
1874 /* Try to get in global packages */
1875 ret = pkgmgrinfo_pkginfo_get_pkginfo (pkgid, &pkginfo_handle);
1876 if (ret != PMINFO_R_OK) {
1877 /* Try to get in user packages */
1878 ret = pkgmgrinfo_pkginfo_get_usr_pkginfo (pkgid, getuid (), &pkginfo_handle);
1881 if (ret == PMINFO_R_OK && pkginfo_handle) {
1883 ret = pkgmgrinfo_pkginfo_get_type (pkginfo_handle, &pkgtype);
1885 if (ret == PMINFO_R_OK)
1886 ime_db.pkgtype = String (pkgtype ? pkgtype : "");
1888 ISF_SAVE_LOG ("pkgtype is not available!");
1889 pkgmgrinfo_pkginfo_destroy_pkginfo (pkginfo_handle);
1894 pkgmgrinfo_pkginfo_get_root_path (pkginfo_handle, &path);
1897 ime_db.languages = "en";
1898 ime_db.display_lang = "";
1900 if (ime_db.pkgtype.compare ("rpm") == 0 && //1 Inhouse IMEngine ISE(IME)
1901 ime_db.exec.find ("scim-launcher") != String::npos) // Some IMEngine's pkgid doesn't have "ise-engine" prefix.
1903 ime_db.mode = TOOLBAR_KEYBOARD_MODE;
1905 ime_db.module_path = String (SCIM_MODULE_PATH) + String (SCIM_PATH_DELIM_STRING) + String (SCIM_BINARY_VERSION)
1906 + String (SCIM_PATH_DELIM_STRING) + String ("IMEngine");
1907 ime_db.module_name = ime_db.pkgid;
1908 ime_db.is_enabled = 1;
1909 ime_db.is_preinstalled = 1;
1910 ime_db.has_option = 0; // It doesn't matter. No option for IMEngine...
1913 ime_db.mode = TOOLBAR_HELPER_MODE;
1914 if (ime_db.pkgtype.compare ("rpm") == 0 && path) //1 Inhouse Helper ISE(IME)
1917 ime_db.options = SCIM_HELPER_STAND_ALONE | SCIM_HELPER_NEED_SCREEN_INFO | SCIM_HELPER_AUTO_RESTART | ISM_HELPER_PROCESS_KEYBOARD_KEYEVENT;
1919 ime_db.options = SCIM_HELPER_STAND_ALONE | SCIM_HELPER_NEED_SCREEN_INFO | SCIM_HELPER_AUTO_RESTART;
1921 ime_db.module_name = ime_db.pkgid;
1923 String module_path = String (path) + String ("/lib");
1924 String fullpath = module_path + String (SCIM_PATH_DELIM_STRING) + ime_db.module_name + String (".so");
1926 if (stat (fullpath.c_str (), &st) < 0) {
1927 /* Not found in lib directory of package's root path */
1928 ime_db.module_path = String (SCIM_MODULE_PATH) + String (SCIM_PATH_DELIM_STRING) + String (SCIM_BINARY_VERSION)
1929 + String (SCIM_PATH_DELIM_STRING) + String ("Helper");
1932 ime_db.module_path = module_path;
1935 ime_db.is_enabled = 1;
1936 ime_db.is_preinstalled = 1;
1937 ime_db.has_option = 1; // Let's assume the inhouse IME always has an option menu.
1939 else if (ime_db.pkgtype.compare ("wgt") == 0) //1 Download Web IME
1941 ime_db.options = SCIM_HELPER_STAND_ALONE | SCIM_HELPER_NEED_SCREEN_INFO | SCIM_HELPER_AUTO_RESTART
1942 | SCIM_HELPER_NEED_SPOT_LOCATION_INFO | ISM_HELPER_PROCESS_KEYBOARD_KEYEVENT | ISM_HELPER_WITHOUT_IMENGINE;
1943 ime_db.module_path = String (SCIM_MODULE_PATH) + String (SCIM_PATH_DELIM_STRING) + String (SCIM_BINARY_VERSION)
1944 + String (SCIM_PATH_DELIM_STRING) + String ("Helper");
1945 ime_db.module_name = String ("ise-web-helper-agent");
1946 if (ime_db.exec.compare (0, 5, "/usr/") == 0) {
1947 ime_db.is_enabled = 1;
1948 ime_db.is_preinstalled = 1;
1952 ime_db.is_enabled = 0;
1954 ime_db.is_enabled = 1;
1956 ime_db.is_preinstalled = 0;
1958 ime_db.has_option = -1; // At this point, we can't know IME has an option (setting) or not; -1 means unknown.
1960 else if (ime_db.pkgtype.compare ("tpk") == 0) //1 Download Native IME
1962 ime_db.options = SCIM_HELPER_STAND_ALONE | SCIM_HELPER_NEED_SCREEN_INFO | SCIM_HELPER_AUTO_RESTART
1963 | ISM_HELPER_PROCESS_KEYBOARD_KEYEVENT | ISM_HELPER_WITHOUT_IMENGINE;
1965 ime_db.module_path = String (path) + String ("/lib");
1967 ime_db.module_path = String (tzplatform_getenv(TZ_SYS_RW_APP)) + ime_db.pkgid + String ("/lib");
1968 ime_db.module_name = String ("lib") + ime_db.exec.substr (ime_db.exec.find_last_of (SCIM_PATH_DELIM) + 1);
1969 if (ime_db.exec.compare (0, 5, "/usr/") == 0) {
1970 ime_db.is_enabled = 1;
1971 ime_db.is_preinstalled = 1;
1975 ime_db.is_enabled = 0;
1977 ime_db.is_enabled = 1;
1979 ime_db.is_preinstalled = 0;
1981 ime_db.has_option = -1; // At this point, we can't know IME has an option (setting) or not; -1 means unknown.
1984 LOGE ("Unsupported pkgtype(%s)", ime_db.pkgtype.c_str ());
1985 if (pkginfo_handle) {
1986 pkgmgrinfo_pkginfo_destroy_pkginfo (pkginfo_handle);
1987 pkginfo_handle = NULL;
1993 _ime_info.push_back(ime_db);
1995 if (pkginfo_handle) {
1996 pkgmgrinfo_pkginfo_destroy_pkginfo (pkginfo_handle);
1997 pkginfo_handle = NULL;
2005 * @brief Set active ISE.
2007 * @param uuid The ISE's uuid.
2008 * @param launch_ise The flag for launching helper ISE.
2010 * @return false if ISE change is failed, otherwise return true.
2012 static bool set_active_ise (const String &uuid, bool launch_ise)
2014 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2015 LOGD ("set ISE (%s) %d", uuid.c_str(), launch_ise);
2017 if (uuid.length () <= 0)
2020 bool ise_changed = false, valid = false;
2022 int ime_num = -1; /* If we failed retrieving the number of IMEs installed, assume we need to clear IME related settings */
2023 pkgmgrinfo_appinfo_filter_h handle;
2024 int ret = pkgmgrinfo_appinfo_filter_create(&handle);
2025 if (ret == PMINFO_R_OK) {
2026 ret = pkgmgrinfo_appinfo_filter_add_string(handle, PMINFO_APPINFO_PROP_APP_CATEGORY, "http://tizen.org/category/ime");
2027 if (ret == PMINFO_R_OK) {
2028 ret = pkgmgrinfo_appinfo_filter_count(handle, &ime_num);
2029 if (ret != PMINFO_R_OK) {
2030 LOGW("pkgmgrinfo_appinfo_filter_count failed(%d)", ret);
2033 pkgmgrinfo_appinfo_filter_destroy (handle);
2036 LOGE ("pkgmgrinfo_appinfo_filter_create failed(%d)", ret);
2039 /* If the ime_num and _ime_info.size() are different, it is likely that the isf-panel-efl was
2040 terminated abnormally while processing package manager's install / uninstall events */
2041 LOGD("Checking whether db file needs to be re-created : %d %zu", ime_num, _ime_info.size());
2042 if (ime_num != (int)_ime_info.size()) {
2044 isf_db_delete_ime_info();
2045 isf_pkg_reload_ime_info_db();
2046 isf_pkg_select_all_ime_info_db(_ime_info);
2049 if (_ime_info.size () == 0) {
2050 #ifdef HAVE_PKGMGR_INFO
2051 int ret = pkgmgrinfo_appinfo_filter_create (&handle);
2052 if (ret == PMINFO_R_OK) {
2053 ret = pkgmgrinfo_appinfo_filter_add_string (handle, PMINFO_APPINFO_PROP_APP_CATEGORY, "http://tizen.org/category/ime");
2054 if (ret == PMINFO_R_OK)
2055 ret = pkgmgrinfo_appinfo_filter_foreach_appinfo (handle, get_ime_app_list_cb, NULL);
2057 LOGE ("pkgmgrinfo_appinfo_filter_add_string failed(%d)", ret);
2059 pkgmgrinfo_appinfo_filter_destroy (handle);
2062 LOGE ("pkgmgrinfo_appinfo_filter_create failed(%d)", ret);
2067 for (unsigned int i = 0; i < _ime_info.size (); i++) {
2068 if (!uuid.compare (_ime_info[i].appid)) {
2069 if (TOOLBAR_KEYBOARD_MODE == _ime_info[i].mode)
2070 ise_changed = set_keyboard_ise (_ime_info[i].appid);
2071 else if (TOOLBAR_HELPER_MODE == _ime_info[i].mode) {
2072 if (_ime_info[i].is_enabled) {
2073 if (_ime_info[i].exec == String (SCIM_HELPER_LAUNCHER_PROGRAM)) {
2074 /* If IME so is deleted somehow, main() in scim_helper_launcher.cpp will return -1.
2075 Checking HelperModule validity seems necessary here. */
2076 HelperModule helper_module (_ime_info[i].module_name);
2077 if (helper_module.valid ())
2079 helper_module.unload ();
2082 /* executable type */
2087 ise_changed = set_helper_ise (_ime_info[i].appid, launch_ise);
2089 LOGW ("Helper ISE(appid=\"%s\",module_name=\"%s\") is not valid.", _ime_info[i].appid.c_str (), _ime_info[i].module_name.c_str ());
2092 LOGW ("Helper ISE(appid=\"%s\") is not enabled.", _ime_info[i].appid.c_str ());
2095 _info_manager->set_current_toolbar_mode (_ime_info[i].mode);
2097 /* From Tizen 4.0 all the ISEs need to handle H/W keyboard events */
2098 _ime_info[i].options |= ISM_HELPER_PROCESS_KEYBOARD_KEYEVENT;
2099 _info_manager->set_current_helper_option (_ime_info[i].options);
2100 _info_manager->set_current_ise_name (_ime_info[i].label);
2103 _ise_state = WINDOW_STATE_HIDE;
2104 _candidate_mode = SOFT_CANDIDATE_WINDOW;
2105 _candidate_port_line = ONE_LINE_CANDIDATE;
2106 _soft_candidate_width = 0;
2107 _soft_candidate_height = 0;
2108 #if ISF_BUILD_CANDIDATE_UI
2109 if (_candidate_window)
2110 ui_create_candidate_window ();
2113 scim_global_config_write (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), _ime_info[i].appid);
2114 scim_global_config_flush ();
2120 vconf_set_str (VCONFKEY_ISF_ACTIVE_KEYBOARD_UUID, uuid.c_str ());
2124 LOGW ("Failed to launch IME (%s)", uuid.c_str ());
2131 LOGW ("Failed to launch IME (%s), %zu", uuid.c_str (), _ime_info.size());
2137 * @brief Set temporary ISE.
2139 * @param uuid The ISE's uuid.
2141 * @return false if ISE change is failed, otherwise return true.
2143 static bool set_temporary_ise (const String &uuid)
2145 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2146 LOGD ("set temporary ISE (%s)", uuid.c_str ());
2148 if (uuid.length () <= 0)
2151 if (_ime_info.size () == 0) {
2152 #ifdef HAVE_PKGMGR_INFO
2153 pkgmgrinfo_appinfo_filter_h handle;
2154 int ret = pkgmgrinfo_appinfo_filter_create (&handle);
2155 if (ret == PMINFO_R_OK) {
2156 /* Add the package info for the IME that matches with our uuid only */
2157 ret = pkgmgrinfo_appinfo_filter_add_string (handle, PMINFO_APPINFO_PROP_APP_ID, uuid.c_str ());
2158 if (ret == PMINFO_R_OK)
2159 ret = pkgmgrinfo_appinfo_filter_foreach_appinfo (handle, get_ime_app_list_cb, NULL);
2161 LOGE ("pkgmgrinfo_appinfo_filter_add_string failed(%d)", ret);
2163 pkgmgrinfo_appinfo_filter_destroy (handle);
2165 LOGE ("pkgmgrinfo_appinfo_filter_create failed(%d)", ret);
2170 #ifdef HAVE_PKGMGR_INFO
2171 bool ise_changed = false;
2173 pkgmgrinfo_appinfo_h handle = NULL;
2174 int ret = pkgmgr_get_appinfo (uuid.c_str (), &handle);
2175 if (ret != PMINFO_R_OK) {
2176 LOGW ("appid \"%s\" is invalid.", uuid.c_str ());
2182 ret = pkgmgrinfo_appinfo_get_label (handle, &label);
2183 if (ret != PMINFO_R_OK) {
2184 LOGW ("Could not get label for appid '%s'", uuid.c_str ());
2185 pkgmgrinfo_appinfo_destroy_appinfo (handle);
2189 ise_changed = set_helper_ise (uuid, true);
2192 _info_manager->set_current_toolbar_mode (TOOLBAR_HELPER_MODE);
2194 _info_manager->set_current_helper_option (SCIM_HELPER_STAND_ALONE | SCIM_HELPER_NEED_SCREEN_INFO |
2195 SCIM_HELPER_AUTO_RESTART | ISM_HELPER_PROCESS_KEYBOARD_KEYEVENT);
2197 _info_manager->set_current_helper_option (SCIM_HELPER_STAND_ALONE | SCIM_HELPER_NEED_SCREEN_INFO |
2198 SCIM_HELPER_AUTO_RESTART);
2199 String label_string = label;
2200 _info_manager->set_current_ise_name (label_string);
2203 vconf_set_str (VCONFKEY_ISF_ACTIVE_KEYBOARD_UUID, uuid.c_str ());
2206 LOGW ("Failed to launch IME (%s)", uuid.c_str ());
2209 pkgmgrinfo_appinfo_destroy_appinfo (handle);
2219 * @brief Load ISF configuration and ISEs information.
2221 static void load_config (void)
2223 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2225 /* Read configurations. */
2226 if (!_config.null ()) {
2227 bool shared_ise = _config->read (String (SCIM_CONFIG_FRONTEND_SHARED_INPUT_METHOD), false);
2228 _info_manager->set_should_shared_ise (shared_ise);
2230 _launch_ise_on_request = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_LAUNCH_ISE_ON_REQUEST), _launch_ise_on_request);
2231 _auto_destroy_ise = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_ENABLE_AUTO_DESTROY_ISE), _auto_destroy_ise);
2233 isf_load_ise_information (ALL_ISE, _config);
2237 * @brief Reload config callback function for ISF panel.
2239 * @param config The config pointer.
2241 static void config_reload_cb (const ConfigPointer &config)
2243 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2244 /* load_config (); */
2245 _info_manager->reload_config ();
2248 #if ISF_BUILD_CANDIDATE_UI
2249 //////////////////////////////////////////////////////////////////////
2250 // Start of Candidate Functions
2251 //////////////////////////////////////////////////////////////////////
2253 * @brief Get candidate window valid height for autoscroll.
2255 * @return The valid height.
2257 static int ui_candidate_get_valid_height (void)
2259 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "\n";
2264 if (_candidate_window) {
2265 if (_candidate_state == WINDOW_STATE_SHOW)
2266 angle = _candidate_angle;
2268 angle = efl_get_app_window_angle ();
2270 if (_aux_area_visible && _candidate_area_1_visible) {
2271 if (angle == 90 || angle == 270)
2272 height = _candidate_land_height_min_2;
2274 height = _candidate_port_height_min_2;
2276 if (angle == 90 || angle == 270)
2277 height = _candidate_land_height_min;
2279 height = _candidate_port_height_min;
2286 * @brief Resize candidate window size.
2288 * @param new_width New width for candidate window.
2289 * @param new_height New height for candidate window.
2291 static void ui_candidate_window_resize (int new_width, int new_height)
2293 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " width:" << new_width << " height:" << new_height << "\n";
2295 if (!_candidate_window)
2300 LOGD ("%s (w: %d, h: %d)", __func__, new_width, new_height);
2301 evas_object_resize (_aux_line, new_width, 2);
2302 _candidate_width = new_width;
2303 _candidate_height = new_height;
2304 if (_candidate_state == WINDOW_STATE_SHOW)
2305 _info_manager->update_candidate_panel_event ((uint32)ECORE_IMF_CANDIDATE_PANEL_GEOMETRY_EVENT, 0);
2307 if (_candidate_state == WINDOW_STATE_SHOW && _candidate_mode == FIXED_CANDIDATE_WINDOW) {
2308 height = ui_candidate_get_valid_height ();
2309 if ((_ise_width == 0 && _ise_height == 0) ||
2310 (_ise_height > 0 && _candidate_valid_height != height) ||
2311 (_ise_height > 0 && (_candidate_height - height) > _ise_height) ||
2312 ((_candidate_angle == 90 || _candidate_angle == 270) && (_ise_width < _screen_height)) ||
2313 ((_candidate_angle == 0 || _candidate_angle == 180) && (_ise_width > _screen_width ))) {
2315 set_keyboard_geometry_atom_info (_app_window, get_ise_geometry ());
2317 _info_manager->update_input_panel_event (ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
2321 /* Get height for portrait and landscape */
2322 int port_width = _candidate_port_width;
2323 int port_height = _candidate_port_height_min;
2324 int land_width = _candidate_land_width;
2325 int land_height = _candidate_land_height_min;
2326 if (_candidate_angle == 90 || _candidate_angle == 270) {
2327 land_height = new_height;
2328 if (land_height == _candidate_land_height_min_2) {
2329 port_height = _candidate_port_height_min_2;
2330 } else if (land_height == _candidate_land_height_max) {
2331 port_height = _candidate_port_height_max;
2332 } else if (land_height == _candidate_land_height_max_2) {
2333 port_height = _candidate_port_height_max_2;
2336 port_height = new_height;
2337 if (port_height == _candidate_port_height_min_2) {
2338 land_height = _candidate_land_height_min_2;
2339 } else if (port_height == _candidate_port_height_max) {
2340 land_height = _candidate_land_height_max;
2341 } else if (port_height == _candidate_port_height_max_2) {
2342 land_height = _candidate_land_height_max_2;
2346 LOGD ("window_rotation_geometry_set (_candidate_window), port (%d, %d), land (%d, %d)",
2347 port_width, port_height, land_width, land_height);
2351 ecore_x_e_window_rotation_geometry_set (elm_win_xwindow_get (_candidate_window),
2352 0, 0, 0, port_width, port_height);
2353 ecore_x_e_window_rotation_geometry_set (elm_win_xwindow_get (_candidate_window),
2354 90, 0, 0, land_height, land_width);
2355 ecore_x_e_window_rotation_geometry_set (elm_win_xwindow_get (_candidate_window),
2356 180, 0, 0, port_width, port_height);
2357 ecore_x_e_window_rotation_geometry_set (elm_win_xwindow_get (_candidate_window),
2358 270, 0, 0, land_height, land_width);
2361 ecore_wl2_window_rotation_geometry_set ((Ecore_Wl2_Window *)elm_win_wl_window_get (_candidate_window),
2362 0, 0, 0, port_width, port_height);
2363 ecore_wl2_window_rotation_geometry_set ((Ecore_Wl2_Window *)elm_win_wl_window_get (_candidate_window),
2364 90, 0, 0, land_height, land_width);
2365 ecore_wl2_window_rotation_geometry_set ((Ecore_Wl2_Window *)elm_win_wl_window_get (_candidate_window),
2366 180, 0, 0, port_width, port_height);
2367 ecore_wl2_window_rotation_geometry_set ((Ecore_Wl2_Window *)elm_win_wl_window_get (_candidate_window),
2368 270, 0, 0, land_height, land_width);
2373 * @brief This function will show/hide widgets of candidate window,
2374 * and resize candidate window size according to aux_area/candidate_area.
2376 static void ui_candidate_window_adjust (void)
2378 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2379 if (!_candidate_window)
2382 int x = 0, y = 0, width = 0, height = 0;
2384 /* Get candidate window size */
2387 if (_candidate_angle == 90 || _candidate_angle == 270) {
2388 ecore_x_e_window_rotation_geometry_get (elm_win_xwindow_get (_candidate_window), _candidate_angle,
2389 &x, &y, &height, &width);
2391 ecore_x_e_window_rotation_geometry_get (elm_win_xwindow_get (_candidate_window), _candidate_angle,
2392 &x, &y, &width, &height);
2396 if (_candidate_angle == 90 || _candidate_angle == 270)
2397 ecore_evas_geometry_get (ecore_evas_ecore_evas_get (evas_object_evas_get (_candidate_window)), &x, &y, &height, &width);
2399 ecore_evas_geometry_get (ecore_evas_ecore_evas_get (evas_object_evas_get (_candidate_window)), &x, &y, &width, &height);
2402 if (_aux_area_visible && _candidate_area_2_visible) {
2403 evas_object_show (_aux_line);
2404 evas_object_move (_candidate_area_1, _candidate_area_1_pos[0], _candidate_area_1_pos[1] + _candidate_port_height_min_2 - _candidate_port_height_min);
2405 if (_candidate_angle == 90 || _candidate_angle == 270) {
2406 if (_candidate_mode == FIXED_CANDIDATE_WINDOW && _ise_state == WINDOW_STATE_SHOW &&
2407 _ise_height > _candidate_land_height_max_2 - _candidate_land_height_min_2)
2408 ui_candidate_window_resize (width, _candidate_land_height_min_2 + _ise_height);
2410 ui_candidate_window_resize (width, _candidate_land_height_max_2);
2411 evas_object_move (_close_btn, _close_btn_pos[2], _close_btn_pos[3] + _candidate_port_height_min_2 - _candidate_port_height_min);
2412 evas_object_move (_candidate_area_2, 0, _candidate_land_height_min_2);
2413 evas_object_move (_scroller_bg, 0, _candidate_land_height_min_2);
2414 evas_object_resize (_candidate_bg, width, _candidate_land_height_min_2);
2416 if (_candidate_mode == FIXED_CANDIDATE_WINDOW && _ise_state == WINDOW_STATE_SHOW &&
2417 _ise_height > _candidate_port_height_max_2 - _candidate_port_height_min_2)
2418 ui_candidate_window_resize (width, _candidate_port_height_min_2 + _ise_height);
2420 ui_candidate_window_resize (width, _candidate_port_height_max_2);
2421 evas_object_move (_close_btn, _close_btn_pos[0], _close_btn_pos[1] + _candidate_port_height_min_2 - _candidate_port_height_min);
2422 evas_object_move (_candidate_area_2, 0, _candidate_port_height_min_2);
2423 evas_object_move (_scroller_bg, 0, _candidate_port_height_min_2);
2424 evas_object_resize (_candidate_bg, width, _candidate_port_height_min_2);
2426 } else if (_aux_area_visible && _candidate_area_1_visible) {
2427 evas_object_show (_aux_line);
2428 evas_object_move (_candidate_area_1, _candidate_area_1_pos[0], _candidate_area_1_pos[1] + _candidate_port_height_min_2 - _candidate_port_height_min);
2429 if (_candidate_angle == 90 || _candidate_angle == 270) {
2430 ui_candidate_window_resize (width, _candidate_land_height_min_2);
2431 evas_object_move (_more_btn, _more_btn_pos[2], _more_btn_pos[3] + _candidate_port_height_min_2 - _candidate_port_height_min);
2432 evas_object_resize (_candidate_bg, width, _candidate_land_height_min_2);
2434 ui_candidate_window_resize (width, _candidate_port_height_min_2);
2435 evas_object_move (_more_btn, _more_btn_pos[0], _more_btn_pos[1] + _candidate_port_height_min_2 - _candidate_port_height_min);
2436 evas_object_resize (_candidate_bg, width, _candidate_port_height_min_2);
2438 } else if (_aux_area_visible) {
2439 evas_object_hide (_aux_line);
2440 ui_candidate_window_resize (width, _aux_height + 2);
2441 evas_object_resize (_candidate_bg, width, _aux_height + 2);
2442 } else if (_candidate_area_2_visible) {
2443 evas_object_hide (_aux_line);
2444 evas_object_move (_candidate_area_1, _candidate_area_1_pos[0], _candidate_area_1_pos[1]);
2445 if (_candidate_angle == 90 || _candidate_angle == 270) {
2446 if (_candidate_mode == FIXED_CANDIDATE_WINDOW && _ise_state == WINDOW_STATE_SHOW &&
2447 _ise_height > _candidate_land_height_max - _candidate_land_height_min)
2448 ui_candidate_window_resize (width, _candidate_land_height_min + _ise_height);
2450 ui_candidate_window_resize (width, _candidate_land_height_max);
2451 evas_object_move (_close_btn, _close_btn_pos[2], _close_btn_pos[3]);
2452 evas_object_move (_candidate_area_2, 0, _candidate_land_height_min);
2453 evas_object_move (_scroller_bg, 0, _candidate_land_height_min);
2454 evas_object_resize (_candidate_bg, width, _candidate_land_height_min);
2456 if (_candidate_mode == FIXED_CANDIDATE_WINDOW && _ise_state == WINDOW_STATE_SHOW &&
2457 _ise_height > _candidate_port_height_max - _candidate_port_height_min)
2458 ui_candidate_window_resize (width, _candidate_port_height_min + _ise_height);
2460 ui_candidate_window_resize (width, _candidate_port_height_max);
2461 evas_object_move (_close_btn, _close_btn_pos[0], _close_btn_pos[1]);
2462 evas_object_move (_candidate_area_2, 0, _candidate_port_height_min);
2463 evas_object_move (_scroller_bg, 0, _candidate_port_height_min);
2464 evas_object_resize (_candidate_bg, width, _candidate_port_height_min);
2467 evas_object_hide (_aux_line);
2468 evas_object_move (_candidate_area_1, _candidate_area_1_pos[0], _candidate_area_1_pos[1]);
2469 if (_candidate_angle == 90 || _candidate_angle == 270) {
2470 ui_candidate_window_resize (width, _candidate_land_height_min);
2471 evas_object_move (_more_btn, _more_btn_pos[2], _more_btn_pos[3]);
2472 evas_object_resize (_candidate_bg, width, _candidate_land_height_min);
2474 ui_candidate_window_resize (width, _candidate_port_height_min);
2475 evas_object_move (_more_btn, _more_btn_pos[0], _more_btn_pos[1]);
2476 evas_object_resize (_candidate_bg, width, _candidate_port_height_min);
2482 * @brief Rotate candidate window.
2484 * @param angle The angle of candidate window.
2486 static void ui_candidate_window_rotate (int angle)
2488 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2489 if (!_candidate_window)
2492 ui_candidate_window_close_button_cb (NULL, NULL, NULL, NULL);
2494 if (angle == 90 || angle == 270) {
2495 _candidate_scroll_width = _candidate_scroll_width_max;
2496 ui_candidate_window_resize (_candidate_land_width, _candidate_land_height_min);
2497 evas_object_resize (_aux_area, _aux_land_width, _aux_height);
2498 evas_object_resize (_candidate_area_1, _candidate_scroll_0_width_max, _item_min_height);
2499 evas_object_resize (_candidate_area_2, _candidate_scroll_width, _candidate_scroll_height_min);
2500 evas_object_resize (_scroller_bg, _candidate_scroll_width, _candidate_scroll_height_min + 6);
2502 _candidate_scroll_width = _candidate_scroll_width_min;
2503 ui_candidate_window_resize (_candidate_port_width, _candidate_port_height_min);
2504 evas_object_resize (_aux_area, _aux_port_width, _aux_height);
2505 evas_object_resize (_candidate_area_1, _candidate_scroll_0_width_min, (_item_min_height+2)*_candidate_port_line-2);
2506 evas_object_resize (_candidate_area_2, _candidate_scroll_width, _candidate_scroll_height_max);
2507 evas_object_resize (_scroller_bg, _candidate_scroll_width, _candidate_scroll_height_max + 6);
2510 evas_object_hide (_candidate_area_2);
2511 _candidate_area_2_visible = false;
2512 ui_candidate_window_adjust ();
2513 if (_candidate_area_1_visible) {
2514 update_table (ISF_CANDIDATE_TABLE, g_isf_candidate_table);
2515 _candidate_tts_focus_index = INVALID_TTS_FOCUS_INDEX;
2516 ui_tts_focus_rect_hide ();
2522 * @brief This function is used to judge whether candidate window should be hidden.
2524 * @return true if candidate window should be hidden, otherwise return false.
2526 static bool ui_candidate_can_be_hide (void)
2528 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2530 if (_aux_area_visible || _candidate_area_1_visible || _candidate_area_2_visible)
2537 * @brief Delete check candidate window size timer.
2541 static void ui_candidate_delete_check_size_timer (void)
2543 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2545 if (_check_size_timer != NULL) {
2546 ecore_timer_del (_check_size_timer);
2547 _check_size_timer = NULL;
2552 * @brief Callback function for check candidate window size timer.
2554 * @param data Data to pass when it is called.
2556 * @return ECORE_CALLBACK_CANCEL
2558 static Eina_Bool ui_candidate_check_size_timeout (void *data)
2560 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2562 ui_candidate_delete_check_size_timer ();
2563 ui_candidate_window_resize (_candidate_width, _candidate_height);
2564 ui_settle_candidate_window ();
2565 return ECORE_CALLBACK_CANCEL;
2569 * @brief Delete longpress timer.
2573 static void ui_candidate_delete_longpress_timer (void)
2575 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2577 if (_longpress_timer != NULL) {
2578 ecore_timer_del (_longpress_timer);
2579 _longpress_timer = NULL;
2584 * @brief Callback function for candidate longpress timer.
2586 * @param data Data to pass when it is called.
2588 * @return ECORE_CALLBACK_CANCEL
2590 static Eina_Bool ui_candidate_longpress_timeout (void *data)
2592 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2594 int index = (int)GPOINTER_TO_INT (data);
2595 ui_candidate_delete_longpress_timer ();
2597 _info_manager->send_longpress_event (_click_object, index);
2598 return ECORE_CALLBACK_CANCEL;
2602 * @brief Delete destroy timer.
2606 static void ui_candidate_delete_destroy_timer (void)
2608 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2610 if (_destroy_timer != NULL) {
2611 ecore_timer_del (_destroy_timer);
2612 _destroy_timer = NULL;
2617 * @brief Callback function for destroy timer.
2619 * @param data Data to pass when it is called.
2621 * @return ECORE_CALLBACK_CANCEL
2623 static Eina_Bool ui_candidate_destroy_timeout (void *data)
2625 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2627 ui_candidate_delete_destroy_timer ();
2628 ui_destroy_candidate_window ();
2629 return ECORE_CALLBACK_CANCEL;
2631 #endif /* CANDIDATE */
2635 * @brief Callback function for off_prepare_done.
2637 * @param data Data to pass when it is called.
2639 * @return ECORE_CALLBACK_CANCEL
2641 static Eina_Bool off_prepare_done_timeout (void *data)
2643 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2645 /* WMSYNC, #8 Let the Window Manager to actually hide keyboard window */
2646 // WILL_HIDE_REQUEST_DONE Ack to WM
2647 Ecore_X_Window root_window = ecore_x_window_root_get (_control_window);
2648 //ecore_x_e_virtual_keyboard_off_prepare_done_send (root_window, _control_window);
2649 LOGD ("_ecore_x_e_virtual_keyboard_off_prepare_done_send (%x, %x)",
2650 root_window, _control_window);
2651 _off_prepare_done_timer = NULL;
2653 return ECORE_CALLBACK_CANCEL;
2655 #endif /* HAVE_ECOREX */
2657 #if ISF_BUILD_CANDIDATE_UI
2659 * @brief Delete candidate hide timer.
2663 static void delete_candidate_hide_timer (void)
2665 LOGD ("deleting candidate_hide_timer");
2666 if (_candidate_hide_timer) {
2667 ecore_timer_del (_candidate_hide_timer);
2668 _candidate_hide_timer = NULL;
2672 static void candidate_window_hide (void)
2674 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "\n";
2676 delete_candidate_hide_timer ();
2677 _candidate_state = WINDOW_STATE_HIDE;
2679 LOGD ("evas_object_hide (_candidate_window, %p)", elm_win_xwindow_get (_candidate_window));
2681 if (_candidate_window) {
2682 /* There are cases that when there are rapid ISE_HIDE and ISE_SHOW requests,
2683 candidate window should be displayed but STATE_OFF for the first ISE_HIDE
2684 calls this function, so when the candidate window is shown by the following
2685 STATE_ON message, a blank area is displayed in candidate window -
2686 so we let the _candidate_area_1 as the default area that would be displayed */
2687 //evas_object_hide (_candidate_area_1);
2688 //evas_object_hide (_more_btn);
2689 _candidate_area_1_visible = false;
2691 evas_object_hide (_candidate_window);
2692 SCIM_DEBUG_MAIN (3) << " Hide candidate window\n";
2697 * @brief Callback function for candidate hide timer
2699 * @param data Data to pass when it is called.
2701 * @return ECORE_CALLBACK_CANCEL
2703 static Eina_Bool candidate_hide_timer (void *data)
2705 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2707 LOGD ("calling candidate_window_hide ()");
2708 candidate_window_hide ();
2710 return ECORE_CALLBACK_CANCEL;
2715 * @brief Delete candidate show handler.
2719 static void delete_candidate_show_handler (void)
2721 if (_candidate_show_handler) {
2722 ecore_event_handler_del (_candidate_show_handler);
2723 _candidate_show_handler = NULL;
2728 * @brief Callback function for window show completion event
2730 * @param data Data to pass when it is called.
2732 * @return ECORE_CALLBACK_CANCEL
2735 static Eina_Bool x_event_window_show_cb (void *data, int ev_type, void *event)
2737 delete_candidate_show_handler ();
2739 Ecore_X_Event_Window_Show *e = (Ecore_X_Event_Window_Show*)event;
2740 if (_candidate_state == WINDOW_STATE_WILL_SHOW) {
2741 if (e->win == elm_win_xwindow_get (_candidate_window)) {
2742 LOGD ("Candidate window show callback");
2744 /* If our candidate window is in WILL_SHOW state and this show callback was called,
2745 now we are finally displayed on to the screen */
2746 _candidate_state = WINDOW_STATE_SHOW;
2748 /* Update the geometry information for auto scrolling */
2749 set_keyboard_geometry_atom_info (_app_window, get_ise_geometry ());
2750 _info_manager->update_input_panel_event (ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
2751 _info_manager->update_input_panel_event (ECORE_IMF_CANDIDATE_PANEL_GEOMETRY_EVENT, 0);
2753 /* And the state event */
2754 _info_manager->update_candidate_panel_event ((uint32)ECORE_IMF_CANDIDATE_PANEL_STATE_EVENT, (uint32)ECORE_IMF_CANDIDATE_PANEL_SHOW);
2756 /* If we are in hardware keyboard mode, this candidate window is now considered to be a input panel */
2757 if (_candidate_mode == FIXED_CANDIDATE_WINDOW) {
2758 if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) {
2759 _info_manager->update_input_panel_event ((uint32)ECORE_IMF_INPUT_PANEL_STATE_EVENT, (uint32)ECORE_IMF_INPUT_PANEL_STATE_SHOW);
2764 if (e->win == elm_win_xwindow_get (_candidate_window)) {
2765 LOGD ("Candidate window show callback, but _candidate_state is %d", _candidate_state);
2769 return ECORE_CALLBACK_CANCEL;
2771 #endif /* HAVE_ECOREX */
2774 * @brief Show candidate window.
2776 * @param bSetVirtualKbd The flag for set_keyboard_geometry_atom_info () calling.
2778 static void ui_candidate_show (bool bSetVirtualKbd)
2780 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2782 delete_candidate_hide_timer ();
2784 if (!_candidate_window) return;
2785 if (_candidate_mode == SOFT_CANDIDATE_WINDOW)
2788 /* FIXME : SHOULD UNIFY THE METHOD FOR CHECKING THE HW KEYBOARD EXISTENCE */
2789 /* If the ISE is not visible currently, wait for the ISE to be opened and then show our candidate window */
2790 _candidate_show_requested = true;
2791 if ((_info_manager->get_current_toolbar_mode () == TOOLBAR_HELPER_MODE) && (_ise_state != WINDOW_STATE_SHOW)) {
2792 LOGD ("setting _show_candidate_requested to TRUE");
2796 /* If the ISE angle is valid, respect the value to make sure
2797 the candidate window always have the same angle with ISE */
2798 if (_ise_angle != -1) {
2799 _candidate_angle = _ise_angle;
2801 ui_candidate_window_rotate (_candidate_angle);
2803 /* If the candidate window was about to hide, turn it back to SHOW state now */
2804 if (_candidate_state == WINDOW_STATE_WILL_HIDE) {
2805 _candidate_state = WINDOW_STATE_SHOW;
2808 /* Change to WILL_SHOW state only when we are not currently in SHOW state */
2809 if (_candidate_state != WINDOW_STATE_SHOW) {
2810 _candidate_state = WINDOW_STATE_WILL_SHOW;
2814 if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) {
2815 /* WMSYNC, #3 Clear the existing application's conformant area and set transient_for */
2816 // Unset conformant area
2817 Ecore_X_Window current_app_window = efl_get_app_window ();
2818 if (_app_window != current_app_window) {
2819 struct rectinfo info = {0, 0, 0, 0};
2820 info.pos_y = _screen_width > _screen_height ? _screen_width : _screen_height;
2821 set_keyboard_geometry_atom_info (_app_window, info);
2822 LOGD ("Conformant reset for window %x", _app_window);
2823 _app_window = current_app_window;
2827 if (_candidate_mode == FIXED_CANDIDATE_WINDOW) {
2828 if (bSetVirtualKbd) {
2829 set_keyboard_geometry_atom_info (_app_window, get_ise_geometry ());
2832 efl_set_transient_for_app_window (elm_win_xwindow_get (_candidate_window));
2835 ui_candidate_delete_check_size_timer ();
2836 _check_size_timer = ecore_timer_add (0.02, ui_candidate_check_size_timeout, NULL);
2838 SCIM_DEBUG_MAIN (3) << " Show candidate window\n";
2840 if (_ise_state == WINDOW_STATE_SHOW) {
2841 edje_object_file_set (_more_btn, _candidate_edje_file.c_str (), "more_button");
2842 edje_object_file_set (_close_btn, _candidate_edje_file.c_str (), "close_button");
2844 edje_object_file_set (_more_btn, _candidate_edje_file.c_str (), "close_button");
2845 edje_object_file_set (_close_btn, _candidate_edje_file.c_str (), "more_button");
2848 /* If we are in hardware keyboard mode, this candidate window is now considered to be a input panel */
2849 if (_candidate_mode == FIXED_CANDIDATE_WINDOW) {
2850 if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) {
2851 LOGD ("sending ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW");
2852 _info_manager->update_input_panel_event ((uint32)ECORE_IMF_INPUT_PANEL_STATE_EVENT, (uint32)ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW);
2856 if (_candidate_state != WINDOW_STATE_SHOW) {
2858 if (_candidate_show_handler) {
2859 LOGD ("Was still waiting for CANDIDATE_WINDOW_SHOW....");
2861 delete_candidate_show_handler ();
2862 LOGD ("Registering ECORE_X_EVENT_WINDOW_SHOW event, %d", _candidate_state);
2863 _candidate_show_handler = ecore_event_handler_add (ECORE_X_EVENT_WINDOW_SHOW, x_event_window_show_cb, NULL);
2867 LOGD ("The candidate window was already in SHOW state, update geometry information");
2868 _info_manager->update_input_panel_event (ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
2869 _info_manager->update_input_panel_event (ECORE_IMF_CANDIDATE_PANEL_GEOMETRY_EVENT, 0);
2871 /* And the state event */
2872 _info_manager->update_candidate_panel_event ((uint32)ECORE_IMF_CANDIDATE_PANEL_STATE_EVENT, (uint32)ECORE_IMF_CANDIDATE_PANEL_SHOW);
2874 /* If we are in hardware keyboard mode, this candidate window is now considered to be a input panel */
2875 if (_candidate_mode == FIXED_CANDIDATE_WINDOW) {
2876 if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) {
2877 _info_manager->update_input_panel_event ((uint32)ECORE_IMF_INPUT_PANEL_STATE_EVENT, (uint32)ECORE_IMF_INPUT_PANEL_STATE_SHOW);
2882 evas_object_show (_candidate_window);
2886 * @brief Hide candidate window.
2888 * @param bForce The flag to hide candidate window by force.
2889 * @param bSetVirtualKbd The flag for set_keyboard_geometry_atom_info () calling.
2891 static void ui_candidate_hide (bool bForce, bool bSetVirtualKbd, bool will_hide)
2893 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " bForce:" << bForce << " bSetVirtualKbd:" << bSetVirtualKbd << " will_hide:" << will_hide << "...\n";
2895 if (!_candidate_window)
2899 if (_candidate_area_2 && _candidate_area_2_visible) {
2900 evas_object_hide (_candidate_area_2);
2901 _candidate_area_2_visible = false;
2902 evas_object_hide (_scroller_bg);
2903 evas_object_hide (_close_btn);
2904 _info_manager->candidate_more_window_hide ();
2905 ui_candidate_window_adjust ();
2909 if (bForce || ui_candidate_can_be_hide ()) {
2911 LOGD ("candidate_state = WILL_HIDE");
2912 _candidate_state = WINDOW_STATE_WILL_HIDE;
2914 delete_candidate_hide_timer ();
2915 _candidate_hide_timer = ecore_timer_add (2.0, candidate_hide_timer, NULL);
2918 if (_candidate_mode == FIXED_CANDIDATE_WINDOW) {
2919 _info_manager->update_input_panel_event (ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
2920 /* FIXME : should check if bSetVirtualKbd flag is really needed in this case */
2922 if (_ise_state == WINDOW_STATE_SHOW) {
2923 set_keyboard_geometry_atom_info (_app_window, get_ise_geometry ());
2925 if (bSetVirtualKbd) {
2926 set_keyboard_geometry_atom_info (_app_window, get_ise_geometry ());
2930 if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) {
2931 _info_manager->update_input_panel_event
2932 ((uint32)ECORE_IMF_INPUT_PANEL_STATE_EVENT, (uint32)ECORE_IMF_INPUT_PANEL_STATE_HIDE);
2936 /* Update the new keyboard geometry first, and then send the candidate hide event */
2937 _info_manager->update_candidate_panel_event ((uint32)ECORE_IMF_CANDIDATE_PANEL_STATE_EVENT, (uint32)ECORE_IMF_CANDIDATE_PANEL_HIDE);
2940 /* If we are not in will_hide state, hide the candidate window immediately */
2941 candidate_window_hide ();
2943 if (_preedit_window)
2944 evas_object_hide (_preedit_window);
2950 * @brief Callback function for more button.
2952 * @param data Data to pass when it is called.
2953 * @param e The evas for current event.
2954 * @param button The evas object for current event.
2955 * @param event_info The information for current event.
2957 static void ui_candidate_window_more_button_cb (void *data, Evas *e, Evas_Object *button, void *event_info)
2959 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2961 _info_manager->candidate_more_window_show ();
2963 if (candidate_expanded == false) {
2964 candidate_expanded = true;
2965 int number = SCIM_LOOKUP_TABLE_MAX_PAGESIZE;
2966 for (int i = 0; i < SCIM_LOOKUP_TABLE_MAX_PAGESIZE; ++i) {
2967 if (_candidate_0 [i] == NULL) {
2972 if (g_isf_candidate_table.get_current_page_size () != number)
2973 update_table (ISF_CANDIDATE_TABLE, g_isf_candidate_table);
2976 if (_candidate_angle == 180) {
2977 Ecore_Evas *ee = ecore_evas_ecore_evas_get (evas_object_evas_get (_candidate_window));
2978 ecore_evas_move_resize (ee, 0, 0, 0, 0);
2979 LOGD ("ecore_evas_move_resize (%p, %d, %d, %d, %d)", ee, 0, 0, 0, 0);
2980 } else if (_candidate_mode == FIXED_CANDIDATE_WINDOW && _candidate_angle == 270) {
2982 * when screen rotate 270 degrees, candidate have to move then resize for expanding more
2983 * candidates, but it will flash or locate in a wrong position, this code just a workaround
2984 * for avoiding this situation.
2986 Ecore_Evas *ee = ecore_evas_ecore_evas_get (evas_object_evas_get (_candidate_window));
2987 ecore_evas_move_resize (ee, 0, 0, _screen_height, ui_candidate_get_valid_height () + _ise_height);
2988 LOGD ("ecore_evas_move_resize (%p, %d, %d, %d, %d)",
2989 ee, 0, 0, _screen_height, ui_candidate_get_valid_height () + _ise_height);
2992 evas_object_show (_candidate_area_2);
2993 _candidate_area_2_visible = true;
2994 evas_object_show (_scroller_bg);
2995 evas_object_hide (_more_btn);
2996 evas_object_show (_close_btn);
2998 ui_candidate_window_adjust ();
2999 ui_settle_candidate_window ();
3004 * @brief Callback function for close button.
3006 * @param data Data to pass when it is called.
3007 * @param e The evas for current event.
3008 * @param button The evas object for current event.
3009 * @param event_info The information for current event.
3011 static void ui_candidate_window_close_button_cb (void *data, Evas *e, Evas_Object *button, void *event_info)
3013 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3015 if (_candidate_area_2 == NULL || !_candidate_area_2_visible)
3018 _info_manager->candidate_more_window_hide ();
3020 evas_object_hide (_candidate_area_2);
3021 _candidate_area_2_visible = false;
3022 evas_object_hide (_scroller_bg);
3023 evas_object_hide (_close_btn);
3025 candidate_expanded = false;
3026 evas_object_show (_candidate_area_1);
3027 _candidate_area_1_visible = true;
3028 evas_object_show (_more_btn);
3030 elm_scroller_region_show (_candidate_area_2, 0, 0, _candidate_scroll_width, 100);
3031 if (_candidate_angle == 180) {
3032 Ecore_Evas *ee= ecore_evas_ecore_evas_get (evas_object_evas_get (_candidate_window));
3033 ecore_evas_move_resize (ee, 0, 0, 0, 0);
3034 LOGD ("ecore_evas_move_resize (%p, %d, %d, %d, %d)", ee, 0, 0, 0, 0);
3035 } else if (_candidate_mode == FIXED_CANDIDATE_WINDOW && _candidate_angle == 270) {
3037 * when screen rotate 270 degrees, candidate have to move then resize for expanding more
3038 * candidates, but it will flash or locate in a wrong position, this code just a workaround
3039 * for avoiding this situation.
3041 Ecore_Evas *ee = ecore_evas_ecore_evas_get (evas_object_evas_get (_candidate_window));
3042 ecore_evas_move_resize (ee, _ise_height, 0, _screen_height, ui_candidate_get_valid_height ());
3043 LOGD ("ecore_evas_move_resize (%p, %d, %d, %d, %d)",
3044 ee, _ise_height, 0, _screen_height, ui_candidate_get_valid_height ());
3047 ui_candidate_window_adjust ();
3048 ui_settle_candidate_window ();
3053 * @brief Callback function for mouse button press.
3055 * @param data Data to pass when it is called.
3056 * @param e The evas for current event.
3057 * @param button The evas object for current event.
3058 * @param event_info The information for current event.
3060 static void ui_mouse_button_pressed_cb (void *data, Evas *e, Evas_Object *button, void *event_info)
3062 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3064 _click_object = GPOINTER_TO_INT (data) & 0xFF;
3067 Evas_Event_Mouse_Down *ev = (Evas_Event_Mouse_Down *)event_info;
3070 _click_down_pos [0] = ev->canvas.x;
3071 _click_down_pos [1] = ev->canvas.y;
3073 if (_click_object == ISF_EFL_CANDIDATE_0 || _click_object == ISF_EFL_CANDIDATE_ITEMS) {
3074 int index = (int)GPOINTER_TO_INT (data) >> 8;
3076 #ifdef HAVE_FEEDBACK
3077 if (feedback_initialized) {
3078 int feedback_result = 0;
3079 bool sound_feedback = _config->read (SCIM_GLOBAL_CONFIG_PANEL_SOUND_FEEDBACK, false);
3081 if (sound_feedback) {
3082 feedback_result = feedback_play_type (FEEDBACK_TYPE_SOUND, FEEDBACK_PATTERN_SIP);
3084 if (FEEDBACK_ERROR_NONE == feedback_result)
3085 LOGD ("Sound play successful");
3087 LOGW ("Cannot play feedback sound : %d", feedback_result);
3090 bool vibrate_feedback = _config->read (SCIM_GLOBAL_CONFIG_PANEL_VIBRATION_FEEDBACK, false);
3092 if (vibrate_feedback) {
3093 feedback_result = feedback_play_type (FEEDBACK_TYPE_VIBRATION, FEEDBACK_PATTERN_SIP);
3095 if (FEEDBACK_ERROR_NONE == feedback_result)
3096 LOGD ("Vibration play successful");
3098 LOGW ("Cannot play feedback vibration : %d", feedback_result);
3103 ui_candidate_delete_longpress_timer ();
3104 _longpress_timer = ecore_timer_add (1.0, ui_candidate_longpress_timeout, (void *)index);
3109 * @brief Callback function for mouse button release.
3111 * @param data Data to pass when it is called.
3112 * @param e The evas for current event.
3113 * @param button The evas object for current event.
3114 * @param event_info The information for current event.
3116 static void ui_mouse_button_released_cb (void *data, Evas *e, Evas_Object *button, void *event_info)
3118 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " index:" << GPOINTER_TO_INT (data) << "...\n";
3120 ui_candidate_delete_longpress_timer ();
3122 int index = GPOINTER_TO_INT (data);
3123 if (_click_object == ISF_EFL_AUX && _is_click) {
3125 const char *buf = edje_object_part_state_get (button, "aux", &ret);
3126 if (strcmp ("selected", buf)) {
3127 for (unsigned int i = 0; i < _aux_items.size (); i++) {
3128 buf = edje_object_part_state_get (_aux_items [i], "aux", &ret);
3129 if (!strcmp ("selected", buf))
3130 edje_object_signal_emit (_aux_items [i], "aux,state,unselected", "aux");
3132 edje_object_signal_emit (button, "aux,state,selected", "aux");
3133 _info_manager->select_aux (index);
3135 int r, g, b, a, r2, g2, b2, a2, r3, g3, b3, a3;
3136 edje_object_color_class_get (_aux_items [index], "text_color", &r, &g, &b, &a, &r2, &g2, &b2, &a2, &r3, &g3, &b3, &a3);
3137 // Normal item is clicked
3138 if (!(r == 62 && g == 207 && b == 255)) {
3139 for (unsigned int i = 0; i < _aux_items.size (); i++) {
3140 edje_object_color_class_set (_aux_items [i], "text_color", 249, 249, 249, 255, r2, g2, b2, a2, r3, g3, b3, a3);
3142 edje_object_color_class_set (_aux_items [index], "text_color", 62, 207, 255, 255, r2, g2, b2, a2, r3, g3, b3, a3);
3143 _info_manager->select_aux (index);
3145 } else if (_click_object == ISF_EFL_CANDIDATE_0 && _is_click) {
3146 ui_candidate_window_close_button_cb (NULL, NULL, _close_btn, NULL);
3147 _info_manager->select_candidate (index);
3148 } else if (_click_object == ISF_EFL_CANDIDATE_ITEMS && _is_click) {
3149 ui_candidate_window_close_button_cb (NULL, NULL, _close_btn, NULL);
3150 _info_manager->select_candidate (index);
3155 * @brief Callback function for mouse move.
3157 * @param data Data to pass when it is called.
3158 * @param e The evas for current event.
3159 * @param button The evas object for current event.
3160 * @param event_info The information for current event.
3162 static void ui_mouse_moved_cb (void *data, Evas *e, Evas_Object *button, void *event_info)
3164 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3166 Evas_Event_Mouse_Down *ev = (Evas_Event_Mouse_Down *)event_info;
3169 _click_up_pos [0] = ev->canvas.x;
3170 _click_up_pos [1] = ev->canvas.y;
3172 if (abs (_click_up_pos [0] - _click_down_pos [0]) >= (int)(15 * _height_rate) ||
3173 abs (_click_up_pos [1] - _click_down_pos [1]) >= (int)(15 * _height_rate)) {
3175 ui_candidate_delete_longpress_timer ();
3181 * @brief Open TTS device.
3183 * @return false if open is failed, otherwise return true.
3185 static bool ui_open_tts (void)
3187 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3189 int r = tts_create (&_tts);
3190 if (TTS_ERROR_NONE != r) {
3191 LOGW ("tts_create FAILED : result (%d)", r);
3196 r = tts_set_mode (_tts, TTS_MODE_SCREEN_READER);
3197 if (TTS_ERROR_NONE != r) {
3198 LOGW ("tts_set_mode FAILED : result (%d)", r);
3201 tts_state_e current_state;
3202 r = tts_get_state (_tts, ¤t_state);
3203 if (TTS_ERROR_NONE != r) {
3204 LOGW ("tts_get_state FAILED : result (%d)", r);
3207 if (TTS_STATE_CREATED == current_state) {
3208 r = tts_prepare (_tts);
3209 if (TTS_ERROR_NONE != r) {
3210 LOGW ("tts_prepare FAILED : ret (%d)", r);
3217 * @brief Close TTS device.
3219 static void ui_close_tts (void)
3221 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3224 int r = tts_unprepare (_tts);
3225 if (TTS_ERROR_NONE != r) {
3226 LOGW ("tts_unprepare FAILED : result (%d)", r);
3229 r = tts_destroy (_tts);
3230 if (TTS_ERROR_NONE != r) {
3231 LOGW ("tts_destroy FAILED : result (%d)", r);
3237 * @brief Play string by TTS.
3239 * @param str The string for playing.
3241 static void ui_play_tts (const char* str)
3243 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " str=" << str << "\n";
3248 if (!ui_open_tts ())
3254 tts_state_e current_state;
3256 r = tts_get_state (_tts, ¤t_state);
3257 if (TTS_ERROR_NONE != r) {
3258 LOGW ("Fail to get state from TTS : ret (%d)", r);
3261 if (TTS_STATE_PLAYING == current_state) {
3262 r = tts_stop (_tts);
3263 if (TTS_ERROR_NONE != r) {
3264 LOGW ("Fail to stop TTS : ret (%d)", r);
3268 /* Get ISE language */
3269 String default_uuid = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), String (""));
3270 String language = String ("en_US");
3271 if (default_uuid.length () > 0) {
3272 language = _ime_info[get_ise_index (default_uuid)].languages;
3273 if (language.length () > 0) {
3274 std::vector<String> ise_langs;
3275 scim_split_string_list (ise_langs, language);
3276 language = ise_langs[0];
3279 LOGD ("TTS language:%s, str:%s", language.c_str (), str);
3281 r = tts_add_text (_tts, str, language.c_str (), TTS_VOICE_TYPE_AUTO, TTS_SPEED_AUTO, &utt_id);
3282 if (TTS_ERROR_NONE == r) {
3283 r = tts_play (_tts);
3284 if (TTS_ERROR_NONE != r) {
3285 LOGW ("Fail to play TTS : ret (%d)", r);
3289 #endif /* HAVE_TTS */
3292 * @brief Show rect for candidate focus object when screen reader is enabled.
3294 * @param x Rect X position.
3295 * @param y Rect Y position.
3296 * @param w Rect width.
3297 * @param h Rect height.
3299 static void ui_tts_focus_rect_show (int x, int y, int w, int h)
3301 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3302 if (_candidate_window == NULL || _candidate_state != WINDOW_STATE_SHOW)
3305 if (_tts_focus_rect == NULL) {
3306 _tts_focus_rect = evas_object_rectangle_add (evas_object_evas_get ((Evas_Object*)_candidate_window));
3307 evas_object_color_set (_tts_focus_rect, 0, 0, 0, 0);
3308 elm_access_highlight_set (elm_access_object_register (_tts_focus_rect, (Evas_Object*)_candidate_window));
3310 evas_object_move (_tts_focus_rect, x, y);
3311 evas_object_resize (_tts_focus_rect, w, h);
3312 evas_object_raise (_tts_focus_rect);
3313 evas_object_show (_tts_focus_rect);
3317 * @brief Hide rect for candidate focus object when screen reader is enabled.
3319 static void ui_tts_focus_rect_hide (void)
3321 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3323 if (_tts_focus_rect) {
3324 //evas_object_hide (_tts_focus_rect);
3325 evas_object_move (_tts_focus_rect, -1000, -1000);
3330 * @brief Callback function for candidate scroller stop event.
3332 * @param data Data to pass when it is called.
3333 * @param obj The evas object for current event.
3334 * @param event_info The information for current event.
3336 static void ui_candidate_scroller_stop_cb (void *data, Evas_Object *obj, void *event_info)
3338 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3339 if (!_wait_stop_event)
3342 if (_candidate_tts_focus_index >= 0 && _candidate_tts_focus_index < g_isf_candidate_table.get_current_page_size ()) {
3343 if (_candidate_0 [_candidate_tts_focus_index]) {
3345 evas_object_geometry_get (_candidate_0 [_candidate_tts_focus_index], &x, &y, &w, &h);
3346 ui_tts_focus_rect_show (x, y, w, h);
3349 _wait_stop_event = false;
3354 * @brief Mouse over (find focus object and play text by TTS) when screen reader is enabled.
3356 * @param mouse_x Mouse X position.
3357 * @param mouse_y Mouse Y position.
3359 static void ui_mouse_over (int mouse_x, int mouse_y)
3361 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3362 if (_candidate_window == NULL || _candidate_state != WINDOW_STATE_SHOW)
3365 int x, y, width, height;
3366 for (int i = 0; i < SCIM_LOOKUP_TABLE_MAX_PAGESIZE; ++i) {
3367 if (_candidate_0 [i]) {
3368 evas_object_geometry_get (_candidate_0 [i], &x, &y, &width, &height);
3369 if (mouse_x >= x && mouse_x <= x + width && mouse_y >= y && mouse_y <= y + height) {
3370 /* FIXME: Should consider emoji case */
3371 String mbs = utf8_wcstombs (g_isf_candidate_table.get_candidate_in_current_page (i));
3372 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " play candidate string: " << mbs << "\n";
3374 ui_play_tts (mbs.c_str ());
3376 _candidate_tts_focus_index = i;
3377 ui_tts_focus_rect_show (x, y, width, height);
3383 String strTts = String ("");
3384 if (_candidate_area_2_visible) {
3385 evas_object_geometry_get (_close_btn, &x, &y, &width, &height);
3386 if (mouse_x >= x && mouse_x <= x + width && mouse_y >= y && mouse_y <= y + height) {
3387 strTts = String (_("close button"));
3388 _candidate_tts_focus_index = CLOSE_BUTTON_INDEX;
3389 ui_tts_focus_rect_show (x, y, width, height);
3392 evas_object_geometry_get (_more_btn, &x, &y, &width, &height);
3393 if (mouse_x >= x && mouse_x <= x + width && mouse_y >= y && mouse_y <= y + height) {
3394 strTts = String (_("more button"));
3395 _candidate_tts_focus_index = MORE_BUTTON_INDEX;
3396 ui_tts_focus_rect_show (x, y, width, height);
3400 if (strTts.length () > 0)
3401 ui_play_tts (strTts.c_str ());
3406 * @brief Mouse click (find focus object and do click event) when screen reader is enabled.
3408 * @param focus_index focused candidate index.
3410 static void ui_mouse_click (int focus_index)
3412 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3413 if (_candidate_window == NULL || _candidate_state != WINDOW_STATE_SHOW || focus_index == INVALID_TTS_FOCUS_INDEX)
3416 if (focus_index >= 0 && focus_index < g_isf_candidate_table.get_current_page_size ()) {
3417 if (_candidate_0 [focus_index]) {
3418 int x, y, width, height;
3419 evas_object_geometry_get (_candidate_0 [focus_index], &x, &y, &width, &height);
3420 Evas_Event_Mouse_Down event_info;
3421 event_info.canvas.x = x + width / 2;
3422 event_info.canvas.y = y + height / 2;
3423 ui_mouse_button_pressed_cb (GINT_TO_POINTER ((focus_index << 8) + ISF_EFL_CANDIDATE_0), NULL, NULL, &event_info);
3424 ui_mouse_button_released_cb (GINT_TO_POINTER (focus_index), NULL, NULL, &event_info);
3426 _candidate_tts_focus_index = INVALID_TTS_FOCUS_INDEX;
3427 ui_tts_focus_rect_hide ();
3431 if (_candidate_area_2_visible) {
3432 if (focus_index == CLOSE_BUTTON_INDEX) {
3433 ui_candidate_window_close_button_cb (NULL, NULL, NULL, NULL);
3434 _candidate_tts_focus_index = MORE_BUTTON_INDEX;
3437 if (focus_index == MORE_BUTTON_INDEX) {
3438 ui_candidate_window_more_button_cb (NULL, NULL, NULL, NULL);
3439 _candidate_tts_focus_index = CLOSE_BUTTON_INDEX;
3443 #endif /* HAVE_ECOREX */
3446 * @brief Create preedit window.
3448 static void ui_create_preedit_window (void)
3450 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3452 if (_candidate_mode == SOFT_CANDIDATE_WINDOW)
3455 _preedit_width = 100;
3456 _preedit_height = _preedit_height * _height_rate;
3457 if (_preedit_window == NULL) {
3458 _preedit_window = efl_create_window ("ISF Popup", "Preedit Window");
3459 evas_object_resize (_preedit_window, _preedit_width, _preedit_height);
3460 int rots [4] = {0, 90, 180, 270};
3461 elm_win_wm_rotation_available_rotations_set (_preedit_window, rots, 4);
3462 int preedit_font_size = (int)(32 * _width_rate);
3464 _preedit_text = edje_object_add (evas_object_evas_get (_preedit_window));
3465 edje_object_file_set (_preedit_text, _candidate_edje_file.c_str (), "preedit_text");
3466 evas_object_size_hint_fill_set (_preedit_text, EVAS_HINT_FILL, EVAS_HINT_FILL);
3467 evas_object_size_hint_weight_set (_preedit_text, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
3468 elm_win_resize_object_add (_preedit_window, _preedit_text);
3469 evas_object_show (_preedit_text);
3471 _tmp_preedit_text = evas_object_text_add (evas_object_evas_get (_preedit_window));
3472 evas_object_text_font_set (_tmp_preedit_text, _candidate_font_name.c_str (), preedit_font_size);
3477 * @brief Create native style candidate window.
3479 static void ui_create_native_candidate_window (void)
3481 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3482 _more_btn_width = 80 * (_width_rate > 1 ? 1 : _width_rate);
3483 _more_btn_height = 64 * _height_rate;
3485 _candidate_port_width = _screen_width;
3486 _candidate_port_height_min = 84 * _height_rate * _candidate_port_line;
3487 _candidate_port_height_min_2 = 84 * _height_rate + _candidate_port_height_min;
3488 _candidate_port_height_max = 426 * _height_rate + _candidate_port_height_min;
3489 _candidate_port_height_max_2 = 84 * _height_rate + _candidate_port_height_max;
3490 _candidate_land_width = _screen_height;
3491 _candidate_land_height_min = 84 * _width_rate;
3492 _candidate_land_height_min_2 = 168 * _width_rate;
3493 _candidate_land_height_max = 342 * _width_rate;
3494 _candidate_land_height_max_2 = 426 * _width_rate;
3496 _candidate_scroll_0_width_min= _screen_width;
3497 _candidate_scroll_0_width_max= _screen_height;
3498 _candidate_scroll_width_min = _screen_width;
3499 _candidate_scroll_width_max = _screen_height;
3500 _candidate_scroll_height_min = 252 * _width_rate;
3501 _candidate_scroll_height_max = 420 * _height_rate;
3503 _candidate_area_1_pos [0] = 0 * _width_rate;
3504 _candidate_area_1_pos [1] = 2 * _height_rate;
3505 _more_btn_pos [0] = _candidate_port_width - _more_btn_width - _h_padding;
3506 _more_btn_pos [1] = 12 * _height_rate;
3507 _more_btn_pos [2] = _candidate_land_width - _more_btn_width - _h_padding;
3508 _more_btn_pos [3] = 12 * _width_rate;
3509 _close_btn_pos [0] = _candidate_port_width - _more_btn_width - _h_padding;
3510 _close_btn_pos [1] = 12 * _height_rate;
3511 _close_btn_pos [2] = _candidate_land_width - _more_btn_width - _h_padding;
3512 _close_btn_pos [3] = 12 * _width_rate;
3514 _aux_height = 84 * _height_rate - 2;
3515 _aux_port_width = _screen_width;
3516 _aux_land_width = _screen_height;
3518 _item_min_height = 84 * _height_rate - 2;
3520 /* Create candidate window */
3521 if (_candidate_window == NULL) {
3522 _candidate_window = efl_create_window ("ISF Popup", "Prediction Window");
3523 int rots [4] = {0, 90, 180, 270};
3524 elm_win_wm_rotation_available_rotations_set (_candidate_window, rots, 4);
3525 if (_candidate_angle == 90 || _candidate_angle == 270) {
3526 _candidate_width = _candidate_land_width;
3527 _candidate_height = _candidate_land_height_min;
3529 _candidate_width = _candidate_port_width;
3530 _candidate_height = _candidate_port_height_min;
3534 ecore_x_e_window_rotation_geometry_set (elm_win_xwindow_get (_candidate_window),
3535 0, 0, 0, _candidate_port_width, _candidate_port_height_min);
3536 ecore_x_e_window_rotation_geometry_set (elm_win_xwindow_get (_candidate_window),
3537 90, 0, 0, _candidate_land_height_min, _candidate_land_width);
3538 ecore_x_e_window_rotation_geometry_set (elm_win_xwindow_get (_candidate_window),
3539 180, 0, 0, _candidate_port_width, _candidate_port_height_min);
3540 ecore_x_e_window_rotation_geometry_set (elm_win_xwindow_get (_candidate_window),
3541 270, 0, 0, _candidate_land_height_min, _candidate_land_width);
3544 ecore_wl2_window_rotation_geometry_set ((Ecore_Wl2_Window *)elm_win_wl_window_get (_candidate_window),
3545 0, 0, 0, _candidate_port_width, _candidate_port_height_min);
3546 ecore_wl2_window_rotation_geometry_set ((Ecore_Wl2_Window *)elm_win_wl_window_get (_candidate_window),
3547 90, 0, 0, _candidate_land_height_min, _candidate_land_width);
3548 ecore_wl2_window_rotation_geometry_set ((Ecore_Wl2_Window *)elm_win_wl_window_get (_candidate_window),
3549 180, 0, 0, _candidate_port_width, _candidate_port_height_min);
3550 ecore_wl2_window_rotation_geometry_set ((Ecore_Wl2_Window *)elm_win_wl_window_get (_candidate_window),
3551 270, 0, 0, _candidate_land_height_min, _candidate_land_width);
3553 /* Add dim background */
3554 Evas_Object *dim_bg = elm_bg_add (_candidate_window);
3555 evas_object_color_set (dim_bg, 0, 0, 0, 153);
3556 elm_win_resize_object_add (_candidate_window, dim_bg);
3557 evas_object_show (dim_bg);
3559 /* Add candidate background */
3560 _candidate_bg = edje_object_add (evas_object_evas_get (_candidate_window));
3561 edje_object_file_set (_candidate_bg, _candidate_edje_file.c_str (), "candidate_bg");
3562 evas_object_size_hint_weight_set (_candidate_bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
3563 evas_object_resize (_candidate_bg, _candidate_port_width, _candidate_port_height_min);
3564 evas_object_move (_candidate_bg, 0, 0);
3565 evas_object_show (_candidate_bg);
3567 /* Create _candidate_0 scroller */
3568 _candidate_0_scroll = elm_scroller_add (_candidate_window);
3569 elm_scroller_bounce_set (_candidate_0_scroll, EINA_TRUE, EINA_FALSE);
3570 elm_scroller_policy_set (_candidate_0_scroll, ELM_SCROLLER_POLICY_AUTO, ELM_SCROLLER_POLICY_OFF);
3571 evas_object_resize (_candidate_0_scroll, _candidate_scroll_0_width_min, (_item_min_height+2)*_candidate_port_line-2);
3572 evas_object_move (_candidate_0_scroll, _candidate_area_1_pos[0], _candidate_area_1_pos[1]);
3574 /* Create candidate table */
3575 _candidate_0_table = elm_table_add (_candidate_window);
3576 evas_object_size_hint_weight_set (_candidate_0_table, 0.0, 0.0);
3577 evas_object_size_hint_align_set (_candidate_0_table, 0.0, 0.0);
3578 elm_table_padding_set (_candidate_0_table, 0, 0);
3579 elm_object_content_set (_candidate_0_scroll, _candidate_0_table);
3580 evas_object_show (_candidate_0_table);
3581 _candidate_area_1 = _candidate_0_scroll;
3583 /* Create more button */
3584 _more_btn = edje_object_add (evas_object_evas_get (_candidate_window));
3585 if (_ise_width == 0 && _ise_height == 0)
3586 edje_object_file_set (_more_btn, _candidate_edje_file.c_str (), "close_button");
3588 edje_object_file_set (_more_btn, _candidate_edje_file.c_str (), "more_button");
3589 evas_object_move (_more_btn, _more_btn_pos[0], _more_btn_pos[1]);
3590 evas_object_resize (_more_btn, _more_btn_width, _more_btn_height);
3591 evas_object_event_callback_add (_more_btn, EVAS_CALLBACK_MOUSE_UP, ui_candidate_window_more_button_cb, NULL);
3593 /* Add scroller background */
3594 _candidate_scroll_width = _candidate_scroll_width_min;
3595 _scroller_bg = edje_object_add (evas_object_evas_get (_candidate_window));
3596 edje_object_file_set (_scroller_bg, _candidate_edje_file.c_str (), "scroller_bg");
3597 evas_object_size_hint_weight_set (_scroller_bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
3598 evas_object_resize (_scroller_bg, _candidate_scroll_width, _candidate_scroll_height_max + 6);
3599 evas_object_move (_scroller_bg, 0, _candidate_port_height_min);
3601 /* Create vertical scroller */
3602 _candidate_scroll = elm_scroller_add (_candidate_window);
3603 elm_scroller_bounce_set (_candidate_scroll, 0, 1);
3604 elm_scroller_policy_set (_candidate_scroll, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_AUTO);
3605 evas_object_resize (_candidate_scroll, _candidate_scroll_width, _candidate_scroll_height_max);
3606 evas_object_resize (_scroller_bg, _candidate_scroll_width, _candidate_scroll_height_max + 6);
3607 elm_scroller_page_size_set (_candidate_scroll, 0, _item_min_height+_v_padding);
3608 evas_object_move (_candidate_scroll, 0, _candidate_port_height_min);
3610 /* Create candidate table */
3611 _candidate_table = elm_table_add (_candidate_window);
3612 evas_object_size_hint_weight_set (_candidate_table, 0.0, 0.0);
3613 evas_object_size_hint_align_set (_candidate_table, 0.0, 0.0);
3614 elm_table_padding_set (_candidate_table, 0, 0);
3615 elm_object_content_set (_candidate_scroll, _candidate_table);
3616 evas_object_show (_candidate_table);
3617 _candidate_area_2 = _candidate_scroll;
3618 evas_object_smart_callback_add (_candidate_scroll, "scroll,anim,stop", ui_candidate_scroller_stop_cb, NULL);
3620 /* Create close button */
3621 _close_btn = edje_object_add (evas_object_evas_get (_candidate_window));
3622 if (_ise_width == 0 && _ise_height == 0)
3623 edje_object_file_set (_close_btn, _candidate_edje_file.c_str (), "more_button");
3625 edje_object_file_set (_close_btn, _candidate_edje_file.c_str (), "close_button");
3626 evas_object_move (_close_btn, _close_btn_pos[0], _close_btn_pos[1]);
3627 evas_object_resize (_close_btn, _more_btn_width, _more_btn_height);
3628 evas_object_event_callback_add (_close_btn, EVAS_CALLBACK_MOUSE_UP, ui_candidate_window_close_button_cb, NULL);
3630 _tmp_candidate_text = evas_object_text_add (evas_object_evas_get (_candidate_window));
3631 evas_object_text_font_set (_tmp_candidate_text, _candidate_font_name.c_str (), _candidate_font_size);
3634 _aux_area = elm_scroller_add (_candidate_window);
3635 elm_scroller_bounce_set (_aux_area, 1, 0);
3636 elm_scroller_policy_set (_aux_area, ELM_SCROLLER_POLICY_AUTO, ELM_SCROLLER_POLICY_OFF);
3637 evas_object_resize (_aux_area, _aux_port_width, _aux_height);
3638 evas_object_move (_aux_area, _candidate_area_1_pos[0], _candidate_area_1_pos[1]);
3640 _aux_table = elm_table_add (_candidate_window);
3641 elm_object_content_set (_aux_area, _aux_table);
3642 elm_table_padding_set (_aux_table, 0, 0);
3643 evas_object_size_hint_weight_set (_aux_table, 0.0, 0.0);
3644 evas_object_size_hint_align_set (_aux_table, 0.0, 0.0);
3645 evas_object_show (_aux_table);
3647 _aux_line = edje_object_add (evas_object_evas_get (_candidate_window));
3648 edje_object_file_set (_aux_line, _candidate_edje_file.c_str (), "popup_line");
3649 evas_object_resize (_aux_line, _candidate_port_width, 2);
3650 evas_object_move (_aux_line, 0, _aux_height + 2);
3652 _tmp_aux_text = evas_object_text_add (evas_object_evas_get (_candidate_window));
3653 evas_object_text_font_set (_tmp_aux_text, _candidate_font_name.c_str (), _aux_font_size);
3655 evas_object_hide (_candidate_window);
3662 * @brief Create candidate window.
3666 static void ui_create_candidate_window (void)
3668 check_time ("\nEnter ui_create_candidate_window");
3669 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3670 if (_candidate_mode == SOFT_CANDIDATE_WINDOW)
3675 _candidate_angle = 0;
3677 ui_create_native_candidate_window ();
3680 unsigned int set = 1;
3682 ecore_x_window_prop_card32_set (elm_win_xwindow_get (_candidate_window),
3683 ECORE_X_ATOM_E_WINDOW_ROTATION_SUPPORTED,
3686 int angle = efl_get_app_window_angle ();
3687 if (_candidate_angle != angle) {
3688 _candidate_angle = angle;
3689 ui_candidate_window_rotate (angle);
3691 ui_settle_candidate_window ();
3694 candidate_expanded = false;
3696 check_time ("Exit ui_create_candidate_window");
3700 * @brief Destroy candidate window.
3704 static void ui_destroy_candidate_window (void)
3706 check_time ("Enter ui_destroy_candidate_window");
3707 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3709 /* Delete candidate items, popup lines and seperator items */
3710 for (int i = 0; i < SCIM_LOOKUP_TABLE_MAX_PAGESIZE; ++i) {
3711 if (_candidate_0 [i]) {
3712 evas_object_del (_candidate_0 [i]);
3713 _candidate_0 [i] = NULL;
3715 if (_seperate_0 [i]) {
3716 evas_object_del (_seperate_0 [i]);
3717 _seperate_0 [i] = NULL;
3719 if (_seperate_items [i]) {
3720 evas_object_del (_seperate_items [i]);
3721 _seperate_items [i] = NULL;
3724 evas_object_del (_line_0 [i]);
3727 if (_line_items [i]) {
3728 evas_object_del (_line_items [i]);
3729 _line_items [i] = NULL;
3733 _aux_items.clear ();
3734 _aux_seperates.clear ();
3735 /* Delete candidate window */
3736 if (_candidate_window) {
3737 LOGD ("calling ui_candidate_hide (true)");
3738 ui_candidate_hide (true);
3740 evas_object_del (_candidate_window);
3741 _candidate_window = NULL;
3743 _candidate_area_1 = NULL;
3744 _candidate_area_2 = NULL;
3747 if (_tts_focus_rect) {
3748 evas_object_del (_tts_focus_rect);
3749 _tts_focus_rect = NULL;
3752 if (_candidate_bg) {
3753 evas_object_del (_candidate_bg);
3754 _candidate_bg = NULL;
3758 evas_object_del (_more_btn);
3763 evas_object_del (_scroller_bg);
3764 _scroller_bg = NULL;
3768 evas_object_del (_close_btn);
3773 evas_object_del (_aux_line);
3777 if (_tmp_candidate_text) {
3778 evas_object_del (_tmp_candidate_text);
3779 _tmp_candidate_text = NULL;
3782 if (_tmp_preedit_text) {
3783 evas_object_del (_tmp_preedit_text);
3784 _tmp_preedit_text = NULL;
3787 if (_tmp_aux_text) {
3788 evas_object_del (_tmp_aux_text);
3789 _tmp_aux_text = NULL;
3792 if (_preedit_text) {
3793 evas_object_del (_preedit_text);
3794 _preedit_text = NULL;
3797 if (_preedit_window) {
3798 evas_object_hide (_preedit_window);
3799 evas_object_del (_preedit_window);
3800 _preedit_window = NULL;
3804 check_time ("Exit ui_destroy_candidate_window");
3808 * @brief Settle candidate window position.
3810 static void ui_settle_candidate_window (void)
3812 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3814 if (!_candidate_window)
3817 /* If both ISE and candidate window are going to be hidden,
3818 let's just not move our candidate window */
3819 if (_ise_state == WINDOW_STATE_WILL_HIDE && _candidate_state == WINDOW_STATE_WILL_HIDE)
3823 int x, y, width, height;
3824 int ise_width = 0, ise_height = 0;
3825 bool get_geometry_result = false;
3827 /* Get candidate window position */
3828 ecore_evas_geometry_get (ecore_evas_ecore_evas_get (evas_object_evas_get (_candidate_window)), &x, &y, &width, &height);
3832 int pos_x = 0, pos_y = 0;
3833 if (_candidate_angle == 90 || _candidate_angle == 270)
3834 get_geometry_result = ecore_x_e_window_rotation_geometry_get (_ise_window, _candidate_angle, &pos_x, &pos_y, &ise_height, &ise_width);
3836 get_geometry_result = ecore_x_e_window_rotation_geometry_get (_ise_window, _candidate_angle, &pos_x, &pos_y, &ise_width, &ise_height);
3841 ise_width = _ise_width;
3842 ise_height = _ise_height;
3843 get_geometry_result = true;
3845 if ((_ise_state != WINDOW_STATE_SHOW && _ise_state != WINDOW_STATE_WILL_HIDE) ||
3846 (get_geometry_result == false) || (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE)) {
3851 int height2 = ui_candidate_get_valid_height ();
3853 if (_candidate_mode == FIXED_CANDIDATE_WINDOW) {
3854 if (_candidate_angle == 90) {
3855 spot_x = _screen_width - ise_height - height2;
3857 } else if (_candidate_angle == 270) {
3858 spot_x = ise_height - (_candidate_height - height2);
3860 } else if (_candidate_angle == 180) {
3862 spot_y = ise_height - (_candidate_height - height2);
3865 spot_y = _screen_height - ise_height - height2;
3868 spot_x = _spot_location_x;
3869 spot_y = _spot_location_y;
3871 rectinfo ise_rect = {0, 0, (uint32)ise_width, (uint32)ise_height};
3872 if (_candidate_angle == 90 || _candidate_angle == 270) {
3873 if (ise_rect.height <= (uint32)0 || ise_rect.height >= (uint32)_screen_width)
3874 ise_rect.height = ISE_DEFAULT_HEIGHT_LANDSCAPE * _width_rate;
3876 if (ise_rect.height <= (uint32)0 || ise_rect.height >= (uint32) _screen_height)
3877 ise_rect.height = ISE_DEFAULT_HEIGHT_PORTRAIT * _height_rate;
3880 int nOffset = _candidate_port_height_min / 3;
3881 if (_candidate_angle == 270) {
3882 if (ise_rect.height > 0 && spot_y + height2 > _screen_width - (int)ise_rect.height + nOffset) {
3883 spot_x = _screen_width - _spot_location_top_y - (_candidate_height - height2);
3885 spot_x = _screen_width - _spot_location_y - _candidate_height;
3887 } else if (_candidate_angle == 90) {
3888 if (ise_rect.height > 0 && spot_y + height2 > _screen_width - (int)ise_rect.height + nOffset) {
3889 spot_x = _spot_location_top_y - height2;
3893 } else if (_candidate_angle == 180) {
3894 if (ise_rect.height > 0 && spot_y + height2 > _screen_height - (int)ise_rect.height + nOffset) {
3895 spot_y = _screen_height - _spot_location_top_y - (_candidate_height - height2);
3897 spot_y = _screen_height - _spot_location_y - _candidate_height;
3900 if (ise_rect.height > 0 && spot_y + height2 > _screen_height - (int)ise_rect.height + nOffset) {
3901 spot_y = _spot_location_top_y - height2;
3906 if (_candidate_angle == 90) {
3907 spot_y = (_screen_height - _candidate_width) / 2;
3908 spot_x = spot_x < _indicator_height ? _indicator_height : spot_x;
3909 if (spot_x > _screen_width - _candidate_height)
3910 spot_x = _screen_width - _candidate_height;
3911 } else if (_candidate_angle == 270) {
3912 spot_y = (_screen_height - _candidate_width) / 2;
3913 spot_x = spot_x < 0 ? 0 : spot_x;
3914 if (spot_x > _screen_width - (_indicator_height+_candidate_height))
3915 spot_x = _screen_width - (_indicator_height+_candidate_height);
3916 } else if (_candidate_angle == 180) {
3917 spot_x = (_screen_width - _candidate_width) / 2;
3918 spot_y = spot_y < 0 ? 0 : spot_y;
3919 if (spot_y > _screen_height - (_indicator_height+_candidate_height))
3920 spot_y = _screen_height - (_indicator_height+_candidate_height);
3922 spot_x = (_screen_width - _candidate_width) / 2;
3923 spot_y = spot_y < _indicator_height ? _indicator_height : spot_y;
3924 if (spot_y > _screen_height - _candidate_height)
3925 spot_y = _screen_height - _candidate_height;
3928 if (spot_x != x || spot_y != y) {
3929 _candidate_x = spot_x;
3930 _candidate_y = spot_y;
3931 evas_object_move (_candidate_window, spot_x, spot_y);
3932 LOGD ("Moving candidate window to : %d %d", spot_x, spot_y);
3933 if (_preedit_window) {
3934 if (_candidate_angle == 90) {
3935 spot_x -= _preedit_height;
3936 spot_y = _screen_height - _preedit_width;
3937 } else if (_candidate_angle == 270) {
3939 } else if (_candidate_angle == 180) {
3940 spot_x = _screen_width - _preedit_width;
3943 spot_y -= _preedit_height;
3945 evas_object_move (_preedit_window, spot_x, spot_y);
3947 if (_candidate_state == WINDOW_STATE_SHOW) {
3948 _info_manager->update_candidate_panel_event ((uint32)ECORE_IMF_CANDIDATE_PANEL_GEOMETRY_EVENT, 0);
3952 #endif /* CANDIDATE */
3955 * @brief Set soft candidate geometry.
3957 * @param x The x position in screen.
3958 * @param y The y position in screen.
3959 * @param width The candidate window width.
3960 * @param height The candidate window height.
3962 static void set_soft_candidate_geometry (int x, int y, int width, int height)
3964 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " x:" << x << " y:" << y << " width:" << width << " height:" << height << "...\n";
3966 LOGD ("candidate geometry x: %d , y: %d , width: %d , height: %d, _ise_state: %d, candidate_mode: %d", x, y, width, height, _ise_state, _candidate_mode);
3968 if ((_candidate_mode != SOFT_CANDIDATE_WINDOW) || (_info_manager->get_current_toolbar_mode () != TOOLBAR_KEYBOARD_MODE))
3971 _soft_candidate_width = width;
3972 _soft_candidate_height = height;
3974 set_keyboard_geometry_atom_info (_app_window, get_ise_geometry());
3976 _info_manager->update_input_panel_event (ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
3979 #if ISF_BUILD_CANDIDATE_UI
3980 //////////////////////////////////////////////////////////////////////
3981 // End of Candidate Functions
3982 //////////////////////////////////////////////////////////////////////
3985 * @brief Set transient for app window.
3987 * @param window The Ecore_X_Window handler of app window.
3989 static void efl_set_transient_for_app_window (Ecore_X_Window window)
3991 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3993 /* Set a transient window for window stack */
3994 Ecore_X_Window xAppWindow = efl_get_app_window ();
3995 ecore_x_icccm_transient_for_set (window, xAppWindow);
3997 LOGD ("win : %x, forwin : %x", window, xAppWindow);
4000 static int efl_get_window_rotate_angle (Ecore_X_Window win)
4002 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4007 unsigned char *prop_data = NULL;
4009 ret = ecore_x_window_prop_property_get (win,
4010 ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE, ECORE_X_ATOM_CARDINAL, 32, &prop_data, &count);
4011 if (ret && prop_data) {
4012 memcpy (&angle, prop_data, sizeof (int));
4013 LOGD ("WINDOW angle of %p is %d", win, angle);
4015 std::cerr << "ecore_x_window_prop_property_get () is failed!!!\n";
4016 LOGW ("WINDOW angle of %p FAILED!", win);
4023 #endif /* HAVE_ECOREX */
4026 * @brief Get angle for app window.
4028 * @param win_obj The Evas_Object handler of application window.
4030 * @return The angle of app window.
4032 static int efl_get_app_window_angle ()
4034 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4036 return efl_get_window_rotate_angle (efl_get_app_window ());
4042 #endif /* CANDIDATE */
4045 * @brief Get angle for ise window.
4047 * @param win_obj The Evas_Object handler of ise window.
4049 * @return The angle of ise window.
4051 static int efl_get_ise_window_angle ()
4053 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4055 return efl_get_window_rotate_angle (_ise_window);
4062 #if ISF_BUILD_CANDIDATE_UI
4065 * @brief Get angle of quickpanel window.
4067 * @return The angle of quickpanel window.
4069 static int efl_get_quickpanel_window_angle ()
4071 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4072 return efl_get_window_rotate_angle (efl_get_quickpanel_window ());
4077 * @brief Set showing effect for application window.
4079 * @param win The Evas_Object handler of application window.
4080 * @param strEffect The pointer of effect string.
4082 static void efl_set_showing_effect_for_app_window (Evas_Object *win, const char* strEffect)
4084 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4086 ecore_x_icccm_name_class_set (elm_win_xwindow_get (static_cast<Evas_Object*>(win)), strEffect, "ISF");
4091 * @brief Create elementary window.
4093 * @param strWinName The window name.
4094 * @param strEffect The window effect string.
4096 * @return The window pointer
4098 static Evas_Object *efl_create_window (const char *strWinName, const char *strEffect)
4100 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4102 Evas_Object *win = elm_win_add (NULL, strWinName, ELM_WIN_UTILITY);
4103 elm_win_title_set (win, strWinName);
4105 /* set window properties */
4106 elm_win_autodel_set (win, EINA_TRUE);
4107 elm_object_focus_allow_set (win, EINA_FALSE);
4108 elm_win_borderless_set (win, EINA_TRUE);
4109 elm_win_alpha_set (win, EINA_TRUE);
4110 elm_win_prop_focus_skip_set (win, EINA_TRUE);
4111 efl_set_showing_effect_for_app_window (win, strEffect);
4115 #endif /* CANDIDATE */
4119 * @brief Create elementary control window.
4121 * @return EINA_TRUE if successful, otherwise return EINA_FALSE
4123 static Eina_Bool efl_create_control_window (void)
4125 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4127 /* WMSYNC, #1 Creating and registering control window */
4128 if (ecore_x_display_get () == NULL)
4131 Ecore_X_Window root = ecore_x_window_root_first_get ();
4132 _control_window = ecore_x_window_input_new (root, -100, -100, 1, 1);
4133 //ecore_x_e_virtual_keyboard_control_window_set (root, _control_window, 0, EINA_TRUE);
4135 Ecore_X_Atom atom = ecore_x_atom_get ("_ISF_CONTROL_WINDOW");
4136 ecore_x_window_prop_xid_set (root, atom, ECORE_X_ATOM_WINDOW, &_control_window, 1);
4142 * @brief Get an window's x window id.
4144 * @param name the property name.
4145 * @return X window id.
4147 static Ecore_X_Window efl_get_window (const char *name)
4149 /* Gets the XID of the window from the root window property */
4153 unsigned long nitems_return;
4154 unsigned long bytes_after_return;
4155 unsigned char *data = NULL;
4156 Ecore_X_Window window = 0;
4158 ret = XGetWindowProperty ((Display *)ecore_x_display_get (),
4159 ecore_x_window_root_get (_control_window),
4160 ecore_x_atom_get (name),
4161 0, G_MAXLONG, False, XA_WINDOW, &type_return,
4162 &format_return, &nitems_return, &bytes_after_return,
4165 if (ret == Success) {
4166 if ((type_return == XA_WINDOW) && (format_return == 32) && (data)) {
4167 window = *(Window *)data;
4170 std::cerr << "XGetWindowProperty () is failed!!!\n";
4180 * @brief Get app window's x window id.
4182 * @return the X window id of application to have focus or to request to show IME.
4184 static Ecore_X_Window efl_get_app_window (void)
4186 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4188 return efl_get_window ("_ISF_ACTIVE_WINDOW");
4192 * @brief Get clipboard window's x window id.
4194 * @return the X window id of clipboard.
4196 static Ecore_X_Window efl_get_clipboard_window (void)
4198 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4200 return efl_get_window ("CBHM_ELM_WIN");
4204 * @brief Get global navigation window's x window id.
4206 * @return the X window id of global navigation.
4208 static Ecore_X_Window efl_get_global_navigation_window (void)
4210 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4212 return efl_get_window ("GNB_WIN");
4216 * @brief Get app window's x window id.
4218 * @return the X window id of quick panel.
4220 static Ecore_X_Window efl_get_quickpanel_window (void)
4222 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4224 Ecore_X_Window rootWin = ecore_x_window_root_first_get ();
4225 Ecore_X_Window qpwin;
4226 ecore_x_window_prop_xid_get (rootWin, ecore_x_atom_get ("_E_ILLUME_QUICKPANEL_WINDOW_LIST"), ECORE_X_ATOM_WINDOW, &qpwin, 1);
4232 * @brief Get default zone geometry.
4234 * @param x The zone x position.
4235 * @param y The zone y position.
4236 * @param w The zone width.
4237 * @param h The zone height.
4239 * @return EINA_TRUE if successful, otherwise return EINA_FALSE
4241 static Eina_Bool efl_get_default_zone_geometry_info (Ecore_X_Window root, uint *x, uint *y, uint *w, uint *h)
4243 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4245 Ecore_X_Atom zone_geometry_atom;
4246 Ecore_X_Window *zone_lists;
4251 zone_geometry_atom = ecore_x_atom_get ("_E_ILLUME_ZONE_GEOMETRY");
4252 if (!zone_geometry_atom) {
4258 num_zone_lists = ecore_x_window_prop_window_list_get (root, ECORE_X_ATOM_E_ILLUME_ZONE_LIST, &zone_lists);
4259 if (num_zone_lists > 0) {
4260 num_ret = ecore_x_window_prop_card32_get (zone_lists[0], zone_geometry_atom, geom, 4);
4262 if (x) *x = geom[0];
4263 if (y) *y = geom[1];
4264 if (w) *w = geom[2];
4265 if (h) *h = geom[3];
4271 /* if there is no zone available */
4276 /* We must free zone_lists */
4282 #endif /* HAVE_ECOREX */
4284 #if ISF_BUILD_CANDIDATE_UI
4286 * @brief Get screen resolution.
4288 * @param width The screen width.
4289 * @param height The screen height.
4291 static void efl_get_screen_resolution (int &width, int &height)
4293 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4295 static Evas_Coord scr_w = 0, scr_h = 0;
4296 if (scr_w == 0 || scr_h == 0) {
4299 if (efl_get_default_zone_geometry_info (ecore_x_window_root_first_get (), NULL, NULL, &w, &h)) {
4303 ecore_x_window_size_get (ecore_x_window_root_first_get (), &scr_w, &scr_h);
4306 Ecore_Wl2_Display *wl2_display = ecore_wl2_connected_display_get(NULL);
4308 ecore_wl2_display_screen_size_get(wl2_display, &scr_w, &scr_h);
4315 #endif /* CANDIDATE */
4317 //////////////////////////////////////////////////////////////////////
4318 // Start of PanelAgent Functions
4319 //////////////////////////////////////////////////////////////////////
4322 * @brief Initialize panel agent.
4324 * @param config The config string for PanelAgent.
4325 * @param display The current display.
4326 * @param resident The variable indicates whether panel will be resident.
4328 * @return true if initialize is successful, otherwise return false.
4330 static bool initialize_panel_agent (const ConfigPointer& config, const String &display, bool resident)
4332 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4334 LOGD ("initializing panel agent");
4336 _info_manager = new InfoManager ();
4338 if (!_info_manager || !_info_manager->initialize (_info_manager, config, display, resident)) {
4339 ISF_SAVE_LOG ("panel_agent initialize fail!");
4343 _info_manager->signal_connect_focus_in (slot (slot_focus_in));
4344 _info_manager->signal_connect_focus_out (slot (slot_focus_out));
4345 _info_manager->signal_connect_expand_candidate (slot (slot_expand_candidate));
4346 _info_manager->signal_connect_contract_candidate (slot (slot_contract_candidate));
4347 _info_manager->signal_connect_set_candidate_ui (slot (slot_set_candidate_style));
4348 _info_manager->signal_connect_update_factory_info (slot (slot_update_factory_info));
4349 _info_manager->signal_connect_update_spot_location (slot (slot_update_spot_location));
4350 _info_manager->signal_connect_update_input_context (slot (slot_update_input_context));
4351 _info_manager->signal_connect_update_ise_geometry (slot (slot_update_ise_geometry));
4352 _info_manager->signal_connect_show_preedit_string (slot (slot_show_preedit_string));
4353 _info_manager->signal_connect_show_aux_string (slot (slot_show_aux_string));
4354 _info_manager->signal_connect_show_lookup_table (slot (slot_show_candidate_table));
4355 _info_manager->signal_connect_hide_preedit_string (slot (slot_hide_preedit_string));
4356 _info_manager->signal_connect_hide_aux_string (slot (slot_hide_aux_string));
4357 _info_manager->signal_connect_hide_lookup_table (slot (slot_hide_candidate_table));
4358 _info_manager->signal_connect_update_preedit_string (slot (slot_update_preedit_string));
4359 _info_manager->signal_connect_update_preedit_caret (slot (slot_update_preedit_caret));
4360 _info_manager->signal_connect_update_aux_string (slot (slot_update_aux_string));
4361 _info_manager->signal_connect_update_lookup_table (slot (slot_update_candidate_table));
4362 _info_manager->signal_connect_select_candidate (slot (slot_select_candidate));
4363 _info_manager->signal_connect_get_candidate_geometry (slot (slot_get_candidate_geometry));
4364 _info_manager->signal_connect_get_input_panel_geometry (slot (slot_get_input_panel_geometry));
4365 _info_manager->signal_connect_set_active_ise_by_uuid (slot (slot_set_active_ise));
4366 _info_manager->signal_connect_get_ise_list (slot (slot_get_ise_list));
4367 _info_manager->signal_connect_get_all_helper_ise_info (slot (slot_get_all_helper_ise_info));
4368 _info_manager->signal_connect_set_has_option_helper_ise_info(slot (slot_set_has_option_helper_ise_info));
4369 _info_manager->signal_connect_set_enable_helper_ise_info (slot (slot_set_enable_helper_ise_info));
4370 _info_manager->signal_connect_show_helper_ise_list (slot (slot_show_helper_ise_list));
4371 _info_manager->signal_connect_show_helper_ise_selector (slot (slot_show_helper_ise_selector));
4372 _info_manager->signal_connect_is_helper_ise_enabled (slot (slot_is_helper_ise_enabled));
4373 _info_manager->signal_connect_get_ise_information (slot (slot_get_ise_information));
4374 _info_manager->signal_connect_get_keyboard_ise_list (slot (slot_get_keyboard_ise_list));
4375 _info_manager->signal_connect_get_language_list (slot (slot_get_language_list));
4376 _info_manager->signal_connect_get_all_language (slot (slot_get_all_language));
4377 _info_manager->signal_connect_get_ise_language (slot (slot_get_ise_language));
4378 _info_manager->signal_connect_get_ise_info_by_uuid (slot (slot_get_ise_info));
4379 _info_manager->signal_connect_set_keyboard_ise (slot (slot_set_keyboard_ise));
4380 _info_manager->signal_connect_get_keyboard_ise (slot (slot_get_keyboard_ise));
4381 _info_manager->signal_connect_accept_connection (slot (slot_accept_connection));
4382 _info_manager->signal_connect_close_connection (slot (slot_close_connection));
4383 _info_manager->signal_connect_exit (slot (slot_exit));
4385 _info_manager->signal_connect_register_helper (slot(slot_register_helper));
4386 _info_manager->signal_connect_register_helper_properties (slot (slot_register_helper_properties));
4387 _info_manager->signal_connect_show_ise (slot (slot_show_ise));
4388 _info_manager->signal_connect_hide_ise (slot (slot_hide_ise));
4390 _info_manager->signal_connect_will_hide_ack (slot (slot_will_hide_ack));
4392 _info_manager->signal_connect_set_keyboard_mode (slot (slot_set_keyboard_mode));
4394 _info_manager->signal_connect_candidate_will_hide_ack (slot (slot_candidate_will_hide_ack));
4395 _info_manager->signal_connect_get_ise_state (slot (slot_get_ise_state));
4396 _info_manager->signal_connect_start_default_ise (slot (slot_start_default_ise));
4397 _info_manager->signal_connect_stop_default_ise (slot (slot_stop_default_ise));
4398 _info_manager->signal_connect_show_panel (slot (slot_show_helper_ise_selector));
4399 #if ENABLE_REMOTE_INPUT
4400 _info_manager->signal_connect_remoteinput_send_input_message(slot (slot_send_remote_input_message));
4401 _info_manager->signal_connect_remoteinput_send_surrounding_text(slot (slot_recv_remote_surrounding_text));
4403 _info_manager->signal_connect_get_recent_ise_geometry (slot (slot_get_recent_ise_geometry));
4404 _info_manager->signal_connect_check_privilege_by_sockfd (slot (slot_check_privilege_by_sockfd));
4406 _info_manager->signal_connect_run_helper (slot (slot_run_helper));
4407 _info_manager->signal_connect_launch_option_application (slot (slot_launch_option_application));
4409 LOGD ("initializing panel agent succeeded");
4414 static void delete_ise_hide_timer (void)
4416 LOGD ("deleting ise_hide_timer");
4417 if (_ise_hide_timer) {
4418 ecore_timer_del (_ise_hide_timer);
4419 _ise_hide_timer = NULL;
4423 static void hide_ise ()
4425 LOGD ("send request to hide helper");
4426 String uuid = _info_manager->get_current_helper_uuid ();
4427 _info_manager->hide_helper (uuid);
4429 /* Only if we are not already in HIDE state */
4430 if (_ise_state != WINDOW_STATE_HIDE) {
4431 /* From this point, slot_get_input_panel_geometry should return hidden state geometry */
4432 _ise_state = WINDOW_STATE_WILL_HIDE;
4434 _updated_hide_state_geometry = false;
4438 ecore_x_event_mask_unset (_app_window, ECORE_X_EVENT_MASK_WINDOW_FOCUS_CHANGE);
4440 #if ISF_BUILD_CANDIDATE_UI
4441 if (_candidate_window) {
4442 if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE)
4443 ui_candidate_hide (true, true, true);
4445 ui_candidate_hide (true, false, true);
4447 #endif /* CANDIDATE */
4450 #ifdef HAVE_NOTIFICATION
4451 delete_notification (&ise_selector_module_noti);
4456 #if ENABLE_MULTIWINDOW_SUPPORT
4457 static Eina_Bool ise_hide_timeout (void *data)
4459 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4461 delete_ise_hide_timer ();
4464 return ECORE_CALLBACK_CANCEL;
4469 * @brief Insert data to ime_info table.
4471 * @param list The list to store uuid
4473 * @return true if it is successful, otherwise return false.
4475 static bool update_ise_list (std::vector<String> &list)
4477 std::vector<String> uuids;
4478 std::vector<TOOLBAR_MODE_T> modes;
4479 std::vector<ImeInfoDB>::iterator iter;
4482 if (_ime_info.size() == 0) {
4483 if (isf_pkg_select_all_ime_info_db(_ime_info) == 0)
4487 /* Update _groups */
4489 std::vector<String> ise_langs;
4490 for (size_t i = 0; i < _ime_info.size (); ++i) {
4491 scim_split_string_list(ise_langs, _ime_info[i].languages);
4492 for (size_t j = 0; j < ise_langs.size (); j++) {
4493 if (std::find (_groups[ise_langs[j]].begin (), _groups[ise_langs[j]].end (), i) == _groups[ise_langs[j]].end ())
4494 _groups[ise_langs[j]].push_back (i);
4499 for (iter = _ime_info.begin(); iter != _ime_info.end(); iter++) {
4500 uuids.push_back(iter->appid);
4501 modes.push_back(iter->mode);
4504 if (uuids.size() > 0) {
4508 _info_manager->update_ise_list (list);
4510 if (_initial_ise_uuid.length () > 0) {
4511 String active_uuid = _initial_ise_uuid;
4512 String default_uuid = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), String (""));
4513 if (std::find (uuids.begin (), uuids.end (), default_uuid) == uuids.end ()) {
4514 if ((_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) && (modes[get_ise_index (_initial_ise_uuid)] != TOOLBAR_KEYBOARD_MODE)) {
4515 active_uuid = String (SCIM_COMPOSE_KEY_FACTORY_UUID);
4518 if (set_active_ise (active_uuid, _soft_keyboard_launched) == false) {
4519 if (_initial_ise_uuid.compare (active_uuid)) {
4520 LOGD ("Trying to launch initial IME (%s)", _initial_ise_uuid.c_str ());
4521 set_active_ise (_initial_ise_uuid, _soft_keyboard_launched);
4524 } else if (_info_manager->get_current_toolbar_mode () == TOOLBAR_HELPER_MODE) { // Check whether keyboard engine is installed
4525 String IMENGINE_KEY = String (SCIM_CONFIG_DEFAULT_IMENGINE_FACTORY) + String ("/") + String ("~other");
4526 String keyboard_uuid = _config->read (IMENGINE_KEY, String (""));
4527 if (std::find (uuids.begin (), uuids.end (), keyboard_uuid) == uuids.end ()) {
4528 active_uuid = String (SCIM_COMPOSE_KEY_FACTORY_UUID);
4529 _info_manager->change_factory (active_uuid);
4530 _config->write (IMENGINE_KEY, active_uuid);
4537 char *lang_str = vconf_get_str (VCONFKEY_LANGSET);
4539 if (_ime_info.size () > 0 && _ime_info[0].display_lang.compare(lang_str) == 0)
4540 _locale_string = String (lang_str);
4546 LOGW ("No IME list");
4548 #ifdef HAVE_PKGMGR_INFO
4550 int ret = package_manager_create (&pkgmgr);
4551 if (ret == PACKAGE_MANAGER_ERROR_NONE) {
4552 ret = package_manager_set_event_cb (pkgmgr, _package_manager_event_cb, NULL);
4553 if (ret == PACKAGE_MANAGER_ERROR_NONE) {
4554 LOGD ("package_manager_set_event_cb succeeded.");
4557 LOGE ("package_manager_set_event_cb failed(%d)", ret);
4561 LOGE ("package_manager_create failed(%d)", ret);
4570 * @brief Focus in slot function for PanelAgent.
4572 static void slot_focus_in (void)
4574 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4577 if ((_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE)) {
4578 if (_launch_ise_on_request && !_soft_keyboard_launched) {
4579 String uuid = _config->read (SCIM_CONFIG_DEFAULT_HELPER_ISE, String (""));
4580 if (uuid.length () > 0 && (_ime_info[get_ise_index(uuid)].options & ISM_HELPER_PROCESS_KEYBOARD_KEYEVENT)) {
4581 LOGD ("Start helper (%s)", uuid.c_str ());
4583 set_keyboard_engine (String (SCIM_COMPOSE_KEY_FACTORY_UUID));
4584 if (_info_manager->start_helper (uuid))
4585 _soft_keyboard_launched = true;
4590 #if ISF_BUILD_CANDIDATE_UI
4591 ui_candidate_delete_destroy_timer ();
4592 #endif /* CANDIDATE */
4596 * @brief Focus out slot function for PanelAgent.
4598 static void slot_focus_out (void)
4600 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4604 #if ISF_BUILD_CANDIDATE_UI
4605 ui_candidate_delete_destroy_timer ();
4606 _destroy_timer = ecore_timer_add (ISF_CANDIDATE_DESTROY_DELAY, ui_candidate_destroy_timeout, NULL);
4607 #endif /* CANDIDATE */
4611 * @brief Expand candidate slot function for PanelAgent.
4613 static void slot_expand_candidate (void)
4615 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4616 if (_candidate_mode == SOFT_CANDIDATE_WINDOW)
4619 #if ISF_BUILD_CANDIDATE_UI
4620 if (_candidate_area_2 && !_candidate_area_2_visible)
4621 ui_candidate_window_more_button_cb (NULL, NULL, NULL, NULL);
4622 #endif /* CANDIDATE */
4626 * @brief Contract candidate slot function for PanelAgent.
4628 static void slot_contract_candidate (void)
4630 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4632 if (_candidate_mode == SOFT_CANDIDATE_WINDOW)
4635 #if ISF_BUILD_CANDIDATE_UI
4636 ui_candidate_window_close_button_cb (NULL, NULL, NULL, NULL);
4637 #endif /* CANDIDATE */
4641 * @brief Set candidate style slot function for PanelAgent.
4643 * @param portrait_line The displayed line number for portrait.
4644 * @param mode The candidate mode.
4646 static void slot_set_candidate_style (int portrait_line, int mode)
4648 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " display_line:" << portrait_line << " mode:" << mode << "\n";
4649 #if ISF_BUILD_CANDIDATE_UI
4650 if ((portrait_line != _candidate_port_line) || (mode != _candidate_mode)) {
4651 _candidate_mode = (ISF_CANDIDATE_MODE_T)mode;
4652 _candidate_port_line = (ISF_CANDIDATE_PORTRAIT_LINE_T)portrait_line;
4653 _soft_candidate_width = 0;
4654 _soft_candidate_height = 0;
4656 if (_candidate_mode == SOFT_CANDIDATE_WINDOW) {
4657 if (_candidate_window)
4658 ui_destroy_candidate_window ();
4663 if (_candidate_window)
4664 ui_create_candidate_window ();
4666 #endif /* CANDIDATE */
4669 #if defined(HAVE_NOTIFICATION) || defined(HAVE_ECOREX)
4670 static unsigned int get_ise_count (TOOLBAR_MODE_T mode, bool valid_helper)
4672 unsigned int ise_count = 0;
4673 for (unsigned int i = 0; i < _ime_info.size (); i++) {
4674 if (mode == _ime_info[i].mode) {
4675 if (mode == TOOLBAR_KEYBOARD_MODE || !valid_helper)
4677 else if (_ime_info[i].is_enabled)
4687 * @brief Update keyboard ISE information slot function for PanelAgent.
4689 * @param info The information of current Keyboard ISE.
4691 static void slot_update_factory_info (const PanelFactoryInfo &info)
4693 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4695 String ise_name = info.name;
4697 String old_ise = _info_manager->get_current_ise_name ();
4698 #if ISF_BUILD_CANDIDATE_UI
4699 if (old_ise != ise_name) {
4700 if ((_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) && _candidate_window) {
4701 ui_destroy_candidate_window ();
4704 #endif /* CANDIDATE */
4706 TOOLBAR_MODE_T mode = _info_manager->get_current_toolbar_mode ();
4708 if (TOOLBAR_HELPER_MODE == mode)
4709 ise_name = _ime_info[get_ise_index (_info_manager->get_current_helper_uuid())].label;
4711 if (ise_name.length () > 0)
4712 _info_manager->set_current_ise_name (ise_name);
4714 #ifdef HAVE_NOTIFICATION
4716 if (old_ise != ise_name) {
4717 if (TOOLBAR_KEYBOARD_MODE == mode) {
4718 char noti_msg[256] = {0};
4719 unsigned int keyboard_ise_count = get_ise_count (TOOLBAR_KEYBOARD_MODE, false);
4720 if (keyboard_ise_count == 0) {
4721 LOGD ("the number of keyboard ise is %d", keyboard_ise_count);
4724 else if (keyboard_ise_count >= 2) {
4725 snprintf (noti_msg, sizeof (noti_msg), _("%s selected"), ise_name.c_str ());
4727 else if (keyboard_ise_count == 1) {
4728 snprintf (noti_msg, sizeof (noti_msg), _("Only %s available"), ise_name.c_str ());
4731 notification_status_message_post (noti_msg);
4732 LOGD ("%s", noti_msg);
4740 * @brief Update cursor position slot function for PanelAgent.
4742 * @param x The x position of current cursor.
4743 * @param y The bottom y position of current cursor.
4744 * @param top_y The top y position of current cursor.
4746 static void slot_update_spot_location (int x, int y, int top_y)
4748 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4750 #if ISF_BUILD_CANDIDATE_UI
4751 if (x >= 0 && x < _screen_height && y >= 0 && y < _screen_height) {
4752 _spot_location_x = x;
4753 _spot_location_y = y;
4754 _spot_location_top_y = top_y;
4756 ui_settle_candidate_window ();
4758 #endif /* CANDIDATE */
4762 * @brief The input context of ISE is changed.
4764 * @param type The event type.
4765 * @param value The event value.
4767 static void slot_update_input_context (int type, int value)
4772 * @brief Update ise geometry.
4774 * @param x The x position in screen.
4775 * @param y The y position in screen.
4776 * @param width The ISE window width.
4777 * @param height The ISE window height.
4779 static void slot_update_ise_geometry (int x, int y, int width, int height)
4781 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " x:" << x << " y:" << y << " width:" << width << " height:" << height << "...\n";
4783 LOGD ("x : %d , y : %d , width : %d , height : %d, _ise_state : %d", x, y, width, height, _ise_state);
4785 if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) {
4786 if (_candidate_mode == SOFT_CANDIDATE_WINDOW) {
4787 /*IF ISE sent the ise_geometry information when the current_keyboard_mode is H/W mode and candidate_mode is SOFT_CANDIDATE,
4788 It means that given geometry information is for the candidate window */
4789 set_soft_candidate_geometry (x, y, width, height);
4797 _ise_height = height;
4799 #if ISF_BUILD_CANDIDATE_UI
4800 if (_candidate_window && _candidate_state == WINDOW_STATE_SHOW) {
4801 ui_settle_candidate_window ();
4803 #endif /* CANDIDATE */
4805 if (_ise_state == WINDOW_STATE_SHOW || _ise_state == WINDOW_STATE_WILL_SHOW) {
4806 _ise_reported_geometry.valid = true;
4807 _ise_reported_geometry.angle = efl_get_ise_window_angle ();
4808 _ise_reported_geometry.geometry.pos_x = x;
4809 _ise_reported_geometry.geometry.pos_y = y;
4810 _ise_reported_geometry.geometry.width = width;
4811 _ise_reported_geometry.geometry.height = height;
4812 if (_ise_state == WINDOW_STATE_SHOW) {
4814 set_keyboard_geometry_atom_info (_app_window, _ise_reported_geometry.geometry);
4816 _info_manager->update_input_panel_event (ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
4822 * @brief Show preedit slot function for PanelAgent.
4824 static void slot_show_preedit_string (void)
4826 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4828 if (_candidate_mode == SOFT_CANDIDATE_WINDOW)
4831 #if ISF_BUILD_CANDIDATE_UI
4832 if (_preedit_window == NULL) {
4833 ui_create_preedit_window ();
4835 /* Move preedit window according to candidate window position */
4836 if (_candidate_window) {
4837 /* Get candidate window position */
4838 int x, y, width, height;
4839 ecore_evas_geometry_get (ecore_evas_ecore_evas_get (evas_object_evas_get (_candidate_window)), &x, &y, &width, &height);
4841 int height2 = ui_candidate_get_valid_height ();
4842 int angle = efl_get_app_window_angle ();
4845 x -= _preedit_height;
4846 y = _screen_height - _preedit_width;
4847 } else if (_candidate_angle == 270) {
4849 } else if (_candidate_angle == 180) {
4850 x = _screen_width - _preedit_width;
4853 y -= _preedit_height;
4856 if (_preedit_window)
4857 evas_object_move (_preedit_window, x, y);
4861 if (_preedit_window && evas_object_visible_get (_preedit_window))
4864 slot_show_candidate_table ();
4866 if (_preedit_window)
4867 evas_object_show (_preedit_window);
4868 #endif /* CANDIDATE */
4872 * @brief Show aux slot function for PanelAgent.
4874 static void slot_show_aux_string (void)
4876 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4878 #if ISF_BUILD_CANDIDATE_UI
4879 if (_candidate_window == NULL)
4880 ui_create_candidate_window ();
4882 if (_aux_area == NULL || _aux_area_visible)
4885 evas_object_show (_aux_area);
4886 _aux_area_visible = true;
4887 ui_candidate_window_adjust ();
4889 LOGD ("calling ui_candidate_show ()");
4890 ui_candidate_show ();
4891 ui_settle_candidate_window ();
4892 ui_candidate_delete_destroy_timer ();
4893 #endif /* CANDIDATE */
4897 * @brief Show candidate table slot function for PanelAgent.
4899 static void slot_show_candidate_table (void)
4901 if (_candidate_mode == SOFT_CANDIDATE_WINDOW) {
4902 _info_manager->helper_candidate_show ();
4906 #if ISF_BUILD_CANDIDATE_UI
4907 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4908 if (_candidate_window == NULL)
4909 ui_create_candidate_window ();
4912 if (_candidate_state == WINDOW_STATE_SHOW &&
4913 (_candidate_area_1_visible || _candidate_area_2_visible)) {
4914 efl_set_transient_for_app_window (elm_win_xwindow_get (_candidate_window));
4919 evas_object_show (_candidate_area_1);
4920 _candidate_area_1_visible = true;
4921 ui_candidate_window_adjust ();
4923 LOGD ("calling ui_candidate_show ()");
4924 ui_candidate_show ();
4925 ui_settle_candidate_window ();
4926 ui_candidate_delete_destroy_timer ();
4928 #ifdef HAVE_FEEDBACK
4929 int feedback_result = feedback_initialize ();
4931 if (FEEDBACK_ERROR_NONE == feedback_result) {
4932 LOGD ("Feedback initialize successful");
4933 feedback_initialized = true;
4935 LOGW ("Feedback initialize fail : %d", feedback_result);
4936 feedback_initialized = false;
4938 #endif /* HAVE_FEEDBACK */
4939 #endif /* CANDIDATE */
4943 * @brief Hide preedit slot function for PanelAgent.
4945 static void slot_hide_preedit_string (void)
4947 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4949 #if ISF_BUILD_CANDIDATE_UI
4950 if (!_preedit_window || !evas_object_visible_get (_preedit_window))
4953 evas_object_hide (_preedit_window);
4954 #endif /* CANDIDATE */
4958 * @brief Hide aux slot function for PanelAgent.
4960 static void slot_hide_aux_string (void)
4962 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4964 #if ISF_BUILD_CANDIDATE_UI
4965 if (!_aux_area || !_aux_area_visible)
4968 evas_object_hide (_aux_area);
4969 _aux_area_visible = false;
4970 elm_scroller_region_show (_aux_area, 0, 0, 10, 10);
4971 ui_candidate_window_adjust ();
4973 LOGD ("calling ui_candidate_hide (false, true, true)");
4974 ui_candidate_hide (false, true, true);
4975 ui_settle_candidate_window ();
4977 if (ui_candidate_can_be_hide ()) {
4978 _candidate_show_requested = false;
4979 LOGD ("setting _show_candidate_requested to FALSE");
4981 #endif /* CANDIDATE */
4985 * @brief Hide candidate table slot function for PanelAgent.
4987 static void slot_hide_candidate_table (void)
4989 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4991 if (_candidate_mode == SOFT_CANDIDATE_WINDOW) {
4992 _info_manager->helper_candidate_hide ();
4996 #if ISF_BUILD_CANDIDATE_UI
4997 if (!_candidate_area_1 || _candidate_state == WINDOW_STATE_WILL_HIDE)
5000 if (_candidate_area_1_visible || _candidate_area_2_visible) {
5001 bool bForce = false;
5002 if (_candidate_area_1_visible) {
5003 if (_aux_area_visible) {
5004 evas_object_hide (_candidate_area_1);
5005 _candidate_area_1_visible = false;
5006 evas_object_hide (_more_btn);
5008 /* Let's not actually hide the _candidate_area_1 object, for the case that
5009 even if the application replies CANDIDATE_WILL_HIDE_ACK a little late,
5010 it is better to display the previous candidates instead of blank screen */
5011 _candidate_area_1_visible = false;
5015 if (_candidate_area_2_visible) {
5016 evas_object_hide (_candidate_area_2);
5017 _candidate_area_2_visible = false;
5018 evas_object_hide (_scroller_bg);
5019 evas_object_hide (_close_btn);
5020 _info_manager->candidate_more_window_hide ();
5022 ui_candidate_window_adjust ();
5024 LOGD ("calling ui_candidate_hide (%d, true, true)", bForce);
5025 ui_candidate_hide (bForce, true, true);
5026 ui_settle_candidate_window ();
5029 #ifdef HAVE_FEEDBACK
5030 int feedback_result = feedback_deinitialize ();
5032 if (FEEDBACK_ERROR_NONE == feedback_result)
5033 LOGD ("Feedback deinitialize successful");
5035 LOGW ("Feedback deinitialize fail : %d", feedback_result);
5037 feedback_initialized = false;
5040 if (ui_candidate_can_be_hide ()) {
5041 _candidate_show_requested = false;
5042 LOGD ("setting _show_candidate_requested to FALSE");
5044 #endif /* CANDIDATE */
5048 * @brief Update preedit slot function for PanelAgent.
5050 * @param str The new preedit string.
5051 * @param attrs The attribute list of new preedit string.
5053 static void slot_update_preedit_string (const String &str, const AttributeList &attrs, int caret)
5055 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " string=" << str << "\n";
5057 #if ISF_BUILD_CANDIDATE_UI
5058 if (str.length () <= 0)
5061 if (_preedit_window == NULL || !evas_object_visible_get (_preedit_window)) {
5062 slot_show_preedit_string ();
5065 int x, y, width, height, candidate_width;
5066 evas_object_text_text_set (_tmp_preedit_text, str.c_str ());
5067 evas_object_geometry_get (_tmp_preedit_text, &x, &y, &width, &height);
5068 ecore_evas_geometry_get (ecore_evas_ecore_evas_get (evas_object_evas_get (_candidate_window)), &x, &y, &candidate_width, &height);
5069 _preedit_width = (width + ISF_PREEDIT_BORDER * 2) < candidate_width ? (width + ISF_PREEDIT_BORDER * 2) : candidate_width;
5071 /* Resize preedit window and avoid text blink */
5072 int old_width, old_height;
5073 evas_object_geometry_get (_preedit_window, &x, &y, &old_width, &old_height);
5074 if (old_width < _preedit_width) {
5075 evas_object_resize (_preedit_window, _preedit_width, _preedit_height);
5076 edje_object_part_text_set (_preedit_text, "preedit", str.c_str ());
5078 edje_object_part_text_set (_preedit_text, "preedit", str.c_str ());
5079 evas_object_resize (_preedit_window, _preedit_width, _preedit_height);
5082 /* Move preedit window */
5083 if (_candidate_angle == 90 || _candidate_angle == 180) {
5084 ecore_evas_geometry_get (ecore_evas_ecore_evas_get (evas_object_evas_get (_preedit_window)), &x, &y, &width, &height);
5085 if (_candidate_angle == 90) {
5086 y = _screen_height - _preedit_width;
5087 } else if (_candidate_angle == 180) {
5088 x = _screen_width - _preedit_width;
5090 evas_object_move (_preedit_window, x, y);
5092 #endif /* CANDIDATE */
5096 * @brief Update caret slot function for PanelAgent.
5098 * @param caret The caret position.
5100 static void slot_update_preedit_caret (int caret)
5102 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " caret=" << caret << "\n";
5105 #if ISF_BUILD_CANDIDATE_UI
5107 * @brief Set highlight text color and background color for edje object.
5109 * @param item The edje object pointer.
5110 * @param nForeGround The text color.
5111 * @param nBackGround The background color.
5112 * @param bSetBack The flag for background color.
5114 static void set_highlight_color (Evas_Object *item, uint32 nForeGround, uint32 nBackGround, bool bSetBack)
5116 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
5118 int r, g, b, a, r2, g2, b2, a2, r3, g3, b3, a3;
5119 if (edje_object_color_class_get (item, "text_color", &r, &g, &b, &a, &r2, &g2, &b2, &a2, &r3, &g3, &b3, &a3)) {
5120 r = SCIM_RGB_COLOR_RED (nForeGround);
5121 g = SCIM_RGB_COLOR_GREEN (nForeGround);
5122 b = SCIM_RGB_COLOR_BLUE (nForeGround);
5123 edje_object_color_class_set (item, "text_color", r, g, b, a, r2, g2, b2, a2, r3, g3, b3, a3);
5125 if (bSetBack && edje_object_color_class_get (item, "rect_color", &r, &g, &b, &a, &r2, &g2, &b2, &a2, &r3, &g3, &b3, &a3)) {
5126 r = SCIM_RGB_COLOR_RED (nBackGround);
5127 g = SCIM_RGB_COLOR_GREEN (nBackGround);
5128 b = SCIM_RGB_COLOR_BLUE (nBackGround);
5129 edje_object_color_class_set (item, "rect_color", r, g, b, 255, r2, g2, b2, a2, r3, g3, b3, a3);
5132 #endif /* CANDIDATE */
5135 * @brief Update aux slot function for PanelAgent.
5137 * @param str The new aux string.
5138 * @param attrs The attribute list of new aux string.
5140 static void slot_update_aux_string (const String &str, const AttributeList &attrs)
5142 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
5143 #if ISF_BUILD_CANDIDATE_UI
5144 if (_candidate_window == NULL)
5145 ui_create_candidate_window ();
5147 if (!_aux_area || (str.length () <= 0))
5150 if (!_aux_area_visible) {
5151 LOGD ("calling ui_candidate_show ()");
5152 ui_candidate_show ();
5153 slot_show_aux_string ();
5156 int x, y, width, height, item_width = 0;
5157 unsigned int window_width = 0, count = 0, i;
5159 Evas_Object *aux_edje = NULL;
5161 /* Get highlight item index */
5162 int aux_index = -1, aux_start = 0, aux_end = 0;
5163 String strAux = str;
5164 bool bSetBack = false;
5165 uint32 nForeGround = SCIM_RGB_COLOR (62, 207, 255);
5166 uint32 nBackGround = SCIM_RGB_COLOR (0, 0, 0);
5167 for (AttributeList::const_iterator ait = attrs.begin (); ait != attrs.end (); ++ait) {
5168 if (aux_index == -1 && ait->get_type () == SCIM_ATTR_DECORATE) {
5169 aux_index = ait->get_value ();
5170 } else if (ait->get_type () == SCIM_ATTR_FOREGROUND) {
5171 nForeGround = ait->get_value ();
5172 } else if (ait->get_type () == SCIM_ATTR_BACKGROUND) {
5173 nBackGround = ait->get_value ();
5178 std::vector<String> aux_list;
5179 scim_split_string_list (aux_list, strAux, '|');
5181 if (_aux_items.size () > 0) {
5182 for (i = 0; i < _aux_items.size (); i++)
5183 evas_object_del (_aux_items [i]);
5184 _aux_items.clear ();
5186 if (_aux_seperates.size () > 0) {
5187 for (i = 0; i < _aux_seperates.size (); i++)
5188 evas_object_del (_aux_seperates [i]);
5189 _aux_seperates.clear ();
5192 int seperate_width = 4;
5193 int seperate_height = 52 * _height_rate;
5194 Evas *evas = evas_object_evas_get (_candidate_window);
5195 for (i = 0; i < aux_list.size (); i++) {
5197 Evas_Object *seperate_item = edje_object_add (evas);
5198 edje_object_file_set (seperate_item, _candidate_edje_file.c_str (), "seperate_line");
5199 evas_object_size_hint_min_set (seperate_item, seperate_width, seperate_height);
5200 elm_table_pack (_aux_table, seperate_item, 2 * i - 1, 0, 1, 1);
5201 evas_object_show (seperate_item);
5202 _aux_seperates.push_back (seperate_item);
5206 aux_edje = edje_object_add (evas);
5207 edje_object_file_set (aux_edje, _candidate_edje_file.c_str (), "aux");
5208 edje_object_part_text_set (aux_edje, "aux", aux_list [i].c_str ());
5209 edje_object_text_class_set (aux_edje, "tizen", _candidate_font_name.c_str (), _aux_font_size);
5210 elm_table_pack (_aux_table, aux_edje, 2 * i, 0, 1, 1);
5211 evas_object_event_callback_add (aux_edje, EVAS_CALLBACK_MOUSE_DOWN, ui_mouse_button_pressed_cb, GINT_TO_POINTER ((i << 8) + ISF_EFL_AUX));
5212 evas_object_event_callback_add (aux_edje, EVAS_CALLBACK_MOUSE_UP, ui_mouse_button_released_cb, GINT_TO_POINTER (i));
5213 evas_object_event_callback_add (aux_edje, EVAS_CALLBACK_MOUSE_MOVE, ui_mouse_moved_cb, GINT_TO_POINTER (ISF_EFL_AUX));
5214 evas_object_show (aux_edje);
5215 _aux_items.push_back (aux_edje);
5216 /* if (i == (unsigned int)aux_index)
5217 edje_object_signal_emit (aux_edje, "aux,state,selected", "aux");
5219 edje_object_signal_emit (aux_edje, "aux,state,unselected", "aux");
5221 evas_object_text_text_set (_tmp_aux_text, aux_list [i].c_str ());
5222 evas_object_geometry_get (_tmp_aux_text, &x, &y, &width, &height);
5223 item_width = width + 2*_blank_width;
5224 item_width = item_width > _item_min_width ? item_width : _item_min_width;
5225 evas_object_size_hint_min_set (aux_edje, item_width, _aux_height);
5226 if (aux_index == (int)i || (aux_index == -1 && i == 0)) {
5227 aux_start = window_width;
5228 aux_end = window_width + item_width;
5230 window_width = window_width + item_width + 4;
5233 // Set highlight item
5234 for (AttributeList::const_iterator ait = attrs.begin (); ait != attrs.end (); ++ait) {
5235 if (ait->get_type () == SCIM_ATTR_DECORATE) {
5236 unsigned int index = ait->get_value ();
5237 if (index < _aux_items.size ())
5238 set_highlight_color (_aux_items [index], nForeGround, nBackGround, bSetBack);
5243 elm_scroller_region_get (_aux_area, &x, &y, &w, &h);
5244 item_width = aux_end - aux_start;
5245 if (item_width > 0) {
5246 if (item_width >= w)
5247 elm_scroller_region_show (_aux_area, aux_end - w, y, w, h);
5248 else if (aux_end > x + w)
5249 elm_scroller_region_show (_aux_area, aux_end - w, y, w, h);
5250 else if (aux_start < x)
5251 elm_scroller_region_show (_aux_area, aux_start, y, w, h);
5254 #endif /* CANDIDATE */
5257 #if ISF_BUILD_CANDIDATE_UI
5259 * @brief Update candidate/associate table.
5261 * @param table_type The table type.
5262 * @param table The lookup table for candidate or associate.
5264 static void update_table (int table_type, const LookupTable &table)
5266 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " (" << table.get_current_page_size () << ")\n";
5268 int item_num = table.get_current_page_size ();
5275 AttributeList attrs;
5276 int i, x, y, item_0_width = 0;
5280 int seperate_width = 2;
5281 int seperate_height = 52 * _height_rate;
5282 int line_width = _candidate_scroll_width;
5283 int line_height = _v_padding;
5284 int total_width = 0;
5285 int current_width = 0;
5288 int more_item_count = 0;
5289 int scroll_0_width = _candidate_scroll_0_width_min;
5290 int cursor_pos = table.get_cursor_pos ();
5291 int cursor_line = 0;
5293 if (_candidate_angle == 90 || _candidate_angle == 270)
5294 scroll_0_width = _screen_height - _more_btn_width - _h_padding;
5296 scroll_0_width = _screen_width - _more_btn_width - _h_padding;
5298 _candidate_image_count = 0;
5299 _candidate_text_count = 0;
5300 _candidate_pop_image_count = 0;
5301 _candidate_display_number = 0;
5302 _candidate_row_items.clear ();
5304 Evas *evas = evas_object_evas_get (_candidate_window);
5305 for (i = 0; i < SCIM_LOOKUP_TABLE_MAX_PAGESIZE; ++i) {
5306 if (_candidate_0 [i]) {
5307 evas_object_del (_candidate_0 [i]);
5308 _candidate_0 [i] = NULL;
5310 if (_seperate_0 [i]) {
5311 evas_object_del (_seperate_0 [i]);
5312 _seperate_0 [i] = NULL;
5314 if (_seperate_items [i]) {
5315 evas_object_del (_seperate_items [i]);
5316 _seperate_items [i] = NULL;
5319 evas_object_del (_line_0 [i]);
5322 if (_line_items [i]) {
5323 evas_object_del (_line_items [i]);
5324 _line_items [i] = NULL;
5328 for (i = 0; i < SCIM_LOOKUP_TABLE_MAX_PAGESIZE; ++i) {
5330 bool bHighLight = false;
5331 bool bSetBack = false;
5332 uint32 nForeGround = SCIM_RGB_COLOR (249, 249, 249);
5333 uint32 nBackGround = SCIM_RGB_COLOR (0, 0, 0);
5334 attrs = table.get_attributes_in_current_page (i);
5335 for (AttributeList::const_iterator ait = attrs.begin (); ait != attrs.end (); ++ait) {
5336 if (ait->get_type () == SCIM_ATTR_DECORATE && ait->get_value () == SCIM_ATTR_DECORATE_HIGHLIGHT) {
5338 nForeGround = SCIM_RGB_COLOR (62, 207, 255);
5339 } else if (ait->get_type () == SCIM_ATTR_FOREGROUND) {
5341 nForeGround = ait->get_value ();
5342 } else if (ait->get_type () == SCIM_ATTR_BACKGROUND) {
5344 nBackGround = ait->get_value ();
5348 wcs = table.get_candidate_in_current_page (i);
5349 mbs = utf8_wcstombs (wcs);
5351 if (!_candidate_0 [i] && total_width <= scroll_0_width) {
5352 _candidate_0 [i] = get_candidate (mbs, _candidate_window, &item_0_width, nForeGround, nBackGround, bHighLight, bSetBack, item_num, i);
5353 evas_object_event_callback_add (_candidate_0 [i], EVAS_CALLBACK_MOUSE_DOWN, ui_mouse_button_pressed_cb, GINT_TO_POINTER ((i << 8) + ISF_EFL_CANDIDATE_0));
5354 evas_object_event_callback_add (_candidate_0 [i], EVAS_CALLBACK_MOUSE_UP, ui_mouse_button_released_cb, GINT_TO_POINTER (i));
5355 evas_object_event_callback_add (_candidate_0 [i], EVAS_CALLBACK_MOUSE_MOVE, ui_mouse_moved_cb, GINT_TO_POINTER (ISF_EFL_CANDIDATE_0));
5357 /* Check whether this item is the last one */
5358 if (i == item_num - 1) {
5359 if (_candidate_angle == 90 || _candidate_angle == 270)
5360 scroll_0_width = _candidate_land_width;
5362 scroll_0_width = _candidate_port_width;
5365 /* Add first item */
5367 item_0_width = item_0_width > scroll_0_width ? scroll_0_width : item_0_width;
5368 evas_object_show (_candidate_0 [i]);
5369 evas_object_size_hint_min_set (_candidate_0 [i], item_0_width, _item_min_height);
5370 elm_table_pack (_candidate_0_table, _candidate_0 [i], 0, 0, item_0_width, _item_min_height);
5371 total_width += item_0_width;
5372 _candidate_display_number++;
5375 total_width += (item_0_width + seperate_width);
5376 if (total_width <= scroll_0_width) {
5377 _seperate_0 [i] = edje_object_add (evas);
5378 edje_object_file_set (_seperate_0 [i], _candidate_edje_file.c_str (), "seperate_line");
5379 evas_object_size_hint_min_set (_seperate_0 [i], seperate_width, seperate_height);
5380 elm_table_pack (_candidate_0_table, _seperate_0 [i],
5381 total_width - item_0_width - seperate_width,
5382 line_0*(_item_min_height+line_height) + (_item_min_height - seperate_height)/2,
5383 seperate_width, seperate_height);
5384 evas_object_show (_seperate_0 [i]);
5385 evas_object_show (_candidate_0 [i]);
5386 evas_object_size_hint_min_set (_candidate_0 [i], item_0_width, _item_min_height);
5387 elm_table_pack (_candidate_0_table, _candidate_0 [i], total_width - item_0_width, line_0*(_item_min_height+line_height), item_0_width, _item_min_height);
5388 _candidate_display_number++;
5390 } else if ((_candidate_angle == 0 || _candidate_angle == 180) &&
5391 (_candidate_port_line > 1 && (line_0 + 1) < _candidate_port_line)) {
5393 scroll_0_width = _candidate_scroll_0_width_min;
5394 item_0_width = item_0_width > scroll_0_width ? scroll_0_width : item_0_width;
5395 evas_object_show (_candidate_0 [i]);
5396 evas_object_size_hint_min_set (_candidate_0 [i], item_0_width, _item_min_height);
5397 elm_table_pack (_candidate_0_table, _candidate_0 [i], 0, line_0*(_item_min_height+line_height), item_0_width, _item_min_height);
5398 total_width = item_0_width;
5399 _candidate_display_number++;
5401 _candidate_row_items.push_back (i - nLast);
5405 _candidate_row_items.push_back (i - nLast);
5411 if (!_candidate_0 [i]) {
5412 _candidate_0 [i] = get_candidate (mbs, _candidate_window, &item_0_width, nForeGround, nBackGround, bHighLight, bSetBack, item_num, i);
5413 evas_object_event_callback_add (_candidate_0 [i], EVAS_CALLBACK_MOUSE_DOWN, ui_mouse_button_pressed_cb, GINT_TO_POINTER ((i << 8) + ISF_EFL_CANDIDATE_ITEMS));
5414 evas_object_event_callback_add (_candidate_0 [i], EVAS_CALLBACK_MOUSE_UP, ui_mouse_button_released_cb, GINT_TO_POINTER (i));
5415 evas_object_event_callback_add (_candidate_0 [i], EVAS_CALLBACK_MOUSE_MOVE, ui_mouse_moved_cb, GINT_TO_POINTER (ISF_EFL_CANDIDATE_ITEMS));
5417 if (current_width > 0 && current_width + item_0_width > _candidate_scroll_width) {
5421 _candidate_row_items.push_back (i - nLast);
5423 if (cursor_pos >= i)
5426 if (current_width == 0 && !_line_items [i]) {
5427 _line_items [i] = edje_object_add (evas);
5428 edje_object_file_set (_line_items [i], _candidate_edje_file.c_str (), "popup_line");
5429 evas_object_size_hint_min_set (_line_items [i], line_width, line_height);
5431 y = line_count*(_item_min_height+line_height);
5432 elm_table_pack (_candidate_table, _line_items [i], x, y, line_width, line_height);
5433 evas_object_show (_line_items [i]);
5435 if (current_width != 0 && !_seperate_items [i]) {
5436 _seperate_items [i] = edje_object_add (evas);
5437 edje_object_file_set (_seperate_items [i], _candidate_edje_file.c_str (), "seperate_line");
5438 evas_object_size_hint_min_set (_seperate_items [i], seperate_width, seperate_height);
5440 y = line_count*(_item_min_height+line_height) + line_height + (_item_min_height - seperate_height)/2;
5441 elm_table_pack (_candidate_table, _seperate_items [i], x, y, seperate_width, seperate_height);
5442 evas_object_show (_seperate_items [i]);
5443 current_width += seperate_width;
5446 y = line_count*(_item_min_height+line_height) + line_height;
5447 evas_object_size_hint_min_set (_candidate_0 [i], item_0_width, _item_min_height);
5448 evas_object_show (_candidate_0 [i]);
5449 elm_table_pack (_candidate_table, _candidate_0 [i], x, y, item_0_width, _item_min_height);
5450 current_width += item_0_width;
5452 if (candidate_expanded == false && !bHighLight)
5455 candidate_expanded = true;
5459 for (i = 1; i < _candidate_port_line; i++) {
5460 if ((_candidate_angle == 0 || _candidate_angle == 180)) {
5461 if (_line_0 [i] == NULL) {
5462 _line_0 [i] = edje_object_add (evas);
5463 edje_object_file_set (_line_0 [i], _candidate_edje_file.c_str (), "popup_line");
5464 evas_object_size_hint_min_set (_line_0 [i], line_width, line_height);
5466 y = i * (_item_min_height + line_height) - line_height;
5467 elm_table_pack (_candidate_0_table, _line_0 [i], x, y, line_width, line_height);
5468 evas_object_show (_line_0 [i]);
5471 // Create blank line
5472 if (line_0 + 1 < _candidate_port_line && i > line_0) {
5473 int nIndex = item_num + i;
5474 nIndex = nIndex < SCIM_LOOKUP_TABLE_MAX_PAGESIZE ? nIndex : SCIM_LOOKUP_TABLE_MAX_PAGESIZE - 1;
5475 _seperate_0 [nIndex] = edje_object_add (evas);
5476 edje_object_file_set (_seperate_0 [nIndex], _candidate_edje_file.c_str (), "seperate_line");
5477 evas_object_size_hint_min_set (_seperate_0 [nIndex], seperate_width, _item_min_height);
5478 elm_table_pack (_candidate_0_table, _seperate_0 [nIndex],
5479 0, i*(_item_min_height+line_height), seperate_width, _item_min_height);
5481 } else if (_line_0 [i]) {
5482 evas_object_del (_line_0 [i]);
5487 _candidate_row_items.push_back (item_num - nLast); /* Add the number of last row */
5488 _info_manager->update_displayed_candidate_number (_candidate_display_number);
5489 _info_manager->update_candidate_item_layout (_candidate_row_items);
5490 if (more_item_count == 0) {
5491 ui_candidate_window_close_button_cb (NULL, NULL, NULL, NULL);
5492 evas_object_hide (_more_btn);
5493 evas_object_hide (_close_btn);
5494 } else if (!_candidate_area_2_visible) {
5495 evas_object_show (_more_btn);
5496 evas_object_hide (_close_btn);
5498 evas_object_hide (_more_btn);
5499 evas_object_show (_close_btn);
5503 elm_scroller_region_get (_candidate_area_2, &x, &y, &w, &h);
5505 int line_h = _item_min_height + _v_padding;
5506 int cursor_y = cursor_line * line_h;
5508 elm_scroller_region_bring_in (_candidate_area_2, 0, cursor_y, w, h);
5509 } else if (cursor_y >= y + h) {
5510 elm_scroller_region_bring_in (_candidate_area_2, 0, cursor_y + line_h - h, w, h);
5515 #endif /* CANDIDATE */
5518 * @brief Update candidate table slot function for PanelAgent.
5520 * @param table The lookup table for candidate.
5522 static void slot_update_candidate_table (const LookupTable &table)
5524 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
5526 if (_candidate_mode == SOFT_CANDIDATE_WINDOW) {
5527 _info_manager->update_helper_lookup_table (table);
5531 #if ISF_BUILD_CANDIDATE_UI
5532 if (_candidate_window == NULL)
5533 ui_create_candidate_window ();
5535 if (!_candidate_window || table.get_current_page_size () < 0)
5538 if (evas_object_visible_get (_candidate_area_2)) {
5539 candidate_expanded = true;
5541 candidate_expanded = false;
5544 update_table (ISF_CANDIDATE_TABLE, table);
5545 _candidate_tts_focus_index = INVALID_TTS_FOCUS_INDEX;
5546 ui_tts_focus_rect_hide ();
5547 #endif /* CANDIDATE */
5551 * @brief Send selected candidate index.
5553 * @param selected candidate string index number.
5555 static void slot_select_candidate (int index)
5557 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
5558 _info_manager->select_candidate (index);
5562 * @brief Get candidate geometry slot function for PanelAgent.
5564 * @param info The data is used to store candidate position and size.
5566 static void slot_get_candidate_geometry (struct rectinfo &info)
5573 if (_candidate_mode == SOFT_CANDIDATE_WINDOW) {
5577 info.height = height;
5581 #if ISF_BUILD_CANDIDATE_UI
5582 if (_candidate_window && _candidate_state == WINDOW_STATE_SHOW) {
5583 /* Get candidate window position */
5584 /*ecore_evas_geometry_get (ecore_evas_ecore_evas_get (evas_object_evas_get (_candidate_window)), &x, &y, &width, &height);*/
5585 /* Get exact candidate window size */
5587 evas_object_geometry_get (_candidate_window, &x2, &y2, &width, &height);*/
5591 width = _candidate_width;
5592 height = _candidate_height;
5594 #endif /* CANDIDATE */
5599 info.height = height;
5601 LOGD ("%d %d %d %d", info.pos_x, info.pos_y, info.width, info.height);
5602 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " x:" << info.pos_x << " y:" << info.pos_y
5603 << " width:" << info.width << " height:" << info.height << "\n";
5607 * @brief Get input panel geometry slot function for PanelAgent.
5609 * @param info The data is used to store input panel position and size.
5611 static void slot_get_input_panel_geometry (struct rectinfo &info)
5613 if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) {
5618 #if ISF_BUILD_CANDIDATE_UI
5619 if (_candidate_mode == FIXED_CANDIDATE_WINDOW) {
5620 if (_candidate_window && _candidate_state == WINDOW_STATE_SHOW) {
5621 info.width = _candidate_width;
5622 info.height = _candidate_height;
5624 } else if (_candidate_mode == SOFT_CANDIDATE_WINDOW) {
5625 info.width = _soft_candidate_width;
5626 info.height = _soft_candidate_height;
5628 int angle = efl_get_app_window_angle ();
5629 if (angle == 90 || angle == 270)
5630 info.pos_y = _screen_width - info.height;
5632 info.pos_y = _screen_height - info.height;
5634 info = get_ise_geometry ();
5635 if (_ise_state != WINDOW_STATE_SHOW) {
5639 if (_candidate_mode == FIXED_CANDIDATE_WINDOW) {
5640 if (_candidate_window && _candidate_state == WINDOW_STATE_SHOW) {
5641 int height = ui_candidate_get_valid_height ();
5643 if ((_candidate_height - height) > _ise_height) {
5644 info.pos_y = info.pos_y + info.height - _candidate_height;
5645 info.height = _candidate_height;
5647 info.pos_y -= height;
5648 info.height += height;
5653 #endif /* CANDIDATE */
5656 LOGD ("%d %d %d %d", info.pos_x, info.pos_y, info.width, info.height);
5657 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " x:" << info.pos_x << " y:" << info.pos_y
5658 << " width:" << info.width << " height:" << info.height << "\n";
5662 * @brief Get the recent input panel geometry slot function for PanelAgent.
5664 * @param angle the rotation angle of application window.
5665 * @param info The data is used to store input panel position and size.
5667 static void slot_get_recent_ise_geometry (int angle, struct rectinfo &info)
5669 LOGD ("slot_get_recent_ise_geometry");
5671 /* If we have geometry reported by ISE, use the geometry information */
5676 if (angle == 0 || angle == 180) {
5677 if (_portrait_recent_ise_geometry.valid) {
5678 info = _portrait_recent_ise_geometry.geometry;
5683 if (_landscape_recent_ise_geometry.valid) {
5684 info = _landscape_recent_ise_geometry.geometry;
5695 static bool slot_check_privilege_by_sockfd (int client_id, String privilege)
5697 PrivilegeChecker privilegeChecker (client_id);
5699 bool priv_ret = privilegeChecker.checkPrivilege (privilege.c_str ());
5701 if (priv_ret == false)
5702 LOGW ("Failed to check privilege (%s)", privilege.c_str ());
5704 LOGD ("Succeeded to check privilege (%s)", privilege.c_str ());
5710 * @brief Set active ISE slot function for PanelAgent.
5712 * @param uuid The active ISE's uuid.
5713 * @param changeDefault The flag for changing default ISE.
5715 static void slot_set_active_ise (const String &uuid, bool changeDefault)
5717 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " (" << uuid << ")\n";
5719 bool invalid = false;
5721 #ifdef HAVE_PKGMGR_INFO
5722 /* When changing the active (default) keyboard, initialize ime_info DB if appid is invalid.
5723 This may be necessary if IME packages are changed while panel process is terminated. */
5724 pkgmgrinfo_appinfo_h handle = NULL;
5725 /* Try to get in global packages */
5726 int ret = pkgmgr_get_appinfo (uuid.c_str (), &handle);
5727 if (ret != PMINFO_R_OK) {
5728 LOGW ("appid \"%s\" is invalid.", uuid.c_str ());
5729 /* This might happen if IME is uninstalled while the panel process is inactive.
5730 The variable uuid would be invalid, so set_active_ise() would return false. */
5735 pkgmgrinfo_appinfo_destroy_appinfo (handle);
5739 _initialize_ime_info ();
5740 set_active_ise (_initial_ise_uuid, _soft_keyboard_launched);
5742 else if (set_active_ise (uuid, _soft_keyboard_launched) == false) {
5743 if (_initial_ise_uuid.compare (uuid))
5744 set_active_ise (_initial_ise_uuid, _soft_keyboard_launched);
5749 * @brief Get all ISEs list slot function for PanelAgent.
5751 * @param list The list is used to store all ISEs.
5753 * @return true if this operation is successful, otherwise return false.
5755 static bool slot_get_ise_list (std::vector<String> &list)
5757 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
5759 bool result = false;
5761 std::vector<String> uuids;
5762 for (std::vector<ImeInfoDB>::iterator iter = _ime_info.begin(); iter != _ime_info.end(); iter++) {
5763 uuids.push_back(iter->appid);
5765 if (_ime_info.size () > 0) {
5770 result = update_ise_list (list);
5777 * @brief Get all Helper ISE information from ime_info DB.
5779 * @param info This is used to store all Helper ISE information.
5781 * @return true if this operation is successful, otherwise return false.
5783 static bool slot_get_all_helper_ise_info (HELPER_ISE_INFO &info)
5785 bool result = false;
5786 String active_ime_appid;
5788 info.appid.clear ();
5789 info.label.clear ();
5790 info.is_enabled.clear ();
5791 info.is_preinstalled.clear ();
5792 info.has_option.clear ();
5794 if (_ime_info.size() == 0)
5795 isf_pkg_select_all_ime_info_db (_ime_info);
5797 //active_ime_appid = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), String (""));
5798 if (_info_manager) {
5799 active_ime_appid = _info_manager->get_current_helper_uuid ();
5802 if (_ime_info.size () > 0) {
5803 for (std::vector<ImeInfoDB>::iterator iter = _ime_info.begin (); iter != _ime_info.end (); iter++) {
5804 if (iter->mode == TOOLBAR_HELPER_MODE) {
5805 info.appid.push_back (iter->appid);
5806 info.label.push_back (iter->label);
5807 info.is_enabled.push_back (iter->is_enabled);
5808 info.is_preinstalled.push_back (iter->is_preinstalled);
5809 info.has_option.push_back (static_cast<uint32>(iter->has_option));
5819 * @brief Update "has_option" column of ime_info DB by Application ID
5821 * @param[in] appid Application ID of IME to enable or disable
5822 * @param[in] has_option @c true to have IME option(setting), otherwise @c false
5824 static void slot_set_has_option_helper_ise_info (const String &appid, bool has_option)
5826 if (appid.length() == 0) {
5827 LOGW ("Invalid appid");
5831 if (_ime_info.size() == 0)
5832 isf_pkg_select_all_ime_info_db(_ime_info);
5834 if (isf_db_update_has_option_by_appid(appid.c_str(), has_option)) { // Update ime_info DB
5835 for (unsigned int i = 0; i < _ime_info.size (); i++) {
5836 if (appid == _ime_info[i].appid) {
5837 _ime_info[i].has_option = static_cast<uint32>(has_option); // Update global variable
5844 * @brief Update "is_enable" column of ime_info DB by Application ID
5846 * @param[in] appid Application ID of IME to enable or disable
5847 * @param[in] is_enabled @c true to enable the IME, otherwise @c false
5849 static void slot_set_enable_helper_ise_info (const String &appid, bool is_enabled)
5851 if (appid.length() == 0) {
5852 LOGW ("Invalid appid");
5856 if (_ime_info.size() == 0)
5857 isf_pkg_select_all_ime_info_db(_ime_info);
5859 if (isf_db_update_is_enabled_by_appid(appid.c_str(), is_enabled)) { // Update ime_info DB
5860 for (unsigned int i = 0; i < _ime_info.size (); i++) {
5861 if (appid == _ime_info[i].appid) {
5862 _ime_info[i].is_enabled = static_cast<uint32>(is_enabled); // Update global variable
5868 #ifdef HAVE_PKGMGR_INFO
5870 * @brief Finds appid with specific category
5872 * @return 0 if success, negative value(<0) if fail. Callback is not called if return value is negative
5874 static int _find_appid_from_category (const pkgmgrinfo_appinfo_h handle, void *user_data)
5877 char **result = static_cast<char **>(user_data);
5882 ret = pkgmgrinfo_appinfo_get_appid (handle, &appid);
5883 if (ret == PMINFO_R_OK) {
5884 *result = strdup (appid);
5887 LOGW ("pkgmgrinfo_appinfo_get_appid failed!");
5891 LOGW ("user_data is null!");
5894 return -1; // This callback is no longer called.
5899 * @brief Requests to open the installed IME list application.
5901 static void slot_show_helper_ise_list (void)
5903 // Launch IME List application; e.g., org.tizen.inputmethod-setting-list
5904 char *app_id = NULL;
5905 #ifdef HAVE_PKGMGR_INFO
5906 pkgmgrinfo_appinfo_filter_h handle;
5909 if (ime_list_app.length() < 1) {
5910 ret = pkgmgrinfo_appinfo_filter_create (&handle);
5911 if (ret == PMINFO_R_OK) {
5912 ret = pkgmgrinfo_appinfo_filter_add_string (handle, PMINFO_APPINFO_PROP_APP_CATEGORY, "http://tizen.org/category/ime-list");
5913 if (ret == PMINFO_R_OK) {
5914 pkgmgrinfo_appinfo_filter_foreach_appinfo (handle, _find_appid_from_category, &app_id);
5916 pkgmgrinfo_appinfo_filter_destroy (handle);
5919 ime_list_app = String (app_id);
5923 app_id = strdup (ime_list_app.c_str());
5927 app_control_launch (app_id);
5931 SECURE_LOGW ("AppID with http://tizen.org/category/ime-list category is not available.");
5936 * @brief Requests to open the installed IME selector application.
5938 static void slot_show_helper_ise_selector (void)
5940 // Launch IME Selector application; e.g., org.tizen.inputmethod-setting-selector
5941 char *app_id = NULL;
5942 #ifdef HAVE_PKGMGR_INFO
5943 pkgmgrinfo_appinfo_filter_h handle;
5946 if (ime_selector_app.length() < 1) {
5947 ret = pkgmgrinfo_appinfo_filter_create(&handle);
5948 if (ret == PMINFO_R_OK) {
5949 ret = pkgmgrinfo_appinfo_filter_add_string(handle, PMINFO_APPINFO_PROP_APP_CATEGORY, "http://tizen.org/category/ime-selector");
5950 if (ret == PMINFO_R_OK) {
5951 pkgmgrinfo_appinfo_filter_foreach_appinfo(handle, _find_appid_from_category, &app_id);
5953 pkgmgrinfo_appinfo_filter_destroy(handle);
5956 ime_selector_app = String(app_id);
5960 app_id = strdup(ime_selector_app.c_str());
5964 app_control_launch (app_id);
5968 SECURE_LOGW ("AppID with http://tizen.org/category/ime-selector category is not available.");
5972 static bool slot_is_helper_ise_enabled (String appid, int &enabled)
5974 bool is_enabled = false;
5976 if (appid.length() == 0) {
5977 LOGW ("Invalid appid.");
5981 if (_ime_info.size() == 0)
5982 isf_pkg_select_all_ime_info_db(_ime_info);
5984 if (isf_db_select_is_enabled_by_appid(appid.c_str(), &is_enabled)) {
5985 enabled = static_cast<int>(is_enabled);
5994 * @brief Get the ISE's information.
5996 * @param uuid The ISE's uuid.
5997 * @param name The ISE's name.
5998 * @param language The ISE's language.
5999 * @param type The ISE's type.
6000 * @param option The ISE's option.
6002 * @return true if this operation is successful, otherwise return false.
6004 static bool slot_get_ise_information (String uuid, String &name, String &language, int &type, int &option, String &module_name)
6006 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6008 if (uuid.length () > 0) {
6009 // update all ISE names according to the display languages
6010 // sometimes get_ise_information is called before vconf display language changed callback is called.
6011 update_ise_locale ();
6013 for (unsigned int i = 0; i < _ime_info.size (); i++) {
6014 if (uuid == _ime_info[i].appid) {
6015 name = _ime_info[i].label;
6016 language = _ime_info[i].languages;
6017 type = _ime_info[i].mode;
6018 option = _ime_info[i].options;
6019 module_name = _ime_info[i].module_name;
6025 std::cerr << __func__ << " is failed!!!\n";
6030 * @brief Get keyboard ISEs list slot function for PanelAgent.
6032 * @param name_list The list is used to store keyboard ISEs.
6034 * @return true if this operation is successful, otherwise return false.
6036 static bool slot_get_keyboard_ise_list (std::vector<String> &name_list)
6038 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6040 isf_load_ise_information (ALL_ISE, _config);
6042 std::vector<String> lang_list, uuid_list;
6043 isf_get_all_languages (lang_list);
6044 isf_get_keyboard_ises_in_languages (lang_list, uuid_list, name_list, false);
6046 _info_manager->update_ise_list (uuid_list);
6051 * @brief Get enable languages list slot function for PanelAgent.
6053 * @param list The list is used to store languages.
6055 static void slot_get_language_list (std::vector<String> &list)
6057 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6060 MapStringVectorSizeT::iterator iter = _groups.begin ();
6062 for (; iter != _groups.end (); iter++) {
6063 lang_name = scim_get_language_name (iter->first);
6064 list.push_back (lang_name);
6069 * @brief Get all languages list slot function for PanelAgent.
6071 * @param lang The list is used to store languages.
6073 static void slot_get_all_language (std::vector<String> &lang)
6075 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6077 isf_get_all_languages (lang);
6081 * @brief Get specific ISE language list slot function for PanelAgent.
6083 * @param name The ISE name.
6084 * @param list The list is used to store ISE languages.
6086 static void slot_get_ise_language (char *name, std::vector<String> &list)
6088 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6093 std::vector<String> list_tmp;
6095 for (unsigned int i = 0; i < _ime_info.size(); i++) {
6096 if (!strcmp (_ime_info[i].label.c_str (), name)) {
6097 scim_split_string_list (list_tmp, _ime_info[i].languages, ',');
6098 for (i = 0; i < list_tmp.size (); i++)
6099 list.push_back (scim_get_language_name (list_tmp[i]));
6106 * @brief Get ISE information slot function for PanelAgent.
6108 * @param uuid The ISE uuid.
6109 * @param info The variable is used to store ISE information.
6111 * @return true if this operation is successful, otherwise return false.
6113 static bool slot_get_ise_info (const String &uuid, ISE_INFO &info)
6115 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6117 for (unsigned int i = 0; i < _ime_info.size (); i++) {
6118 if (!uuid.compare (_ime_info[i].appid)) {
6119 info.uuid = _ime_info[i].appid;
6120 info.name = _ime_info[i].label;
6121 info.icon = _ime_info[i].iconpath;
6122 info.lang = _ime_info[i].languages;
6123 info.option = _ime_info[i].options;
6124 info.type = _ime_info[i].mode;
6133 * @brief Set keyboard ISE slot function for PanelAgent.
6135 * @param uuid The variable is ISE uuid.
6137 static void slot_set_keyboard_ise (const String &uuid)
6139 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " uuid = " << uuid << "\n";
6141 std::vector<String> uuids;
6142 std::vector<ImeInfoDB>::iterator iter;
6143 for (iter = _ime_info.begin(); iter != _ime_info.end(); iter++) {
6144 uuids.push_back(iter->appid);
6147 if (uuid.length () <= 0 || std::find (uuids.begin (), uuids.end (), uuid) == uuids.end ())
6150 String default_uuid = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), String (""));
6151 if (_ime_info[get_ise_index (default_uuid)].mode == TOOLBAR_KEYBOARD_MODE)
6154 uint32 ise_option = 0;
6155 String ise_uuid, ise_name;
6156 isf_get_keyboard_ise (_config, ise_uuid, ise_name, ise_option);
6157 if (ise_uuid == uuid)
6160 String language = String ("~other");/*scim_get_locale_language (scim_get_current_locale ());*/
6161 _config->write (String (SCIM_CONFIG_DEFAULT_IMENGINE_FACTORY) + String ("/") + language, uuid);
6165 _info_manager->change_factory (uuid);
6169 * @brief Get current keyboard ISE name and uuid slot function for PanelAgent.
6171 * @param ise_name The variable is used to store ISE name.
6172 * @param ise_uuid The variable is used to store ISE uuid.
6174 static void slot_get_keyboard_ise (String &ise_name, String &ise_uuid)
6176 uint32 ise_option = 0;
6177 isf_get_keyboard_ise (_config, ise_uuid, ise_name, ise_option);
6179 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " uuid = " << ise_uuid << "\n";
6183 * @brief Accept connection slot function for PanelAgent.
6185 * @param fd The file descriptor to connect.
6187 static void slot_accept_connection (int fd)
6189 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6192 get_input_window ();
6197 * @brief Close connection slot function for PanelAgent.
6199 * @param fd The file descriptor to connect.
6201 static void slot_close_connection (int fd)
6203 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6207 * @brief Exit panel process slot function for PanelAgent.
6209 static void slot_exit (void)
6211 std::cerr << __FUNCTION__ << "...\n";
6212 ISF_SAVE_LOG ("exit");
6214 #if ISF_BUILD_CANDIDATE_UI
6217 ecore_main_loop_quit ();
6218 #endif /* CANDIDATE */
6221 static void delete_ise_check_pid_alive_timer(void)
6223 LOGD("deleting ise_check_alive_timer");
6224 if (_ise_check_pid_alive_timer) {
6225 ecore_timer_del(_ise_check_pid_alive_timer);
6226 _ise_check_pid_alive_timer = NULL;
6230 static Eina_Bool ise_check_pid_alive_timer(void *data)
6232 Eina_Bool ret = ECORE_CALLBACK_RENEW;
6233 Eina_Bool retry = EINA_FALSE;
6235 int status = aul_app_get_status (_ise_check_pid_alive_uuid.c_str ());
6236 LOGD ("STATUS : %d", status);
6237 if (status >= STATUS_LAUNCHING) {
6238 /* If the status is not one of STATUS_LAUNCHING, STATUS_VISIBLE, STATUS_BG */
6239 if (status >= STATUS_DYING) {
6240 LOGE ("aul_app_get_status reports %d", status);
6245 /* Status query not successful, the ISE could have failed launching */
6246 LOGE ("aul_app_get_status failed. %d", status);
6251 _soft_keyboard_launched = false;
6252 String uuid = _config->read (SCIM_CONFIG_DEFAULT_HELPER_ISE, String(""));
6253 /* The start_helper() function below will going to call slot_run_helper,
6254 which will going to assign a new timer handle to the _ise_check_pid_alive_timer variable.
6256 LOGW ("The previous attempt to launch %s seems to be failed, restarting",
6257 _ise_check_pid_alive_uuid.c_str ());
6258 if (_info_manager->start_helper (uuid))
6259 _soft_keyboard_launched = true;
6260 ret = ECORE_CALLBACK_CANCEL;
6266 static void slot_register_helper(int id, const HelperInfo& info)
6268 LOGD ("app id : %s", info.uuid.c_str ());
6269 /* Do we need to check whether the pid of this helper is the one we are watching? */
6270 if (info.uuid.compare(_ise_check_pid_alive_uuid) == 0) {
6271 delete_ise_check_pid_alive_timer();
6275 static void slot_register_helper_properties (int id, const PropertyList &props)
6277 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6279 /* WMSYNC, #2 Receiving X window ID from ISE */
6280 /* FIXME : We should add an API to set window id of ISE */
6281 Property prop = props[0];
6282 if (prop.get_label ().compare ("XID") == 0) {
6283 Ecore_X_Window xwindow = atoi (prop.get_key ().c_str ());
6284 _ise_window = xwindow;
6285 LOGD ("ISE XID : %x", _ise_window);
6287 /* Just in case for the helper sent this message later than show_ise request */
6288 if (_ise_state == WINDOW_STATE_SHOW || _ise_state == WINDOW_STATE_WILL_SHOW) {
6289 efl_set_transient_for_app_window (_ise_window);
6292 Ecore_X_Atom atom = ecore_x_atom_get ("_ISF_ISE_WINDOW");
6293 if (atom && _control_window && _ise_window) {
6294 ecore_x_window_prop_xid_set (_control_window, atom, ECORE_X_ATOM_WINDOW, &_ise_window, 1);
6296 #ifdef HAVE_NOTIFICATION
6297 delete_notification (&ise_selector_module_noti);
6303 #if ENABLE_REMOTE_INPUT
6304 static void slot_send_remote_input_message (const String &msg, bool len)
6306 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6308 String con = msg.c_str ();
6309 ISE_MESSAGE message = CISEMessageSerializer::deserialize(con);
6311 if (remote_input_impl == NULL) {
6312 remote_input_impl = Remote_Input::get_instance();
6315 if (remote_input_impl)
6316 remote_input_impl->handle_websocket_message(message);
6319 static void slot_recv_remote_surrounding_text (int cursor, const String &text)
6321 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6323 if (remote_input_impl == NULL) {
6324 remote_input_impl = Remote_Input::get_instance();
6327 if (remote_input_impl)
6328 remote_input_impl->handle_recv_panel_message(3, text.c_str (), cursor);
6332 static void slot_show_ise (void)
6334 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6336 /* If the current toolbar mode is not HELPER_MODE, do not proceed */
6337 if (_info_manager->get_current_toolbar_mode () != TOOLBAR_HELPER_MODE) {
6338 LOGD ("Current toolbar mode should be TOOLBAR_HELPER_MODE but is %d, returning",
6339 _info_manager->get_current_toolbar_mode ());
6343 LOGD ("slot_show_ise ()");
6345 delete_ise_hide_timer ();
6347 /* WMSYNC, #3 Clear the existing application's conformant area and set transient_for */
6348 // Unset conformant area
6349 Ecore_X_Window current_app_window = efl_get_app_window ();
6350 if (_app_window != current_app_window) {
6351 struct rectinfo info = {0, 0, 0, 0};
6352 info.pos_y = _screen_width > _screen_height ? _screen_width : _screen_height;
6353 set_keyboard_geometry_atom_info (_app_window, info);
6354 ecore_x_event_mask_unset (_app_window, ECORE_X_EVENT_MASK_WINDOW_FOCUS_CHANGE);
6355 LOGD ("Conformant reset for window %x", _app_window);
6356 _app_window = current_app_window;
6358 /* If the target window has changed but our ISE is still in visible state,
6359 update the keyboard geometry information */
6360 if (_ise_state == WINDOW_STATE_SHOW) {
6361 set_keyboard_geometry_atom_info (_app_window, get_ise_geometry ());
6365 /* If the candidate was already in SHOW state, respect the current angle */
6366 if (_candidate_state != WINDOW_STATE_SHOW) {
6367 /* FIXME : Need to check if candidate_angle and window_angle should be left as separated */
6368 _candidate_angle = efl_get_app_window_angle ();
6370 /* If the ise was already in SHOW state, respect the current angle */
6371 if (_ise_state != WINDOW_STATE_SHOW) {
6372 _ise_angle = efl_get_app_window_angle ();
6375 ecore_x_event_mask_set (_app_window, ECORE_X_EVENT_MASK_WINDOW_FOCUS_CHANGE);
6376 efl_set_transient_for_app_window (_ise_window);
6378 /* Make clipboard window to have transient_for information on ISE window,
6379 so that the clipboard window will always be above ISE window */
6380 Ecore_X_Window clipboard_window = efl_get_clipboard_window ();
6381 if (_ise_window && clipboard_window) {
6382 ecore_x_icccm_transient_for_set (clipboard_window, _ise_window);
6385 /* If our ISE was already in SHOW state, skip state transition to WILL_SHOW */
6386 if (_ise_state != WINDOW_STATE_SHOW) {
6387 _ise_state = WINDOW_STATE_WILL_SHOW;
6391 #if ISF_BUILD_CANDIDATE_UI
6392 _candidate_angle = 0;
6393 #endif /* CANDIDATE */
6394 _ise_state = WINDOW_STATE_SHOW;
6396 #ifdef HAVE_NOTIFICATION
6397 if (_info_manager->get_current_toolbar_mode () == TOOLBAR_HELPER_MODE) {
6398 if (get_ise_count (TOOLBAR_HELPER_MODE, true) >= 2) {
6399 show_ime_selector_notification ();
6406 static void slot_hide_ise (void)
6408 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6410 LOGD ("slot_hide_ise ()");
6412 if (!_ise_hide_timer)
6416 static void slot_will_hide_ack (void)
6418 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6420 /* WMSYNC, #8 Let the Window Manager to actually hide keyboard window */
6421 // WILL_HIDE_REQUEST_DONE Ack to WM
6422 Ecore_X_Window root_window = ecore_x_window_root_get (_control_window);
6423 //ecore_x_e_virtual_keyboard_off_prepare_done_send (root_window, _control_window);
6424 LOGD ("_ecore_x_e_virtual_keyboard_off_prepare_done_send (%x, %x)",
6425 root_window, _control_window);
6426 if (_info_manager->get_current_toolbar_mode () == TOOLBAR_HELPER_MODE) {
6427 LOGD ("calling ui_candidate_hide (true, false)");
6428 ui_candidate_hide (true, false);
6431 /* WILL_HIDE_ACK means that the application finished redrawing the autoscroll area,
6432 now hide the candidate window right away if it is also in WILL_HIDE state */
6433 if (_candidate_state == WINDOW_STATE_WILL_HIDE) {
6434 candidate_window_hide ();
6437 if (_off_prepare_done_timer) {
6438 ecore_timer_del (_off_prepare_done_timer);
6439 _off_prepare_done_timer = NULL;
6444 static void slot_candidate_will_hide_ack (void)
6446 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6448 LOGD ("candidate_will_hide_ack");
6449 if (_candidate_state == WINDOW_STATE_WILL_HIDE) {
6450 candidate_window_hide ();
6455 static void slot_set_keyboard_mode (int mode)
6457 LOGD ("slot_set_keyboard_mode called (TOOLBAR_MODE : %d)", mode);
6459 change_keyboard_mode ((TOOLBAR_MODE_T)mode);
6462 static void slot_get_ise_state (int &state)
6464 if (_ise_state == WINDOW_STATE_SHOW ||
6465 ((_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) && (_candidate_state == WINDOW_STATE_SHOW))) {
6466 state = ECORE_IMF_INPUT_PANEL_STATE_SHOW;
6468 /* Currently we don't have WILL_HIDE / HIDE state distinction in Ecore_IMF */
6469 switch (_ise_state) {
6470 case WINDOW_STATE_SHOW :
6471 state = ECORE_IMF_INPUT_PANEL_STATE_SHOW;
6473 case WINDOW_STATE_WILL_SHOW :
6474 state = ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW;
6476 case WINDOW_STATE_WILL_HIDE :
6477 state = ECORE_IMF_INPUT_PANEL_STATE_HIDE;
6479 case WINDOW_STATE_HIDE :
6480 state = ECORE_IMF_INPUT_PANEL_STATE_HIDE;
6483 state = ECORE_IMF_INPUT_PANEL_STATE_HIDE;
6486 LOGD ("state = %d", state);
6487 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " state = " << state << "\n";
6490 static void slot_start_default_ise (void)
6492 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6494 if ((_info_manager->get_current_toolbar_mode () == TOOLBAR_HELPER_MODE)) {
6495 String uuid = _config->read (SCIM_CONFIG_DEFAULT_HELPER_ISE, String (""));
6496 int pid = aul_app_get_pid (uuid.c_str ());
6498 if (STATUS_DYING == aul_app_get_status (uuid.c_str ()))
6501 if (_launch_ise_on_request && !_soft_keyboard_launched && pid < 0) {
6502 LOGD ("Start helper (%s)", uuid.c_str ());
6503 set_keyboard_engine (String (SCIM_COMPOSE_KEY_FACTORY_UUID));
6505 if (_info_manager->start_helper (uuid))
6506 _soft_keyboard_launched = true;
6508 LOGW ("Failed to start helper (%s)", uuid.c_str ());
6513 static void slot_stop_default_ise (bool is_exist)
6515 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6518 if (_launch_ise_on_request && _auto_destroy_ise && _soft_keyboard_launched) {
6519 String uuid = _info_manager->get_current_helper_uuid ();
6521 if (uuid.length () > 0) {
6522 _info_manager->hide_helper (uuid);
6523 _info_manager->stop_helper (uuid);
6524 _soft_keyboard_launched = false;
6525 LOGD ("stop helper (%s)", uuid.c_str ());
6529 if (_soft_keyboard_launched)
6530 _soft_keyboard_launched = false;
6534 static void launch_helper (const char* exec, const char *name, const char *appid, const char *config, const char *display)
6540 if (pid < 0) return;
6543 const char *argv [] = { exec,
6546 "--display", display,
6547 const_cast<char*> (name),
6548 const_cast<char*> (appid),
6551 SCIM_DEBUG_MAIN (2) << " Call scim-helper-launcher.\n";
6552 ISF_SAVE_LOG ("Exec scim_helper_launcher(%s %s)", name, appid);
6554 unsetenv ("ELM_THEME");
6555 unsetenv ("ELM_SCALE");
6558 LOGD ("launch execpath : %s", exec);
6559 execv (exec, const_cast<char **>(argv));
6560 #if ISF_BUILD_CANDIDATE_UI
6563 ecore_main_loop_quit ();
6564 #endif /* CANDIDATE */
6568 static bool app_control_launch (const char *app_id)
6570 app_control_h app_control;
6573 ret = app_control_create (&app_control);
6574 if (ret != APP_CONTROL_ERROR_NONE) {
6575 LOGW ("app_control_create returned %08x", ret);
6579 ret = app_control_set_operation (app_control, APP_CONTROL_OPERATION_DEFAULT);
6580 if (ret != APP_CONTROL_ERROR_NONE) {
6581 LOGW ("app_control_set_operation returned %08x", ret);
6582 app_control_destroy (app_control);
6586 ret = app_control_set_app_id (app_control, app_id);
6587 if (ret != APP_CONTROL_ERROR_NONE) {
6588 LOGW ("app_control_set_app_id returned %08x", ret);
6589 app_control_destroy (app_control);
6595 if (tries != 0) usleep(1000000); /* If we are retrying to launch, pause for a while */
6596 ret = app_control_send_launch_request(app_control, NULL, NULL);
6597 LOGW ("app_control_send_launch_request returned %08x, app_id=%s", ret, app_id);
6598 } while (ret != APP_CONTROL_ERROR_NONE && (++tries) < 3);
6600 app_control_destroy (app_control);
6602 if (ret != APP_CONTROL_ERROR_NONE) {
6603 LOGW ("Failed to launch IME (%s)", app_id);
6605 LOGD ("Succeeded to launch IME (%s)", app_id);
6608 return (ret == APP_CONTROL_ERROR_NONE);
6611 static void add_ise_check_pid_alive_timer(const String &uuid) {
6612 delete_ise_check_pid_alive_timer ();
6613 LOGD ("Register check_alive timer for uuid : %s", uuid.c_str ());
6614 _ise_check_pid_alive_uuid = uuid;
6615 _ise_check_pid_alive_timer = ecore_timer_add (_ise_check_pid_alive_time,
6616 ise_check_pid_alive_timer, NULL);
6619 static void terminate_active_ise (const String uuid)
6621 /* Check if IME with the same AppID is alive */
6622 int status_ret = aul_app_get_status (uuid.c_str ());
6623 if (status_ret >= STATUS_LAUNCHING) {
6624 /* Request to terminate IME */
6625 int ime_pid = aul_app_get_pid (uuid.c_str ());
6626 status_ret = aul_terminate_pid (ime_pid);
6627 if (status_ret < AUL_R_OK) {
6628 LOGE ("aul_terminate_pid(%d) failed: %d", ime_pid, status_ret);
6631 LOGD ("Requested to terminate IME(%s)", uuid.c_str ());
6637 static void slot_run_helper (const String &uuid, const String &config, const String &display)
6639 ISF_SAVE_LOG ("time:%ld pid:%d %s %s uuid(%s)",
6640 time (0), getpid (), __FILE__, __func__, uuid.c_str ());
6642 String scim_helper_path;
6644 delete_ise_check_pid_alive_timer ();
6646 #ifdef HAVE_PKGMGR_INFO
6647 char *execpath = NULL;
6649 pkgmgrinfo_appinfo_h appinfo_handle;
6651 /* get app info handle */
6652 /* Try to get in global packages */
6653 ret = pkgmgr_get_appinfo (uuid.c_str (), &appinfo_handle);
6654 if (ret != PMINFO_R_OK) {
6655 LOGE ("pkgmgr_get_appinfo failed. appid : %s, ret : %d ", uuid.c_str (), ret);
6656 add_ise_check_pid_alive_timer (uuid);
6661 ret = pkgmgrinfo_appinfo_get_exec (appinfo_handle, &execpath);
6662 if (ret != PMINFO_R_OK) {
6663 LOGE ("pkgmgrinfo_appinfo_get_exec failed. appid : %s, ret : %d ", uuid.c_str (), ret);
6664 pkgmgrinfo_appinfo_destroy_appinfo (appinfo_handle);
6665 add_ise_check_pid_alive_timer (uuid);
6669 LOGD ("exec path : %s %zu", execpath, _ime_info.size ());
6670 scim_helper_path = String (execpath);
6672 if (appinfo_handle) {
6673 pkgmgrinfo_appinfo_destroy_appinfo (appinfo_handle);
6674 appinfo_handle = NULL;
6677 scim_helper_path = String (SCIM_HELPER_LAUNCHER_PROGRAM);
6680 for (size_t i = 0; i < _ime_info.size (); ++i) {
6681 if (_ime_info[i].appid == uuid && _ime_info[i].module_name.length ()) {
6682 if (scim_helper_path != String (SCIM_HELPER_LAUNCHER_PROGRAM)) {
6683 terminate_active_ise (uuid);
6684 /* execute type IME */
6685 LOGD ("Try to launch IME (%s)", uuid.c_str ());
6686 app_control_launch (uuid.c_str ());
6688 /* ISE check alive only works for AUL based IMEs */
6689 add_ise_check_pid_alive_timer (uuid);
6692 /* shared object (so) type IME */
6693 launch_helper (scim_helper_path.c_str(), _ime_info[i].module_name.c_str (), uuid.c_str (), config.c_str (), display.c_str ());
6700 SCIM_DEBUG_MAIN (2) << " exit run_helper ().\n";
6703 static bool slot_launch_option_application (String ime_appid)
6705 String ime_setting_app = isf_pkg_get_setting_app (ime_appid);
6707 LOGD ("IME appid : %s, IME setting app id : %s", ime_appid.c_str (), ime_setting_app.c_str ());
6709 if (ime_setting_app.length () > 0) {
6710 app_control_launch (ime_setting_app.c_str ());
6717 //////////////////////////////////////////////////////////////////////
6718 // End of PanelAgent-Functions
6719 //////////////////////////////////////////////////////////////////////
6723 * @brief Callback function for abnormal signal.
6725 * @param sig The signal.
6727 static void signalhandler (int sig)
6729 std::cerr << __FUNCTION__ << " Signal=" << sig << "\n";
6730 ISF_SAVE_LOG ("Signal=%d", sig);
6732 #if ISF_BUILD_CANDIDATE_UI
6735 ecore_main_loop_quit ();
6736 #endif /* CANDIDATE */
6740 static void update_ise_locale (const char *language)
6745 strLang = String (language);
6748 char *lang_str = vconf_get_str (VCONFKEY_LANGSET);
6750 if (_locale_string.compare(lang_str) == 0) {
6755 strLang = String (lang_str);
6761 LOGD ("update all ISE names according to display language : %s", strLang.c_str ());
6762 set_language_and_locale (strLang.c_str ());
6764 bool need_to_init_db = false;
6765 #ifdef HAVE_PKGMGR_INFO
6769 pkgmgrinfo_appinfo_h handle = NULL;
6771 /* Read DB from ime_info table */
6772 isf_load_ise_information(ALL_ISE, _config);
6774 for (unsigned int i = 0; i < _ime_info.size (); i++) {
6775 ret = pkgmgr_get_appinfo (_ime_info[i].appid.c_str(), &handle);
6777 if (ret == PMINFO_R_OK) {
6778 ret = pkgmgrinfo_appinfo_is_category_exist(handle, "http://tizen.org/category/ime", &exist);
6779 if (ret == PMINFO_R_OK && exist) {
6780 ret = pkgmgrinfo_appinfo_get_label(handle, &label);
6781 if (ret == PMINFO_R_OK && label) {
6782 _ime_info[i].label = String(label);
6783 /* Update label column in ime_info db table */
6784 if (isf_db_update_label_by_appid(_ime_info[i].appid.c_str(), label)) {
6785 _ime_info[i].label = label;
6790 // The appid is invalid.. Need to initialize ime_info DB.
6791 need_to_init_db = true;
6793 pkgmgrinfo_appinfo_destroy_appinfo(handle);
6796 // The appid is invalid.. Need to initialize ime_info DB.
6797 need_to_init_db = true;
6802 if (need_to_init_db) {
6803 _initialize_ime_info ();
6806 if (strLang.length () > 0) {
6807 isf_db_update_disp_lang (strLang.c_str ());
6808 _locale_string = strLang;
6813 * @brief Set language and locale.
6817 static void set_language_and_locale (const char *lang_str)
6819 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6824 LOGD ("language : %s", lang_str);
6825 #if ISF_BUILD_CANDIDATE_UI
6826 elm_language_set (lang_str);
6827 #endif /* CANDIDATE */
6829 snprintf (language, sizeof (language), "%s:en_US:en_GB:en", lang_str);
6830 setenv ("LANGUAGE", language, 1);
6831 setenv ("LANG", lang_str, 1);
6832 setlocale (LC_MESSAGES, lang_str);
6834 setenv ("LANG", "en_US.utf8", 1);
6835 setlocale (LC_MESSAGES, "en_US.utf8");
6840 * @brief Callback function for display language change.
6842 * @param key The key node.
6843 * @param data The data to pass to this callback.
6847 static void display_language_changed_cb (keynode_t *key, void* data)
6849 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6851 char *lang_str = vconf_keynode_get_str (key);
6852 LOGD ("lang : %s", lang_str);
6853 set_language_and_locale (lang_str);
6855 /* Update all ISE names according to display language */
6856 update_ise_locale ();
6858 String default_uuid = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), _initial_ise_uuid);
6859 unsigned int ise_idx = get_ise_index (default_uuid);
6861 if (ise_idx < _ime_info.size ()) {
6862 String default_name = _ime_info[ise_idx].label;
6863 _info_manager->set_current_ise_name (default_name);
6869 * @brief Callback function for keyboard mode change.
6871 * @param key The key node.
6872 * @param data The data to pass to this callback.
6876 static void keyboard_mode_changed_cb (keynode_t *key, void* data)
6878 bool val = vconf_keynode_get_bool (key);
6881 _info_manager->reset_keyboard_ise ();
6882 change_keyboard_mode (TOOLBAR_HELPER_MODE);
6883 _info_manager->update_input_panel_event (ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
6889 * @brief Change keyboard mode.
6891 * @param mode The keyboard mode.
6895 static void change_keyboard_mode (TOOLBAR_MODE_T mode)
6897 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6900 bool _support_hw_keyboard_mode = false;
6902 unsigned int val = 0;
6906 int input_detect = false;
6909 String helper_uuid = _config->read (SCIM_CONFIG_DEFAULT_HELPER_ISE, String (""));
6910 String default_uuid = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), String (""));
6911 _support_hw_keyboard_mode = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_SUPPORT_HW_KEYBOARD_MODE), _support_hw_keyboard_mode);
6913 if (mode == TOOLBAR_KEYBOARD_MODE && _support_hw_keyboard_mode) {
6914 if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) {
6915 LOGD ("HARDWARE_KEYBOARD_MODE return");
6919 LOGD ("HARDWARE KEYBOARD MODE");
6920 _config->write (ISF_CONFIG_HARDWARE_KEYBOARD_DETECT, 1);
6923 if (_ime_info[get_ise_index(default_uuid)].mode == TOOLBAR_HELPER_MODE) {
6924 /* Get the keyboard ISE */
6925 isf_get_keyboard_ise (_config, uuid, name, option);
6926 if (option & SCIM_IME_NOT_SUPPORT_HARDWARE_KEYBOARD) {
6927 uuid = String (SCIM_COMPOSE_KEY_FACTORY_UUID);
6928 std::cerr << __FUNCTION__ << ": Keyboard ISE (" << name << ") can not support hardware keyboard!!!\n";
6930 /* Try to find reasonable keyboard ISE according to helper ISE language */
6931 if (uuid == String (SCIM_COMPOSE_KEY_FACTORY_UUID)) {
6932 String helper_language = _ime_info[get_ise_index(default_uuid)].languages;
6933 if (helper_language.length () > 0) {
6934 std::vector<String> ise_langs;
6935 scim_split_string_list (ise_langs, helper_language);
6936 for (size_t i = 0; i < _groups[ise_langs[0]].size (); ++i) {
6937 int j = _groups[ise_langs[0]][i];
6938 if (_ime_info[j].appid != uuid && _ime_info[j].mode == TOOLBAR_KEYBOARD_MODE) {
6939 uuid = _ime_info[j].appid;
6947 uuid = default_uuid;
6949 #if ISF_BUILD_CANDIDATE_UI
6950 _soft_candidate_width = 0;
6951 _soft_candidate_height = 0;
6952 #endif /* CANDIDATE */
6953 _ise_state = WINDOW_STATE_HIDE;
6954 _info_manager->set_current_toolbar_mode (TOOLBAR_KEYBOARD_MODE);
6955 _info_manager->hide_helper (helper_uuid);
6957 /* Check whether stop soft keyboard */
6958 if (_focus_in && (_ime_info[get_ise_index (helper_uuid)].options & ISM_HELPER_PROCESS_KEYBOARD_KEYEVENT)) {
6959 /* If focus in and soft keyboard can support hardware key event, then don't stop it */
6961 } else if (_launch_ise_on_request && _soft_keyboard_launched) {
6962 _info_manager->stop_helper (helper_uuid);
6963 _soft_keyboard_launched = false;
6966 ecore_x_event_mask_set (efl_get_quickpanel_window (), ECORE_X_EVENT_MASK_WINDOW_PROPERTY);
6969 #ifdef HAVE_NOTIFICATION
6971 notification_status_message_post (_("Input detected from hardware keyboard"));
6973 /* Read configurations for notification app (isf-kbd-mode-changer) */
6974 String kbd_mode_changer = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_DEFAULT_KBD_MODE_CHANGER_PROGRAM), String (""));
6975 hwkbd_module_noti.launch_app = kbd_mode_changer;
6976 LOGD ("Create kbd_mode_changer notification with : %s", kbd_mode_changer.c_str ());
6977 create_notification (&hwkbd_module_noti);
6982 vconf_get_bool (VCONFKEY_ISF_HW_KEYBOARD_INPUT_DETECTED, &input_detect);
6984 if (!input_detect) {
6985 if (vconf_set_bool (VCONFKEY_ISF_HW_KEYBOARD_INPUT_DETECTED, 1) != 0)
6986 LOGW ("Failed to set vconf key");
6988 LOGD ("Succeeded to set vconf key");
6991 } else if (mode == TOOLBAR_HELPER_MODE) {
6992 LOGD ("SOFTWARE KEYBOARD MODE");
6993 /* When switching back to S/W keyboard mode, let's hide candidate window first */
6994 #if ISF_BUILD_CANDIDATE_UI
6995 LOGD ("calling ui_candidate_hide (true, true, true)");
6996 ui_candidate_hide (true, true, true);
6997 #endif /* CANDIDATE */
6998 _config->write (ISF_CONFIG_HARDWARE_KEYBOARD_DETECT, 0);
7000 if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) {
7001 uuid = helper_uuid.length () > 0 ? helper_uuid : _initial_ise_uuid;
7002 if (_launch_ise_on_request) {
7003 if (set_active_ise (uuid, false) == false) {
7004 if (_initial_ise_uuid.compare(uuid))
7005 set_active_ise (_initial_ise_uuid, false);
7009 if (set_active_ise (uuid, true) == false) {
7010 if (_initial_ise_uuid.compare(uuid)) {
7011 LOGD ("Trying to launch initial IME (%s)", _initial_ise_uuid.c_str ());
7012 set_active_ise (_initial_ise_uuid, true);
7018 #ifdef HAVE_NOTIFICATION
7019 delete_notification (&hwkbd_module_noti);
7023 vconf_get_bool (VCONFKEY_ISF_HW_KEYBOARD_INPUT_DETECTED, &input_detect);
7026 if (vconf_set_bool (VCONFKEY_ISF_HW_KEYBOARD_INPUT_DETECTED, 0) != 0)
7027 LOGW ("Failed to set vconf key");
7029 LOGD ("Succeeded to set vconf key");
7036 #ifdef HAVE_BLUETOOTH
7038 * @brief Callback function for the connection state of Bluetooth Keyboard
7040 * @param result The result of changing the connection state
7041 * @param connected The state to be changed. true means connected state, Otherwise, false.
7042 * @param remote_address The remote address
7043 * @param user_data The user data passed from the callback registration function
7047 static void _bt_cb_hid_state_changed (int result, bool connected, const char *remote_address, void *user_data)
7049 if (connected == false) {
7050 LOGD ("Bluetooth keyboard disconnected");
7051 if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) {
7052 change_keyboard_mode (TOOLBAR_HELPER_MODE);
7058 #ifdef HAVE_NOTIFICATION
7059 static void show_ime_selector_notification ()
7063 if (!_MOBILE) return;
7065 unsigned int idx = get_ise_index (_info_manager->get_current_helper_uuid ());
7066 if (idx < _ime_info.size ())
7067 ise_name = _ime_info[idx].label;
7069 String noti_icon_path = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_QUICK_PANEL_ICON_PATH), String (SCIM_ICONDIR));
7070 noti_icon_path += ISF_ISE_SELECTOR_ICON_FILE;
7072 LOGD("IME selector icon path : %s", noti_icon_path.c_str ());
7074 ise_selector_module_noti.icon = noti_icon_path;
7075 ise_selector_module_noti.content = ise_name;
7077 /* Find IME Selector appid for notification */
7078 if (ime_selector_app.length () < 1) {
7079 char *app_id = NULL;
7080 pkgmgrinfo_appinfo_filter_h handle;
7081 int ret = pkgmgrinfo_appinfo_filter_create (&handle);
7082 if (ret == PMINFO_R_OK) {
7083 ret = pkgmgrinfo_appinfo_filter_add_string (handle, PMINFO_APPINFO_PROP_APP_CATEGORY, "http://tizen.org/category/ime-selector");
7084 if (ret == PMINFO_R_OK) {
7085 pkgmgrinfo_appinfo_filter_foreach_appinfo (handle, _find_appid_from_category, &app_id);
7087 pkgmgrinfo_appinfo_filter_destroy (handle);
7090 ime_selector_app = String (app_id);
7097 if (ime_selector_app.length () > 0) {
7098 ise_selector_module_noti.launch_app = ime_selector_app;
7099 LOGD ("Create ise_selector notification with : %s", ime_selector_app.c_str ());
7100 create_notification (&ise_selector_module_noti);
7103 LOGW ("AppID with http://tizen.org/category/ime-selector category is not available");
7109 * @brief Callback function for ECORE_X_EVENT_WINDOW_PROPERTY.
7111 * @param data Data to pass when it is called.
7112 * @param ev_type The event type.
7113 * @param ev The information for current message.
7115 * @return ECORE_CALLBACK_PASS_ON
7117 static Eina_Bool x_event_window_property_cb (void *data, int ev_type, void *event)
7119 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
7121 Ecore_X_Event_Window_Property *ev = (Ecore_X_Event_Window_Property *)event;
7124 return ECORE_CALLBACK_PASS_ON;
7126 if (ev->atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE) {
7127 if (ev->win == _control_window) {
7128 /* WMSYNC, #6 The keyboard window is displayed fully so set the conformant geometry */
7129 LOGD ("ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE : win : %p, atom : %d", ev->win, ev->atom);
7130 Ecore_X_Virtual_Keyboard_State state;
7131 state = ecore_x_e_virtual_keyboard_state_get (ev->win);
7132 if (state == ECORE_X_VIRTUAL_KEYBOARD_STATE_ON) {
7133 LOGD ("ECORE_X_VIRTUAL_KEYBOARD_STATE_ON");
7134 _ise_state = WINDOW_STATE_SHOW;
7136 /* Make sure that we have the same rotation angle with the keyboard window */
7138 _candidate_angle = efl_get_ise_window_angle ();
7139 _ise_angle = efl_get_ise_window_angle ();
7142 if (_candidate_show_requested) {
7143 LOGD ("calling ui_candidate_show (true)");
7144 ui_candidate_show (true);
7146 if (_candidate_area_1_visible) {
7147 LOGD ("calling ui_candidate_show (false)");
7148 ui_candidate_show (false);
7152 set_keyboard_geometry_atom_info (_app_window, get_ise_geometry ());
7153 _info_manager->update_input_panel_event (ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
7154 _info_manager->update_input_panel_event (
7155 ECORE_IMF_INPUT_PANEL_STATE_EVENT, ECORE_IMF_INPUT_PANEL_STATE_SHOW);
7158 vconf_set_int (VCONFKEY_ISF_INPUT_PANEL_STATE, VCONFKEY_ISF_INPUT_PANEL_STATE_SHOW);
7161 if (_info_manager->get_current_toolbar_mode () == TOOLBAR_HELPER_MODE) {
7162 if (get_ise_count (TOOLBAR_HELPER_MODE, true) >= 2) {
7163 ecore_x_event_mask_set (efl_get_quickpanel_window (), ECORE_X_EVENT_MASK_WINDOW_PROPERTY);
7165 #ifdef HAVE_NOTIFICATION
7166 show_ime_selector_notification ();
7171 _updated_hide_state_geometry = false;
7173 ecore_x_e_virtual_keyboard_state_set (_ise_window, ECORE_X_VIRTUAL_KEYBOARD_STATE_ON);
7174 } else if (state == ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF) {
7175 /* WMSYNC, #9 The keyboard window is hidden fully so send HIDE state */
7176 LOGD ("ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF");
7177 // For now don't send HIDE signal here
7178 //_info_manager->update_input_panel_event (
7179 // ECORE_IMF_INPUT_PANEL_STATE_EVENT, ECORE_IMF_INPUT_PANEL_STATE_HIDE);
7180 _ise_state = WINDOW_STATE_HIDE;
7182 if (!_updated_hide_state_geometry) {
7183 /* When the ISE gets hidden by the window manager forcefully without OFF_PREPARE,
7184 the application might not have updated its autoscroll area */
7185 set_keyboard_geometry_atom_info (_app_window, get_ise_geometry ());
7186 _info_manager->update_input_panel_event (ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
7187 _info_manager->update_input_panel_event (
7188 ECORE_IMF_INPUT_PANEL_STATE_EVENT, ECORE_IMF_INPUT_PANEL_STATE_HIDE);
7190 _updated_hide_state_geometry = true;
7192 if (_info_manager->get_current_toolbar_mode () == TOOLBAR_HELPER_MODE) {
7193 LOGD ("calling ui_candidate_hide (true, false)");
7194 ui_candidate_hide (true, false);
7196 ui_settle_candidate_window ();
7200 vconf_set_int (VCONFKEY_ISF_INPUT_PANEL_STATE, VCONFKEY_ISF_INPUT_PANEL_STATE_HIDE);
7203 #ifdef HAVE_NOTIFICATION
7204 delete_notification (&ise_selector_module_noti);
7207 _ise_reported_geometry.valid = false;
7209 ecore_x_e_virtual_keyboard_state_set (_ise_window, ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF);
7211 ui_settle_candidate_window ();
7213 } else if (ev->atom == ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE) {
7214 if (ev->win == efl_get_quickpanel_window ()) {
7215 int angle = efl_get_quickpanel_window_angle ();
7216 LOGD ("ev->win : %p, change window angle : %d", ev->win, angle);
7220 return ECORE_CALLBACK_PASS_ON;
7224 * @brief Callback function for X event client message.
7226 * @param data Data to pass when it is called.
7227 * @param type The event type.
7228 * @param event The information for current message.
7230 * @return ECORE_CALLBACK_RENEW
7232 static Eina_Bool x_event_client_message_cb (void *data, int type, void *event)
7234 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
7236 Ecore_X_Event_Client_Message *ev = (Ecore_X_Event_Client_Message *)event;
7239 return ECORE_CALLBACK_RENEW;
7242 if ((ev->win == _control_window)) {
7243 if (ev->message_type == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ON_PREPARE_REQUEST) {
7244 /* WMSYNC, #4 Send WILL_SHOW event when the keyboard window is about to displayed */
7245 LOGD ("_ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ON_PREPARE_REQUEST");
7247 /* WMSYNC, #5 Let the Window Manager to actually show keyboard window */
7248 // WILL_SHOW_REQUEST_DONE Ack to WM
7249 Ecore_X_Window root_window = ecore_x_window_root_get (_control_window);
7250 ecore_x_e_virtual_keyboard_on_prepare_done_send (root_window, _control_window);
7251 LOGD ("_ecore_x_e_virtual_keyboard_on_prepare_done_send (%x, %x)",
7252 root_window, _control_window);
7254 _info_manager->update_input_panel_event (
7255 ECORE_IMF_INPUT_PANEL_STATE_EVENT, ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW);
7256 ui_create_candidate_window ();
7258 vconf_set_int (VCONFKEY_ISF_INPUT_PANEL_STATE, VCONFKEY_ISF_INPUT_PANEL_STATE_WILL_SHOW);
7259 } else if (ev->message_type == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_OFF_PREPARE_REQUEST) {
7260 _ise_state = WINDOW_STATE_WILL_HIDE;
7261 /* WMSYNC, #7 Send WILL_HIDE event when the keyboard window is about to hidden */
7262 LOGD ("_ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_OFF_PREPARE_REQUEST");
7263 // Clear conformant geometry information first
7265 if (_off_prepare_done_timer) {
7266 ecore_timer_del (_off_prepare_done_timer);
7267 _off_prepare_done_timer = NULL;
7269 _off_prepare_done_timer = ecore_timer_add (1.0, off_prepare_done_timeout, NULL);
7271 _ise_reported_geometry.valid = false;
7272 set_keyboard_geometry_atom_info (_app_window, get_ise_geometry ());
7273 _info_manager->update_input_panel_event (ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
7274 _updated_hide_state_geometry = true;
7276 /* If the input panel is getting hidden because of hw keyboard mode while
7277 the candidate window is still opened, it is considered to be an
7278 "input panel being resized" event instead of "input panel being hidden",
7279 since the candidate window will work as an "input panel" afterwards */
7280 bool send_input_panel_hide_event = true;
7281 if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) {
7282 LOGD ("_candidate_state : %d", _candidate_state);
7283 if (_candidate_state == WINDOW_STATE_SHOW) {
7284 send_input_panel_hide_event = false;
7287 if (send_input_panel_hide_event) {
7288 _info_manager->update_input_panel_event (
7289 ECORE_IMF_INPUT_PANEL_STATE_EVENT, ECORE_IMF_INPUT_PANEL_STATE_HIDE);
7291 // For now don't send WILL_HIDE signal here
7292 //_info_manager->update_input_panel_event (
7293 // ECORE_IMF_INPUT_PANEL_STATE_EVENT, ECORE_IMF_INPUT_PANEL_STATE_WILL_HIDE);
7294 // Instead send HIDE signal
7295 vconf_set_int (VCONFKEY_ISF_INPUT_PANEL_STATE, VCONFKEY_ISF_INPUT_PANEL_STATE_WILL_HIDE);
7296 } else if (ev->message_type == ECORE_X_ATOM_E_WINDOW_ROTATION_CHANGE_PREPARE) {
7297 /* WMSYNC, #10 Register size hints for candidate window and set conformant geometry */
7298 // PRE_ROTATE_DONE Ack to WM
7299 _candidate_angle = ev->data.l[1];
7300 _ise_angle = ev->data.l[1];
7301 LOGD ("ECORE_X_ATOM_E_WINDOW_ROTATION_CHANGE_PREPARE : %d", _candidate_angle);
7303 if (_candidate_angle == 90 || _candidate_angle == 270) {
7304 ui_candidate_window_resize (_candidate_land_width, _candidate_land_height_min);
7306 ui_candidate_window_resize (_candidate_port_width, _candidate_port_height_min);
7308 if (_ise_state == WINDOW_STATE_SHOW) {
7309 set_keyboard_geometry_atom_info (_app_window, get_ise_geometry ());
7310 _info_manager->update_input_panel_event (ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
7312 ui_settle_candidate_window ();
7313 ui_candidate_window_rotate (_candidate_angle);
7314 Ecore_X_Window root_window = ecore_x_window_root_get (_control_window);
7315 LOGD ("ecore_x_e_window_rotation_change_prepare_done_send (%d)", _candidate_angle);
7316 ecore_x_e_window_rotation_change_prepare_done_send (root_window,
7317 _control_window, _candidate_angle);
7318 } else if (ev->message_type == ECORE_X_ATOM_E_WINDOW_ROTATION_CHANGE_REQUEST) {
7319 int ise_angle = (int)ev->data.l[1];
7320 LOGD ("ECORE_X_ATOM_E_WINDOW_ROTATION_CHANGE_REQUEST for ISE WINDOW : ISE angle : %d, Candidate angle : %d", ise_angle, _candidate_angle);
7321 _candidate_angle = ise_angle;
7322 _ise_angle = ise_angle;
7323 if (_ise_state == WINDOW_STATE_SHOW) {
7324 set_keyboard_geometry_atom_info (_app_window, get_ise_geometry ());
7325 _info_manager->update_input_panel_event (ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
7326 ui_settle_candidate_window ();
7329 } else if (ev->win == elm_win_xwindow_get (_candidate_window)) {
7330 if (ev->message_type == ECORE_X_ATOM_E_WINDOW_ROTATION_CHANGE_REQUEST || ev->message_type == ECORE_X_ATOM_E_ILLUME_ROTATE_ROOT_ANGLE) {
7331 /* WMSYNC, #11 Actual rotate the candidate window */
7332 if (ev->message_type == ECORE_X_ATOM_E_WINDOW_ROTATION_CHANGE_REQUEST) {
7333 _candidate_angle = (int)ev->data.l[1];
7334 ui_candidate_window_rotate (_candidate_angle);
7335 LOGD ("ECORE_X_ATOM_E_WINDOW_ROTATION_CHANGE_REQUEST : %d", _candidate_angle);
7336 } else if (ev->message_type == ECORE_X_ATOM_E_ILLUME_ROTATE_ROOT_ANGLE &&
7337 _ise_state != WINDOW_STATE_SHOW) {
7338 ecore_x_e_window_rotation_app_set (elm_win_xwindow_get (_candidate_window), EINA_TRUE);
7339 _candidate_angle = (int)ev->data.l[0];
7340 if (_candidate_angle == 90 || _candidate_angle == 270) {
7341 evas_object_resize (_candidate_window, _candidate_land_width, _candidate_land_height_min);
7343 evas_object_resize (_candidate_window, _candidate_port_width, _candidate_port_height_min);
7345 ui_candidate_window_rotate (_candidate_angle);
7346 ui_settle_candidate_window ();
7347 ecore_x_e_window_rotation_app_set (elm_win_xwindow_get (_candidate_window), EINA_FALSE);
7348 LOGD ("ECORE_X_ATOM_E_ILLUME_ROTATE_ROOT_ANGLE : %d", _candidate_angle);
7350 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " : ANGLE (" << _candidate_angle << ")\n";
7355 /* Screen reader feature */
7356 if (ev->message_type == ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL) {
7357 static int last_pos_x = -10000;
7358 static int last_pos_y = -10000;
7360 if (_candidate_window) {
7361 if ((unsigned int)ev->data.l[0] == elm_win_xwindow_get (_candidate_window)) {
7362 if ((unsigned int)ev->data.l[1] == ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_ACTIVATE) {
7363 // 1 finger double tap
7364 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " 1 finger double tap focus index = " << _candidate_tts_focus_index << "\n";
7365 ui_mouse_click (_candidate_tts_focus_index);
7366 } else if ((unsigned int)ev->data.l[1] == ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ) {
7368 // 1 finger touch & move
7369 last_pos_x = ev->data.l[2];
7370 last_pos_y = ev->data.l[3];
7371 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " 1 finger touch & move (" << last_pos_x << ", " << last_pos_y << ")\n";
7372 ui_mouse_over (last_pos_x, last_pos_y);
7373 } else if ((unsigned int)ev->data.l[1] == ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ_NEXT ||
7374 (unsigned int)ev->data.l[1] == ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ_PREV) {
7375 if ((unsigned int)ev->data.l[1] == ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ_NEXT) {
7377 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " 1 finger flick right\n";
7378 if (evas_object_visible_get (_more_btn) && _candidate_tts_focus_index == (int)(_candidate_display_number - 1))
7379 _candidate_tts_focus_index = _candidate_display_number == _candidate_row_items[0] ? MORE_BUTTON_INDEX : 0;
7380 else if (evas_object_visible_get (_more_btn) && _candidate_tts_focus_index == (int)(_candidate_row_items[0] - 1))
7381 _candidate_tts_focus_index = MORE_BUTTON_INDEX;
7382 else if (evas_object_visible_get (_close_btn) && _candidate_tts_focus_index == (int)(_candidate_row_items[0] - 1))
7383 _candidate_tts_focus_index = CLOSE_BUTTON_INDEX;
7384 else if (_candidate_tts_focus_index == MORE_BUTTON_INDEX)
7385 _candidate_tts_focus_index = _candidate_display_number == _candidate_row_items[0] ? 0 : _candidate_row_items[0];
7386 else if (_candidate_tts_focus_index == CLOSE_BUTTON_INDEX)
7387 _candidate_tts_focus_index = _candidate_row_items[0];
7388 else if (_candidate_tts_focus_index >= 0 && _candidate_tts_focus_index < (g_isf_candidate_table.get_current_page_size () - 1))
7389 _candidate_tts_focus_index++;
7390 else if (_candidate_tts_focus_index == (g_isf_candidate_table.get_current_page_size () - 1))
7391 _candidate_tts_focus_index = 0;
7394 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " 1 finger flick left\n";
7395 if (evas_object_visible_get (_more_btn) && _candidate_tts_focus_index == 0)
7396 _candidate_tts_focus_index = _candidate_display_number == _candidate_row_items[0] ? MORE_BUTTON_INDEX : _candidate_display_number - 1;
7397 else if (evas_object_visible_get (_more_btn) && _candidate_tts_focus_index == (int)_candidate_row_items[0])
7398 _candidate_tts_focus_index = MORE_BUTTON_INDEX;
7399 else if (evas_object_visible_get (_close_btn) && _candidate_tts_focus_index == (int)_candidate_row_items[0])
7400 _candidate_tts_focus_index = CLOSE_BUTTON_INDEX;
7401 else if (_candidate_tts_focus_index == MORE_BUTTON_INDEX)
7402 _candidate_tts_focus_index = _candidate_row_items[0] - 1;
7403 else if (_candidate_tts_focus_index == CLOSE_BUTTON_INDEX)
7404 _candidate_tts_focus_index = _candidate_row_items[0] - 1;
7405 else if (_candidate_tts_focus_index > 0 && _candidate_tts_focus_index < g_isf_candidate_table.get_current_page_size ())
7406 _candidate_tts_focus_index--;
7407 else if (_candidate_tts_focus_index == 0)
7408 _candidate_tts_focus_index = g_isf_candidate_table.get_current_page_size () - 1;
7411 int x = 0, y = 0, w = 0, h = 0;
7412 _wait_stop_event = false;
7413 if (candidate_expanded) {
7415 int cursor_line = 0;
7416 for (unsigned int i = 0; i < _candidate_row_items.size (); i++) {
7417 total += _candidate_row_items [i];
7418 if (total > (int)_candidate_display_number && _candidate_tts_focus_index >= total)
7422 elm_scroller_region_get (_candidate_area_2, &x, &y, &w, &h);
7424 int line_h = _item_min_height + _v_padding;
7425 int cursor_y = cursor_line * line_h;
7427 elm_scroller_region_bring_in (_candidate_area_2, 0, cursor_y, w, h);
7428 _wait_stop_event = true;
7429 } else if (cursor_y >= y + h) {
7430 elm_scroller_region_bring_in (_candidate_area_2, 0, cursor_y + line_h - h, w, h);
7431 _wait_stop_event = true;
7436 String strTts = String ("");
7437 if (_candidate_tts_focus_index >= 0 && _candidate_tts_focus_index < g_isf_candidate_table.get_current_page_size ()) {
7438 strTts = utf8_wcstombs (g_isf_candidate_table.get_candidate_in_current_page (_candidate_tts_focus_index));
7439 if (_candidate_0 [_candidate_tts_focus_index])
7440 evas_object_geometry_get (_candidate_0 [_candidate_tts_focus_index], &x, &y, &w, &h);
7441 } else if (_candidate_tts_focus_index == MORE_BUTTON_INDEX) {
7442 strTts = String (_("more button"));
7443 evas_object_geometry_get (_more_btn, &x, &y, &w, &h);
7444 } else if (_candidate_tts_focus_index == CLOSE_BUTTON_INDEX) {
7445 strTts = String (_("close button"));
7446 evas_object_geometry_get (_close_btn, &x, &y, &w, &h);
7448 LOGW ("TTS focus index = %d", _candidate_tts_focus_index);
7449 ui_tts_focus_rect_hide ();
7453 if (strTts.length () > 0)
7454 ui_play_tts (strTts.c_str ());
7456 if (w > 0 && h > 0) {
7457 if (!_wait_stop_event)
7458 ui_tts_focus_rect_show (x, y, w, h);
7460 ui_tts_focus_rect_hide ();
7467 return ECORE_CALLBACK_RENEW;
7471 Eina_Bool check_focus_out_by_popup_win ()
7473 Eina_Bool ret = EINA_FALSE;
7475 Ecore_X_Window focus_win = ecore_x_window_focus_get ();
7476 Ecore_X_Window_Type win_type = ECORE_X_WINDOW_TYPE_UNKNOWN;
7478 if (!ecore_x_netwm_window_type_get (focus_win, &win_type))
7481 LOGD ("win type : %d", win_type);
7483 if (win_type == ECORE_X_WINDOW_TYPE_POPUP_MENU ||
7484 win_type == ECORE_X_WINDOW_TYPE_NOTIFICATION) {
7493 * @brief Callback function for focus out event of application window
7495 * @param data Data to pass when it is called.
7497 * @return ECORE_CALLBACK_RENEW
7499 static Eina_Bool x_event_window_focus_out_cb (void *data, int ev_type, void *event)
7501 Ecore_X_Event_Window_Focus_Out *e = (Ecore_X_Event_Window_Focus_Out*)event;
7503 if (e && e->win == _app_window) {
7504 if (_info_manager->get_current_toolbar_mode () == TOOLBAR_HELPER_MODE) {
7505 if (check_focus_out_by_popup_win ())
7506 return ECORE_CALLBACK_RENEW;
7508 #if ENABLE_MULTIWINDOW_SUPPORT
7509 unsigned int layout = 0;
7510 LOGD ("Application window focus OUT!");
7511 delete_ise_hide_timer ();
7513 // Check multi window mode
7514 if (ecore_x_window_prop_card32_get (efl_get_app_window (), ECORE_X_ATOM_E_WINDOW_DESKTOP_LAYOUT, &layout, 1) != -1) {
7515 if (layout == 0 || layout == 1) {
7517 LOGD ("Multi window mode. start timer to hide IME");
7519 // Use timer not to hide and show IME again in focus-out and focus-in event between applications
7520 _ise_hide_timer = ecore_timer_add (ISF_ISE_HIDE_DELAY, ise_hide_timeout, NULL);
7524 if (!_ise_hide_timer) {
7525 LOGD ("Panel hides ISE");
7526 _info_manager->hide_helper (_info_manager->get_current_helper_uuid ());
7528 ui_candidate_hide (true, false, false);
7531 LOGD ("Application window focus OUT! Panel hides ISE");
7532 _info_manager->hide_helper (_info_manager->get_current_helper_uuid ());
7534 ui_candidate_hide (true, false, false);
7539 return ECORE_CALLBACK_RENEW;
7543 static void restore_config ()
7545 if (!_config.null ()) {
7546 String uuid = _initial_ise_uuid;
7548 String global_uuid = scim_global_config_read (String(SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), String(""));
7549 if (global_uuid.length () > 0) uuid = global_uuid;
7551 String default_uuid = _config->read (SCIM_CONFIG_DEFAULT_HELPER_ISE, String(""));
7552 if (default_uuid.length() > 0) uuid = default_uuid;
7554 if (global_uuid.length() == 0) {
7555 scim_global_config_write (String(SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), uuid);
7557 if (default_uuid.length() == 0) {
7558 _config->write (SCIM_CONFIG_DEFAULT_HELPER_ISE, uuid);
7561 scim_global_config_flush ();
7564 scim_global_config_reload ();
7570 * @brief : Launches default soft keyboard for performance enhancement (It's not mandatory)
7572 static void launch_default_soft_keyboard (keynode_t *key, void* data)
7574 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
7577 if (!_config.null()) {
7578 helper_uuid = _config->read(SCIM_CONFIG_DEFAULT_HELPER_ISE, String(""));
7580 if (helper_uuid.length () > 0) {
7581 /* Start default ISE */
7582 change_keyboard_mode (TOOLBAR_HELPER_MODE);
7584 if (!_launch_ise_on_request) {
7585 set_temporary_ise (_initial_ise_uuid);
7591 static String sanitize_string (const char *str, int maxlen = 32)
7594 static char acceptables[] =
7595 "abcdefghijklmnopqrstuvwxyz"
7596 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
7599 char *newstr = NULL;
7601 newstr = new char[maxlen + 1];
7605 memset (newstr, 0x00, sizeof (char) * (maxlen + 1));
7608 while (len < maxlen && str[len] != '\0' && strchr (acceptables, str[len]) != NULL) {
7609 newstr[len] = str[len];
7619 static Eina_Bool monitor_user_data_path_timer(void *data)
7621 const char *path = static_cast<const char*>(data);
7622 bool user_data_path_exists = ecore_file_exists (path);
7623 bool user_data_path_is_dir = ecore_file_is_dir (path);
7624 if (user_data_path_exists && user_data_path_is_dir) {
7625 LOGW ("'%s' exists : %d, is_dir : %d", path,
7626 (user_data_path_exists ? 1 : 0), (user_data_path_is_dir ? 1 : 0));
7628 scim_global_config_reload (true);
7632 /* Read all ime info from db */
7634 isf_pkg_select_all_ime_info_db (_ime_info);
7637 if (_info_manager->get_current_toolbar_mode () != TOOLBAR_HELPER_MODE) {
7640 if (_launch_ise_on_request) {
7643 String default_ise_uuid = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), _initial_ise_uuid);
7645 set_active_ise (default_ise_uuid, launch);
7649 g_monitor_user_data_path_timer = NULL;
7650 return ECORE_CALLBACK_CANCEL;
7653 return ECORE_CALLBACK_RENEW;
7656 int main (int argc, char *argv [])
7658 struct tms tiks_buf;
7659 _clock_start = times (&tiks_buf);
7664 bool daemon = false;
7665 bool should_resident = true;
7668 char **new_argv = new char * [40];
7669 int display_name_c = 0;
7670 ConfigModule *config_module = NULL;
7671 String config_name = String ("simple");
7672 String display_name = String ();
7673 char buf[256] = {0};
7675 String user_data_path = String ();
7676 bool user_data_path_exists = false;
7677 bool user_data_path_is_dir = false;
7680 Ecore_Event_Handler *xclient_message_handler = NULL;
7681 Ecore_Event_Handler *xwindow_property_handler = NULL;
7682 Ecore_Event_Handler *xwindow_focus_out_handler = NULL;
7685 check_time ("\nStarting ISF Panel EFL...... ");
7686 ISF_SAVE_LOG ("Starting ISF Panel EFL......");
7688 DebugOutput::disable_debug (SCIM_DEBUG_AllMask);
7689 DebugOutput::enable_debug (SCIM_DEBUG_MainMask);
7691 /* Parse command options */
7697 if (String ("-c") == argv [i] || String ("--config") == argv [i]) {
7699 std::cerr << "no argument for option " << argv [i-1] << "\n";
7703 config_name = argv [i];
7707 if (String ("-h") == argv [i] || String ("--help") == argv [i]) {
7708 std::cout << "Usage: " << argv [0] << " [option]...\n\n"
7709 << "The options are: \n"
7710 << " --display DISPLAY Run on display DISPLAY.\n"
7711 << " -c, --config NAME Uses specified Config module.\n"
7712 << " -d, --daemon Run " << argv [0] << " as a daemon.\n"
7713 << " -ns, --no-stay Quit if no connected client.\n"
7715 << " -v, --verbose LEVEL Enable debug info, to specific LEVEL.\n"
7716 << " -o, --output FILE Output debug information into FILE.\n"
7718 << " -h, --help Show this help message.\n";
7723 if (String ("-d") == argv [i] || String ("--daemon") == argv [i]) {
7728 if (String ("-ns") == argv [i] || String ("--no-stay") == argv [i]) {
7729 should_resident = false;
7733 if (String ("-v") == argv [i] || String ("--verbose") == argv [i]) {
7735 std::cerr << "no argument for option " << argv [i-1] << "\n";
7739 DebugOutput::set_verbose_level (atoi (argv [i]));
7743 if (String ("-o") == argv [i] || String ("--output") == argv [i]) {
7745 std::cerr << "No argument for option " << argv [i-1] << "\n";
7749 DebugOutput::set_output (sanitize_string (argv [i]));
7753 if (String ("--display") == argv [i]) {
7755 std::cerr << "No argument for option " << argv [i-1] << "\n";
7759 display_name = sanitize_string (argv [i]);
7763 if (String ("--") == argv [i])
7766 std::cerr << "Invalid command line option: " << argv [i] << "\n";
7769 } /* End of command line parsing. */
7772 new_argv [new_argc ++] = argv [0];
7774 /* Store the rest argvs into new_argv. */
7775 for (++i; i < argc && new_argc < 37; ++i) {
7776 new_argv [new_argc ++] = argv [i];
7779 /* Make up DISPLAY env. */
7780 if (display_name.length ()) {
7781 new_argv [new_argc ++] = const_cast <char*> ("--display");
7782 display_name_c = new_argc;
7783 new_argv [new_argc ++] = strdup (display_name.c_str ());
7785 setenv ("DISPLAY", display_name.c_str (), 1);
7788 new_argv [new_argc] = 0;
7791 if (!config_name.length ()) {
7792 std::cerr << "No Config module is available!\n";
7797 /* Get current display. */
7799 const char *p = getenv ("DISPLAY");
7801 display_name = String (p);
7804 snprintf (buf, sizeof (buf), "config_name=%s display_name=%s", config_name.c_str (), display_name.c_str ());
7808 check_time ("ISF Panel EFL run as daemon");
7812 /* No loading default theme to reduce heap memory */
7813 setenv ("ELM_THEME", "", 1);
7815 #if ISF_BUILD_CANDIDATE_UI
7816 elm_init (argc, argv);
7819 ecore_app_args_set(argc, (const char **)argv);
7820 #endif /* CANDIDATE */
7822 check_time ("elm_init");
7826 #if ISF_BUILD_CANDIDATE_UI
7827 elm_policy_set (ELM_POLICY_THROTTLE, ELM_POLICY_THROTTLE_NEVER);
7828 #endif /* CANDIDATE */
7830 if (config_name != "dummy") {
7831 /* Load config module */
7832 config_module = new ConfigModule (config_name);
7834 if (!config_module || !config_module->valid ()) {
7835 std::cerr << "Can not load " << config_name << " Config module.\n";
7840 _config = new DummyConfig ();
7843 /* Create config instance */
7844 if (_config.null () && config_module && config_module->valid ())
7845 _config = config_module->create_config ();
7846 if (_config.null ()) {
7847 std::cerr << "Failed to create Config instance from " << config_name << " Config module.\n";
7851 ConfigBase::set (_config);
7852 check_time ("create config instance");
7855 if (!initialize_panel_agent (_config, display_name, should_resident)) {
7856 check_time ("Failed to initialize Panel Agent!");
7857 std::cerr << "Failed to initialize Panel Agent!\n";
7858 LOGE ("Failed to initialize Panel Agent!");
7862 } catch (scim::Exception & e) {
7863 std::cerr << e.what () << "\n";
7868 check_time ("initialize_panel_agent");
7870 #if ISF_BUILD_CANDIDATE_UI
7871 /* Initialize global variables and pointers for candidate items and etc. */
7872 for (i = 0; i < SCIM_LOOKUP_TABLE_MAX_PAGESIZE; i++) {
7873 _candidate_0 [i] = NULL;
7874 _seperate_0 [i] = NULL;
7875 _seperate_items [i] = NULL;
7877 _line_items [i] = NULL;
7878 _candidate_text [i] = NULL;
7879 _candidate_image [i] = NULL;
7880 _candidate_pop_image [i] = NULL;
7882 #endif /* CANDIDATE */
7884 /* Connect the configuration reload signal. */
7885 _config_connection = _config->signal_connect_reload (slot (config_reload_cb));
7888 if (!efl_create_control_window ()) {
7889 LOGW ("Failed to create control window");
7894 #if ISF_BUILD_CANDIDATE_UI
7895 efl_get_screen_resolution (_screen_width, _screen_height);
7897 _width_rate = (float)(_screen_width / 720.0);
7898 _height_rate = (float)(_screen_height / 1280.0);
7899 _blank_width = (int)(_blank_width * _width_rate);
7900 _item_min_width = (int)(_item_min_width * _width_rate);
7901 _item_min_height = (int)(_item_min_height * _height_rate);
7902 _candidate_width = (int)(_candidate_port_width * _width_rate);
7903 _candidate_height = (int)(_candidate_port_height_min * _height_rate);
7904 _indicator_height = (int)(_indicator_height * _height_rate);
7906 _aux_font_size = (int)(_aux_font_size * (_width_rate < _height_rate ? _width_rate : _height_rate));
7907 _candidate_font_size = (int)(_candidate_font_size * (_width_rate < _height_rate ? _width_rate : _height_rate));
7908 #endif /* CANDIDATE */
7910 /* Load ISF configuration */
7911 user_data_path = scim_get_user_data_dir ();
7912 user_data_path_exists = ecore_file_exists (user_data_path.c_str ());
7913 user_data_path_is_dir = ecore_file_is_dir (user_data_path.c_str ());
7914 _launch_ise_on_request = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_LAUNCH_ISE_ON_REQUEST), _launch_ise_on_request);
7915 if (vconf_set_bool (VCONFKEY_ISF_IME_LAUNCH_ON_DEMAND, _launch_ise_on_request) != 0)
7916 LOGW ("Failed to set vconf key");
7918 if (user_data_path_exists && user_data_path_is_dir) {
7921 LOGW ("'%s' exists : %d, is_dir : %d", user_data_path.c_str (),
7922 (user_data_path_exists ? 1 : 0), (user_data_path_is_dir ? 1 : 0));
7923 g_monitor_user_data_path_timer = ecore_timer_add (1.0, monitor_user_data_path_timer, user_data_path.c_str ());
7925 check_time("load_config");
7929 lang_str = vconf_get_str (VCONFKEY_LANGSET);
7930 set_language_and_locale (lang_str);
7934 /* Add callback function for input language and display language */
7935 vconf_notify_key_changed (VCONFKEY_LANGSET, display_language_changed_cb, NULL);
7936 vconf_notify_key_changed (VCONFKEY_ISF_HW_KEYBOARD_INPUT_DETECTED, keyboard_mode_changed_cb, NULL);
7940 if (0 != register_edbus_signal_handler ())
7941 LOGW ("register edbus signal fail");
7945 /* Update ISE list */
7946 std::vector<String> list;
7947 update_ise_list (list);
7949 /* Load initial ISE information */
7950 _initial_ise_uuid = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_INITIAL_ISE_UUID), String (SCIM_COMPOSE_KEY_FACTORY_UUID));
7952 /* Check if SCIM_CONFIG_DEFAULT_HELPER_ISE is available. If it's not, set it as _initial_ise_uuid.
7953 e.g., This might be necessary when the platform is upgraded from 2.3 to 2.4. */
7954 String helper_uuid = _config->read (SCIM_CONFIG_DEFAULT_HELPER_ISE, String (""));
7955 if (_initial_ise_uuid.length() > 0 && helper_uuid != _initial_ise_uuid) {
7957 for (unsigned int u = 0; u < _ime_info.size (); u++) {
7958 if (_ime_info[u].mode == TOOLBAR_HELPER_MODE && helper_uuid == _ime_info[u].appid) {
7964 _config->write (String (SCIM_CONFIG_DEFAULT_HELPER_ISE), _initial_ise_uuid);
7968 /* Request to terminate active IME */
7969 terminate_active_ise (_initial_ise_uuid);
7971 /* Launches default soft keyboard when all conditions are satisfied */
7972 launch_default_soft_keyboard ();
7974 /* Update the name of each ISE according to display language */
7975 update_ise_locale ();
7976 } catch (scim::Exception & e) {
7977 std::cerr << e.what () << "\n";
7978 } catch (std::logic_error & e) {
7979 std::cerr << e.what () << "\n";
7982 xclient_message_handler = ecore_event_handler_add (ECORE_X_EVENT_CLIENT_MESSAGE, x_event_client_message_cb, NULL);
7983 xwindow_property_handler = ecore_event_handler_add (ECORE_X_EVENT_WINDOW_PROPERTY, x_event_window_property_cb, NULL);
7984 xwindow_focus_out_handler = ecore_event_handler_add (ECORE_X_EVENT_WINDOW_FOCUS_OUT, x_event_window_focus_out_cb, NULL);
7987 #ifdef HAVE_BLUETOOTH
7988 /* Register the callback function of Bluetooth connection */
7989 ret = bt_initialize ();
7990 if (ret != BT_ERROR_NONE)
7991 LOGW ("Fail to init Bluetooth");
7993 ret = bt_hid_host_initialize (_bt_cb_hid_state_changed, NULL);
7994 if (ret != BT_ERROR_NONE)
7995 LOGW ("bt_hid_host_initialize failed");
7999 launch_remote_input = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_LAUNCH_REMOTE_INPUT), launch_remote_input);
8001 /* Create remote input */
8002 if (launch_remote_input) {
8003 LOGD("remote input start");
8004 remote_input_impl = new Remote_Input();
8005 if (remote_input_impl) {
8006 remote_input_impl->init(_info_manager);
8011 #if ISF_BUILD_CANDIDATE_UI
8012 _system_scale = elm_config_scale_get ();
8014 /* Set elementary scale */
8015 if (_screen_width) {
8016 _app_scale = _screen_width / 720.0;
8017 elm_config_scale_set (_app_scale);
8019 snprintf (buf, sizeof (buf), "%4.3f", _app_scale);
8020 setenv ("ELM_SCALE", buf, 1);
8022 #endif /* CANDIDATE */
8024 signal (SIGQUIT, signalhandler);
8025 signal (SIGTERM, signalhandler);
8026 signal (SIGINT, signalhandler);
8027 signal (SIGHUP, signalhandler);
8029 check_time ("EFL Panel launch time");
8031 if (!isf_cynara_initialize())
8032 LOGW ("Failed to initialize cynara");
8034 #if ISF_BUILD_CANDIDATE_UI
8037 ecore_main_loop_begin ();
8038 #endif /* CANDIDATE */
8040 LOGW("out of loop");
8042 isf_cynara_finish();
8047 if (g_monitor_user_data_path_timer) {
8048 ecore_timer_del (g_monitor_user_data_path_timer);
8049 g_monitor_user_data_path_timer = NULL;
8052 #ifdef HAVE_BLUETOOTH
8053 /* deinitialize the callback function of Bluetooth connection */
8054 ret = bt_hid_host_deinitialize ();
8055 if (ret != BT_ERROR_NONE)
8056 LOGW ("bt_hid_host_deinitialize failed: %d", ret);
8058 ret = bt_deinitialize ();
8059 if (ret != BT_ERROR_NONE)
8060 LOGW ("bt_deinitialize failed: %d", ret);
8064 if (xclient_message_handler) {
8065 ecore_event_handler_del (xclient_message_handler);
8066 xclient_message_handler = NULL;
8069 if (xwindow_property_handler) {
8070 ecore_event_handler_del (xwindow_property_handler);
8071 xwindow_property_handler = NULL;
8074 if (xwindow_focus_out_handler) {
8075 ecore_event_handler_del (xwindow_focus_out_handler);
8076 xwindow_focus_out_handler = NULL;
8081 /* Remove callback function for input language and display language */
8082 vconf_ignore_key_changed (VCONFKEY_LANGSET, display_language_changed_cb);
8083 vconf_ignore_key_changed (VCONFKEY_ISF_HW_KEYBOARD_INPUT_DETECTED, keyboard_mode_changed_cb);
8087 #if ISF_BUILD_CANDIDATE_UI
8088 ui_destroy_candidate_window ();
8089 ui_candidate_delete_check_size_timer ();
8090 ui_candidate_delete_longpress_timer ();
8091 ui_candidate_delete_destroy_timer ();
8092 #endif /* CANDIDATE */
8093 #ifdef HAVE_PKGMGR_INFO
8095 package_manager_destroy (pkgmgr);
8099 delete_ise_check_pid_alive_timer();
8101 #if ISF_BUILD_CANDIDATE_UI
8108 unregister_edbus_signal_handler ();
8111 if (_info_manager) {
8113 _info_manager->stop ();
8114 } catch (scim::Exception & e) {
8115 std::cerr << "Exception is thrown from _info_manager->stop (), error is " << e.what () << "\n";
8117 delete _info_manager;
8119 _config_connection.disconnect ();
8120 if (!_config.null ())
8122 ConfigBase::set (0);
8125 delete config_module;
8127 #if ISF_BUILD_CANDIDATE_UI
8131 #endif /* CANDIDATE */
8134 if ((display_name_c > 0) && new_argv [display_name_c]) {
8135 free (new_argv [display_name_c]);
8140 ISF_SAVE_LOG ("ret=%d", ret);
8142 std::cerr << "Successfully exited.\n";
8145 std::cerr << "Abnormally exited.\n";
8151 vi:ts=4:nowrap:expandtab