Add signal, slot to Infomanager for restarting IME in on-demand mode
[platform/core/uifw/isf.git] / ism / extras / efl_panel / isf_panel_efl.cpp
1 /*
2  * ISF(Input Service Framework)
3  *
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.
6  *
7  * Contact: Haifeng Deng <haifeng.deng@samsung.com>, Jihoon Kim <jihoon48.kim@samsung.com>
8  *
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)
12  * any later version.
13  *
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.
18  *
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
22  *
23  */
24
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
30 #define WAIT_WM
31
32 #include <sys/wait.h>
33 #include <sys/types.h>
34 #include <sys/time.h>
35 #include <sys/times.h>
36 #include <signal.h>
37 #include <unistd.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <Eina.h>
41 #include <Ecore.h>
42 #include <Ecore_File.h>
43 #include <malloc.h>
44 #include "scim_private.h"
45 #include "scim.h"
46 #include "scim_stl_map.h"
47 #if ISF_BUILD_CANDIDATE_UI
48 #include <glib.h>
49 #include <Elementary.h>
50 #include <Evas.h>
51 #ifdef HAVE_ECOREWL
52 #include <Ecore_Wayland.h>
53 #endif /* HAVE_ECOREWL */
54 #ifdef HAVE_ECOREX
55 #include <Ecore_X.h>
56 #endif /* HAVE_ECOREX */
57 #ifdef HAVE_X
58 #include <X11/Xlib.h>
59 #include <X11/Xatom.h>
60 #endif /* HAVE_X */
61 #ifdef HAVE_TTS
62 #include <tts.h>
63 #endif /* HAVE_TTS */
64 #ifdef HAVE_FEEDBACK
65 #include <feedback.h>
66 #endif /* HAVE_FEEDBACK */
67 #endif /* CANDIDATE */
68 #ifdef HAVE_VCONF
69 #include <vconf.h>
70 #include <vconf-keys.h>
71 #endif
72 #include <dlog.h>
73 #ifdef HAVE_NOTIFICATION
74 #include <notification.h>
75 #include <notification_internal.h>
76 #endif
77 #ifdef HAVE_EDBUS
78 #include <E_DBus.h>
79 #endif
80 #ifdef HAVE_BLUETOOTH
81 #include <bluetooth.h>
82 #endif
83 #ifdef HAVE_PKGMGR_INFO
84 #include <package_manager.h>
85 #include <pkgmgr-info.h>
86 #endif
87 #include <app_control.h>
88 #include <aul.h>
89
90 #include "isf_panel_efl.h"
91 #include "isf_panel_utility.h"
92 #include "isf_query_utility.h"
93 #include "isf_pkg.h"
94 #include "privilege_checker.h"
95 #include "remote_input.h"
96 #include "tizen_profile.h"
97
98 using namespace scim;
99
100
101 /////////////////////////////////////////////////////////////////////////////
102 // Declaration of macro.
103 /////////////////////////////////////////////////////////////////////////////
104 #define EFL_CANDIDATE_THEME1                            (SCIM_DATADIR "/isf_candidate_theme1.edj")
105
106 #define ISF_CANDIDATE_TABLE                             0
107
108 #define ISF_EFL_AUX                                     1
109 #define ISF_EFL_CANDIDATE_0                             2
110 #define ISF_EFL_CANDIDATE_ITEMS                         3
111
112 #define ISE_DEFAULT_HEIGHT_PORTRAIT                     444
113 #define ISE_DEFAULT_HEIGHT_LANDSCAPE                    316
114
115 #define ISF_CANDIDATE_DESTROY_DELAY                     3
116 #define ISF_ISE_HIDE_DELAY                              0.15
117
118 #define ISF_PREEDIT_BORDER                              16
119 #define ISE_LAUNCH_TIMEOUT                              2.0
120
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"
124
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"
131
132 #define E_PROP_DEVICEMGR_INPUTWIN                       "DeviceMgr Input Window"
133
134
135 /////////////////////////////////////////////////////////////////////////////
136 // Declaration of external variables.
137 /////////////////////////////////////////////////////////////////////////////
138 extern MapStringVectorSizeT         _groups;
139 extern std::vector<ImeInfoDB>       _ime_info;
140
141 CommonLookupTable       g_isf_candidate_table;
142
143
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,
151     WINDOW_STATE_SHOW,
152     WINDOW_STATE_ON,
153 } WINDOW_STATE;
154
155 typedef struct NotiData
156 {
157     String title;
158     String content;
159     String icon;
160     String launch_app;
161     int noti_id;
162 } NotificationData;
163
164 typedef std::vector < std::pair <String, uint32> >    VectorPairStringUint32;
165
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 */
172
173 #ifdef HAVE_ECOREX
174 static void       efl_set_transient_for_app_window     (Ecore_X_Window window);
175 #endif
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
181 #ifdef HAVE_ECOREX
182 static int        efl_get_quickpanel_window_angle      (void);
183 #endif /* HAVE_ECOREX */
184
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 */
199
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 */
204
205 static void       launch_default_soft_keyboard         (keynode_t *key = NULL, void* data = NULL);
206
207 /* PanelAgent related functions */
208 static bool       initialize_panel_agent               (const ConfigPointer& config, const String &display, bool resident);
209
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);
253
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);
258
259 static void       slot_will_hide_ack                   (void);
260 static void       slot_candidate_will_hide_ack         (void);
261
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);
268
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);
272 #endif
273
274 #ifdef HAVE_ECOREX
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);
279 #endif
280
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);
290 #endif
291 static void       set_language_and_locale              (const char *lang_str);
292 static bool       app_control_launch                   (const char *app_id);
293
294 /////////////////////////////////////////////////////////////////////////////
295 // Declaration of internal variables.
296 /////////////////////////////////////////////////////////////////////////////
297 #if ISF_BUILD_CANDIDATE_UI
298 static Evas_Object       *_candidate_window                 = 0;
299 static Evas_Object       *_candidate_area_1                 = 0;
300 static Evas_Object       *_candidate_area_2                 = 0;
301 static Evas_Object       *_candidate_bg                     = 0;
302 static Evas_Object       *_candidate_0_scroll               = 0;
303 static Evas_Object       *_candidate_scroll                 = 0;
304 static Evas_Object       *_scroller_bg                      = 0;
305 static Evas_Object       *_candidate_0_table                = 0;
306 static Evas_Object       *_candidate_table                  = 0;
307 static Evas_Object       *_candidate_0 [SCIM_LOOKUP_TABLE_MAX_PAGESIZE];
308 static Evas_Object       *_candidate_text [SCIM_LOOKUP_TABLE_MAX_PAGESIZE];
309 static Evas_Object       *_candidate_image [SCIM_LOOKUP_TABLE_MAX_PAGESIZE];
310 static Evas_Object       *_candidate_pop_image [SCIM_LOOKUP_TABLE_MAX_PAGESIZE];
311 static Evas_Object       *_seperate_0 [SCIM_LOOKUP_TABLE_MAX_PAGESIZE];
312 static Evas_Object       *_seperate_items [SCIM_LOOKUP_TABLE_MAX_PAGESIZE];
313 static Evas_Object       *_line_0 [SCIM_LOOKUP_TABLE_MAX_PAGESIZE];
314 static Evas_Object       *_line_items [SCIM_LOOKUP_TABLE_MAX_PAGESIZE];
315 static Evas_Object       *_more_btn                         = 0;
316 static Evas_Object       *_close_btn                        = 0;
317 static bool               _candidate_show_requested         = false;
318 #endif /* CANDIDATE */
319 static bool               _updated_hide_state_geometry      = false;
320 #if ISF_BUILD_CANDIDATE_UI
321 static int                _candidate_x                      = 0;
322 static int                _candidate_y                      = 0;
323 static int                _candidate_width                  = 0;
324 static int                _candidate_height                 = 0;
325 #endif /* CANDIDATE */
326 static int                _soft_candidate_width             = 0;
327 static int                _soft_candidate_height            = 0;
328 #if ISF_BUILD_CANDIDATE_UI
329 static int                _candidate_valid_height           = 0;
330
331 static bool               _candidate_area_1_visible         = false;
332 static bool               _candidate_area_2_visible         = false;
333 static bool               _aux_area_visible                 = false;
334 #endif /* CANDIDATE */
335
336 static ISF_CANDIDATE_MODE_T          _candidate_mode        = SOFT_CANDIDATE_WINDOW;
337 static ISF_CANDIDATE_PORTRAIT_LINE_T _candidate_port_line   = ONE_LINE_CANDIDATE;
338
339 #if ISF_BUILD_CANDIDATE_UI
340 static int                _candidate_port_width             = 480;
341 static int                _candidate_port_height_min        = 76;
342 static int                _candidate_port_height_min_2      = 150;
343 static int                _candidate_port_height_max        = 286;
344 static int                _candidate_port_height_max_2      = 350;
345 static int                _candidate_land_width             = 784;
346 static int                _candidate_land_height_min        = 84;
347 static int                _candidate_land_height_min_2      = 168;
348 static int                _candidate_land_height_max        = 150;
349 static int                _candidate_land_height_max_2      = 214;
350 static int                _candidate_area_1_pos [2]         = {0, 2};
351 static int                _more_btn_pos [4]                 = {369, 11, 689, 11};
352 static int                _close_btn_pos [4]                = {362, 211, 682, 75};
353 static int                _more_btn_width                   = 80;
354 static int                _more_btn_height                  = 64;
355
356 static int                _h_padding                        = 4;
357 static int                _v_padding                        = 2;
358 static int                _item_min_width                   = 99;
359 static int                _item_min_height                  = 82;
360
361 static int                _candidate_scroll_0_width_min     = 350;
362 static int                _candidate_scroll_0_width_max     = 670;
363
364 static int                _candidate_scroll_width           = 453;
365 static int                _candidate_scroll_width_min       = 453;
366 static int                _candidate_scroll_width_max       = 663;
367 static int                _candidate_scroll_height_min      = 124;
368 static int                _candidate_scroll_height_max      = 190;
369
370 const  int                MORE_BUTTON_INDEX                 = -1;
371 const  int                CLOSE_BUTTON_INDEX                = -2;
372 const  int                INVALID_TTS_FOCUS_INDEX           = -100;
373 static int                _candidate_tts_focus_index        = INVALID_TTS_FOCUS_INDEX;
374 static uint32             _candidate_display_number         = 0;
375 static std::vector<uint32> _candidate_row_items;
376 static Evas_Object       *_tts_focus_rect                   = 0;
377 static bool               _wait_stop_event                  = false;
378
379 static Evas_Object       *_preedit_window                   = 0;
380 static Evas_Object       *_preedit_text                     = 0;
381 static int                _preedit_width                    = 100;
382 static int                _preedit_height                   = 54;
383
384 static Evas_Object       *_aux_area                         = 0;
385 static Evas_Object       *_aux_line                         = 0;
386 static Evas_Object       *_aux_table                        = 0;
387 static int                _aux_height                       = 0;
388 static int                _aux_port_width                   = 444;
389 static int                _aux_land_width                   = 764;
390 static std::vector<Evas_Object *> _aux_items;
391 static std::vector<Evas_Object *> _aux_seperates;
392
393 static Evas_Object       *_tmp_preedit_text                 = 0;
394 static Evas_Object       *_tmp_aux_text                     = 0;
395 static Evas_Object       *_tmp_candidate_text               = 0;
396
397 static int                _spot_location_x                  = -1;
398 static int                _spot_location_y                  = -1;
399 static int                _spot_location_top_y              = -1;
400 static int                _candidate_angle                  = 0;
401 #endif /* CANDIDATE */
402
403 static int                _ise_angle                        = -1;
404 static int                _ise_x                            = 0;
405 static int                _ise_y                            = 0;
406 static int                _ise_width                        = 0;
407 static int                _ise_height                       = 0;
408 static WINDOW_STATE       _ise_state                        = WINDOW_STATE_HIDE;
409 static WINDOW_STATE       _candidate_state                  = WINDOW_STATE_HIDE;
410
411 #if ISF_BUILD_CANDIDATE_UI
412 static int                _indicator_height                 = 0;//24;
413 static int                _screen_width                     = 720;
414 static int                _screen_height                    = 1280;
415 static float              _width_rate                       = 1.0;
416 static float              _height_rate                      = 1.0;
417 static int                _blank_width                      = 30;
418
419 static String             _candidate_name                   = String ("candidate");
420 static String             _candidate_edje_file              = String (EFL_CANDIDATE_THEME1);
421
422 static String             _candidate_font_name              = String ("Tizen");
423 static int                _candidate_font_size              = 38;
424 static int                _aux_font_size                    = 38;
425 static int                _click_object                     = 0;
426 static int                _click_down_pos [2]               = {0, 0};
427 static int                _click_up_pos [2]                 = {0, 0};
428 static bool               _is_click                         = true;
429 #endif /* CANDIDATE */
430 static String             _initial_ise_uuid                 = String ("");
431 static String             _locale_string                    = String ("");
432 static ConfigPointer      _config;
433 static Connection         _config_connection;
434
435 static InfoManager       *_info_manager                      = 0;
436
437 static clock_t            _clock_start;
438
439 #if ISF_BUILD_CANDIDATE_UI
440 static Ecore_Timer       *_check_size_timer                 = NULL;
441 static Ecore_Timer       *_longpress_timer                  = NULL;
442 static Ecore_Timer       *_destroy_timer                    = NULL;
443 #endif /* CANDIDATE */
444 #ifdef HAVE_ECOREX
445 static Ecore_Timer       *_off_prepare_done_timer           = NULL;
446 #endif
447 #if ISF_BUILD_CANDIDATE_UI
448 static Ecore_Timer       *_candidate_hide_timer             = NULL;
449 #endif /* CANDIDATE */
450 static Ecore_Timer       *_ise_hide_timer                   = NULL;
451
452 #ifdef HAVE_ECOREX
453 static Ecore_X_Window     _ise_window                       = 0;
454 static Ecore_X_Window     _app_window                       = 0;
455 static Ecore_X_Window     _control_window                   = 0;
456 static Ecore_X_Window     _input_win                        = 0;
457 #endif
458
459 #ifdef HAVE_PKGMGR_INFO
460 static package_manager_h    pkgmgr                          = NULL;
461 static VectorPairStringUint32   g_pkgids_to_be_uninstalled;
462 static Ecore_Timer    *g_release_uninstalled_ime_info_timer = NULL;
463 static String               g_stopped_helper_pkgid          = "";
464 static Ecore_Timer          *g_start_default_helper_timer   = NULL;
465 static VectorPairStringUint32   g_pkgids_to_be_updated_and_installed;
466 static String               g_updated_helper_pkgid          = "";
467 #endif
468
469 static bool               _launch_ise_on_request            = false;
470 static bool               _auto_destroy_ise                 = false;
471 static bool               _soft_keyboard_launched           = false;
472 static bool               _focus_in                         = false;
473
474 #if ISF_BUILD_CANDIDATE_UI
475 static bool               candidate_expanded                = false;
476 static int                _candidate_image_count            = 0;
477 static int                _candidate_text_count             = 0;
478 static int                _candidate_pop_image_count        = 0;
479 static int                candidate_image_height            = 38;
480 static int                candidate_play_image_width_height = 19;
481
482 static const int          CANDIDATE_TEXT_OFFSET             = 2;
483
484 static double             _app_scale                        = 1.0;
485 static double             _system_scale                     = 1.0;
486 #endif /* CANDIDATE */
487
488 #ifdef HAVE_NOTIFICATION
489 static NotificationData hwkbd_module_noti                   = {"Input detected from hardware keyboard", "Tap to use virtual keyboard", ISF_KEYBOARD_ICON_FILE, "", 0};
490 static NotificationData ise_selector_module_noti            = {"Select input method", "", "", "", 0};
491 #endif
492
493 #if ISF_BUILD_CANDIDATE_UI
494 #ifdef HAVE_TTS
495 static tts_h              _tts                              = NULL;
496 #endif
497
498 #ifdef HAVE_FEEDBACK
499 static bool               feedback_initialized              = false;
500 #endif
501 #endif /* CANDIDATE */
502
503 #ifdef HAVE_EDBUS
504 static E_DBus_Connection     *edbus_conn;
505 static E_DBus_Signal_Handler *edbus_handler;
506 #endif
507
508 #if ENABLE_REMOTE_INPUT
509 static Remote_Input*      remote_input_impl                 = NULL;
510 static bool               launch_remote_input               = false;
511 #endif
512
513 #if ISF_BUILD_CANDIDATE_UI
514 #ifdef HAVE_ECOREX
515 static Ecore_Event_Handler *_candidate_show_handler         = NULL;
516 #endif
517 #endif /* CANDIDATE */
518
519 static String ime_selector_app = "";
520 static String ime_list_app = "";
521
522 static Ecore_Timer       *_ise_check_pid_alive_timer            = NULL;
523 static const double      _ise_check_pid_alive_time              = 3.0f;
524 static String            _ise_check_pid_alive_uuid;
525
526 static Ecore_Timer       *g_monitor_user_data_path_timer = NULL;
527
528 enum {
529     EMOJI_IMAGE_WIDTH = 0,
530     EMOJI_IMAGE_HEIGHT,
531     EMOJI_IMAGE_KIND,
532     EMOJI_IMAGE_TAG_FLAG,
533     EMOJI_IMAGE_POP_FLAG,
534     EMOJI_IMAGE_END
535 };
536
537 struct image
538 {
539     String path;
540     int emoji_option[EMOJI_IMAGE_END];
541 };
542
543 /* This structure stores the geometry information reported by ISE */
544 struct GeometryCache
545 {
546     bool valid;                /* Whether this information is currently valid */
547     int angle;                 /* For which angle this information is useful */
548     struct rectinfo geometry;  /* Geometry information */
549 };
550
551 static struct GeometryCache _ise_reported_geometry          = {0, 0, {0, 0, 0, 0}};
552 static struct GeometryCache _portrait_recent_ise_geometry   = {0, 0, {0, 0, 0, 0}};
553 static struct GeometryCache _landscape_recent_ise_geometry  = {0, 0, {0, 0, 0, 0}};
554
555 #ifdef HAVE_ECOREX
556 static void get_input_window (void)
557 {
558     int win_ret = -1;
559     Ecore_X_Atom atom = 0;
560
561     if (_input_win == 0) {
562         atom = ecore_x_atom_get (E_PROP_DEVICEMGR_INPUTWIN);
563         win_ret = ecore_x_window_prop_window_get (ecore_x_window_root_first_get (), atom, &_input_win, 1);
564         if (_input_win == 0 || win_ret < 1) {
565             LOGW ("Input window is NULL!");
566         } else {
567             ecore_x_event_mask_set (_input_win, ECORE_X_EVENT_MASK_WINDOW_PROPERTY);
568         }
569     }
570 }
571 #endif
572
573 static int pkgmgr_get_appinfo (const char *appid, pkgmgrinfo_appinfo_h *handle)
574 {
575     int ret = 0;
576     /* Try to get in global packages */
577     ret = pkgmgrinfo_appinfo_get_appinfo (appid, handle);
578     if (ret != PMINFO_R_OK) {
579         LOGW ("[pkgmgrinfo_appinfo_get_appinfo] appid : '%s', ret : %d, uid : %d", appid, ret, getuid ());
580         /* Try to get in user packages */
581         ret = pkgmgrinfo_appinfo_get_usr_appinfo (appid, getuid (), handle);
582         if (ret != PMINFO_R_OK)
583             LOGW ("[pkgmgrinfo_appinfo_get_usr_appinfo] appid : '%s', ret : %d", appid, ret);
584     }
585
586     return ret;
587 }
588
589 #ifdef HAVE_EDBUS
590 static void usb_keyboard_signal_cb (void *data, DBusMessage *msg)
591 {
592     DBusError err;
593     char *str = NULL;
594
595     if (!msg) {
596         LOGW ("No Message");
597         return;
598     }
599
600     if (dbus_message_is_signal (msg, HOST_INTERFACE_NAME, HOST_KEYBOARD_SIGNAL) == 0) {
601         LOGW ("HOST_KEYBOARD_SIGNAL");
602         return;
603     }
604
605     dbus_error_init (&err);
606
607     if (dbus_message_get_args (msg, &err, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID) == 0) {
608         LOGW ("DBUS_TYPE_INVALID");
609         return;
610     }
611
612     if (!str) return;
613
614     if (!strncmp (str, HOST_ADDED, strlen (HOST_ADDED))) {
615         LOGD ("HOST_ADDED");
616         return;
617     }
618
619     if (!strncmp (str, HOST_REMOVED, strlen (HOST_REMOVED))) {
620         LOGD ("HOST_REMOVED");
621         if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) {
622             change_keyboard_mode (TOOLBAR_HELPER_MODE);
623         }
624         return;
625     }
626
627     LOGW ("ERROR: msg (%s) is improper", str);
628 }
629
630 static void unregister_edbus_signal_handler (void)
631 {
632     if (edbus_conn) {
633         LOGD ("unregister signal handler for keyboard");
634         if (edbus_handler) {
635             e_dbus_signal_handler_del (edbus_conn, edbus_handler);
636             edbus_handler = NULL;
637         }
638         e_dbus_connection_close (edbus_conn);
639         edbus_conn = NULL;
640     }
641     e_dbus_shutdown ();
642 }
643
644 static int register_edbus_signal_handler (void)
645 {
646     int retry;
647
648     retry = 0;
649     while (e_dbus_init () == 0) {
650         retry++;
651         if (retry >= 10) {
652             return -1;
653         }
654     }
655
656     edbus_conn = e_dbus_bus_get (DBUS_BUS_SYSTEM);
657     if (!edbus_conn) {
658         LOGW ("edbus connection fail");
659         return -1;
660     }
661
662     edbus_handler = e_dbus_signal_handler_add (edbus_conn, NULL, HOST_OBJECT_PATH, HOST_INTERFACE_NAME, HOST_KEYBOARD_SIGNAL, usb_keyboard_signal_cb, NULL);
663     if (!edbus_handler) {
664         LOGW ("cannot register signal");
665         return -1;
666     }
667
668     LOGD ("Success edbus register");
669
670     return 0;
671 }
672 #endif
673
674 #ifdef HAVE_NOTIFICATION
675 static void delete_notification (NotificationData *noti_data)
676 {
677     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
678
679     if (!_MOBILE) return;
680
681     if (noti_data->noti_id != 0) {
682         notification_delete_by_priv_id ("isf-panel-efl", NOTIFICATION_TYPE_ONGOING, noti_data->noti_id);
683         LOGD ("deleted notification : %s", noti_data->launch_app.c_str ());
684         noti_data->noti_id = 0;
685     }
686 }
687
688 static void create_notification (NotificationData *noti_data)
689 {
690     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
691
692     notification_h notification = NULL;
693     int ret;
694
695     if (!_MOBILE) return;
696
697     if (noti_data->noti_id != 0) {
698         notification_delete_by_priv_id ("isf-panel-efl", NOTIFICATION_TYPE_ONGOING, noti_data->noti_id);
699         noti_data->noti_id = 0;
700     }
701
702     notification = notification_create (NOTIFICATION_TYPE_ONGOING);
703     if (notification != NULL) {
704         notification_set_pkgname (notification, "isf-panel-efl");
705         notification_set_layout (notification, NOTIFICATION_LY_ONGOING_EVENT);
706         notification_set_image (notification, NOTIFICATION_IMAGE_TYPE_ICON, noti_data->icon.c_str());
707         notification_set_text (notification, NOTIFICATION_TEXT_TYPE_TITLE, _(noti_data->title.c_str()), NULL, NOTIFICATION_VARIABLE_TYPE_NONE);
708         notification_set_text (notification, NOTIFICATION_TEXT_TYPE_CONTENT, _(noti_data->content.c_str ()), NULL, NOTIFICATION_VARIABLE_TYPE_NONE);
709         notification_set_display_applist (notification, NOTIFICATION_DISPLAY_APP_NOTIFICATION_TRAY);
710
711         app_control_h service = NULL;
712         if (app_control_create (&service) == APP_CONTROL_ERROR_NONE) {
713             app_control_set_operation (service, APP_CONTROL_OPERATION_DEFAULT);
714             app_control_set_app_id (service, noti_data->launch_app.c_str ());
715
716             notification_set_launch_option (notification, NOTIFICATION_LAUNCH_OPTION_APP_CONTROL, (void *)service);
717             ret = notification_insert (notification, &noti_data->noti_id);
718             if (ret != NOTIFICATION_ERROR_NONE) {
719                 LOGW ("Failed to insert notification. error code : %d", ret);
720             }
721             app_control_destroy (service);
722         }
723         else {
724             LOGW ("Failed to create appcontrol");
725         }
726         notification_free (notification);
727     }
728     else {
729         LOGW ("Failed to create notification");
730     }
731 }
732 #endif /* HAVE_NOTIFICATION */
733
734 #if ISF_BUILD_CANDIDATE_UI
735 static bool tokenize_tag (const String& str, struct image *image_token)
736 {
737     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " str=" << str << ", length=" << str.length () << "\n";
738     if (str.length () <= 0) {
739         LOGW ("str is empty!!!");
740         return false;
741     }
742
743     char **tag_str = NULL;
744     int i = 0;
745     tag_str = eina_str_split (str.c_str (), "\u3013", 0);
746
747     if (!tag_str)
748         return false;
749
750     for (i = 0; tag_str [i]; i++) {
751         if (i == 0) {
752             if (str.length () == strlen (tag_str[i])) {
753                 if (tag_str) {
754                     if (tag_str[0])
755                         free (tag_str[0]);
756
757                     free (tag_str);
758                 }
759                 return false;
760             }
761
762             image_token->path = String (tag_str[i]);
763         } else {
764             if (i - 1 < EMOJI_IMAGE_END)
765                 image_token->emoji_option [i - 1] = atoi (tag_str[i]);
766             else
767                 LOGW ("emoji option is more than EMOJI_IMAGE_END!!!");
768         }
769     }
770
771     if (tag_str[0])
772         free (tag_str[0]);
773
774     free (tag_str);
775
776     return true;
777 }
778
779 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)
780 {
781     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " str=" << str << ", length=" << str.length () << "\n";
782
783     struct image image_data;
784     int object_width = 0, text_width = 0, image_width = 0, image_height = 0, max_width = 0, button_width = 0;
785     int i = 0, j = 0;
786     int image_get_width = 0, image_get_height = 0;
787     char image_key [10] = {0, };
788     char **splited_string = NULL;
789     char **sub_splited_string = NULL;
790     double image_rate = 0.0;
791     bool tokenize_result = false;
792     bool candidate_is_long = false;
793
794     Evas_Object *candidate_object_table = NULL;
795     Evas_Object *candidate_object_table_bg_rect = NULL;
796     Evas_Object *candidate_left_padding = NULL;
797
798     candidate_object_table = elm_table_add (parent);
799
800     candidate_left_padding = evas_object_rectangle_add (evas_object_evas_get (parent));
801     evas_object_size_hint_weight_set (candidate_left_padding, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
802     evas_object_size_hint_align_set (candidate_left_padding, EVAS_HINT_FILL, EVAS_HINT_FILL);
803     evas_object_size_hint_min_set (candidate_left_padding, _blank_width, 1);
804     evas_object_color_set (candidate_left_padding, 0, 0, 0, 0);
805     elm_table_pack (candidate_object_table, candidate_left_padding, 0, 0, _blank_width, 1);
806     evas_object_show (candidate_left_padding);
807
808     object_width += _blank_width;
809     if (item_num > 1 && item_index == 0)
810         button_width = 92 * _width_rate;
811     else
812         button_width = 0;
813
814     splited_string = eina_str_split (str.c_str (), "\uE000", 0);
815     if (splited_string) {
816         for (i = 0; splited_string [i]; i++) {
817             if (candidate_is_long)
818                 break;
819             sub_splited_string = eina_str_split (splited_string [i], "\uE001", 0);
820             if (sub_splited_string) {
821                 for (j = 0; sub_splited_string [j]; j++) {
822                     if (candidate_is_long)
823                         break;
824                     tokenize_result = tokenize_tag (sub_splited_string [j], &image_data);
825                     if (tokenize_result && _candidate_image_count < SCIM_LOOKUP_TABLE_MAX_PAGESIZE && _candidate_text_count < SCIM_LOOKUP_TABLE_MAX_PAGESIZE) {
826                         _candidate_image [_candidate_image_count] = elm_image_add (parent);
827                         snprintf (image_key, sizeof (image_key), "%d", _candidate_image_count);
828                         elm_image_file_set (_candidate_image [_candidate_image_count], image_data.path.c_str (), image_key);
829                         elm_image_animated_set (_candidate_image [_candidate_image_count], EINA_TRUE);
830                         elm_image_animated_play_set (_candidate_image [_candidate_image_count], EINA_TRUE);
831                         elm_image_object_size_get (_candidate_image [_candidate_image_count], &image_get_width, &image_get_height);
832                         LOGD ("image_path=%s, key=%s", image_data.path.c_str (), image_key);
833
834                         if (image_get_height > image_get_width)
835                             image_rate = ((double)candidate_image_height / (double)image_get_width);
836                         else
837                             image_rate = ((double)candidate_image_height / (double)image_get_height);
838
839                         image_width = (int)((double)image_get_width * image_rate);
840                         image_height = candidate_image_height;
841
842                         if (_candidate_angle == 90 || _candidate_angle == 270)
843                             max_width = _candidate_land_width - (_blank_width + object_width + button_width + (2 * CANDIDATE_TEXT_OFFSET));
844                         else
845                             max_width = _candidate_port_width - (_blank_width + object_width + button_width + (2 * CANDIDATE_TEXT_OFFSET));
846
847                         if (image_width > max_width) {
848                             Evas_Object *candidate_end = edje_object_add (evas_object_evas_get (parent));
849                             edje_object_file_set (candidate_end, _candidate_edje_file.c_str (), _candidate_name.c_str ());
850                             evas_object_show (candidate_end);
851                             edje_object_part_text_set (candidate_end, "candidate", "...");
852                             edje_object_scale_set (_candidate_text [_candidate_text_count], _height_rate);
853
854                             text_width = max_width;
855                             evas_object_size_hint_min_set (candidate_end, text_width + (2 * CANDIDATE_TEXT_OFFSET), _item_min_height);
856                             if (HighLight || SetBack) {
857                                 set_highlight_color (candidate_end, ForeGround, BackGround, SetBack);
858                             }
859                             elm_table_pack (candidate_object_table, candidate_end, object_width, 0, text_width + (2 * CANDIDATE_TEXT_OFFSET), _candidate_font_size);
860                             object_width += (text_width + (2 * CANDIDATE_TEXT_OFFSET));
861
862                             if (_candidate_image [_candidate_image_count]) {
863                                 evas_object_del (_candidate_image [_candidate_image_count]);
864                                 _candidate_image [_candidate_image_count] = NULL;
865                             }
866                             candidate_is_long = true;
867                             break;
868                         }
869
870                         evas_object_resize (_candidate_image [_candidate_image_count], image_width, image_height);
871                         evas_object_show (_candidate_image [_candidate_image_count]);
872                         evas_object_size_hint_min_set (_candidate_image [_candidate_image_count], image_width, image_height);
873
874                         elm_table_pack (candidate_object_table, _candidate_image [_candidate_image_count], object_width, 1, image_width, image_height);
875                         object_width += image_width;
876                         _candidate_image_count++;
877
878                         if (image_data.emoji_option [EMOJI_IMAGE_POP_FLAG] == 1 && image_width > 0 &&  _candidate_pop_image_count < SCIM_LOOKUP_TABLE_MAX_PAGESIZE) {
879                             _candidate_pop_image [_candidate_pop_image_count] = elm_image_add (parent);
880                             elm_image_file_set (_candidate_pop_image [_candidate_pop_image_count], ISF_POP_PLAY_ICON_FILE, image_key);
881                             evas_object_resize (_candidate_pop_image [_candidate_pop_image_count], candidate_play_image_width_height, candidate_play_image_width_height);
882                             evas_object_show (_candidate_pop_image [_candidate_pop_image_count]);
883                             evas_object_size_hint_min_set (_candidate_pop_image [_candidate_pop_image_count], candidate_play_image_width_height, candidate_play_image_width_height);
884
885                             elm_table_pack (candidate_object_table, _candidate_pop_image [_candidate_pop_image_count],
886                                     object_width - candidate_play_image_width_height, image_height - candidate_play_image_width_height - 2,
887                                     candidate_play_image_width_height, candidate_play_image_width_height);
888
889                             _candidate_pop_image_count++;
890                         }
891
892                     } else if (strlen (sub_splited_string [j]) > 0 && _candidate_text_count < SCIM_LOOKUP_TABLE_MAX_PAGESIZE) {
893                         _candidate_text [_candidate_text_count] = edje_object_add (evas_object_evas_get (parent));
894                         edje_object_file_set (_candidate_text [_candidate_text_count], _candidate_edje_file.c_str (), _candidate_name.c_str ());
895                         evas_object_show (_candidate_text [_candidate_text_count]);
896                         edje_object_part_text_set (_candidate_text [_candidate_text_count], "candidate", sub_splited_string [j]);
897                         edje_object_text_class_set (_candidate_text [_candidate_text_count], "tizen",
898                                 _candidate_font_name.c_str (), _candidate_font_size);
899                         evas_object_text_text_set (_tmp_candidate_text, sub_splited_string [j]);
900                         evas_object_geometry_get (_tmp_candidate_text, NULL, NULL, &text_width, NULL);
901
902                         if (_candidate_angle == 90 || _candidate_angle == 270)
903                             max_width = _candidate_land_width - (_blank_width + object_width + button_width + (2 * CANDIDATE_TEXT_OFFSET));
904                         else
905                             max_width = _candidate_port_width - (_blank_width + object_width + button_width + (2 * CANDIDATE_TEXT_OFFSET));
906
907                         if (text_width > max_width) {
908                             candidate_is_long = true;
909                             /* In order to avoid overlap issue, calculate show_string */
910                             String show_string = String (sub_splited_string [j]);
911                             int    show_length = text_width;
912                             while (show_length > max_width && show_string.length () > 1) {
913                                 show_string = show_string.substr (0, show_string.length () - 1);
914                                 evas_object_text_text_set (_tmp_candidate_text, (show_string + String ("...")).c_str ());
915                                 evas_object_geometry_get (_tmp_candidate_text, NULL, NULL, &show_length, NULL);
916                             }
917                             edje_object_part_text_set (_candidate_text [_candidate_text_count], "candidate", (show_string + String ("...")).c_str ());
918                             text_width = max_width;
919                         }
920
921                         evas_object_size_hint_min_set (_candidate_text [_candidate_text_count], text_width + (2 * CANDIDATE_TEXT_OFFSET), _item_min_height);
922                         if (HighLight || SetBack) {
923                             set_highlight_color (_candidate_text [_candidate_text_count], ForeGround, BackGround, SetBack);
924                         }
925                         elm_table_pack (candidate_object_table, _candidate_text [_candidate_text_count], object_width, 0, text_width + (2 * CANDIDATE_TEXT_OFFSET), _candidate_font_size);
926                         object_width += (text_width + (2 * CANDIDATE_TEXT_OFFSET));
927                         _candidate_text_count++;
928                     }
929                 }
930             }
931         }
932
933         if (splited_string [0])
934             free (splited_string [0]);
935
936         free (splited_string);
937     }
938
939     if (sub_splited_string) {
940         if (sub_splited_string [0])
941             free (sub_splited_string [0]);
942
943         free (sub_splited_string);
944     }
945
946     *total_width = object_width + _blank_width;
947
948     candidate_object_table_bg_rect = edje_object_add (evas_object_evas_get (parent));
949     edje_object_file_set (candidate_object_table_bg_rect, _candidate_edje_file.c_str (), "candidate_object_table");
950     evas_object_size_hint_weight_set (candidate_object_table_bg_rect, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
951     evas_object_size_hint_align_set (candidate_object_table_bg_rect, EVAS_HINT_FILL, EVAS_HINT_FILL);
952     evas_object_size_hint_min_set (candidate_object_table_bg_rect, *total_width, _item_min_height);
953     elm_table_pack (candidate_object_table, candidate_object_table_bg_rect, 0, 0, *total_width, _item_min_height);
954     evas_object_show (candidate_object_table_bg_rect);
955
956     evas_object_size_hint_align_set (candidate_object_table, EVAS_HINT_FILL, EVAS_HINT_FILL);
957     evas_object_size_hint_weight_set (candidate_object_table, EVAS_HINT_EXPAND, 0.0);
958
959     return candidate_object_table;
960 }
961 #endif /* CANDIDATE */
962
963 /////////////////////////////////////////////////////////////////////////////
964 // Implementation of internal functions.
965 /////////////////////////////////////////////////////////////////////////////
966 /**
967  * @brief Print system time point for panel performance.
968  *
969  * @param strInfo The output information.
970  */
971 static void check_time (const char *strInfo)
972 {
973     gettime (_clock_start, strInfo);
974     ISF_LOG ("%s ppid=%d pid=%d\n", strInfo, getppid (), getpid ());
975 }
976
977 /**
978  * @brief Flush memory for elm.
979  *
980  * @return void
981  */
982 static void flush_memory (void)
983 {
984 #if ISF_BUILD_CANDIDATE_UI
985     elm_cache_all_flush ();
986 #endif
987     malloc_trim (0);
988 }
989
990 #if ISF_BUILD_CANDIDATE_UI
991 /**
992  * @brief Get ISE geometry information.
993  *        Returns the "expected" ISE geometry when kbd_state is ON, otherwise w/h set to 0
994  *
995  * @param info The data is used to store ISE position and size.
996  * @param kbd_state The keyboard state.
997  */
998 static struct rectinfo get_ise_geometry ()
999 {
1000     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
1001
1002     struct rectinfo info = {0, 0, 0, 0};
1003
1004 #ifdef HAVE_ECOREX
1005     int w = 0, h = 0;
1006     Ecore_X_Window gnb_win = efl_get_global_navigation_window ();
1007     if (gnb_win > 0)
1008         ecore_x_window_size_get (gnb_win, &w, &h);
1009 #endif
1010
1011     int win_w = _screen_width, win_h = _screen_height;
1012     int angle = (_ise_angle == -1) ? efl_get_app_window_angle () : _ise_angle;
1013
1014 #ifdef HAVE_ECOREX
1015     /* The height of global navigation bar */
1016     int gnb_height = h;
1017
1018     if (angle == 90 || angle == 270) {
1019         win_w = _screen_height;
1020         win_h = _screen_width;
1021         gnb_height = w;
1022     }
1023 #endif
1024
1025     /* If we have geometry reported by ISE, use the geometry information */
1026     if (_ise_reported_geometry.valid && _ise_reported_geometry.angle == angle) {
1027         info = _ise_reported_geometry.geometry;
1028         /* But still, if the current ISE is not in SHOW state, set w/h to 0 */
1029         if (_ise_state != WINDOW_STATE_SHOW) {
1030             info.pos_y = (win_h > win_w) ? win_h : win_w;
1031             info.width = 0;
1032             info.height = 0;
1033         }
1034     } else {
1035         /* READ ISE's SIZE HINT HERE */
1036 #ifdef HAVE_ECOREX
1037         /*
1038         int pos_x, pos_y, width, height;
1039         if (ecore_x_e_window_rotation_geometry_get (_ise_window, angle,
1040                 &pos_x, &pos_y, &width, &height)) {
1041             info.pos_x = pos_x;
1042             info.pos_y = pos_y;
1043
1044             if (angle == 90 || angle == 270) {
1045                 info.width = height;
1046                 info.height = width;
1047             } else {
1048                 info.width = width;
1049                 info.height = height;
1050             }
1051
1052             info.pos_x = (int)info.width > win_w ? 0 : (win_w - info.width) / 2;
1053             if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) {
1054                 info.pos_x = 0;
1055                 info.pos_y = (win_h > win_w) ? win_h : win_w;
1056                 info.width = 0;
1057                 info.height = 0;
1058             } else {
1059                 if (_ise_state == WINDOW_STATE_SHOW) {
1060                     info.pos_y = win_h - info.height - gnb_height;
1061                 } else {
1062                     info.pos_y = (win_h > win_w) ? win_h : win_w;
1063                     info.width = 0;
1064                     info.height = 0;
1065                 }
1066             }
1067
1068             LOGD ("angle : %d, w_angle : %d, mode : %d, Geometry : %d %d %d %d",
1069                     angle, _ise_angle,
1070                     _info_manager->get_current_toolbar_mode (),
1071                     info.pos_x, info.pos_y, info.width, info.height);
1072         } else {
1073             pos_x = 0;
1074             pos_y = 0;
1075             width = 0;
1076             height = 0;
1077         }
1078         */
1079 #else
1080         // FIXME: Get the ISE's SIZE.
1081         info.pos_x = 0;
1082         info.pos_y = 0;
1083         info.width = 0;
1084         info.height = 0;
1085 #endif
1086     }
1087
1088     _ise_width  = info.width;
1089     _ise_height = info.height;
1090
1091     return info;
1092 }
1093 #endif /* CANDIDATE */
1094
1095 #ifdef HAVE_ECOREX
1096 /**
1097  * @brief Set keyboard geometry for autoscroll.
1098  *        This includes the ISE geometry together with candidate window
1099  *
1100  * @param kbd_state The keyboard state.
1101  */
1102 static void set_keyboard_geometry_atom_info (Ecore_X_Window window, struct rectinfo ise_rect)
1103 {
1104     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
1105
1106     if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) {
1107         ise_rect.pos_x = 0;
1108
1109         if (_candidate_mode == FIXED_CANDIDATE_WINDOW) {
1110             if (_candidate_window && _candidate_state == WINDOW_STATE_SHOW) {
1111                 ise_rect.width  = _candidate_width;
1112                 ise_rect.height = _candidate_height;
1113             }
1114         } else if (_candidate_mode == SOFT_CANDIDATE_WINDOW) {
1115             ise_rect.width  = _soft_candidate_width;
1116             ise_rect.height = _soft_candidate_height;
1117         }
1118
1119         int angle = efl_get_app_window_angle ();
1120         if (angle == 90 || angle == 270)
1121             ise_rect.pos_y = _screen_width - ise_rect.height;
1122         else
1123             ise_rect.pos_y = _screen_height - ise_rect.height;
1124     } else {
1125         if (_candidate_mode == FIXED_CANDIDATE_WINDOW) {
1126             if (_candidate_window && _candidate_state == WINDOW_STATE_SHOW) {
1127                 _candidate_valid_height = ui_candidate_get_valid_height ();
1128                 if ((_candidate_height - _candidate_valid_height) > _ise_height) {
1129                     _candidate_valid_height = _candidate_height;
1130                     ise_rect.pos_y  = ise_rect.pos_y + ise_rect.height - _candidate_height;
1131                     ise_rect.height = _candidate_height;
1132                 } else {
1133                     ise_rect.pos_y  -= _candidate_valid_height;
1134                     ise_rect.height += _candidate_valid_height;
1135                 }
1136             }
1137         }
1138     }
1139
1140     ecore_x_e_illume_keyboard_geometry_set (window, ise_rect.pos_x, ise_rect.pos_y, ise_rect.width, ise_rect.height);
1141     LOGD ("KEYBOARD_GEOMETRY_SET : %d %d %d %d", ise_rect.pos_x, ise_rect.pos_y, ise_rect.width, ise_rect.height);
1142     SCIM_DEBUG_MAIN (3) << "    KEYBOARD_GEOMETRY x=" << ise_rect.pos_x << " y=" << ise_rect.pos_y
1143         << " width=" << ise_rect.width << " height=" << ise_rect.height << "\n";
1144
1145     /* even the kbd_state is OFF, consider the keyboard is still ON if we have candidate opened */
1146     if (ise_rect.width == 0 && ise_rect.height == 0) {
1147         ecore_x_e_virtual_keyboard_state_set (window, ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF);
1148     } else {
1149         ecore_x_e_virtual_keyboard_state_set (window, ECORE_X_VIRTUAL_KEYBOARD_STATE_ON);
1150
1151         if (_ise_angle == 0 || _ise_angle == 180) {
1152             _portrait_recent_ise_geometry.valid = true;
1153             _portrait_recent_ise_geometry.geometry = ise_rect;
1154         }
1155         else {
1156             _landscape_recent_ise_geometry.valid = true;
1157             _landscape_recent_ise_geometry.geometry = ise_rect;
1158         }
1159     }
1160 }
1161 #endif
1162
1163 /**
1164  * @brief Get ISE index according to uuid.
1165  *
1166  * @param uuid The ISE uuid.
1167  *
1168  * @return The ISE index
1169  */
1170 static unsigned int get_ise_index (const String uuid)
1171 {
1172     unsigned int index = 0;
1173     if (uuid.length () > 0) {
1174         for (unsigned int i = 0; i < _ime_info.size (); i++) {
1175             if (uuid == _ime_info[i].appid) {
1176                 index = i;
1177                 break;
1178             }
1179         }
1180     }
1181
1182     return index;
1183 }
1184
1185 static void set_keyboard_engine (String active_uuid)
1186 {
1187     String IMENGINE_KEY  = String (SCIM_CONFIG_DEFAULT_IMENGINE_FACTORY) + String ("/") + String ("~other");
1188     String keyboard_uuid = _config->read (IMENGINE_KEY, String (""));
1189     if (active_uuid != keyboard_uuid) {
1190         _info_manager->change_factory (active_uuid);
1191         _config->write (IMENGINE_KEY, active_uuid);
1192         _config->flush ();
1193     }
1194 }
1195
1196 static void _update_ime_info(void)
1197 {
1198     std::vector<String> ise_langs;
1199
1200     _ime_info.clear();
1201     isf_pkg_select_all_ime_info_db(_ime_info);
1202
1203     /* Update _groups */
1204     _groups.clear();
1205     for (size_t i = 0; i < _ime_info.size (); ++i) {
1206         scim_split_string_list(ise_langs, _ime_info[i].languages);
1207         for (size_t j = 0; j < ise_langs.size (); j++) {
1208             if (std::find (_groups[ise_langs[j]].begin (), _groups[ise_langs[j]].end (), i) == _groups[ise_langs[j]].end ())
1209                 _groups[ise_langs[j]].push_back (i);
1210         }
1211         ise_langs.clear ();
1212     }
1213 }
1214
1215 static void _initialize_ime_info (void)
1216 {
1217     std::vector<ImeInfoDB>::iterator iter;
1218     VectorPairStringUint32   ime_on_off;
1219     // Store is_enabled values of each keyboard
1220     for (iter = _ime_info.begin (); iter != _ime_info.end (); iter++) {
1221         if (iter->mode == TOOLBAR_HELPER_MODE) {
1222             ime_on_off.push_back (std::make_pair (iter->appid, iter->is_enabled));
1223         }
1224     }
1225     // Delete the whole ime_info DB and reload
1226     isf_db_delete_ime_info ();
1227     _update_ime_info ();
1228     // Restore is_enabled value to valid keyboards
1229     for (iter = _ime_info.begin (); iter != _ime_info.end (); iter++) {
1230         if (iter->mode == TOOLBAR_HELPER_MODE) {
1231             for (VectorPairStringUint32::iterator it = ime_on_off.begin (); it != ime_on_off.end (); it++) {
1232                 if (it->first.compare (iter->appid) == 0) {
1233                     if (it->second != iter->is_enabled) {
1234                         iter->is_enabled = it->second;
1235                         isf_db_update_is_enabled_by_appid (iter->appid.c_str (), static_cast<bool>(iter->is_enabled));
1236                     }
1237                     ime_on_off.erase (it);
1238                     break;
1239                 }
1240             }
1241         }
1242     }
1243 }
1244
1245 #ifdef HAVE_PKGMGR_INFO
1246 /**
1247  * @brief Insert or update ime_info data with pkgid.
1248  *
1249  * @param pkgid pkgid to insert/update ime_info table.
1250  *
1251  * @return 1 on successful insert, 2 on successful update, -1 if pkgid is not IME package, otherwise return 0.
1252  */
1253 static int _isf_insert_ime_info_by_pkgid(const char *pkgid)
1254 {
1255     int ret = -1;
1256     pkgmgrinfo_pkginfo_h handle = NULL;
1257     int result = 0;  // 0: not IME, 1: Inserted, 2: Updated (because of the same appid)
1258     uid_t uid = getuid ();
1259     bool user = false;
1260
1261     if (!pkgid) {
1262         LOGW ("pkgid is null.");
1263         return 0;
1264     }
1265
1266     /* Try to get in global packages */
1267     ret = pkgmgrinfo_pkginfo_get_pkginfo (pkgid, &handle);
1268     if (ret != PMINFO_R_OK) {
1269         /* Try to get in user packages */
1270         ret = pkgmgrinfo_pkginfo_get_usr_pkginfo (pkgid, uid, &handle);
1271         if (ret != PMINFO_R_OK) {
1272             LOGW ("Failed to call pkgmgrinfo_pkginfo_get_pkginfo & get_usr_pkginfo(\"%s\",~) returned %d, uid : %d", pkgid, ret, getuid ());
1273             return 0;
1274         }
1275         else {
1276             user = true;
1277         }
1278     }
1279
1280     if (user) {
1281         /* Try to get in user packages */
1282         ret = pkgmgrinfo_appinfo_get_usr_list (handle, PMINFO_UI_APP, isf_pkg_ime_app_list_cb, (void *)&result, uid);
1283     }
1284     else {
1285         /* Try to get in global packages */
1286         ret = pkgmgrinfo_appinfo_get_list (handle, PMINFO_UI_APP, isf_pkg_ime_app_list_cb, (void *)&result);
1287     }
1288
1289     if (ret != PMINFO_R_OK) {
1290         LOGW ("Failed to call %s failed(%d)", user ? "pkgmgrinfo_appinfo_get_usr_list" : "pkgmgrinfo_appinfo_get_list", ret);
1291
1292         ret = 0;
1293     }
1294     else if (result)
1295         ret = result;
1296
1297     pkgmgrinfo_pkginfo_destroy_pkginfo (handle);
1298
1299     return ret;
1300 }
1301
1302 /**
1303  * @brief Timer to start initial Helper ISE if the active (selected) 3rd party keyboard is uninstalled.
1304  *
1305  * @param data User data
1306  *
1307  * @return If it returns ECORE_CALLBACK_RENEW, it will be called again at the next tick, or if it returns
1308  * ECORE_CALLBACK_CANCEL it will be deleted automatically making any references/handles for it invalid.
1309  */
1310 static Eina_Bool _start_default_helper_timer(void *data)
1311 {
1312     std::vector<String> total_appids;
1313     std::vector<ImeInfoDB>::iterator it;
1314     VectorPairStringUint32::iterator iter;
1315
1316     /* Let panel know that ISE is deleted... */
1317     for (it = _ime_info.begin(); it != _ime_info.end(); it++) {
1318         total_appids.push_back(it->appid);
1319     }
1320     if (total_appids.size() > 0)
1321         _info_manager->update_ise_list (total_appids);
1322
1323     LOGD ("Try to start the initial helper");
1324     set_active_ise(_initial_ise_uuid, true);
1325
1326     for (iter = g_pkgids_to_be_uninstalled.begin (); iter != g_pkgids_to_be_uninstalled.end (); iter++) {
1327         if (iter->first.compare(g_stopped_helper_pkgid) == 0) {
1328             g_pkgids_to_be_uninstalled.erase (iter);
1329             break;
1330         }
1331     }
1332     g_stopped_helper_pkgid = "";
1333
1334     g_start_default_helper_timer = NULL;
1335     return ECORE_CALLBACK_CANCEL;
1336 }
1337
1338 /**
1339  * @brief Timer to release uninstalled IME related info; g_pkgids_to_be_uninstalled has appid and is_enabled.
1340  *
1341  * @param data User data
1342  *
1343  * @return If it returns ECORE_CALLBACK_RENEW, it will be called again at the next tick, or if it returns
1344  * ECORE_CALLBACK_CANCEL it will be deleted automatically making any references/handles for it invalid.
1345  */
1346 static Eina_Bool _release_uninstalled_pkginfo_timer(void *data)
1347 {
1348     g_pkgids_to_be_uninstalled.clear ();
1349     g_release_uninstalled_ime_info_timer = NULL;
1350     return ECORE_CALLBACK_CANCEL;
1351 }
1352
1353 /**
1354  * @brief Called when the package is installed, uninstalled or updated, and the progress of the request to the package manager changes.
1355  * @since_tizen 2.3
1356  * @param[in] type The type of the package to be installed, uninstalled or updated
1357  * @param[in] package The name of the package to be installed, uninstalled or updated
1358  * @param[in] event_type The type of the request to the package manager
1359  * @param[in] event_state The current state of the request to the package manager
1360  * @param[in] progress The progress for the request that is being processed by the package manager \n
1361  *            The range of progress is from 0 to 100
1362  * @param[in] error The error code when the package manager failed to process the request
1363  * @param[in] user_data The user data passed from package_manager_set_event_cb()
1364  * @see package_manager_set_event_cb()
1365  * @see package_manager_unset_event_cb()
1366
1367 INFO: Package install/update/uninstall scenario
1368 Install and Uninstall are obviously simple.
1369    Install: just INSTALL
1370    Uninstall: just UNINSTALL
1371 Update package (change the source codes in IME project and Run As again), there are four scenarios:
1372 1. UPDATE
1373    Source code change
1374 2. UNINSTALL -> INSTALL
1375    This happens when Tizen IDE Property > Tizen SDK > Rapid Development Support > Check "Enable Project specific settings"
1376    and change Application ID in tizen-manifest.xml file and Run As.
1377 3. UPDATE -> INSTALL
1378    This happens when Tizen IDE Property > Tizen SDK > Rapid Development Support > Uncheck "Enable Project specific settings"
1379    and change Application ID in tizen-manifest.xml file and Run As.
1380    At UPDATE event, pkgid (package parameter) is invalid...
1381 4. UPDATE
1382    Exceptionally, only UPDATE can be called when Application ID in tizen-manifest.xml file is changed.
1383    At UPDATE event, pkgid (package parameter) is valid, and only appid is changed; the previous appid is invalid.
1384
1385 If multiple packages (including non-IME pkgs) are uninstalled and installed; Z300H UPS (ultra power saving) mode scenario.
1386 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
1387
1388 Assuming IMEngine won't be changed through this. IMEngine might have multiple appids for one pkgid.
1389 Assuming preinstalled IME won't be changed through this.
1390  */
1391 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)
1392 {
1393     String current_ime_appid; // now appid is uuid.
1394     std::vector<String> appids;
1395     std::vector<String> total_appids;
1396     std::vector<ImeInfoDB>::iterator it;
1397     std::vector<String>::iterator it2;
1398     VectorPairStringUint32::iterator it3;
1399     int ret = 0;
1400
1401     if (!package || !type)
1402         return;
1403
1404     if (event_type == PACKAGE_MANAGER_EVENT_TYPE_UPDATE) {
1405         if (event_state == PACKAGE_MANAGER_EVENT_STATE_COMPLETED) {
1406             LOGD ("type=%s package=%s event_type=UPDATE event_state=COMPLETED progress=%d error=%d", type, package, progress, error);
1407
1408             ret = _isf_insert_ime_info_by_pkgid (package);   // If package is not IME, -1 would be returned.
1409             if (ret == 1) { // In case the package is updated with the changed appid. In this case, there will be two IMEs
1410                 ret = isf_db_select_appids_by_pkgid (package, appids);
1411                 if (ret > 1) {
1412                     if (_ime_info.size () > 0 && _ime_info [get_ise_index (appids.front ())].is_enabled)
1413                         isf_db_update_is_enabled_by_appid (appids.back ().c_str (), true);
1414                     isf_db_delete_ime_info_by_appid (appids.front ().c_str ());
1415                 }
1416
1417                 _update_ime_info ();
1418
1419                 /* Let panel know that ise list is changed... */
1420                 for (it = _ime_info.begin(); it != _ime_info.end(); it++) {
1421                     total_appids.push_back(it->appid);
1422                 }
1423                 if (total_appids.size() > 0)
1424                     _info_manager->update_ise_list (total_appids);
1425
1426                 if (ret > 1 && _soft_keyboard_launched) { // If the previous appid of pkgid is the current IME, restart it with new appid.
1427                     current_ime_appid = scim_global_config_read(String(SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), _initial_ise_uuid);
1428                     if (current_ime_appid.compare (appids.front ()) == 0) {
1429                         LOGD ("Stop IME(%s)", current_ime_appid.c_str ());
1430                         _info_manager->hide_helper (current_ime_appid);
1431                         _info_manager->stop_helper (current_ime_appid);
1432                         LOGD ("Start IME(%s)", appids.back ().c_str ());
1433                         scim_global_config_write (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), appids.back ());
1434                         set_keyboard_engine (String (SCIM_COMPOSE_KEY_FACTORY_UUID));
1435                         _info_manager->start_helper (appids.back ());
1436                     }
1437                 }
1438             }
1439             else if (ret == 2) {  // In case IME package is just updated...
1440                 _update_ime_info ();
1441
1442                 if (_soft_keyboard_launched) { // If package is the current IME, restart it.
1443                     current_ime_appid = scim_global_config_read(String(SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), _initial_ise_uuid);
1444                     if (isf_db_select_appids_by_pkgid(package, appids)) {
1445                         if (std::find(appids.begin(), appids.end(), current_ime_appid) != appids.end()) { // If the current ISE package is updated, restart it.
1446                             for (it = _ime_info.begin (); it != _ime_info.end (); it++) {
1447                                 if (it->mode == TOOLBAR_HELPER_MODE && it->appid.compare(current_ime_appid) == 0) { // Make sure it's Helper ISE...
1448                                     LOGD ("Restart IME(%s)", current_ime_appid.c_str ());
1449                                     _info_manager->hide_helper (current_ime_appid);
1450                                     _info_manager->stop_helper (current_ime_appid);
1451                                     _info_manager->start_helper (current_ime_appid);
1452                                     break;
1453                                 }
1454                             }
1455                         }
1456                     }
1457                 }
1458             }
1459             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...
1460                 if (isf_db_select_appids_by_pkgid(package, appids) == 1) {
1461                     for (it = _ime_info.begin (); it != _ime_info.end (); it++) {
1462                         if (it->pkgid.compare(package) == 0) {
1463                             g_pkgids_to_be_updated_and_installed.push_back (std::make_pair (it->pkgid, it->is_enabled));
1464                             break;
1465                         }
1466                     }
1467                     if (it == _ime_info.end ()) // Probably not going to happen.
1468                         g_pkgids_to_be_updated_and_installed.push_back(std::make_pair (String(package), 0));
1469
1470                     current_ime_appid = scim_global_config_read(String(SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), _initial_ise_uuid);
1471                     if (_soft_keyboard_launched && std::find(appids.begin(), appids.end(), current_ime_appid) != appids.end()) { // If the updated IME is the current ISE...
1472                         for (it = _ime_info.begin (); it != _ime_info.end (); it++) {
1473                             if (it->appid.compare(current_ime_appid) == 0 && it->mode == TOOLBAR_HELPER_MODE) { // Make sure it's Helper ISE...
1474                                 LOGD ("Stop IME(%s)", current_ime_appid.c_str ());
1475                                 _info_manager->hide_helper (current_ime_appid);
1476                                 _info_manager->stop_helper (current_ime_appid);
1477                                 _soft_keyboard_launched = false;
1478                                 g_updated_helper_pkgid = package;
1479                                 break;
1480                             }
1481                         }
1482                     }
1483
1484                     if (appids.size () > 0) // Probably appids size is 1.
1485                         LOGD ("Delete IME(%s)", appids[0].c_str ());
1486                     if (isf_db_delete_ime_info_by_pkgid(package)) { // Delete package from ime_info db.
1487                         _update_ime_info();
1488
1489                        /* Let panel know that ise is deleted... */
1490                        for (it = _ime_info.begin(); it != _ime_info.end(); it++) {
1491                            total_appids.push_back(it->appid);
1492                        }
1493                        if (total_appids.size() > 0)
1494                            _info_manager->update_ise_list (total_appids);
1495                     }
1496                 }
1497                 else {
1498                     LOGW ("isf_db_select_appids_by_pkgid returned %d.", ret);
1499                 }
1500             }
1501         }
1502     }
1503     else if (event_type == PACKAGE_MANAGER_EVENT_TYPE_INSTALL) {
1504         if (event_state == PACKAGE_MANAGER_EVENT_STATE_COMPLETED) {
1505             LOGD ("type=%s package=%s event_type=INSTALL event_state=COMPLETED progress=%d error=%d", type, package, progress, error);
1506
1507             ///////////////// UNINSTALL -> INSTALL and if the uninstalled IME is reinstalled /////////////////
1508             if (g_stopped_helper_pkgid.compare(package) == 0 && g_start_default_helper_timer) {
1509                 LOGD ("Cancel timer to start the default IME");
1510                 ecore_timer_del(g_start_default_helper_timer);
1511                 g_start_default_helper_timer = NULL;
1512                 g_stopped_helper_pkgid = "";
1513
1514                 ret = _isf_insert_ime_info_by_pkgid(package);
1515                 if (ret > 0) {
1516                     /* Find appid by pkgid. There might be multiple appid, but assume Helper always has one appid.
1517                        And appid can be changed, but pkgid won't be changed. */
1518                     ret = isf_db_select_appids_by_pkgid(package, appids);
1519                     if (ret == 1 && appids.size () == 1) {
1520                         for (it3 = g_pkgids_to_be_uninstalled.begin (); it3 != g_pkgids_to_be_uninstalled.end (); it3++) {
1521                             if (it3->first.compare(package) == 0) {
1522                                 if (it3->second)
1523                                     isf_db_update_is_enabled_by_appid(appids[0].c_str (), (bool)it3->second);
1524
1525                                 _update_ime_info();
1526
1527                                 /* Let panel know that ise is added... */
1528                                 for (it = _ime_info.begin(); it != _ime_info.end(); it++) {
1529                                     total_appids.push_back(it->appid);
1530                                 }
1531                                 if (total_appids.size() > 0)
1532                                     _info_manager->update_ise_list (total_appids);
1533
1534                                 LOGD ("Restart IME(%s)", appids[0].c_str ());
1535                                 scim_global_config_write (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), appids[0]);
1536                                 set_keyboard_engine (String (SCIM_COMPOSE_KEY_FACTORY_UUID));
1537                                 _info_manager->start_helper (appids[0]);
1538                                 _soft_keyboard_launched = true;
1539
1540                                 g_pkgids_to_be_uninstalled.erase (it3);
1541                                 break;
1542                             }
1543                         }
1544                     }
1545                     else {
1546                         LOGW ("isf_db_select_appids_by_pkgid returned %d.", ret);
1547
1548                         _update_ime_info();
1549
1550                         /* Let panel know that ise is added... */
1551                         for (it = _ime_info.begin(); it != _ime_info.end(); it++) {
1552                             total_appids.push_back(it->appid);
1553                         }
1554                         if (total_appids.size() > 0)
1555                             _info_manager->update_ise_list (total_appids);
1556                     }
1557                 }
1558                 else {
1559                     LOGW ("_isf_insert_ime_info_by_pkgid returned %d.", ret);
1560                 }
1561             }
1562             else {  // If new package is installed...
1563                 ret = _isf_insert_ime_info_by_pkgid(package);   // If package is not IME, -1 would be returned.
1564                 if (ret > 0) { // In case package is IME...
1565                     ///////////////// INSTALL /////////////////
1566                     _update_ime_info();
1567
1568                     /* Let panel know that ise is added... */
1569                     for (it = _ime_info.begin(); it != _ime_info.end(); it++) {
1570                         total_appids.push_back(it->appid);
1571                     }
1572                     if (total_appids.size() > 0)
1573                        _info_manager->update_ise_list (total_appids);
1574                     ///////////////// END /////////////////
1575
1576                     /* For example, the following happens if appid is changed in IME project and Run As again. The appid would be changed this time.
1577                        Assuming only Helper (3rd party) might be installed after update or uninstall and there is one appid per each pkgid...*/
1578
1579                     ///////////////// UPDATE -> INSTALL /////////////////
1580                     for (it3 = g_pkgids_to_be_updated_and_installed.begin (); it3 != g_pkgids_to_be_updated_and_installed.end (); it3++) {
1581                         if (it3->first.compare(package) == 0) {
1582                             if (it3->second) {
1583                                 for (it = _ime_info.begin(); it != _ime_info.end(); it++) {
1584                                     if (it->pkgid.compare(package) == 0) {
1585                                         it->is_enabled = it3->second;
1586                                         isf_db_update_is_enabled_by_appid(it->appid.c_str (), (bool)it->is_enabled);
1587                                         break;
1588                                     }
1589                                 }
1590                             }
1591                             g_pkgids_to_be_updated_and_installed.erase (it3);
1592                             break;
1593                         }
1594                     }
1595                     if (g_updated_helper_pkgid.compare(package) == 0) {
1596                         for (it = _ime_info.begin(); it != _ime_info.end(); it++) {
1597                             if (it->mode == TOOLBAR_HELPER_MODE && it->pkgid.compare(package) == 0) {
1598                                 LOGD ("Start IME(%s)", it->appid.c_str ());
1599                                 scim_global_config_write (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), it->appid);
1600                                 set_keyboard_engine (String (SCIM_COMPOSE_KEY_FACTORY_UUID));
1601                                 _info_manager->start_helper (it->appid);
1602                                 _soft_keyboard_launched = true;
1603                                 break;
1604                             }
1605                         }
1606                         g_updated_helper_pkgid = "";
1607                         return;
1608                     }
1609                     ///////////////// END /////////////////
1610
1611                     ///////////////// UNINSTALL -> INSTALL /////////////////
1612                     for (it3 = g_pkgids_to_be_uninstalled.begin (); it3 != g_pkgids_to_be_uninstalled.end (); it3++) {
1613                         if (it3->first.compare(package) == 0) {
1614                             if (it3->second) {
1615                                 for (it = _ime_info.begin(); it != _ime_info.end(); it++) {
1616                                     if (it->pkgid.compare(package) == 0) {
1617                                         it->is_enabled = it3->second;
1618                                         isf_db_update_is_enabled_by_appid(it->appid.c_str (), (bool)it->is_enabled);
1619                                         break;
1620                                     }
1621                                 }
1622                             }
1623                             g_pkgids_to_be_uninstalled.erase (it3);
1624                             break;
1625                         }
1626                     }
1627                     ///////////////// END /////////////////
1628                 }
1629                 else if (ret == 0) {
1630                     LOGW ("_isf_insert_ime_info_by_pkgid returned %d.", ret);
1631                 }
1632             }
1633         }
1634     }
1635     else if (event_type == PACKAGE_MANAGER_EVENT_TYPE_UNINSTALL) {
1636         switch (event_state) {
1637             case PACKAGE_MANAGER_EVENT_STATE_STARTED:
1638                 LOGD ("type=%s package=%s event_type=UNINSTALL event_state=STARTED progress=%d error=%d", type, package, progress, error);
1639                 {
1640                     // Need to check if there is "http://tizen.org/category/ime" category; it can be done by comparing pkgid with ime_info db.
1641                     int imeCnt = 0;
1642                     if (_ime_info.size() == 0)
1643                         _update_ime_info();
1644
1645                     for (it = _ime_info.begin (); it != _ime_info.end (); it++) {
1646                         if (it->pkgid.compare(package) == 0 && it->is_preinstalled == 0) {   // Ignore if it's preinstalled IME and IMEngine.
1647                             imeCnt++;
1648                             break;
1649                         }
1650                     }
1651
1652                     if (imeCnt > 0) {
1653                         // 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.
1654                         LOGD ("%s for pkgid(\"%s\") is about to be deleted", it->appid.c_str (), package);
1655                         g_pkgids_to_be_uninstalled.push_back(std::make_pair (String(package), it->is_enabled));
1656
1657                         if (_soft_keyboard_launched && isf_db_select_appids_by_pkgid(package, appids)) {
1658                             current_ime_appid = scim_global_config_read(String(SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), _initial_ise_uuid);
1659                             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.
1660                                 for (it = _ime_info.begin (); it != _ime_info.end (); it++) {
1661                                     if (it->appid.compare(current_ime_appid) == 0 && it->mode == TOOLBAR_HELPER_MODE) { // Make sure it's Helper ISE...
1662                                         LOGD ("Stop IME(%s)", current_ime_appid.c_str ());
1663                                         _info_manager->hide_helper (current_ime_appid);
1664                                         _info_manager->stop_helper (current_ime_appid);
1665                                         _soft_keyboard_launched = false;
1666                                         g_stopped_helper_pkgid = package;
1667                                         break;
1668                                     }
1669                                 }
1670                             }
1671                         }
1672                     }
1673                 }
1674                 break;
1675
1676             case PACKAGE_MANAGER_EVENT_STATE_COMPLETED:
1677                 LOGD ("type=%s package=%s event_type=UNINSTALL event_state=COMPLETED progress=%d error=%d", type, package, progress, error);
1678
1679                 for (it3 = g_pkgids_to_be_uninstalled.begin (); it3 != g_pkgids_to_be_uninstalled.end (); it3++) {
1680                     if (it3->first.compare(package) == 0) {
1681                         if (isf_db_delete_ime_info_by_pkgid(package)) { // Delete package from ime_info db.
1682                             _update_ime_info();
1683                         }
1684
1685                         if (g_stopped_helper_pkgid.compare(package) == 0) { // If the uninstalled ISE is the current ISE, start the initial helper ISE by timer.
1686                             if (g_start_default_helper_timer)
1687                                 ecore_timer_del(g_start_default_helper_timer);
1688                             LOGD ("Add timer to start the default IME");
1689                             g_start_default_helper_timer = ecore_timer_add(3.0, _start_default_helper_timer, NULL);
1690                         }
1691                         else {  // Need to clean up g_pkgids_to_be_uninstalled info unless the same package is installed again; e.g., UNINSTALL -> INSTALL case.
1692                             if (g_release_uninstalled_ime_info_timer)
1693                                 ecore_timer_del(g_release_uninstalled_ime_info_timer);
1694                             LOGD ("Add timer to release uninstalled IME pkg info");
1695                             g_release_uninstalled_ime_info_timer = ecore_timer_add(7.0, _release_uninstalled_pkginfo_timer, NULL);
1696                         }
1697
1698                         /* Let panel know that ise is deleted... */
1699                         for (it = _ime_info.begin(); it != _ime_info.end(); it++) {
1700                             total_appids.push_back(it->appid);
1701                         }
1702                         if (total_appids.size() > 0)
1703                             _info_manager->update_ise_list (total_appids);
1704
1705                         break;
1706                     }
1707                 }
1708                 break;
1709
1710             case PACKAGE_MANAGER_EVENT_STATE_FAILED:
1711                 LOGD ("type=%s package=%s event_type=UNINSTALL event_state=FAILED progress=%d error=%d", type, package, progress, error);
1712
1713                 for (it3 = g_pkgids_to_be_uninstalled.begin (); it3 != g_pkgids_to_be_uninstalled.end (); it3++) {
1714                     if (it3->first.compare(package) == 0) {
1715                         // Update _ime_info for sure...
1716                         _update_ime_info();
1717
1718                         if (g_stopped_helper_pkgid.compare(package) == 0) {
1719                             ret = isf_db_select_appids_by_pkgid(package, appids);
1720                             if (ret == 1 && appids.size () == 1) {
1721                                 for (it = _ime_info.begin (); it != _ime_info.end (); it++) {
1722                                     if (it->appid.compare(appids[0]) == 0 && it->mode == TOOLBAR_HELPER_MODE) { // Make sure it's Helper ISE...
1723                                         LOGD ("Restart IME(%s)", appids[0].c_str ());
1724                                         set_keyboard_engine (String (SCIM_COMPOSE_KEY_FACTORY_UUID));
1725                                         _info_manager->start_helper (appids[0]);
1726                                         _soft_keyboard_launched = true;
1727                                         break;
1728                                     }
1729                                 }
1730                             }
1731                             else {
1732                                 LOGW ("isf_db_select_appids_by_pkgid returned %d.", ret);
1733                             }
1734                             g_stopped_helper_pkgid = "";
1735                         }
1736
1737                         g_pkgids_to_be_uninstalled.erase (it3);
1738                         break;
1739                     }
1740                 }
1741                 break;
1742
1743             default:
1744                 break;
1745         }
1746     }
1747 }
1748 #endif
1749
1750 /**
1751  * @brief Set keyboard ISE.
1752  *
1753  * @param uuid The keyboard ISE's uuid.
1754  *
1755  * @return false if keyboard ISE change is failed, otherwise return true.
1756  */
1757 static bool set_keyboard_ise (const String &uuid)
1758 {
1759     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
1760
1761     TOOLBAR_MODE_T mode = _info_manager->get_current_toolbar_mode ();
1762
1763     if (TOOLBAR_HELPER_MODE == mode) {
1764         String pre_uuid = _info_manager->get_current_helper_uuid ();
1765         _info_manager->hide_helper (pre_uuid);
1766         _info_manager->stop_helper (pre_uuid);
1767         _soft_keyboard_launched = false;
1768     } else if (TOOLBAR_KEYBOARD_MODE == mode) {
1769         uint32 kbd_option = 0;
1770         String kbd_uuid, kbd_name;
1771         isf_get_keyboard_ise (_config, kbd_uuid, kbd_name, kbd_option);
1772         if (kbd_uuid == uuid)
1773             return false;
1774     }
1775
1776     _info_manager->change_factory (uuid);
1777
1778     String language = String ("~other");/*scim_get_locale_language (scim_get_current_locale ());*/
1779     _config->write (String (SCIM_CONFIG_DEFAULT_IMENGINE_FACTORY) + String ("/") + language, uuid);
1780
1781     return true;
1782 }
1783
1784 /**
1785  * @brief Set helper ISE.
1786  *
1787  * @param uuid The helper ISE's uuid.
1788  * @param launch_ise The flag for launching helper ISE.
1789  *
1790  * @return false if helper ISE change is failed, otherwise return true.
1791  */
1792 static bool set_helper_ise (const String &uuid, bool launch_ise)
1793 {
1794     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
1795
1796     TOOLBAR_MODE_T mode = _info_manager->get_current_toolbar_mode ();
1797     String pre_uuid = _info_manager->get_current_helper_uuid ();
1798     LOGD ("pre_appid=%s, appid=%s, launch_ise=%d, %d", pre_uuid.c_str(), uuid.c_str(), launch_ise, _soft_keyboard_launched);
1799     if (pre_uuid == uuid && _soft_keyboard_launched)
1800         return true;
1801
1802     if (TOOLBAR_HELPER_MODE == mode && pre_uuid.length () > 0 && _soft_keyboard_launched) {
1803         _info_manager->hide_helper (pre_uuid);
1804         _info_manager->stop_helper (pre_uuid);
1805         _soft_keyboard_launched = false;
1806         LOGD ("stop helper : %s", pre_uuid.c_str ());
1807     }
1808
1809     if (launch_ise) {
1810         LOGD ("Start helper (%s)", uuid.c_str ());
1811
1812         set_keyboard_engine (String (SCIM_COMPOSE_KEY_FACTORY_UUID));
1813         if (_info_manager->start_helper (uuid))
1814             _soft_keyboard_launched = true;
1815     }
1816     _config->write (String (SCIM_CONFIG_DEFAULT_HELPER_ISE), uuid);
1817
1818     return true;
1819 }
1820
1821 #ifdef HAVE_PKGMGR_INFO
1822 int get_ime_app_list_cb (const pkgmgrinfo_appinfo_h handle, void *user_data)
1823 {
1824     int ret = 0;
1825     char *appid = NULL, *pkgid = NULL, *pkgtype = NULL, *exec = NULL, *label = NULL, *path = NULL;
1826     pkgmgrinfo_pkginfo_h  pkginfo_handle = NULL;
1827     ImeInfoDB ime_db;
1828     int *result = static_cast<int*>(user_data);
1829
1830     if (result) /* in this case, need to check category */ {
1831         bool exist = true;
1832         ret = pkgmgrinfo_appinfo_is_category_exist (handle, "http://tizen.org/category/ime", &exist);
1833         if (ret != PMINFO_R_OK || !exist) {
1834             return 0;
1835         }
1836     }
1837
1838     /* appid */
1839     ret = pkgmgrinfo_appinfo_get_appid (handle, &appid);
1840     if (ret == PMINFO_R_OK)
1841         ime_db.appid = String (appid ? appid : "");
1842     else {
1843         LOGE ("pkgmgrinfo_appinfo_get_appid failed! error code=%d", ret);
1844         return 0;
1845     }
1846
1847     ime_db.iconpath = "";
1848
1849     /* pkgid */
1850     ret = pkgmgrinfo_appinfo_get_pkgid (handle, &pkgid);
1851     if (ret == PMINFO_R_OK)
1852         ime_db.pkgid = String (pkgid ? pkgid : "");
1853     else {
1854         LOGE ("pkgmgrinfo_appinfo_get_pkgid failed! error code=%d", ret);
1855         return 0;
1856     }
1857
1858     /* exec path */
1859     ret = pkgmgrinfo_appinfo_get_exec (handle, &exec);
1860     if (ret == PMINFO_R_OK)
1861         ime_db.exec = String (exec ? exec : "");
1862     else {
1863         LOGE ("pkgmgrinfo_appinfo_get_exec failed! error code=%d", ret);
1864         return 0;
1865     }
1866
1867     /* label */
1868     ret = pkgmgrinfo_appinfo_get_label (handle, &label);
1869     if (ret == PMINFO_R_OK)
1870         ime_db.label = String (label ? label : "");
1871
1872     /* get pkgmgrinfo_pkginfo_h */
1873     /* Try to get in global packages */
1874     ret = pkgmgrinfo_pkginfo_get_pkginfo (pkgid, &pkginfo_handle);
1875     if (ret != PMINFO_R_OK) {
1876         /* Try to get in user packages */
1877         ret = pkgmgrinfo_pkginfo_get_usr_pkginfo (pkgid, getuid (), &pkginfo_handle);
1878     }
1879
1880     if (ret == PMINFO_R_OK && pkginfo_handle) {
1881         /* pkgtype */
1882         ret = pkgmgrinfo_pkginfo_get_type (pkginfo_handle, &pkgtype);
1883
1884         if (ret == PMINFO_R_OK)
1885             ime_db.pkgtype = String (pkgtype ? pkgtype : "");
1886         else {
1887             ISF_SAVE_LOG ("pkgtype is not available!");
1888             pkgmgrinfo_pkginfo_destroy_pkginfo (pkginfo_handle);
1889             return 0;
1890         }
1891
1892         /* pkgrootpath */
1893         pkgmgrinfo_pkginfo_get_root_path (pkginfo_handle, &path);
1894     }
1895
1896     ime_db.languages = "en";
1897     ime_db.display_lang = "";
1898
1899     if (ime_db.pkgtype.compare ("rpm") == 0 &&   //1 Inhouse IMEngine ISE(IME)
1900         ime_db.exec.find ("scim-launcher") != String::npos)  // Some IMEngine's pkgid doesn't have "ise-engine" prefix.
1901     {
1902         ime_db.mode = TOOLBAR_KEYBOARD_MODE;
1903         ime_db.options = 0;
1904         ime_db.module_path = String (SCIM_MODULE_PATH) + String (SCIM_PATH_DELIM_STRING) + String (SCIM_BINARY_VERSION)
1905             + String (SCIM_PATH_DELIM_STRING) + String ("IMEngine");
1906         ime_db.module_name = ime_db.pkgid;
1907         ime_db.is_enabled = 1;
1908         ime_db.is_preinstalled = 1;
1909         ime_db.has_option = 0; // It doesn't matter. No option for IMEngine...
1910     }
1911     else {
1912         ime_db.mode = TOOLBAR_HELPER_MODE;
1913         if (ime_db.pkgtype.compare ("rpm") == 0 && path) //1 Inhouse Helper ISE(IME)
1914         {
1915             if (_TV)
1916                 ime_db.options = SCIM_HELPER_STAND_ALONE | SCIM_HELPER_NEED_SCREEN_INFO | SCIM_HELPER_AUTO_RESTART | ISM_HELPER_PROCESS_KEYBOARD_KEYEVENT;
1917             else
1918                 ime_db.options = SCIM_HELPER_STAND_ALONE | SCIM_HELPER_NEED_SCREEN_INFO | SCIM_HELPER_AUTO_RESTART;
1919
1920             ime_db.module_name = ime_db.pkgid;
1921
1922             String module_path = String (path) + String ("/lib");
1923             String fullpath = module_path + String (SCIM_PATH_DELIM_STRING) + ime_db.module_name + String (".so");
1924             struct stat st;
1925             if (stat (fullpath.c_str (), &st) < 0) {
1926                 /* Not found in lib directory of package's root path */
1927                 ime_db.module_path = String (SCIM_MODULE_PATH) + String (SCIM_PATH_DELIM_STRING) + String (SCIM_BINARY_VERSION)
1928                     + String (SCIM_PATH_DELIM_STRING) + String ("Helper");
1929             }
1930             else {
1931                 ime_db.module_path = module_path;
1932             }
1933
1934             ime_db.is_enabled = 1;
1935             ime_db.is_preinstalled = 1;
1936             ime_db.has_option = 1;  // Let's assume the inhouse IME always has an option menu.
1937         }
1938         else if (ime_db.pkgtype.compare ("wgt") == 0)    //1 Download Web IME
1939         {
1940             ime_db.options = SCIM_HELPER_STAND_ALONE | SCIM_HELPER_NEED_SCREEN_INFO | SCIM_HELPER_AUTO_RESTART
1941                 | SCIM_HELPER_NEED_SPOT_LOCATION_INFO | ISM_HELPER_PROCESS_KEYBOARD_KEYEVENT | ISM_HELPER_WITHOUT_IMENGINE;
1942             ime_db.module_path = String (SCIM_MODULE_PATH) + String (SCIM_PATH_DELIM_STRING) + String (SCIM_BINARY_VERSION)
1943                 + String (SCIM_PATH_DELIM_STRING) + String ("Helper");
1944             ime_db.module_name = String ("ise-web-helper-agent");
1945             if (ime_db.exec.compare (0, 5, "/usr/") == 0) {
1946                 ime_db.is_enabled = 1;
1947                 ime_db.is_preinstalled = 1;
1948             }
1949             else {
1950                 if (_MOBILE)
1951                     ime_db.is_enabled = 0;
1952                 else
1953                     ime_db.is_enabled = 1;
1954
1955                 ime_db.is_preinstalled = 0;
1956             }
1957             ime_db.has_option = -1; // At this point, we can't know IME has an option (setting) or not; -1 means unknown.
1958         }
1959         else if (ime_db.pkgtype.compare ("tpk") == 0)    //1 Download Native IME
1960         {
1961             ime_db.options = SCIM_HELPER_STAND_ALONE | SCIM_HELPER_NEED_SCREEN_INFO | SCIM_HELPER_AUTO_RESTART
1962                 | ISM_HELPER_PROCESS_KEYBOARD_KEYEVENT | ISM_HELPER_WITHOUT_IMENGINE;
1963             if (path)
1964                 ime_db.module_path = String (path) + String ("/lib");
1965             else
1966                 ime_db.module_path = String (tzplatform_getenv(TZ_SYS_RW_APP)) + ime_db.pkgid + String ("/lib");
1967             ime_db.module_name = String ("lib") + ime_db.exec.substr (ime_db.exec.find_last_of (SCIM_PATH_DELIM) + 1);
1968             if (ime_db.exec.compare (0, 5, "/usr/") == 0) {
1969                 ime_db.is_enabled = 1;
1970                 ime_db.is_preinstalled = 1;
1971             }
1972             else {
1973                 if (_MOBILE)
1974                     ime_db.is_enabled = 0;
1975                 else
1976                     ime_db.is_enabled = 1;
1977
1978                 ime_db.is_preinstalled = 0;
1979             }
1980             ime_db.has_option = -1; // At this point, we can't know IME has an option (setting) or not; -1 means unknown.
1981         }
1982         else {
1983             LOGE ("Unsupported pkgtype(%s)", ime_db.pkgtype.c_str ());
1984             if (pkginfo_handle) {
1985                 pkgmgrinfo_pkginfo_destroy_pkginfo (pkginfo_handle);
1986                 pkginfo_handle = NULL;
1987             }
1988             return 0;
1989         }
1990     }
1991
1992     _ime_info.push_back(ime_db);
1993
1994     if (pkginfo_handle) {
1995         pkgmgrinfo_pkginfo_destroy_pkginfo (pkginfo_handle);
1996         pkginfo_handle = NULL;
1997     }
1998
1999     return 0;
2000 }
2001 #endif
2002
2003 /**
2004  * @brief Set active ISE.
2005  *
2006  * @param uuid The ISE's uuid.
2007  * @param launch_ise The flag for launching helper ISE.
2008  *
2009  * @return false if ISE change is failed, otherwise return true.
2010  */
2011 static bool set_active_ise (const String &uuid, bool launch_ise)
2012 {
2013     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2014     LOGD ("set ISE (%s) %d", uuid.c_str(), launch_ise);
2015
2016     if (uuid.length () <= 0)
2017         return false;
2018
2019     bool ise_changed = false, valid = false;
2020
2021     int ime_num = -1; /* If we failed retrieving the number of IMEs installed, assume we need to clear IME related settings */
2022     pkgmgrinfo_appinfo_filter_h handle;
2023     int ret = pkgmgrinfo_appinfo_filter_create(&handle);
2024     if (ret == PMINFO_R_OK) {
2025         ret = pkgmgrinfo_appinfo_filter_add_string(handle, PMINFO_APPINFO_PROP_APP_CATEGORY, "http://tizen.org/category/ime");
2026         if (ret == PMINFO_R_OK) {
2027             ret = pkgmgrinfo_appinfo_filter_count(handle, &ime_num);
2028             if (ret != PMINFO_R_OK) {
2029                 LOGW("pkgmgrinfo_appinfo_filter_count failed(%d)", ret);
2030             }
2031         }
2032         pkgmgrinfo_appinfo_filter_destroy (handle);
2033     }
2034     else {
2035         LOGE ("pkgmgrinfo_appinfo_filter_create failed(%d)", ret);
2036     }
2037
2038     /* If the ime_num and _ime_info.size() are different, it is likely that the isf-panel-efl was
2039        terminated abnormally while processing package manager's install / uninstall events */
2040     LOGD("Checking whether db file needs to be re-created : %d %d", ime_num, _ime_info.size());
2041     if (ime_num != (int)_ime_info.size()) {
2042         _ime_info.clear();
2043         isf_db_delete_ime_info();
2044         isf_pkg_reload_ime_info_db();
2045         isf_pkg_select_all_ime_info_db(_ime_info);
2046     }
2047
2048     if (_ime_info.size () == 0) {
2049 #ifdef HAVE_PKGMGR_INFO
2050         int ret = pkgmgrinfo_appinfo_filter_create (&handle);
2051         if (ret == PMINFO_R_OK) {
2052             ret = pkgmgrinfo_appinfo_filter_add_string (handle, PMINFO_APPINFO_PROP_APP_CATEGORY, "http://tizen.org/category/ime");
2053             if (ret == PMINFO_R_OK)
2054                 ret = pkgmgrinfo_appinfo_filter_foreach_appinfo (handle, get_ime_app_list_cb, NULL);
2055             else {
2056                 LOGE ("pkgmgrinfo_appinfo_filter_add_string failed(%d)", ret);
2057             }
2058             pkgmgrinfo_appinfo_filter_destroy (handle);
2059         }
2060         else {
2061             LOGE ("pkgmgrinfo_appinfo_filter_create failed(%d)", ret);
2062         }
2063 #endif
2064     }
2065
2066     for (unsigned int i = 0; i < _ime_info.size (); i++) {
2067         if (!uuid.compare (_ime_info[i].appid)) {
2068             if (TOOLBAR_KEYBOARD_MODE == _ime_info[i].mode)
2069                 ise_changed = set_keyboard_ise (_ime_info[i].appid);
2070             else if (TOOLBAR_HELPER_MODE == _ime_info[i].mode) {
2071                 if (_ime_info[i].is_enabled) {
2072                     if (_ime_info[i].exec == String (SCIM_HELPER_LAUNCHER_PROGRAM)) {
2073                         /* If IME so is deleted somehow, main() in scim_helper_launcher.cpp will return -1.
2074                            Checking HelperModule validity seems necessary here. */
2075                         HelperModule helper_module (_ime_info[i].module_name);
2076                         if (helper_module.valid ())
2077                             valid = true;
2078                         helper_module.unload ();
2079                     }
2080                     else {
2081                         /* executable type */
2082                         valid = true;
2083                     }
2084
2085                     if (valid)
2086                         ise_changed = set_helper_ise (_ime_info[i].appid, launch_ise);
2087                     else
2088                         LOGW ("Helper ISE(appid=\"%s\",module_name=\"%s\") is not valid.", _ime_info[i].appid.c_str (), _ime_info[i].module_name.c_str ());
2089                 }
2090                 else {
2091                     LOGW ("Helper ISE(appid=\"%s\") is not enabled.", _ime_info[i].appid.c_str ());
2092                 }
2093             }
2094             _info_manager->set_current_toolbar_mode (_ime_info[i].mode);
2095             if (ise_changed) {
2096                 /* From Tizen 4.0 all the ISEs need to handle H/W keyboard events */
2097                 _ime_info[i].options |= ISM_HELPER_PROCESS_KEYBOARD_KEYEVENT;
2098                 _info_manager->set_current_helper_option (_ime_info[i].options);
2099                 _info_manager->set_current_ise_name (_ime_info[i].label);
2100                 _ise_width  = 0;
2101                 _ise_height = 0;
2102                 _ise_state  = WINDOW_STATE_HIDE;
2103                 _candidate_mode      = SOFT_CANDIDATE_WINDOW;
2104                 _candidate_port_line = ONE_LINE_CANDIDATE;
2105                 _soft_candidate_width = 0;
2106                 _soft_candidate_height = 0;
2107 #if ISF_BUILD_CANDIDATE_UI
2108                 if (_candidate_window)
2109                     ui_create_candidate_window ();
2110 #endif
2111
2112                 scim_global_config_write (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), _ime_info[i].appid);
2113                 scim_global_config_flush ();
2114
2115                 _config->flush ();
2116                 _config->reload ();
2117
2118 #ifdef HAVE_VCONF
2119                 vconf_set_str (VCONFKEY_ISF_ACTIVE_KEYBOARD_UUID, uuid.c_str ());
2120 #endif
2121             }
2122             else {
2123                 LOGW ("Failed to launch IME (%s)", uuid.c_str ());
2124             }
2125
2126             return ise_changed;
2127         }
2128     }
2129
2130     LOGW ("Failed to launch IME (%s), %d", uuid.c_str (), _ime_info.size());
2131
2132     return false;
2133 }
2134
2135 /**
2136  * @brief Set temporary ISE.
2137  *
2138  * @param uuid The ISE's uuid.
2139  *
2140  * @return false if ISE change is failed, otherwise return true.
2141  */
2142 static bool set_temporary_ise (const String &uuid)
2143 {
2144     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2145     LOGD ("set temporary ISE (%s)", uuid.c_str ());
2146
2147     if (uuid.length () <= 0)
2148         return false;
2149
2150     if (_ime_info.size () == 0) {
2151 #ifdef HAVE_PKGMGR_INFO
2152         pkgmgrinfo_appinfo_filter_h handle;
2153         int ret = pkgmgrinfo_appinfo_filter_create (&handle);
2154         if (ret == PMINFO_R_OK) {
2155             /* Add the package info for the IME that matches with our uuid only */
2156             ret = pkgmgrinfo_appinfo_filter_add_string (handle, PMINFO_APPINFO_PROP_APP_ID, uuid.c_str ());
2157             if (ret == PMINFO_R_OK)
2158                 ret = pkgmgrinfo_appinfo_filter_foreach_appinfo (handle, get_ime_app_list_cb, NULL);
2159             else {
2160                 LOGE ("pkgmgrinfo_appinfo_filter_add_string failed(%d)", ret);
2161             }
2162             pkgmgrinfo_appinfo_filter_destroy (handle);
2163         } else {
2164             LOGE ("pkgmgrinfo_appinfo_filter_create failed(%d)", ret);
2165         }
2166 #endif
2167     }
2168
2169 #ifdef HAVE_PKGMGR_INFO
2170     bool ise_changed = false;
2171
2172     pkgmgrinfo_appinfo_h handle = NULL;
2173     int ret = pkgmgr_get_appinfo (uuid.c_str (), &handle);
2174     if (ret != PMINFO_R_OK) {
2175         LOGW ("appid \"%s\" is invalid.", uuid.c_str ());
2176         return false;
2177     }
2178
2179     if (handle) {
2180         char *label = NULL;
2181         ret = pkgmgrinfo_appinfo_get_label (handle, &label);
2182         if (ret != PMINFO_R_OK) {
2183             LOGW ("Could not get label for appid '%s'", uuid.c_str ());
2184             pkgmgrinfo_appinfo_destroy_appinfo (handle);
2185             return false;
2186         }
2187
2188         ise_changed = set_helper_ise (uuid, true);
2189
2190         if (ise_changed) {
2191             _info_manager->set_current_toolbar_mode (TOOLBAR_HELPER_MODE);
2192             if (_TV)
2193                 _info_manager->set_current_helper_option (SCIM_HELPER_STAND_ALONE | SCIM_HELPER_NEED_SCREEN_INFO |
2194                     SCIM_HELPER_AUTO_RESTART | ISM_HELPER_PROCESS_KEYBOARD_KEYEVENT);
2195             else
2196                 _info_manager->set_current_helper_option (SCIM_HELPER_STAND_ALONE | SCIM_HELPER_NEED_SCREEN_INFO |
2197                     SCIM_HELPER_AUTO_RESTART);
2198             String label_string = label;
2199             _info_manager->set_current_ise_name (label_string);
2200
2201 #ifdef HAVE_VCONF
2202             vconf_set_str (VCONFKEY_ISF_ACTIVE_KEYBOARD_UUID, uuid.c_str ());
2203 #endif
2204         } else {
2205             LOGW ("Failed to launch IME (%s)", uuid.c_str ());
2206         }
2207
2208         pkgmgrinfo_appinfo_destroy_appinfo (handle);
2209
2210         return ise_changed;
2211     }
2212 #endif
2213
2214     return false;
2215 }
2216
2217 /**
2218  * @brief Load ISF configuration and ISEs information.
2219  */
2220 static void load_config (void)
2221 {
2222     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2223
2224     /* Read configurations. */
2225     if (!_config.null ()) {
2226         bool shared_ise = _config->read (String (SCIM_CONFIG_FRONTEND_SHARED_INPUT_METHOD), false);
2227         _info_manager->set_should_shared_ise (shared_ise);
2228     }
2229     _launch_ise_on_request = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_LAUNCH_ISE_ON_REQUEST), _launch_ise_on_request);
2230     _auto_destroy_ise = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_ENABLE_AUTO_DESTROY_ISE), _auto_destroy_ise);
2231
2232     isf_load_ise_information (ALL_ISE, _config);
2233 }
2234
2235 /**
2236  * @brief Reload config callback function for ISF panel.
2237  *
2238  * @param config The config pointer.
2239  */
2240 static void config_reload_cb (const ConfigPointer &config)
2241 {
2242     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2243     /* load_config (); */
2244     _info_manager->reload_config ();
2245 }
2246
2247 #if ISF_BUILD_CANDIDATE_UI
2248 //////////////////////////////////////////////////////////////////////
2249 // Start of Candidate Functions
2250 //////////////////////////////////////////////////////////////////////
2251 /**
2252  * @brief Get candidate window valid height for autoscroll.
2253  *
2254  * @return The valid height.
2255  */
2256 static int ui_candidate_get_valid_height (void)
2257 {
2258     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "\n";
2259
2260     int height = 0;
2261     int angle = 0;
2262
2263     if (_candidate_window) {
2264         if (_candidate_state == WINDOW_STATE_SHOW)
2265             angle = _candidate_angle;
2266         else
2267             angle = efl_get_app_window_angle ();
2268
2269         if (_aux_area_visible && _candidate_area_1_visible) {
2270             if (angle == 90 || angle == 270)
2271                 height = _candidate_land_height_min_2;
2272             else
2273                 height = _candidate_port_height_min_2;
2274         } else {
2275             if (angle == 90 || angle == 270)
2276                 height = _candidate_land_height_min;
2277             else
2278                 height = _candidate_port_height_min;
2279         }
2280     }
2281     return height;
2282 }
2283
2284 /**
2285  * @brief Resize candidate window size.
2286  *
2287  * @param new_width  New width for candidate window.
2288  * @param new_height New height for candidate window.
2289  */
2290 static void ui_candidate_window_resize (int new_width, int new_height)
2291 {
2292     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " width:" << new_width << " height:" << new_height << "\n";
2293
2294     if (!_candidate_window)
2295         return;
2296
2297     int height;
2298
2299     LOGD ("%s (w: %d, h: %d)", __func__, new_width, new_height);
2300     evas_object_resize (_aux_line, new_width, 2);
2301     _candidate_width  = new_width;
2302     _candidate_height = new_height;
2303     if (_candidate_state == WINDOW_STATE_SHOW)
2304         _info_manager->update_candidate_panel_event ((uint32)ECORE_IMF_CANDIDATE_PANEL_GEOMETRY_EVENT, 0);
2305
2306     if (_candidate_state == WINDOW_STATE_SHOW && _candidate_mode == FIXED_CANDIDATE_WINDOW) {
2307         height = ui_candidate_get_valid_height ();
2308         if ((_ise_width == 0 && _ise_height == 0) ||
2309             (_ise_height > 0 && _candidate_valid_height != height) ||
2310             (_ise_height > 0 && (_candidate_height - height) > _ise_height) ||
2311             ((_candidate_angle == 90 || _candidate_angle == 270) && (_ise_width < _screen_height)) ||
2312             ((_candidate_angle == 0  || _candidate_angle == 180) && (_ise_width > _screen_width ))) {
2313 #ifdef HAVE_ECOREX
2314             set_keyboard_geometry_atom_info (_app_window, get_ise_geometry ());
2315 #endif
2316             _info_manager->update_input_panel_event (ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
2317         }
2318     }
2319
2320     /* Get height for portrait and landscape */
2321     int port_width  = _candidate_port_width;
2322     int port_height = _candidate_port_height_min;
2323     int land_width  = _candidate_land_width;
2324     int land_height = _candidate_land_height_min;
2325     if (_candidate_angle == 90 || _candidate_angle == 270) {
2326         land_height = new_height;
2327         if (land_height == _candidate_land_height_min_2) {
2328             port_height = _candidate_port_height_min_2;
2329         } else if (land_height == _candidate_land_height_max) {
2330             port_height = _candidate_port_height_max;
2331         } else if (land_height == _candidate_land_height_max_2) {
2332             port_height = _candidate_port_height_max_2;
2333         }
2334     } else {
2335         port_height = new_height;
2336         if (port_height == _candidate_port_height_min_2) {
2337             land_height = _candidate_land_height_min_2;
2338         } else if (port_height == _candidate_port_height_max) {
2339             land_height = _candidate_land_height_max;
2340         } else if (port_height == _candidate_port_height_max_2) {
2341             land_height = _candidate_land_height_max_2;
2342         }
2343     }
2344
2345     LOGD ("window_rotation_geometry_set (_candidate_window), port (%d, %d), land (%d, %d)",
2346             port_width, port_height, land_width, land_height);
2347
2348 #ifdef HAVE_ECOREX
2349     /*
2350     ecore_x_e_window_rotation_geometry_set (elm_win_xwindow_get (_candidate_window),
2351             0, 0, 0, port_width, port_height);
2352     ecore_x_e_window_rotation_geometry_set (elm_win_xwindow_get (_candidate_window),
2353             90, 0, 0, land_height, land_width);
2354     ecore_x_e_window_rotation_geometry_set (elm_win_xwindow_get (_candidate_window),
2355             180, 0, 0, port_width, port_height);
2356     ecore_x_e_window_rotation_geometry_set (elm_win_xwindow_get (_candidate_window),
2357             270, 0, 0, land_height, land_width);
2358     */
2359 #else
2360     ecore_wl2_window_rotation_geometry_set ((Ecore_Wl2_Window *)elm_win_wl_window_get (_candidate_window),
2361             0, 0, 0, port_width, port_height);
2362     ecore_wl2_window_rotation_geometry_set ((Ecore_Wl2_Window *)elm_win_wl_window_get (_candidate_window),
2363             90, 0, 0, land_height, land_width);
2364     ecore_wl2_window_rotation_geometry_set ((Ecore_Wl2_Window *)elm_win_wl_window_get (_candidate_window),
2365             180, 0, 0, port_width, port_height);
2366     ecore_wl2_window_rotation_geometry_set ((Ecore_Wl2_Window *)elm_win_wl_window_get (_candidate_window),
2367             270, 0, 0, land_height, land_width);
2368 #endif
2369 }
2370
2371 /**
2372  * @brief This function will show/hide widgets of candidate window,
2373  *        and resize candidate window size according to aux_area/candidate_area.
2374  */
2375 static void ui_candidate_window_adjust (void)
2376 {
2377     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2378     if (!_candidate_window)
2379         return;
2380
2381     int x = 0, y = 0, width = 0, height = 0;
2382
2383     /* Get candidate window size */
2384 #ifdef HAVE_ECOREX
2385     /*
2386     if (_candidate_angle == 90 || _candidate_angle == 270) {
2387         ecore_x_e_window_rotation_geometry_get (elm_win_xwindow_get (_candidate_window), _candidate_angle,
2388                 &x, &y, &height, &width);
2389     } else {
2390         ecore_x_e_window_rotation_geometry_get (elm_win_xwindow_get (_candidate_window), _candidate_angle,
2391                 &x, &y, &width, &height);
2392     }
2393     */
2394 #else
2395     if (_candidate_angle == 90 || _candidate_angle == 270)
2396         ecore_evas_geometry_get (ecore_evas_ecore_evas_get (evas_object_evas_get (_candidate_window)), &x, &y, &height, &width);
2397     else
2398         ecore_evas_geometry_get (ecore_evas_ecore_evas_get (evas_object_evas_get (_candidate_window)), &x, &y, &width, &height);
2399 #endif
2400
2401     if (_aux_area_visible && _candidate_area_2_visible) {
2402         evas_object_show (_aux_line);
2403         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);
2404         if (_candidate_angle == 90 || _candidate_angle == 270) {
2405             if (_candidate_mode == FIXED_CANDIDATE_WINDOW && _ise_state == WINDOW_STATE_SHOW &&
2406                 _ise_height > _candidate_land_height_max_2 - _candidate_land_height_min_2)
2407                 ui_candidate_window_resize (width, _candidate_land_height_min_2 + _ise_height);
2408             else
2409                 ui_candidate_window_resize (width, _candidate_land_height_max_2);
2410             evas_object_move (_close_btn, _close_btn_pos[2], _close_btn_pos[3] + _candidate_port_height_min_2 - _candidate_port_height_min);
2411             evas_object_move (_candidate_area_2, 0, _candidate_land_height_min_2);
2412             evas_object_move (_scroller_bg, 0, _candidate_land_height_min_2);
2413             evas_object_resize (_candidate_bg, width, _candidate_land_height_min_2);
2414         } else {
2415             if (_candidate_mode == FIXED_CANDIDATE_WINDOW && _ise_state == WINDOW_STATE_SHOW &&
2416                 _ise_height > _candidate_port_height_max_2 - _candidate_port_height_min_2)
2417                 ui_candidate_window_resize (width, _candidate_port_height_min_2 + _ise_height);
2418             else
2419                 ui_candidate_window_resize (width, _candidate_port_height_max_2);
2420             evas_object_move (_close_btn, _close_btn_pos[0], _close_btn_pos[1] + _candidate_port_height_min_2 - _candidate_port_height_min);
2421             evas_object_move (_candidate_area_2, 0, _candidate_port_height_min_2);
2422             evas_object_move (_scroller_bg, 0, _candidate_port_height_min_2);
2423             evas_object_resize (_candidate_bg, width, _candidate_port_height_min_2);
2424         }
2425     } else if (_aux_area_visible && _candidate_area_1_visible) {
2426         evas_object_show (_aux_line);
2427         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);
2428         if (_candidate_angle == 90 || _candidate_angle == 270) {
2429             ui_candidate_window_resize (width, _candidate_land_height_min_2);
2430             evas_object_move (_more_btn, _more_btn_pos[2], _more_btn_pos[3] + _candidate_port_height_min_2 - _candidate_port_height_min);
2431             evas_object_resize (_candidate_bg, width, _candidate_land_height_min_2);
2432         } else {
2433             ui_candidate_window_resize (width, _candidate_port_height_min_2);
2434             evas_object_move (_more_btn, _more_btn_pos[0], _more_btn_pos[1] + _candidate_port_height_min_2 - _candidate_port_height_min);
2435             evas_object_resize (_candidate_bg, width, _candidate_port_height_min_2);
2436         }
2437     } else if (_aux_area_visible) {
2438         evas_object_hide (_aux_line);
2439         ui_candidate_window_resize (width, _aux_height + 2);
2440         evas_object_resize (_candidate_bg, width, _aux_height + 2);
2441     } else if (_candidate_area_2_visible) {
2442         evas_object_hide (_aux_line);
2443         evas_object_move (_candidate_area_1, _candidate_area_1_pos[0], _candidate_area_1_pos[1]);
2444         if (_candidate_angle == 90 || _candidate_angle == 270) {
2445             if (_candidate_mode == FIXED_CANDIDATE_WINDOW && _ise_state == WINDOW_STATE_SHOW &&
2446                 _ise_height > _candidate_land_height_max - _candidate_land_height_min)
2447                 ui_candidate_window_resize (width, _candidate_land_height_min + _ise_height);
2448             else
2449                 ui_candidate_window_resize (width, _candidate_land_height_max);
2450             evas_object_move (_close_btn, _close_btn_pos[2], _close_btn_pos[3]);
2451             evas_object_move (_candidate_area_2, 0, _candidate_land_height_min);
2452             evas_object_move (_scroller_bg, 0, _candidate_land_height_min);
2453             evas_object_resize (_candidate_bg, width, _candidate_land_height_min);
2454         } else {
2455             if (_candidate_mode == FIXED_CANDIDATE_WINDOW && _ise_state == WINDOW_STATE_SHOW &&
2456                 _ise_height > _candidate_port_height_max - _candidate_port_height_min)
2457                 ui_candidate_window_resize (width, _candidate_port_height_min + _ise_height);
2458             else
2459                 ui_candidate_window_resize (width, _candidate_port_height_max);
2460             evas_object_move (_close_btn, _close_btn_pos[0], _close_btn_pos[1]);
2461             evas_object_move (_candidate_area_2, 0, _candidate_port_height_min);
2462             evas_object_move (_scroller_bg, 0, _candidate_port_height_min);
2463             evas_object_resize (_candidate_bg, width, _candidate_port_height_min);
2464         }
2465     } else {
2466         evas_object_hide (_aux_line);
2467         evas_object_move (_candidate_area_1, _candidate_area_1_pos[0], _candidate_area_1_pos[1]);
2468         if (_candidate_angle == 90 || _candidate_angle == 270) {
2469             ui_candidate_window_resize (width, _candidate_land_height_min);
2470             evas_object_move (_more_btn, _more_btn_pos[2], _more_btn_pos[3]);
2471             evas_object_resize (_candidate_bg, width, _candidate_land_height_min);
2472         } else {
2473             ui_candidate_window_resize (width, _candidate_port_height_min);
2474             evas_object_move (_more_btn, _more_btn_pos[0], _more_btn_pos[1]);
2475             evas_object_resize (_candidate_bg, width, _candidate_port_height_min);
2476         }
2477     }
2478 }
2479
2480 /**
2481  * @brief Rotate candidate window.
2482  *
2483  * @param angle The angle of candidate window.
2484  */
2485 static void ui_candidate_window_rotate (int angle)
2486 {
2487     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2488     if (!_candidate_window)
2489         return;
2490
2491     ui_candidate_window_close_button_cb (NULL, NULL, NULL, NULL);
2492
2493     if (angle == 90 || angle == 270) {
2494         _candidate_scroll_width = _candidate_scroll_width_max;
2495         ui_candidate_window_resize (_candidate_land_width, _candidate_land_height_min);
2496         evas_object_resize (_aux_area, _aux_land_width, _aux_height);
2497         evas_object_resize (_candidate_area_1, _candidate_scroll_0_width_max, _item_min_height);
2498         evas_object_resize (_candidate_area_2, _candidate_scroll_width, _candidate_scroll_height_min);
2499         evas_object_resize (_scroller_bg, _candidate_scroll_width, _candidate_scroll_height_min + 6);
2500     } else {
2501         _candidate_scroll_width = _candidate_scroll_width_min;
2502         ui_candidate_window_resize (_candidate_port_width, _candidate_port_height_min);
2503         evas_object_resize (_aux_area, _aux_port_width, _aux_height);
2504         evas_object_resize (_candidate_area_1, _candidate_scroll_0_width_min, (_item_min_height+2)*_candidate_port_line-2);
2505         evas_object_resize (_candidate_area_2, _candidate_scroll_width, _candidate_scroll_height_max);
2506         evas_object_resize (_scroller_bg, _candidate_scroll_width, _candidate_scroll_height_max + 6);
2507     }
2508
2509     evas_object_hide (_candidate_area_2);
2510     _candidate_area_2_visible = false;
2511     ui_candidate_window_adjust ();
2512     if (_candidate_area_1_visible) {
2513         update_table (ISF_CANDIDATE_TABLE, g_isf_candidate_table);
2514         _candidate_tts_focus_index = INVALID_TTS_FOCUS_INDEX;
2515         ui_tts_focus_rect_hide ();
2516     }
2517     flush_memory ();
2518 }
2519
2520 /**
2521  * @brief This function is used to judge whether candidate window should be hidden.
2522  *
2523  * @return true if candidate window should be hidden, otherwise return false.
2524  */
2525 static bool ui_candidate_can_be_hide (void)
2526 {
2527     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2528
2529     if (_aux_area_visible || _candidate_area_1_visible || _candidate_area_2_visible)
2530         return false;
2531     else
2532         return true;
2533 }
2534
2535 /**
2536  * @brief Delete check candidate window size timer.
2537  *
2538  * @return void
2539  */
2540 static void ui_candidate_delete_check_size_timer (void)
2541 {
2542     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2543
2544     if (_check_size_timer != NULL) {
2545         ecore_timer_del (_check_size_timer);
2546         _check_size_timer = NULL;
2547     }
2548 }
2549
2550 /**
2551  * @brief Callback function for check candidate window size timer.
2552  *
2553  * @param data Data to pass when it is called.
2554  *
2555  * @return ECORE_CALLBACK_CANCEL
2556  */
2557 static Eina_Bool ui_candidate_check_size_timeout (void *data)
2558 {
2559     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2560
2561     ui_candidate_delete_check_size_timer ();
2562     ui_candidate_window_resize (_candidate_width, _candidate_height);
2563     ui_settle_candidate_window ();
2564     return ECORE_CALLBACK_CANCEL;
2565 }
2566
2567 /**
2568  * @brief Delete longpress timer.
2569  *
2570  * @return void
2571  */
2572 static void ui_candidate_delete_longpress_timer (void)
2573 {
2574     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2575
2576     if (_longpress_timer != NULL) {
2577         ecore_timer_del (_longpress_timer);
2578         _longpress_timer = NULL;
2579     }
2580 }
2581
2582 /**
2583  * @brief Callback function for candidate longpress timer.
2584  *
2585  * @param data Data to pass when it is called.
2586  *
2587  * @return ECORE_CALLBACK_CANCEL
2588  */
2589 static Eina_Bool ui_candidate_longpress_timeout (void *data)
2590 {
2591     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2592
2593     int index = (int)GPOINTER_TO_INT (data);
2594     ui_candidate_delete_longpress_timer ();
2595     _is_click = false;
2596     _info_manager->send_longpress_event (_click_object, index);
2597     return ECORE_CALLBACK_CANCEL;
2598 }
2599
2600 /**
2601  * @brief Delete destroy timer.
2602  *
2603  * @return void
2604  */
2605 static void ui_candidate_delete_destroy_timer (void)
2606 {
2607     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2608
2609     if (_destroy_timer != NULL) {
2610         ecore_timer_del (_destroy_timer);
2611         _destroy_timer = NULL;
2612     }
2613 }
2614
2615 /**
2616  * @brief Callback function for destroy timer.
2617  *
2618  * @param data Data to pass when it is called.
2619  *
2620  * @return ECORE_CALLBACK_CANCEL
2621  */
2622 static Eina_Bool ui_candidate_destroy_timeout (void *data)
2623 {
2624     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2625
2626     ui_candidate_delete_destroy_timer ();
2627     ui_destroy_candidate_window ();
2628     return ECORE_CALLBACK_CANCEL;
2629 }
2630 #endif /* CANDIDATE */
2631
2632 #ifdef HAVE_ECOREX
2633 /**
2634  * @brief Callback function for off_prepare_done.
2635  *
2636  * @param data Data to pass when it is called.
2637  *
2638  * @return ECORE_CALLBACK_CANCEL
2639  */
2640 static Eina_Bool off_prepare_done_timeout (void *data)
2641 {
2642     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2643
2644     /* WMSYNC, #8 Let the Window Manager to actually hide keyboard window */
2645     // WILL_HIDE_REQUEST_DONE Ack to WM
2646     Ecore_X_Window root_window = ecore_x_window_root_get (_control_window);
2647     //ecore_x_e_virtual_keyboard_off_prepare_done_send (root_window, _control_window);
2648     LOGD ("_ecore_x_e_virtual_keyboard_off_prepare_done_send (%x, %x)",
2649             root_window, _control_window);
2650     _off_prepare_done_timer = NULL;
2651
2652     return ECORE_CALLBACK_CANCEL;
2653 }
2654 #endif /* HAVE_ECOREX */
2655
2656 #if ISF_BUILD_CANDIDATE_UI
2657 /**
2658  * @brief Delete candidate hide timer.
2659  *
2660  * @return void
2661  */
2662 static void delete_candidate_hide_timer (void)
2663 {
2664     LOGD ("deleting candidate_hide_timer");
2665     if (_candidate_hide_timer) {
2666         ecore_timer_del (_candidate_hide_timer);
2667         _candidate_hide_timer = NULL;
2668     }
2669 }
2670
2671 static void candidate_window_hide (void)
2672 {
2673     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "\n";
2674
2675     delete_candidate_hide_timer ();
2676     _candidate_state = WINDOW_STATE_HIDE;
2677
2678     LOGD ("evas_object_hide (_candidate_window, %p)", elm_win_xwindow_get (_candidate_window));
2679
2680     if (_candidate_window) {
2681         /* There are cases that when there are rapid ISE_HIDE and ISE_SHOW requests,
2682            candidate window should be displayed but STATE_OFF for the first ISE_HIDE
2683            calls this function, so when the candidate window is shown by the following
2684            STATE_ON message, a blank area is displayed in candidate window -
2685            so we let the _candidate_area_1 as the default area that would be displayed */
2686         //evas_object_hide (_candidate_area_1);
2687         //evas_object_hide (_more_btn);
2688         _candidate_area_1_visible = false;
2689
2690         evas_object_hide (_candidate_window);
2691         SCIM_DEBUG_MAIN (3) << "    Hide candidate window\n";
2692     }
2693 }
2694
2695 /**
2696  * @brief Callback function for candidate hide timer
2697  *
2698  * @param data Data to pass when it is called.
2699  *
2700  * @return ECORE_CALLBACK_CANCEL
2701  */
2702 static Eina_Bool candidate_hide_timer (void *data)
2703 {
2704     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2705
2706     LOGD ("calling candidate_window_hide ()");
2707     candidate_window_hide ();
2708
2709     return ECORE_CALLBACK_CANCEL;
2710 }
2711
2712 #ifdef HAVE_ECOREX
2713 /**
2714  * @brief Delete candidate show handler.
2715  *
2716  * @return void
2717  */
2718 static void delete_candidate_show_handler (void)
2719 {
2720     if (_candidate_show_handler) {
2721         ecore_event_handler_del (_candidate_show_handler);
2722         _candidate_show_handler = NULL;
2723     }
2724 }
2725
2726 /**
2727  * @brief Callback function for window show completion event
2728  *
2729  * @param data Data to pass when it is called.
2730  *
2731  * @return ECORE_CALLBACK_CANCEL
2732  */
2733
2734 static Eina_Bool x_event_window_show_cb (void *data, int ev_type, void *event)
2735 {
2736     delete_candidate_show_handler ();
2737
2738     Ecore_X_Event_Window_Show *e = (Ecore_X_Event_Window_Show*)event;
2739     if (_candidate_state == WINDOW_STATE_WILL_SHOW) {
2740         if (e->win == elm_win_xwindow_get (_candidate_window)) {
2741             LOGD ("Candidate window show callback");
2742
2743             /* If our candidate window is in WILL_SHOW state and this show callback was called,
2744                now we are finally displayed on to the screen */
2745             _candidate_state = WINDOW_STATE_SHOW;
2746
2747             /* Update the geometry information for auto scrolling */
2748             set_keyboard_geometry_atom_info (_app_window, get_ise_geometry ());
2749             _info_manager->update_input_panel_event (ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
2750             _info_manager->update_input_panel_event (ECORE_IMF_CANDIDATE_PANEL_GEOMETRY_EVENT, 0);
2751
2752             /* And the state event */
2753             _info_manager->update_candidate_panel_event ((uint32)ECORE_IMF_CANDIDATE_PANEL_STATE_EVENT, (uint32)ECORE_IMF_CANDIDATE_PANEL_SHOW);
2754
2755             /* If we are in hardware keyboard mode, this candidate window is now considered to be a input panel */
2756             if (_candidate_mode == FIXED_CANDIDATE_WINDOW) {
2757                 if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) {
2758                     _info_manager->update_input_panel_event ((uint32)ECORE_IMF_INPUT_PANEL_STATE_EVENT, (uint32)ECORE_IMF_INPUT_PANEL_STATE_SHOW);
2759                 }
2760             }
2761         }
2762     } else {
2763         if (e->win == elm_win_xwindow_get (_candidate_window)) {
2764             LOGD ("Candidate window show callback, but _candidate_state is %d", _candidate_state);
2765         }
2766     }
2767
2768     return ECORE_CALLBACK_CANCEL;
2769 }
2770 #endif /* HAVE_ECOREX */
2771
2772 /**
2773  * @brief Show candidate window.
2774  *
2775  * @param bSetVirtualKbd The flag for set_keyboard_geometry_atom_info () calling.
2776  */
2777 static void ui_candidate_show (bool bSetVirtualKbd)
2778 {
2779     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2780
2781     delete_candidate_hide_timer ();
2782
2783     if (!_candidate_window) return;
2784     if (_candidate_mode == SOFT_CANDIDATE_WINDOW)
2785         return;
2786
2787     /* FIXME : SHOULD UNIFY THE METHOD FOR CHECKING THE HW KEYBOARD EXISTENCE */
2788     /* If the ISE is not visible currently, wait for the ISE to be opened and then show our candidate window */
2789     _candidate_show_requested = true;
2790     if ((_info_manager->get_current_toolbar_mode () == TOOLBAR_HELPER_MODE) && (_ise_state != WINDOW_STATE_SHOW)) {
2791         LOGD ("setting _show_candidate_requested to TRUE");
2792         return;
2793     }
2794
2795     /* If the ISE angle is valid, respect the value to make sure
2796        the candidate window always have the same angle with ISE */
2797     if (_ise_angle != -1) {
2798         _candidate_angle = _ise_angle;
2799     }
2800     ui_candidate_window_rotate (_candidate_angle);
2801
2802     /* If the candidate window was about to hide, turn it back to SHOW state now */
2803     if (_candidate_state == WINDOW_STATE_WILL_HIDE) {
2804         _candidate_state = WINDOW_STATE_SHOW;
2805     }
2806
2807     /* Change to WILL_SHOW state only when we are not currently in SHOW state */
2808     if (_candidate_state != WINDOW_STATE_SHOW) {
2809         _candidate_state = WINDOW_STATE_WILL_SHOW;
2810     }
2811
2812 #ifdef HAVE_ECOREX
2813     if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) {
2814         /* WMSYNC, #3 Clear the existing application's conformant area and set transient_for */
2815         // Unset conformant area
2816         Ecore_X_Window current_app_window = efl_get_app_window ();
2817         if (_app_window != current_app_window) {
2818             struct rectinfo info = {0, 0, 0, 0};
2819             info.pos_y = _screen_width > _screen_height ? _screen_width : _screen_height;
2820             set_keyboard_geometry_atom_info (_app_window, info);
2821             LOGD ("Conformant reset for window %x", _app_window);
2822             _app_window = current_app_window;
2823         }
2824     }
2825
2826     if (_candidate_mode == FIXED_CANDIDATE_WINDOW) {
2827         if (bSetVirtualKbd) {
2828             set_keyboard_geometry_atom_info (_app_window, get_ise_geometry ());
2829         }
2830     }
2831     efl_set_transient_for_app_window (elm_win_xwindow_get (_candidate_window));
2832 #endif
2833
2834     ui_candidate_delete_check_size_timer ();
2835     _check_size_timer = ecore_timer_add (0.02, ui_candidate_check_size_timeout, NULL);
2836
2837     SCIM_DEBUG_MAIN (3) << "    Show candidate window\n";
2838
2839     if (_ise_state == WINDOW_STATE_SHOW) {
2840         edje_object_file_set (_more_btn, _candidate_edje_file.c_str (), "more_button");
2841         edje_object_file_set (_close_btn, _candidate_edje_file.c_str (), "close_button");
2842     } else {
2843         edje_object_file_set (_more_btn, _candidate_edje_file.c_str (), "close_button");
2844         edje_object_file_set (_close_btn, _candidate_edje_file.c_str (), "more_button");
2845     }
2846
2847     /* If we are in hardware keyboard mode, this candidate window is now considered to be a input panel */
2848     if (_candidate_mode == FIXED_CANDIDATE_WINDOW) {
2849         if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) {
2850             LOGD ("sending ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW");
2851             _info_manager->update_input_panel_event ((uint32)ECORE_IMF_INPUT_PANEL_STATE_EVENT, (uint32)ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW);
2852         }
2853     }
2854
2855     if (_candidate_state != WINDOW_STATE_SHOW) {
2856 #ifdef HAVE_ECOREX
2857         if (_candidate_show_handler) {
2858             LOGD ("Was still waiting for CANDIDATE_WINDOW_SHOW....");
2859         } else {
2860             delete_candidate_show_handler ();
2861             LOGD ("Registering ECORE_X_EVENT_WINDOW_SHOW event, %d", _candidate_state);
2862             _candidate_show_handler = ecore_event_handler_add (ECORE_X_EVENT_WINDOW_SHOW, x_event_window_show_cb, NULL);
2863         }
2864 #endif
2865     } else {
2866         LOGD ("The candidate window was already in SHOW state, update geometry information");
2867         _info_manager->update_input_panel_event (ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
2868         _info_manager->update_input_panel_event (ECORE_IMF_CANDIDATE_PANEL_GEOMETRY_EVENT, 0);
2869
2870         /* And the state event */
2871         _info_manager->update_candidate_panel_event ((uint32)ECORE_IMF_CANDIDATE_PANEL_STATE_EVENT, (uint32)ECORE_IMF_CANDIDATE_PANEL_SHOW);
2872
2873         /* If we are in hardware keyboard mode, this candidate window is now considered to be a input panel */
2874         if (_candidate_mode == FIXED_CANDIDATE_WINDOW) {
2875             if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) {
2876                 _info_manager->update_input_panel_event ((uint32)ECORE_IMF_INPUT_PANEL_STATE_EVENT, (uint32)ECORE_IMF_INPUT_PANEL_STATE_SHOW);
2877             }
2878         }
2879     }
2880
2881     evas_object_show (_candidate_window);
2882 }
2883
2884 /**
2885  * @brief Hide candidate window.
2886  *
2887  * @param bForce The flag to hide candidate window by force.
2888  * @param bSetVirtualKbd The flag for set_keyboard_geometry_atom_info () calling.
2889  */
2890 static void ui_candidate_hide (bool bForce, bool bSetVirtualKbd, bool will_hide)
2891 {
2892     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " bForce:" << bForce << " bSetVirtualKbd:" << bSetVirtualKbd << " will_hide:" << will_hide << "...\n";
2893
2894     if (!_candidate_window)
2895         return;
2896
2897     if (bForce) {
2898         if (_candidate_area_2 && _candidate_area_2_visible) {
2899             evas_object_hide (_candidate_area_2);
2900             _candidate_area_2_visible = false;
2901             evas_object_hide (_scroller_bg);
2902             evas_object_hide (_close_btn);
2903             _info_manager->candidate_more_window_hide ();
2904             ui_candidate_window_adjust ();
2905         }
2906     }
2907
2908     if (bForce || ui_candidate_can_be_hide ()) {
2909         if (will_hide) {
2910             LOGD ("candidate_state = WILL_HIDE");
2911             _candidate_state = WINDOW_STATE_WILL_HIDE;
2912
2913             delete_candidate_hide_timer ();
2914             _candidate_hide_timer = ecore_timer_add (2.0, candidate_hide_timer, NULL);
2915         }
2916
2917         if (_candidate_mode == FIXED_CANDIDATE_WINDOW) {
2918             _info_manager->update_input_panel_event (ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
2919             /* FIXME : should check if bSetVirtualKbd flag is really needed in this case */
2920 #ifdef HAVE_ECOREX
2921             if (_ise_state == WINDOW_STATE_SHOW) {
2922                 set_keyboard_geometry_atom_info (_app_window, get_ise_geometry ());
2923             } else {
2924                 if (bSetVirtualKbd) {
2925                     set_keyboard_geometry_atom_info (_app_window, get_ise_geometry ());
2926                 }
2927             }
2928 #endif
2929             if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) {
2930                 _info_manager->update_input_panel_event
2931                     ((uint32)ECORE_IMF_INPUT_PANEL_STATE_EVENT, (uint32)ECORE_IMF_INPUT_PANEL_STATE_HIDE);
2932             }
2933         }
2934
2935         /* Update the new keyboard geometry first, and then send the candidate hide event */
2936         _info_manager->update_candidate_panel_event ((uint32)ECORE_IMF_CANDIDATE_PANEL_STATE_EVENT, (uint32)ECORE_IMF_CANDIDATE_PANEL_HIDE);
2937
2938         if (!will_hide) {
2939             /* If we are not in will_hide state, hide the candidate window immediately */
2940             candidate_window_hide ();
2941
2942             if (_preedit_window)
2943                 evas_object_hide (_preedit_window);
2944         }
2945     }
2946 }
2947
2948 /**
2949  * @brief Callback function for more button.
2950  *
2951  * @param data Data to pass when it is called.
2952  * @param e The evas for current event.
2953  * @param button The evas object for current event.
2954  * @param event_info The information for current event.
2955  */
2956 static void ui_candidate_window_more_button_cb (void *data, Evas *e, Evas_Object *button, void *event_info)
2957 {
2958     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
2959
2960     _info_manager->candidate_more_window_show ();
2961
2962     if (candidate_expanded == false) {
2963         candidate_expanded = true;
2964         int number = SCIM_LOOKUP_TABLE_MAX_PAGESIZE;
2965         for (int i = 0; i < SCIM_LOOKUP_TABLE_MAX_PAGESIZE; ++i) {
2966             if (_candidate_0 [i] == NULL) {
2967                 number = i;
2968                 break;
2969             }
2970         }
2971         if (g_isf_candidate_table.get_current_page_size () != number)
2972             update_table (ISF_CANDIDATE_TABLE, g_isf_candidate_table);
2973     }
2974
2975     if (_candidate_angle == 180) {
2976         Ecore_Evas *ee = ecore_evas_ecore_evas_get (evas_object_evas_get (_candidate_window));
2977         ecore_evas_move_resize (ee, 0, 0, 0, 0);
2978         LOGD ("ecore_evas_move_resize (%p, %d, %d, %d, %d)", ee, 0, 0, 0, 0);
2979     } else if (_candidate_mode == FIXED_CANDIDATE_WINDOW && _candidate_angle == 270) {
2980         /*
2981          * when screen rotate 270 degrees, candidate have to move then resize for expanding more
2982          * candidates, but it will flash or locate in a wrong position, this code just a workaround
2983          * for avoiding this situation.
2984          */
2985         Ecore_Evas *ee = ecore_evas_ecore_evas_get (evas_object_evas_get (_candidate_window));
2986         ecore_evas_move_resize (ee, 0, 0, _screen_height, ui_candidate_get_valid_height () + _ise_height);
2987         LOGD ("ecore_evas_move_resize (%p, %d, %d, %d, %d)",
2988             ee, 0, 0, _screen_height, ui_candidate_get_valid_height () + _ise_height);
2989     }
2990
2991     evas_object_show (_candidate_area_2);
2992     _candidate_area_2_visible = true;
2993     evas_object_show (_scroller_bg);
2994     evas_object_hide (_more_btn);
2995     evas_object_show (_close_btn);
2996
2997     ui_candidate_window_adjust ();
2998     ui_settle_candidate_window ();
2999     flush_memory ();
3000 }
3001
3002 /**
3003  * @brief Callback function for close button.
3004  *
3005  * @param data Data to pass when it is called.
3006  * @param e The evas for current event.
3007  * @param button The evas object for current event.
3008  * @param event_info The information for current event.
3009  */
3010 static void ui_candidate_window_close_button_cb (void *data, Evas *e, Evas_Object *button, void *event_info)
3011 {
3012     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3013
3014     if (_candidate_area_2 == NULL || !_candidate_area_2_visible)
3015         return;
3016
3017     _info_manager->candidate_more_window_hide ();
3018
3019     evas_object_hide (_candidate_area_2);
3020     _candidate_area_2_visible = false;
3021     evas_object_hide (_scroller_bg);
3022     evas_object_hide (_close_btn);
3023
3024     candidate_expanded = false;
3025     evas_object_show (_candidate_area_1);
3026     _candidate_area_1_visible = true;
3027     evas_object_show (_more_btn);
3028
3029     elm_scroller_region_show (_candidate_area_2, 0, 0, _candidate_scroll_width, 100);
3030     if (_candidate_angle == 180) {
3031         Ecore_Evas *ee= ecore_evas_ecore_evas_get (evas_object_evas_get (_candidate_window));
3032         ecore_evas_move_resize (ee, 0, 0, 0, 0);
3033         LOGD ("ecore_evas_move_resize (%p, %d, %d, %d, %d)", ee, 0, 0, 0, 0);
3034     } else if (_candidate_mode == FIXED_CANDIDATE_WINDOW && _candidate_angle == 270) {
3035         /*
3036          * when screen rotate 270 degrees, candidate have to move then resize for expanding more
3037          * candidates, but it will flash or locate in a wrong position, this code just a workaround
3038          * for avoiding this situation.
3039          */
3040         Ecore_Evas *ee = ecore_evas_ecore_evas_get (evas_object_evas_get (_candidate_window));
3041         ecore_evas_move_resize (ee, _ise_height, 0, _screen_height, ui_candidate_get_valid_height ());
3042         LOGD ("ecore_evas_move_resize (%p, %d, %d, %d, %d)",
3043             ee, _ise_height, 0, _screen_height, ui_candidate_get_valid_height ());
3044     }
3045
3046     ui_candidate_window_adjust ();
3047     ui_settle_candidate_window ();
3048     flush_memory ();
3049 }
3050
3051 /**
3052  * @brief Callback function for mouse button press.
3053  *
3054  * @param data Data to pass when it is called.
3055  * @param e The evas for current event.
3056  * @param button The evas object for current event.
3057  * @param event_info The information for current event.
3058  */
3059 static void ui_mouse_button_pressed_cb (void *data, Evas *e, Evas_Object *button, void *event_info)
3060 {
3061     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3062
3063     _click_object = GPOINTER_TO_INT (data) & 0xFF;
3064     _is_click     = true;
3065
3066     Evas_Event_Mouse_Down *ev = (Evas_Event_Mouse_Down *)event_info;
3067     if (!ev) return;
3068
3069     _click_down_pos [0] = ev->canvas.x;
3070     _click_down_pos [1] = ev->canvas.y;
3071
3072     if (_click_object == ISF_EFL_CANDIDATE_0 || _click_object == ISF_EFL_CANDIDATE_ITEMS) {
3073         int index = (int)GPOINTER_TO_INT (data) >> 8;
3074
3075 #ifdef HAVE_FEEDBACK
3076         if (feedback_initialized) {
3077             int feedback_result = 0;
3078             bool sound_feedback = _config->read (SCIM_GLOBAL_CONFIG_PANEL_SOUND_FEEDBACK, false);
3079
3080             if (sound_feedback) {
3081                 feedback_result = feedback_play_type (FEEDBACK_TYPE_SOUND, FEEDBACK_PATTERN_SIP);
3082
3083                 if (FEEDBACK_ERROR_NONE == feedback_result)
3084                     LOGD ("Sound play successful");
3085                 else
3086                     LOGW ("Cannot play feedback sound : %d", feedback_result);
3087             }
3088
3089             bool vibrate_feedback = _config->read (SCIM_GLOBAL_CONFIG_PANEL_VIBRATION_FEEDBACK, false);
3090
3091             if (vibrate_feedback) {
3092                 feedback_result = feedback_play_type (FEEDBACK_TYPE_VIBRATION, FEEDBACK_PATTERN_SIP);
3093
3094                 if (FEEDBACK_ERROR_NONE == feedback_result)
3095                     LOGD ("Vibration play successful");
3096                 else
3097                     LOGW ("Cannot play feedback vibration : %d", feedback_result);
3098             }
3099         }
3100 #endif
3101
3102         ui_candidate_delete_longpress_timer ();
3103         _longpress_timer = ecore_timer_add (1.0, ui_candidate_longpress_timeout, (void *)index);
3104     }
3105 }
3106
3107 /**
3108  * @brief Callback function for mouse button release.
3109  *
3110  * @param data Data to pass when it is called.
3111  * @param e The evas for current event.
3112  * @param button The evas object for current event.
3113  * @param event_info The information for current event.
3114  */
3115 static void ui_mouse_button_released_cb (void *data, Evas *e, Evas_Object *button, void *event_info)
3116 {
3117     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " index:" << GPOINTER_TO_INT (data) << "...\n";
3118
3119     ui_candidate_delete_longpress_timer ();
3120
3121     int index = GPOINTER_TO_INT (data);
3122     if (_click_object == ISF_EFL_AUX && _is_click) {
3123 /*      double ret = 0;
3124         const char *buf = edje_object_part_state_get (button, "aux", &ret);
3125         if (strcmp ("selected", buf)) {
3126             for (unsigned int i = 0; i < _aux_items.size (); i++) {
3127                 buf = edje_object_part_state_get (_aux_items [i], "aux", &ret);
3128                 if (!strcmp ("selected", buf))
3129                     edje_object_signal_emit (_aux_items [i], "aux,state,unselected", "aux");
3130             }
3131             edje_object_signal_emit (button, "aux,state,selected", "aux");
3132             _info_manager->select_aux (index);
3133         }*/
3134         int r, g, b, a, r2, g2, b2, a2, r3, g3, b3, a3;
3135         edje_object_color_class_get (_aux_items [index], "text_color", &r, &g, &b, &a, &r2, &g2, &b2, &a2, &r3, &g3, &b3, &a3);
3136         // Normal item is clicked
3137         if (!(r == 62 && g == 207 && b == 255)) {
3138             for (unsigned int i = 0; i < _aux_items.size (); i++) {
3139                 edje_object_color_class_set (_aux_items [i], "text_color", 249, 249, 249, 255, r2, g2, b2, a2, r3, g3, b3, a3);
3140             }
3141             edje_object_color_class_set (_aux_items [index], "text_color", 62, 207, 255, 255, r2, g2, b2, a2, r3, g3, b3, a3);
3142             _info_manager->select_aux (index);
3143         }
3144     } else if (_click_object == ISF_EFL_CANDIDATE_0 && _is_click) {
3145         ui_candidate_window_close_button_cb (NULL, NULL, _close_btn, NULL);
3146         _info_manager->select_candidate (index);
3147     } else if (_click_object == ISF_EFL_CANDIDATE_ITEMS && _is_click) {
3148         ui_candidate_window_close_button_cb (NULL, NULL, _close_btn, NULL);
3149         _info_manager->select_candidate (index);
3150     }
3151 }
3152
3153 /**
3154  * @brief Callback function for mouse move.
3155  *
3156  * @param data Data to pass when it is called.
3157  * @param e The evas for current event.
3158  * @param button The evas object for current event.
3159  * @param event_info The information for current event.
3160  */
3161 static void ui_mouse_moved_cb (void *data, Evas *e, Evas_Object *button, void *event_info)
3162 {
3163     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3164
3165     Evas_Event_Mouse_Down *ev = (Evas_Event_Mouse_Down *)event_info;
3166     if (!ev) return;
3167
3168     _click_up_pos [0] = ev->canvas.x;
3169     _click_up_pos [1] = ev->canvas.y;
3170
3171     if (abs (_click_up_pos [0] - _click_down_pos [0]) >= (int)(15 * _height_rate) ||
3172         abs (_click_up_pos [1] - _click_down_pos [1]) >= (int)(15 * _height_rate)) {
3173         _is_click = false;
3174         ui_candidate_delete_longpress_timer ();
3175     }
3176 }
3177
3178 #ifdef HAVE_TTS
3179 /**
3180  * @brief Open TTS device.
3181  *
3182  * @return false if open is failed, otherwise return true.
3183  */
3184 static bool ui_open_tts (void)
3185 {
3186     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3187
3188     int r = tts_create (&_tts);
3189     if (TTS_ERROR_NONE != r) {
3190         LOGW ("tts_create FAILED : result (%d)", r);
3191         _tts = NULL;
3192         return false;
3193     }
3194
3195     r = tts_set_mode (_tts, TTS_MODE_SCREEN_READER);
3196     if (TTS_ERROR_NONE != r) {
3197         LOGW ("tts_set_mode FAILED : result (%d)", r);
3198     }
3199
3200     tts_state_e current_state;
3201     r = tts_get_state (_tts, &current_state);
3202     if (TTS_ERROR_NONE != r) {
3203         LOGW ("tts_get_state FAILED : result (%d)", r);
3204     }
3205
3206     if (TTS_STATE_CREATED == current_state)  {
3207         r = tts_prepare (_tts);
3208         if (TTS_ERROR_NONE != r) {
3209             LOGW ("tts_prepare FAILED : ret (%d)", r);
3210         }
3211     }
3212     return true;
3213 }
3214
3215 /**
3216  * @brief Close TTS device.
3217  */
3218 static void ui_close_tts (void)
3219 {
3220     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3221
3222     if (_tts) {
3223         int r = tts_unprepare (_tts);
3224         if (TTS_ERROR_NONE != r) {
3225             LOGW ("tts_unprepare FAILED : result (%d)", r);
3226         }
3227
3228         r = tts_destroy (_tts);
3229         if (TTS_ERROR_NONE != r) {
3230             LOGW ("tts_destroy FAILED : result (%d)", r);
3231         }
3232     }
3233 }
3234
3235 /**
3236  * @brief Play string by TTS.
3237  *
3238  * @param str The string for playing.
3239  */
3240 static void ui_play_tts (const char* str)
3241 {
3242     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " str=" << str << "\n";
3243
3244     if (!str) return;
3245
3246     if (_tts == NULL) {
3247         if (!ui_open_tts ())
3248             return;
3249     }
3250
3251     int r;
3252     int utt_id = 0;
3253     tts_state_e current_state;
3254
3255     r = tts_get_state (_tts, &current_state);
3256     if (TTS_ERROR_NONE != r) {
3257         LOGW ("Fail to get state from TTS : ret (%d)", r);
3258     }
3259
3260     if (TTS_STATE_PLAYING == current_state)  {
3261         r = tts_stop (_tts);
3262         if (TTS_ERROR_NONE != r) {
3263             LOGW ("Fail to stop TTS : ret (%d)", r);
3264         }
3265     }
3266
3267     /* Get ISE language */
3268     String default_uuid = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), String (""));
3269     String language = String ("en_US");
3270     if (default_uuid.length () > 0) {
3271         language = _ime_info[get_ise_index (default_uuid)].languages;
3272         if (language.length () > 0) {
3273             std::vector<String> ise_langs;
3274             scim_split_string_list (ise_langs, language);
3275             language = ise_langs[0];
3276         }
3277     }
3278     LOGD ("TTS language:%s, str:%s", language.c_str (), str);
3279
3280     r = tts_add_text (_tts, str, language.c_str (), TTS_VOICE_TYPE_AUTO, TTS_SPEED_AUTO, &utt_id);
3281     if (TTS_ERROR_NONE == r) {
3282         r = tts_play (_tts);
3283         if (TTS_ERROR_NONE != r) {
3284             LOGW ("Fail to play TTS : ret (%d)", r);
3285         }
3286     }
3287 }
3288 #endif /* HAVE_TTS */
3289
3290 /**
3291  * @brief Show rect for candidate focus object when screen reader is enabled.
3292  *
3293  * @param x Rect X position.
3294  * @param y Rect Y position.
3295  * @param w Rect width.
3296  * @param h Rect height.
3297  */
3298 static void ui_tts_focus_rect_show (int x, int y, int w, int h)
3299 {
3300     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3301     if (_candidate_window == NULL || _candidate_state != WINDOW_STATE_SHOW)
3302         return;
3303
3304     if (_tts_focus_rect == NULL) {
3305         _tts_focus_rect = evas_object_rectangle_add (evas_object_evas_get ((Evas_Object*)_candidate_window));
3306         evas_object_color_set (_tts_focus_rect, 0, 0, 0, 0);
3307         elm_access_highlight_set (elm_access_object_register (_tts_focus_rect, (Evas_Object*)_candidate_window));
3308     }
3309     evas_object_move (_tts_focus_rect, x, y);
3310     evas_object_resize (_tts_focus_rect, w, h);
3311     evas_object_raise (_tts_focus_rect);
3312     evas_object_show (_tts_focus_rect);
3313 }
3314
3315 /**
3316  * @brief Hide rect for candidate focus object when screen reader is enabled.
3317  */
3318 static void ui_tts_focus_rect_hide (void)
3319 {
3320     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3321
3322     if (_tts_focus_rect) {
3323         //evas_object_hide (_tts_focus_rect);
3324         evas_object_move (_tts_focus_rect, -1000, -1000);
3325     }
3326 }
3327
3328 /**
3329  * @brief Callback function for candidate scroller stop event.
3330  *
3331  * @param data Data to pass when it is called.
3332  * @param obj The evas object for current event.
3333  * @param event_info The information for current event.
3334  */
3335 static void ui_candidate_scroller_stop_cb (void *data, Evas_Object *obj, void *event_info)
3336 {
3337     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3338     if (!_wait_stop_event)
3339         return;
3340
3341     if (_candidate_tts_focus_index >= 0 && _candidate_tts_focus_index < g_isf_candidate_table.get_current_page_size ()) {
3342         if (_candidate_0 [_candidate_tts_focus_index]) {
3343             int x, y, w, h;
3344             evas_object_geometry_get (_candidate_0 [_candidate_tts_focus_index], &x, &y, &w, &h);
3345             ui_tts_focus_rect_show (x, y, w, h);
3346         }
3347     }
3348     _wait_stop_event = false;
3349 }
3350
3351 #ifdef HAVE_ECOREX
3352 /**
3353  * @brief Mouse over (find focus object and play text by TTS) when screen reader is enabled.
3354  *
3355  * @param mouse_x Mouse X position.
3356  * @param mouse_y Mouse Y position.
3357  */
3358 static void ui_mouse_over (int mouse_x, int mouse_y)
3359 {
3360     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3361     if (_candidate_window == NULL || _candidate_state != WINDOW_STATE_SHOW)
3362         return;
3363
3364     int x, y, width, height;
3365     for (int i = 0; i < SCIM_LOOKUP_TABLE_MAX_PAGESIZE; ++i) {
3366         if (_candidate_0 [i]) {
3367             evas_object_geometry_get (_candidate_0 [i], &x, &y, &width, &height);
3368             if (mouse_x >= x && mouse_x <= x + width && mouse_y >= y && mouse_y <= y + height) {
3369                 /* FIXME: Should consider emoji case */
3370                 String mbs = utf8_wcstombs (g_isf_candidate_table.get_candidate_in_current_page (i));
3371                 SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " play candidate string: " << mbs << "\n";
3372 #ifdef HAVE_TTS
3373                 ui_play_tts (mbs.c_str ());
3374 #endif
3375                 _candidate_tts_focus_index = i;
3376                 ui_tts_focus_rect_show (x, y, width, height);
3377                 return;
3378             }
3379         }
3380     }
3381
3382     String strTts = String ("");
3383     if (_candidate_area_2_visible) {
3384         evas_object_geometry_get (_close_btn, &x, &y, &width, &height);
3385         if (mouse_x >= x && mouse_x <= x + width && mouse_y >= y && mouse_y <= y + height) {
3386             strTts = String (_("close button"));
3387             _candidate_tts_focus_index = CLOSE_BUTTON_INDEX;
3388             ui_tts_focus_rect_show (x, y, width, height);
3389         }
3390     } else {
3391         evas_object_geometry_get (_more_btn, &x, &y, &width, &height);
3392         if (mouse_x >= x && mouse_x <= x + width && mouse_y >= y && mouse_y <= y + height) {
3393             strTts = String (_("more button"));
3394             _candidate_tts_focus_index = MORE_BUTTON_INDEX;
3395             ui_tts_focus_rect_show (x, y, width, height);
3396         }
3397     }
3398 #ifdef HAVE_TTS
3399     if (strTts.length () > 0)
3400         ui_play_tts (strTts.c_str ());
3401 #endif
3402 }
3403
3404 /**
3405  * @brief Mouse click (find focus object and do click event) when screen reader is enabled.
3406  *
3407  * @param focus_index focused candidate index.
3408  */
3409 static void ui_mouse_click (int focus_index)
3410 {
3411     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3412     if (_candidate_window == NULL || _candidate_state != WINDOW_STATE_SHOW || focus_index == INVALID_TTS_FOCUS_INDEX)
3413         return;
3414
3415     if (focus_index >= 0 && focus_index < g_isf_candidate_table.get_current_page_size ()) {
3416         if (_candidate_0 [focus_index]) {
3417             int x, y, width, height;
3418             evas_object_geometry_get (_candidate_0 [focus_index], &x, &y, &width, &height);
3419             Evas_Event_Mouse_Down event_info;
3420             event_info.canvas.x = x + width / 2;
3421             event_info.canvas.y = y + height / 2;
3422             ui_mouse_button_pressed_cb (GINT_TO_POINTER ((focus_index << 8) + ISF_EFL_CANDIDATE_0), NULL, NULL, &event_info);
3423             ui_mouse_button_released_cb (GINT_TO_POINTER (focus_index), NULL, NULL, &event_info);
3424         }
3425         _candidate_tts_focus_index = INVALID_TTS_FOCUS_INDEX;
3426         ui_tts_focus_rect_hide ();
3427         return;
3428     }
3429
3430     if (_candidate_area_2_visible) {
3431         if (focus_index == CLOSE_BUTTON_INDEX) {
3432             ui_candidate_window_close_button_cb (NULL, NULL, NULL, NULL);
3433             _candidate_tts_focus_index = MORE_BUTTON_INDEX;
3434         }
3435     } else {
3436         if (focus_index == MORE_BUTTON_INDEX) {
3437             ui_candidate_window_more_button_cb (NULL, NULL, NULL, NULL);
3438             _candidate_tts_focus_index = CLOSE_BUTTON_INDEX;
3439         }
3440     }
3441 }
3442 #endif /* HAVE_ECOREX */
3443
3444 /**
3445  * @brief Create preedit window.
3446  */
3447 static void ui_create_preedit_window (void)
3448 {
3449     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3450
3451     if (_candidate_mode == SOFT_CANDIDATE_WINDOW)
3452         return;
3453
3454     _preedit_width  = 100;
3455     _preedit_height = _preedit_height * _height_rate;
3456     if (_preedit_window == NULL) {
3457         _preedit_window = efl_create_window ("ISF Popup", "Preedit Window");
3458         evas_object_resize (_preedit_window, _preedit_width, _preedit_height);
3459         int rots [4] = {0, 90, 180, 270};
3460         elm_win_wm_rotation_available_rotations_set (_preedit_window, rots, 4);
3461         int preedit_font_size = (int)(32 * _width_rate);
3462
3463         _preedit_text = edje_object_add (evas_object_evas_get (_preedit_window));
3464         edje_object_file_set (_preedit_text, _candidate_edje_file.c_str (), "preedit_text");
3465         evas_object_size_hint_fill_set (_preedit_text, EVAS_HINT_FILL, EVAS_HINT_FILL);
3466         evas_object_size_hint_weight_set (_preedit_text, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
3467         elm_win_resize_object_add (_preedit_window, _preedit_text);
3468         evas_object_show (_preedit_text);
3469
3470         _tmp_preedit_text = evas_object_text_add (evas_object_evas_get (_preedit_window));
3471         evas_object_text_font_set (_tmp_preedit_text, _candidate_font_name.c_str (), preedit_font_size);
3472     }
3473 }
3474
3475 /**
3476  * @brief Create native style candidate window.
3477  */
3478 static void ui_create_native_candidate_window (void)
3479 {
3480     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3481     _more_btn_width = 80 * (_width_rate > 1 ? 1 : _width_rate);
3482     _more_btn_height = 64 * _height_rate;
3483
3484     _candidate_port_width        = _screen_width;
3485     _candidate_port_height_min   = 84 * _height_rate * _candidate_port_line;
3486     _candidate_port_height_min_2 = 84 * _height_rate + _candidate_port_height_min;
3487     _candidate_port_height_max   = 426 * _height_rate + _candidate_port_height_min;
3488     _candidate_port_height_max_2 = 84 * _height_rate + _candidate_port_height_max;
3489     _candidate_land_width        = _screen_height;
3490     _candidate_land_height_min   = 84 * _width_rate;
3491     _candidate_land_height_min_2 = 168 * _width_rate;
3492     _candidate_land_height_max   = 342 * _width_rate;
3493     _candidate_land_height_max_2 = 426 * _width_rate;
3494
3495     _candidate_scroll_0_width_min= _screen_width;
3496     _candidate_scroll_0_width_max= _screen_height;
3497     _candidate_scroll_width_min  = _screen_width;
3498     _candidate_scroll_width_max  = _screen_height;
3499     _candidate_scroll_height_min = 252 * _width_rate;
3500     _candidate_scroll_height_max = 420 * _height_rate;
3501
3502     _candidate_area_1_pos [0]    = 0 * _width_rate;
3503     _candidate_area_1_pos [1]    = 2 * _height_rate;
3504     _more_btn_pos [0]            = _candidate_port_width - _more_btn_width - _h_padding;
3505     _more_btn_pos [1]            = 12 * _height_rate;
3506     _more_btn_pos [2]            = _candidate_land_width - _more_btn_width - _h_padding;
3507     _more_btn_pos [3]            = 12 * _width_rate;
3508     _close_btn_pos [0]           = _candidate_port_width - _more_btn_width - _h_padding;
3509     _close_btn_pos [1]           = 12 * _height_rate;
3510     _close_btn_pos [2]           = _candidate_land_width - _more_btn_width - _h_padding;
3511     _close_btn_pos [3]           = 12 * _width_rate;
3512
3513     _aux_height                  = 84 * _height_rate - 2;
3514     _aux_port_width              = _screen_width;
3515     _aux_land_width              = _screen_height;
3516
3517     _item_min_height             = 84 * _height_rate - 2;
3518
3519     /* Create candidate window */
3520     if (_candidate_window == NULL) {
3521         _candidate_window = efl_create_window ("ISF Popup", "Prediction Window");
3522         int rots [4] = {0, 90, 180, 270};
3523         elm_win_wm_rotation_available_rotations_set (_candidate_window, rots, 4);
3524         if (_candidate_angle == 90 || _candidate_angle == 270) {
3525             _candidate_width  = _candidate_land_width;
3526             _candidate_height = _candidate_land_height_min;
3527         } else {
3528             _candidate_width  = _candidate_port_width;
3529             _candidate_height = _candidate_port_height_min;
3530         }
3531 #ifdef HAVE_ECOREX
3532         /*
3533         ecore_x_e_window_rotation_geometry_set (elm_win_xwindow_get (_candidate_window),
3534                 0, 0, 0, _candidate_port_width, _candidate_port_height_min);
3535         ecore_x_e_window_rotation_geometry_set (elm_win_xwindow_get (_candidate_window),
3536                 90, 0, 0, _candidate_land_height_min, _candidate_land_width);
3537         ecore_x_e_window_rotation_geometry_set (elm_win_xwindow_get (_candidate_window),
3538                 180, 0, 0, _candidate_port_width, _candidate_port_height_min);
3539         ecore_x_e_window_rotation_geometry_set (elm_win_xwindow_get (_candidate_window),
3540                 270, 0, 0, _candidate_land_height_min, _candidate_land_width);
3541         */
3542 #else
3543         ecore_wl2_window_rotation_geometry_set ((Ecore_Wl2_Window *)elm_win_wl_window_get (_candidate_window),
3544                 0, 0, 0, _candidate_port_width, _candidate_port_height_min);
3545         ecore_wl2_window_rotation_geometry_set ((Ecore_Wl2_Window *)elm_win_wl_window_get (_candidate_window),
3546                 90, 0, 0, _candidate_land_height_min, _candidate_land_width);
3547         ecore_wl2_window_rotation_geometry_set ((Ecore_Wl2_Window *)elm_win_wl_window_get (_candidate_window),
3548                 180, 0, 0, _candidate_port_width, _candidate_port_height_min);
3549         ecore_wl2_window_rotation_geometry_set ((Ecore_Wl2_Window *)elm_win_wl_window_get (_candidate_window),
3550                 270, 0, 0, _candidate_land_height_min, _candidate_land_width);
3551 #endif
3552         /* Add dim background */
3553         Evas_Object *dim_bg = elm_bg_add (_candidate_window);
3554         evas_object_color_set (dim_bg, 0, 0, 0, 153);
3555         elm_win_resize_object_add (_candidate_window, dim_bg);
3556         evas_object_show (dim_bg);
3557
3558         /* Add candidate background */
3559         _candidate_bg = edje_object_add (evas_object_evas_get (_candidate_window));
3560         edje_object_file_set (_candidate_bg, _candidate_edje_file.c_str (), "candidate_bg");
3561         evas_object_size_hint_weight_set (_candidate_bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
3562         evas_object_resize (_candidate_bg, _candidate_port_width, _candidate_port_height_min);
3563         evas_object_move (_candidate_bg, 0, 0);
3564         evas_object_show (_candidate_bg);
3565
3566         /* Create _candidate_0 scroller */
3567         _candidate_0_scroll = elm_scroller_add (_candidate_window);
3568         elm_scroller_bounce_set (_candidate_0_scroll, EINA_TRUE, EINA_FALSE);
3569         elm_scroller_policy_set (_candidate_0_scroll, ELM_SCROLLER_POLICY_AUTO, ELM_SCROLLER_POLICY_OFF);
3570         evas_object_resize (_candidate_0_scroll, _candidate_scroll_0_width_min, (_item_min_height+2)*_candidate_port_line-2);
3571         evas_object_move (_candidate_0_scroll, _candidate_area_1_pos[0], _candidate_area_1_pos[1]);
3572
3573         /* Create candidate table */
3574         _candidate_0_table = elm_table_add (_candidate_window);
3575         evas_object_size_hint_weight_set (_candidate_0_table, 0.0, 0.0);
3576         evas_object_size_hint_align_set (_candidate_0_table, 0.0, 0.0);
3577         elm_table_padding_set (_candidate_0_table, 0, 0);
3578         elm_object_content_set (_candidate_0_scroll, _candidate_0_table);
3579         evas_object_show (_candidate_0_table);
3580         _candidate_area_1 = _candidate_0_scroll;
3581
3582         /* Create more button */
3583         _more_btn = edje_object_add (evas_object_evas_get (_candidate_window));
3584         if (_ise_width == 0 && _ise_height == 0)
3585             edje_object_file_set (_more_btn, _candidate_edje_file.c_str (), "close_button");
3586         else
3587             edje_object_file_set (_more_btn, _candidate_edje_file.c_str (), "more_button");
3588         evas_object_move (_more_btn, _more_btn_pos[0], _more_btn_pos[1]);
3589         evas_object_resize (_more_btn, _more_btn_width, _more_btn_height);
3590         evas_object_event_callback_add (_more_btn, EVAS_CALLBACK_MOUSE_UP, ui_candidate_window_more_button_cb, NULL);
3591
3592         /* Add scroller background */
3593         _candidate_scroll_width = _candidate_scroll_width_min;
3594         _scroller_bg = edje_object_add (evas_object_evas_get (_candidate_window));
3595         edje_object_file_set (_scroller_bg, _candidate_edje_file.c_str (), "scroller_bg");
3596         evas_object_size_hint_weight_set (_scroller_bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
3597         evas_object_resize (_scroller_bg, _candidate_scroll_width, _candidate_scroll_height_max + 6);
3598         evas_object_move (_scroller_bg, 0, _candidate_port_height_min);
3599
3600         /* Create vertical scroller */
3601         _candidate_scroll = elm_scroller_add (_candidate_window);
3602         elm_scroller_bounce_set (_candidate_scroll, 0, 1);
3603         elm_scroller_policy_set (_candidate_scroll, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_AUTO);
3604         evas_object_resize (_candidate_scroll, _candidate_scroll_width, _candidate_scroll_height_max);
3605         evas_object_resize (_scroller_bg, _candidate_scroll_width, _candidate_scroll_height_max + 6);
3606         elm_scroller_page_size_set (_candidate_scroll, 0, _item_min_height+_v_padding);
3607         evas_object_move (_candidate_scroll, 0, _candidate_port_height_min);
3608
3609         /* Create candidate table */
3610         _candidate_table = elm_table_add (_candidate_window);
3611         evas_object_size_hint_weight_set (_candidate_table, 0.0, 0.0);
3612         evas_object_size_hint_align_set (_candidate_table, 0.0, 0.0);
3613         elm_table_padding_set (_candidate_table, 0, 0);
3614         elm_object_content_set (_candidate_scroll, _candidate_table);
3615         evas_object_show (_candidate_table);
3616         _candidate_area_2 = _candidate_scroll;
3617         evas_object_smart_callback_add (_candidate_scroll, "scroll,anim,stop", ui_candidate_scroller_stop_cb, NULL);
3618
3619         /* Create close button */
3620         _close_btn = edje_object_add (evas_object_evas_get (_candidate_window));
3621         if (_ise_width == 0 && _ise_height == 0)
3622             edje_object_file_set (_close_btn, _candidate_edje_file.c_str (), "more_button");
3623         else
3624             edje_object_file_set (_close_btn, _candidate_edje_file.c_str (), "close_button");
3625         evas_object_move (_close_btn, _close_btn_pos[0], _close_btn_pos[1]);
3626         evas_object_resize (_close_btn, _more_btn_width, _more_btn_height);
3627         evas_object_event_callback_add (_close_btn, EVAS_CALLBACK_MOUSE_UP, ui_candidate_window_close_button_cb, NULL);
3628
3629         _tmp_candidate_text = evas_object_text_add (evas_object_evas_get (_candidate_window));
3630         evas_object_text_font_set (_tmp_candidate_text, _candidate_font_name.c_str (), _candidate_font_size);
3631
3632         /* Create aux */
3633         _aux_area = elm_scroller_add (_candidate_window);
3634         elm_scroller_bounce_set (_aux_area, 1, 0);
3635         elm_scroller_policy_set (_aux_area, ELM_SCROLLER_POLICY_AUTO, ELM_SCROLLER_POLICY_OFF);
3636         evas_object_resize (_aux_area, _aux_port_width, _aux_height);
3637         evas_object_move (_aux_area, _candidate_area_1_pos[0], _candidate_area_1_pos[1]);
3638
3639         _aux_table = elm_table_add (_candidate_window);
3640         elm_object_content_set (_aux_area, _aux_table);
3641         elm_table_padding_set (_aux_table, 0, 0);
3642         evas_object_size_hint_weight_set (_aux_table, 0.0, 0.0);
3643         evas_object_size_hint_align_set (_aux_table, 0.0, 0.0);
3644         evas_object_show (_aux_table);
3645
3646         _aux_line = edje_object_add (evas_object_evas_get (_candidate_window));
3647         edje_object_file_set (_aux_line, _candidate_edje_file.c_str (), "popup_line");
3648         evas_object_resize (_aux_line, _candidate_port_width, 2);
3649         evas_object_move (_aux_line, 0, _aux_height + 2);
3650
3651         _tmp_aux_text = evas_object_text_add (evas_object_evas_get (_candidate_window));
3652         evas_object_text_font_set (_tmp_aux_text, _candidate_font_name.c_str (), _aux_font_size);
3653     } else {
3654         evas_object_hide (_candidate_window);
3655     }
3656
3657     flush_memory ();
3658 }
3659
3660 /**
3661  * @brief Create candidate window.
3662  *
3663  * @return void
3664  */
3665 static void ui_create_candidate_window (void)
3666 {
3667     check_time ("\nEnter ui_create_candidate_window");
3668     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3669     if (_candidate_mode == SOFT_CANDIDATE_WINDOW)
3670         return;
3671
3672     _candidate_x     = 0;
3673     _candidate_y     = 0;
3674     _candidate_angle = 0;
3675
3676     ui_create_native_candidate_window ();
3677
3678 #ifdef HAVE_ECOREX
3679     unsigned int set = 1;
3680
3681     ecore_x_window_prop_card32_set (elm_win_xwindow_get (_candidate_window),
3682             ECORE_X_ATOM_E_WINDOW_ROTATION_SUPPORTED,
3683             &set, 1);
3684 #endif
3685     int angle = efl_get_app_window_angle ();
3686     if (_candidate_angle != angle) {
3687         _candidate_angle = angle;
3688         ui_candidate_window_rotate (angle);
3689     } else {
3690         ui_settle_candidate_window ();
3691     }
3692
3693     candidate_expanded = false;
3694
3695     check_time ("Exit ui_create_candidate_window");
3696 }
3697
3698 /**
3699  * @brief Destroy candidate window.
3700  *
3701  * @return void
3702  */
3703 static void ui_destroy_candidate_window (void)
3704 {
3705     check_time ("Enter ui_destroy_candidate_window");
3706     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3707
3708     /* Delete candidate items, popup lines and seperator items */
3709     for (int i = 0; i < SCIM_LOOKUP_TABLE_MAX_PAGESIZE; ++i) {
3710         if (_candidate_0 [i]) {
3711             evas_object_del (_candidate_0 [i]);
3712             _candidate_0 [i] = NULL;
3713         }
3714         if (_seperate_0 [i]) {
3715             evas_object_del (_seperate_0 [i]);
3716             _seperate_0 [i] = NULL;
3717         }
3718         if (_seperate_items [i]) {
3719             evas_object_del (_seperate_items [i]);
3720             _seperate_items [i] = NULL;
3721         }
3722         if (_line_0 [i]) {
3723             evas_object_del (_line_0 [i]);
3724             _line_0 [i] = NULL;
3725         }
3726         if (_line_items [i]) {
3727             evas_object_del (_line_items [i]);
3728             _line_items [i] = NULL;
3729         }
3730     }
3731
3732     _aux_items.clear ();
3733     _aux_seperates.clear ();
3734     /* Delete candidate window */
3735     if (_candidate_window) {
3736         LOGD ("calling ui_candidate_hide (true)");
3737         ui_candidate_hide (true);
3738
3739         evas_object_del (_candidate_window);
3740         _candidate_window = NULL;
3741         _aux_area         = NULL;
3742         _candidate_area_1 = NULL;
3743         _candidate_area_2 = NULL;
3744     }
3745
3746     if (_tts_focus_rect) {
3747         evas_object_del (_tts_focus_rect);
3748         _tts_focus_rect = NULL;
3749     }
3750
3751     if (_candidate_bg) {
3752         evas_object_del (_candidate_bg);
3753         _candidate_bg = NULL;
3754     }
3755
3756     if (_more_btn) {
3757         evas_object_del (_more_btn);
3758         _more_btn = NULL;
3759     }
3760
3761     if (_scroller_bg) {
3762         evas_object_del (_scroller_bg);
3763         _scroller_bg = NULL;
3764     }
3765
3766     if (_close_btn) {
3767         evas_object_del (_close_btn);
3768         _close_btn = NULL;
3769     }
3770
3771     if (_aux_line) {
3772         evas_object_del (_aux_line);
3773         _aux_line = NULL;
3774     }
3775
3776     if (_tmp_candidate_text) {
3777         evas_object_del (_tmp_candidate_text);
3778         _tmp_candidate_text = NULL;
3779     }
3780
3781     if (_tmp_preedit_text) {
3782         evas_object_del (_tmp_preedit_text);
3783         _tmp_preedit_text = NULL;
3784     }
3785
3786     if (_tmp_aux_text) {
3787         evas_object_del (_tmp_aux_text);
3788         _tmp_aux_text = NULL;
3789     }
3790
3791     if (_preedit_text) {
3792         evas_object_del (_preedit_text);
3793         _preedit_text = NULL;
3794     }
3795
3796     if (_preedit_window) {
3797         evas_object_hide (_preedit_window);
3798         evas_object_del (_preedit_window);
3799         _preedit_window = NULL;
3800     }
3801
3802     flush_memory ();
3803     check_time ("Exit ui_destroy_candidate_window");
3804 }
3805
3806 /**
3807  * @brief Settle candidate window position.
3808  */
3809 static void ui_settle_candidate_window (void)
3810 {
3811     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3812
3813     if (!_candidate_window)
3814         return;
3815
3816     /* If both ISE and candidate window are going to be hidden,
3817        let's just not move our candidate window */
3818     if (_ise_state == WINDOW_STATE_WILL_HIDE && _candidate_state == WINDOW_STATE_WILL_HIDE)
3819         return;
3820
3821     int spot_x, spot_y;
3822     int x, y, width, height;
3823     int ise_width = 0, ise_height = 0;
3824     bool get_geometry_result = false;
3825
3826     /* Get candidate window position */
3827     ecore_evas_geometry_get (ecore_evas_ecore_evas_get (evas_object_evas_get (_candidate_window)), &x, &y, &width, &height);
3828
3829 #ifdef HAVE_ECOREX
3830     /*
3831     int pos_x = 0, pos_y = 0;
3832     if (_candidate_angle == 90 || _candidate_angle == 270)
3833         get_geometry_result = ecore_x_e_window_rotation_geometry_get (_ise_window, _candidate_angle, &pos_x, &pos_y, &ise_height, &ise_width);
3834     else
3835         get_geometry_result = ecore_x_e_window_rotation_geometry_get (_ise_window, _candidate_angle, &pos_x, &pos_y, &ise_width, &ise_height);
3836     */
3837 #else
3838     spot_x = _ise_x;
3839     spot_y = _ise_y;
3840     ise_width = _ise_width;
3841     ise_height = _ise_height;
3842     get_geometry_result = true;
3843 #endif
3844     if ((_ise_state != WINDOW_STATE_SHOW && _ise_state != WINDOW_STATE_WILL_HIDE) ||
3845             (get_geometry_result == false) || (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE)) {
3846         ise_height = 0;
3847         ise_width = 0;
3848     }
3849
3850     int height2 = ui_candidate_get_valid_height ();
3851
3852     if (_candidate_mode == FIXED_CANDIDATE_WINDOW) {
3853         if (_candidate_angle == 90) {
3854             spot_x = _screen_width - ise_height - height2;
3855             spot_y = 0;
3856         } else if (_candidate_angle == 270) {
3857             spot_x = ise_height - (_candidate_height - height2);
3858             spot_y = 0;
3859         } else if (_candidate_angle == 180) {
3860             spot_x = 0;
3861             spot_y = ise_height - (_candidate_height - height2);
3862         } else {
3863             spot_x = 0;
3864             spot_y = _screen_height - ise_height - height2;
3865         }
3866     } else {
3867         spot_x = _spot_location_x;
3868         spot_y = _spot_location_y;
3869
3870         rectinfo ise_rect = {0, 0, (uint32)ise_width, (uint32)ise_height};
3871         if (_candidate_angle == 90 || _candidate_angle == 270) {
3872             if (ise_rect.height <= (uint32)0 || ise_rect.height >= (uint32)_screen_width)
3873                 ise_rect.height = ISE_DEFAULT_HEIGHT_LANDSCAPE * _width_rate;
3874         } else {
3875             if (ise_rect.height <= (uint32)0 || ise_rect.height >= (uint32) _screen_height)
3876                 ise_rect.height = ISE_DEFAULT_HEIGHT_PORTRAIT * _height_rate;
3877         }
3878
3879         int nOffset = _candidate_port_height_min / 3;
3880         if (_candidate_angle == 270) {
3881             if (ise_rect.height > 0 && spot_y + height2 > _screen_width - (int)ise_rect.height + nOffset) {
3882                 spot_x = _screen_width - _spot_location_top_y - (_candidate_height - height2);
3883             } else {
3884                 spot_x = _screen_width - _spot_location_y - _candidate_height;
3885             }
3886         } else if (_candidate_angle == 90) {
3887             if (ise_rect.height > 0 && spot_y + height2 > _screen_width - (int)ise_rect.height + nOffset) {
3888                 spot_x = _spot_location_top_y - height2;
3889             } else {
3890                 spot_x = spot_y;
3891             }
3892         } else if (_candidate_angle == 180) {
3893             if (ise_rect.height > 0 && spot_y + height2 > _screen_height - (int)ise_rect.height + nOffset) {
3894                 spot_y = _screen_height - _spot_location_top_y - (_candidate_height - height2);
3895             } else {
3896                 spot_y = _screen_height - _spot_location_y - _candidate_height;
3897             }
3898         } else {
3899             if (ise_rect.height > 0 && spot_y + height2 > _screen_height - (int)ise_rect.height + nOffset) {
3900                 spot_y = _spot_location_top_y - height2;
3901             }
3902         }
3903     }
3904
3905     if (_candidate_angle == 90) {
3906         spot_y = (_screen_height - _candidate_width) / 2;
3907         spot_x = spot_x < _indicator_height ? _indicator_height : spot_x;
3908         if (spot_x > _screen_width - _candidate_height)
3909             spot_x = _screen_width - _candidate_height;
3910     } else if (_candidate_angle == 270) {
3911         spot_y = (_screen_height - _candidate_width) / 2;
3912         spot_x = spot_x < 0 ? 0 : spot_x;
3913         if (spot_x > _screen_width - (_indicator_height+_candidate_height))
3914             spot_x = _screen_width - (_indicator_height+_candidate_height);
3915     } else if (_candidate_angle == 180) {
3916         spot_x = (_screen_width - _candidate_width) / 2;
3917         spot_y = spot_y < 0 ? 0 : spot_y;
3918         if (spot_y > _screen_height - (_indicator_height+_candidate_height))
3919             spot_y = _screen_height - (_indicator_height+_candidate_height);
3920     } else {
3921         spot_x = (_screen_width - _candidate_width) / 2;
3922         spot_y = spot_y < _indicator_height ? _indicator_height : spot_y;
3923         if (spot_y > _screen_height - _candidate_height)
3924             spot_y = _screen_height - _candidate_height;
3925     }
3926
3927     if (spot_x != x || spot_y != y) {
3928         _candidate_x = spot_x;
3929         _candidate_y = spot_y;
3930         evas_object_move (_candidate_window, spot_x, spot_y);
3931         LOGD ("Moving candidate window to : %d %d", spot_x, spot_y);
3932         if (_preedit_window) {
3933             if (_candidate_angle == 90) {
3934                 spot_x -= _preedit_height;
3935                 spot_y = _screen_height - _preedit_width;
3936             } else if (_candidate_angle == 270) {
3937                 spot_x += height2;
3938             } else if (_candidate_angle == 180) {
3939                 spot_x = _screen_width - _preedit_width;
3940                 spot_y += height2;
3941             } else {
3942                 spot_y -= _preedit_height;
3943             }
3944             evas_object_move (_preedit_window, spot_x, spot_y);
3945         }
3946         if (_candidate_state == WINDOW_STATE_SHOW) {
3947             _info_manager->update_candidate_panel_event ((uint32)ECORE_IMF_CANDIDATE_PANEL_GEOMETRY_EVENT, 0);
3948         }
3949     }
3950 }
3951 #endif /* CANDIDATE */
3952
3953 /**
3954  * @brief Set soft candidate geometry.
3955  *
3956  * @param x      The x position in screen.
3957  * @param y      The y position in screen.
3958  * @param width  The candidate window width.
3959  * @param height The candidate window height.
3960  */
3961 static void set_soft_candidate_geometry (int x, int y, int width, int height)
3962 {
3963     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " x:" << x << " y:" << y << " width:" << width << " height:" << height << "...\n";
3964
3965     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);
3966
3967     if ((_candidate_mode != SOFT_CANDIDATE_WINDOW) || (_info_manager->get_current_toolbar_mode () != TOOLBAR_KEYBOARD_MODE))
3968         return;
3969
3970      _soft_candidate_width  = width;
3971      _soft_candidate_height = height;
3972 #ifdef HAVE_ECOREX
3973      set_keyboard_geometry_atom_info (_app_window, get_ise_geometry());
3974 #endif
3975     _info_manager->update_input_panel_event (ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
3976 }
3977
3978 #if ISF_BUILD_CANDIDATE_UI
3979 //////////////////////////////////////////////////////////////////////
3980 // End of Candidate Functions
3981 //////////////////////////////////////////////////////////////////////
3982 #ifdef HAVE_ECOREX
3983 /**
3984  * @brief Set transient for app window.
3985  *
3986  * @param window The Ecore_X_Window handler of app window.
3987  */
3988 static void efl_set_transient_for_app_window (Ecore_X_Window window)
3989 {
3990     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
3991
3992     /* Set a transient window for window stack */
3993     Ecore_X_Window   xAppWindow = efl_get_app_window ();
3994     ecore_x_icccm_transient_for_set (window, xAppWindow);
3995
3996     LOGD ("win : %x, forwin : %x", window, xAppWindow);
3997 }
3998
3999 static int efl_get_window_rotate_angle (Ecore_X_Window win)
4000 {
4001     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4002
4003     int ret;
4004     int count;
4005     int angle = 0;
4006     unsigned char *prop_data = NULL;
4007
4008     ret = ecore_x_window_prop_property_get (win,
4009             ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE, ECORE_X_ATOM_CARDINAL, 32, &prop_data, &count);
4010     if (ret && prop_data) {
4011         memcpy (&angle, prop_data, sizeof (int));
4012         LOGD ("WINDOW angle of %p is %d", win, angle);
4013     } else {
4014         std::cerr << "ecore_x_window_prop_property_get () is failed!!!\n";
4015         LOGW ("WINDOW angle of %p FAILED!", win);
4016     }
4017     if (prop_data)
4018         XFree (prop_data);
4019
4020     return angle;
4021 }
4022 #endif /* HAVE_ECOREX */
4023
4024 /**
4025  * @brief Get angle for app window.
4026  *
4027  * @param win_obj The Evas_Object handler of application window.
4028  *
4029  * @return The angle of app window.
4030  */
4031 static int efl_get_app_window_angle ()
4032 {
4033     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4034 #ifdef HAVE_ECOREX
4035     return efl_get_window_rotate_angle (efl_get_app_window ());
4036 #else
4037     //FIXME:
4038     return 0;
4039 #endif
4040 }
4041 #endif /* CANDIDATE */
4042
4043 /**
4044  * @brief Get angle for ise window.
4045  *
4046  * @param win_obj The Evas_Object handler of ise window.
4047  *
4048  * @return The angle of ise window.
4049  */
4050 static int efl_get_ise_window_angle ()
4051 {
4052     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4053 #ifdef HAVE_ECOREX
4054     return efl_get_window_rotate_angle (_ise_window);
4055 #else
4056     //FIXME:
4057     return 0;
4058 #endif
4059 }
4060
4061 #if ISF_BUILD_CANDIDATE_UI
4062 #ifdef HAVE_ECOREX
4063 /**
4064  * @brief Get angle of quickpanel window.
4065  *
4066  * @return The angle of quickpanel window.
4067  */
4068 static int efl_get_quickpanel_window_angle ()
4069 {
4070     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4071     return efl_get_window_rotate_angle (efl_get_quickpanel_window ());
4072 }
4073 #endif
4074
4075 /**
4076  * @brief Set showing effect for application window.
4077  *
4078  * @param win The Evas_Object handler of application window.
4079  * @param strEffect The pointer of effect string.
4080  */
4081 static void efl_set_showing_effect_for_app_window (Evas_Object *win, const char* strEffect)
4082 {
4083     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4084 #ifdef HAVE_ECOREX
4085     ecore_x_icccm_name_class_set (elm_win_xwindow_get (static_cast<Evas_Object*>(win)), strEffect, "ISF");
4086 #endif
4087 }
4088
4089 /**
4090  * @brief Create elementary window.
4091  *
4092  * @param strWinName The window name.
4093  * @param strEffect The window effect string.
4094  *
4095  * @return The window pointer
4096  */
4097 static Evas_Object *efl_create_window (const char *strWinName, const char *strEffect)
4098 {
4099     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4100
4101     Evas_Object *win = elm_win_add (NULL, strWinName, ELM_WIN_UTILITY);
4102     elm_win_title_set (win, strWinName);
4103
4104     /* set window properties */
4105     elm_win_autodel_set (win, EINA_TRUE);
4106     elm_object_focus_allow_set (win, EINA_FALSE);
4107     elm_win_borderless_set (win, EINA_TRUE);
4108     elm_win_alpha_set (win, EINA_TRUE);
4109     elm_win_prop_focus_skip_set (win, EINA_TRUE);
4110     efl_set_showing_effect_for_app_window (win, strEffect);
4111
4112     return win;
4113 }
4114 #endif /* CANDIDATE */
4115
4116 #ifdef HAVE_ECOREX
4117 /**
4118  * @brief Create elementary control window.
4119  *
4120  * @return EINA_TRUE if successful, otherwise return EINA_FALSE
4121  */
4122 static Eina_Bool efl_create_control_window (void)
4123 {
4124     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4125
4126     /* WMSYNC, #1 Creating and registering control window */
4127     if (ecore_x_display_get () == NULL)
4128         return EINA_FALSE;
4129
4130     Ecore_X_Window root = ecore_x_window_root_first_get ();
4131     _control_window = ecore_x_window_input_new (root, -100, -100, 1, 1);
4132     //ecore_x_e_virtual_keyboard_control_window_set (root, _control_window, 0, EINA_TRUE);
4133
4134     Ecore_X_Atom atom = ecore_x_atom_get ("_ISF_CONTROL_WINDOW");
4135     ecore_x_window_prop_xid_set (root, atom, ECORE_X_ATOM_WINDOW, &_control_window, 1);
4136
4137     return EINA_TRUE;
4138 }
4139
4140 /**
4141  * @brief Get an window's x window id.
4142  *
4143  * @param name the property name.
4144  * @return X window id.
4145  */
4146 static Ecore_X_Window efl_get_window (const char *name)
4147 {
4148     /* Gets the XID of the window from the root window property */
4149     int  ret = 0;
4150     Atom type_return;
4151     int  format_return;
4152     unsigned long    nitems_return;
4153     unsigned long    bytes_after_return;
4154     unsigned char   *data = NULL;
4155     Ecore_X_Window   window = 0;
4156
4157     ret = XGetWindowProperty ((Display *)ecore_x_display_get (),
4158                               ecore_x_window_root_get (_control_window),
4159                               ecore_x_atom_get (name),
4160                               0, G_MAXLONG, False, XA_WINDOW, &type_return,
4161                               &format_return, &nitems_return, &bytes_after_return,
4162                               &data);
4163
4164     if (ret == Success) {
4165         if ((type_return == XA_WINDOW) && (format_return == 32) && (data)) {
4166             window = *(Window *)data;
4167         }
4168     } else {
4169         std::cerr << "XGetWindowProperty () is failed!!!\n";
4170     }
4171
4172     if (data)
4173         XFree (data);
4174
4175     return window;
4176 }
4177
4178 /**
4179  * @brief Get app window's x window id.
4180  *
4181  * @return the X window id of application to have focus or to request to show IME.
4182  */
4183 static Ecore_X_Window efl_get_app_window (void)
4184 {
4185     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4186
4187     return efl_get_window ("_ISF_ACTIVE_WINDOW");
4188 }
4189
4190 /**
4191  * @brief Get clipboard window's x window id.
4192  *
4193  * @return the X window id of clipboard.
4194  */
4195 static Ecore_X_Window efl_get_clipboard_window (void)
4196 {
4197     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4198
4199     return efl_get_window ("CBHM_ELM_WIN");
4200 }
4201
4202 /**
4203  * @brief Get global natigation window's x window id.
4204  *
4205  * @return the X window id of global navigation.
4206  */
4207 static Ecore_X_Window efl_get_global_navigation_window (void)
4208 {
4209     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4210
4211     return efl_get_window ("GNB_WIN");
4212 }
4213
4214 /**
4215  * @brief Get app window's x window id.
4216  *
4217  * @return the X window id of quick panel.
4218  */
4219 static Ecore_X_Window efl_get_quickpanel_window (void)
4220 {
4221     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4222
4223     Ecore_X_Window rootWin = ecore_x_window_root_first_get ();
4224     Ecore_X_Window qpwin;
4225     ecore_x_window_prop_xid_get (rootWin, ecore_x_atom_get ("_E_ILLUME_QUICKPANEL_WINDOW_LIST"), ECORE_X_ATOM_WINDOW, &qpwin, 1);
4226
4227     return qpwin;
4228 }
4229
4230 /**
4231  * @brief Get default zone geometry.
4232  *
4233  * @param x The zone x position.
4234  * @param y The zone y position.
4235  * @param w The zone width.
4236  * @param h The zone height.
4237  *
4238  * @return EINA_TRUE if successful, otherwise return EINA_FALSE
4239  */
4240 static Eina_Bool efl_get_default_zone_geometry_info (Ecore_X_Window root, uint *x, uint *y, uint *w, uint *h)
4241 {
4242     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4243
4244     Ecore_X_Atom    zone_geometry_atom;
4245     Ecore_X_Window *zone_lists;
4246     int             num_zone_lists;
4247     int             num_ret;
4248     Eina_Bool       ret;
4249
4250     zone_geometry_atom = ecore_x_atom_get ("_E_ILLUME_ZONE_GEOMETRY");
4251     if (!zone_geometry_atom) {
4252         /* Error... */
4253         return EINA_FALSE;
4254     }
4255
4256     uint geom[4];
4257     num_zone_lists = ecore_x_window_prop_window_list_get (root, ECORE_X_ATOM_E_ILLUME_ZONE_LIST, &zone_lists);
4258     if (num_zone_lists > 0) {
4259         num_ret = ecore_x_window_prop_card32_get (zone_lists[0], zone_geometry_atom, geom, 4);
4260         if (num_ret == 4) {
4261             if (x) *x = geom[0];
4262             if (y) *y = geom[1];
4263             if (w) *w = geom[2];
4264             if (h) *h = geom[3];
4265             ret = EINA_TRUE;
4266         } else {
4267             ret = EINA_FALSE;
4268         }
4269     } else {
4270         /* if there is no zone available */
4271         ret = EINA_FALSE;
4272     }
4273
4274     if (zone_lists) {
4275         /* We must free zone_lists */
4276         free (zone_lists);
4277     }
4278
4279     return ret;
4280 }
4281 #endif /* HAVE_ECOREX */
4282
4283 #if ISF_BUILD_CANDIDATE_UI
4284 /**
4285  * @brief Get screen resolution.
4286  *
4287  * @param width The screen width.
4288  * @param height The screen height.
4289  */
4290 static void efl_get_screen_resolution (int &width, int &height)
4291 {
4292     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4293
4294     static Evas_Coord scr_w = 0, scr_h = 0;
4295     if (scr_w == 0 || scr_h == 0) {
4296 #ifdef HAVE_ECOREX
4297         uint w = 0, h = 0;
4298         if (efl_get_default_zone_geometry_info (ecore_x_window_root_first_get (), NULL, NULL, &w, &h)) {
4299             scr_w = w;
4300             scr_h = h;
4301         } else {
4302             ecore_x_window_size_get (ecore_x_window_root_first_get (), &scr_w, &scr_h);
4303         }
4304 #else
4305         Ecore_Wl2_Display *wl2_display = ecore_wl2_connected_display_get(NULL);
4306         if (wl2_display)
4307             ecore_wl2_display_screen_size_get(wl2_display, &scr_w, &scr_h);
4308 #endif
4309     }
4310
4311     width  = scr_w;
4312     height = scr_h;
4313 }
4314 #endif /* CANDIDATE */
4315
4316 //////////////////////////////////////////////////////////////////////
4317 // Start of PanelAgent Functions
4318 //////////////////////////////////////////////////////////////////////
4319
4320 /**
4321  * @brief Initialize panel agent.
4322  *
4323  * @param config The config string for PanelAgent.
4324  * @param display The current display.
4325  * @param resident The variable indicates whether panel will be resident.
4326  *
4327  * @return true if initialize is successful, otherwise return false.
4328  */
4329 static bool initialize_panel_agent (const ConfigPointer& config, const String &display, bool resident)
4330 {
4331     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4332
4333     LOGD ("initializing panel agent");
4334
4335     _info_manager = new InfoManager ();
4336
4337     if (!_info_manager || !_info_manager->initialize (_info_manager, config, display, resident)) {
4338         ISF_SAVE_LOG ("panel_agent initialize fail!");
4339         return false;
4340     }
4341
4342     _info_manager->signal_connect_focus_in                   (slot (slot_focus_in));
4343     _info_manager->signal_connect_focus_out                  (slot (slot_focus_out));
4344     _info_manager->signal_connect_expand_candidate           (slot (slot_expand_candidate));
4345     _info_manager->signal_connect_contract_candidate         (slot (slot_contract_candidate));
4346     _info_manager->signal_connect_set_candidate_ui           (slot (slot_set_candidate_style));
4347     _info_manager->signal_connect_update_factory_info        (slot (slot_update_factory_info));
4348     _info_manager->signal_connect_update_spot_location       (slot (slot_update_spot_location));
4349     _info_manager->signal_connect_update_input_context       (slot (slot_update_input_context));
4350     _info_manager->signal_connect_update_ise_geometry        (slot (slot_update_ise_geometry));
4351     _info_manager->signal_connect_show_preedit_string        (slot (slot_show_preedit_string));
4352     _info_manager->signal_connect_show_aux_string            (slot (slot_show_aux_string));
4353     _info_manager->signal_connect_show_lookup_table          (slot (slot_show_candidate_table));
4354     _info_manager->signal_connect_hide_preedit_string        (slot (slot_hide_preedit_string));
4355     _info_manager->signal_connect_hide_aux_string            (slot (slot_hide_aux_string));
4356     _info_manager->signal_connect_hide_lookup_table          (slot (slot_hide_candidate_table));
4357     _info_manager->signal_connect_update_preedit_string      (slot (slot_update_preedit_string));
4358     _info_manager->signal_connect_update_preedit_caret       (slot (slot_update_preedit_caret));
4359     _info_manager->signal_connect_update_aux_string          (slot (slot_update_aux_string));
4360     _info_manager->signal_connect_update_lookup_table        (slot (slot_update_candidate_table));
4361     _info_manager->signal_connect_select_candidate           (slot (slot_select_candidate));
4362     _info_manager->signal_connect_get_candidate_geometry     (slot (slot_get_candidate_geometry));
4363     _info_manager->signal_connect_get_input_panel_geometry   (slot (slot_get_input_panel_geometry));
4364     _info_manager->signal_connect_set_active_ise_by_uuid     (slot (slot_set_active_ise));
4365     _info_manager->signal_connect_get_ise_list               (slot (slot_get_ise_list));
4366     _info_manager->signal_connect_get_all_helper_ise_info    (slot (slot_get_all_helper_ise_info));
4367     _info_manager->signal_connect_set_has_option_helper_ise_info(slot (slot_set_has_option_helper_ise_info));
4368     _info_manager->signal_connect_set_enable_helper_ise_info (slot (slot_set_enable_helper_ise_info));
4369     _info_manager->signal_connect_show_helper_ise_list       (slot (slot_show_helper_ise_list));
4370     _info_manager->signal_connect_show_helper_ise_selector   (slot (slot_show_helper_ise_selector));
4371     _info_manager->signal_connect_is_helper_ise_enabled      (slot (slot_is_helper_ise_enabled));
4372     _info_manager->signal_connect_get_ise_information        (slot (slot_get_ise_information));
4373     _info_manager->signal_connect_get_keyboard_ise_list      (slot (slot_get_keyboard_ise_list));
4374     _info_manager->signal_connect_get_language_list          (slot (slot_get_language_list));
4375     _info_manager->signal_connect_get_all_language           (slot (slot_get_all_language));
4376     _info_manager->signal_connect_get_ise_language           (slot (slot_get_ise_language));
4377     _info_manager->signal_connect_get_ise_info_by_uuid       (slot (slot_get_ise_info));
4378     _info_manager->signal_connect_set_keyboard_ise           (slot (slot_set_keyboard_ise));
4379     _info_manager->signal_connect_get_keyboard_ise           (slot (slot_get_keyboard_ise));
4380     _info_manager->signal_connect_accept_connection          (slot (slot_accept_connection));
4381     _info_manager->signal_connect_close_connection           (slot (slot_close_connection));
4382     _info_manager->signal_connect_exit                       (slot (slot_exit));
4383
4384     _info_manager->signal_connect_register_helper            (slot(slot_register_helper));
4385     _info_manager->signal_connect_register_helper_properties (slot (slot_register_helper_properties));
4386     _info_manager->signal_connect_show_ise                   (slot (slot_show_ise));
4387     _info_manager->signal_connect_hide_ise                   (slot (slot_hide_ise));
4388
4389     _info_manager->signal_connect_will_hide_ack              (slot (slot_will_hide_ack));
4390
4391     _info_manager->signal_connect_set_keyboard_mode          (slot (slot_set_keyboard_mode));
4392
4393     _info_manager->signal_connect_candidate_will_hide_ack    (slot (slot_candidate_will_hide_ack));
4394     _info_manager->signal_connect_get_ise_state              (slot (slot_get_ise_state));
4395     _info_manager->signal_connect_start_default_ise          (slot (slot_start_default_ise));
4396     _info_manager->signal_connect_stop_default_ise           (slot (slot_stop_default_ise));
4397     _info_manager->signal_connect_show_panel                 (slot (slot_show_helper_ise_selector));
4398 #if ENABLE_REMOTE_INPUT
4399     _info_manager->signal_connect_remoteinput_send_input_message(slot (slot_send_remote_input_message));
4400     _info_manager->signal_connect_remoteinput_send_surrounding_text(slot (slot_recv_remote_surrounding_text));
4401 #endif
4402     _info_manager->signal_connect_get_recent_ise_geometry    (slot (slot_get_recent_ise_geometry));
4403     _info_manager->signal_connect_check_privilege_by_sockfd  (slot (slot_check_privilege_by_sockfd));
4404
4405     _info_manager->signal_connect_run_helper                 (slot (slot_run_helper));
4406     _info_manager->signal_connect_launch_option_application  (slot (slot_launch_option_application));
4407
4408     LOGD ("initializing panel agent succeeded");
4409
4410     return true;
4411 }
4412
4413 static void delete_ise_hide_timer (void)
4414 {
4415     LOGD ("deleting ise_hide_timer");
4416     if (_ise_hide_timer) {
4417         ecore_timer_del (_ise_hide_timer);
4418         _ise_hide_timer = NULL;
4419     }
4420 }
4421
4422 static void hide_ise ()
4423 {
4424     LOGD ("send request to hide helper");
4425     String uuid = _info_manager->get_current_helper_uuid ();
4426     _info_manager->hide_helper (uuid);
4427
4428     /* Only if we are not already in HIDE state */
4429     if (_ise_state != WINDOW_STATE_HIDE) {
4430         /* From this point, slot_get_input_panel_geometry should return hidden state geometry */
4431         _ise_state = WINDOW_STATE_WILL_HIDE;
4432
4433         _updated_hide_state_geometry = false;
4434     }
4435     _ise_angle = -1;
4436 #ifdef HAVE_ECOREX
4437     ecore_x_event_mask_unset (_app_window, ECORE_X_EVENT_MASK_WINDOW_FOCUS_CHANGE);
4438 #endif
4439 #if ISF_BUILD_CANDIDATE_UI
4440     if (_candidate_window) {
4441         if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE)
4442             ui_candidate_hide (true, true, true);
4443         else
4444             ui_candidate_hide (true, false, true);
4445     }
4446 #endif /* CANDIDATE */
4447
4448 #ifdef HAVE_ECOREWL
4449 #ifdef HAVE_NOTIFICATION
4450     delete_notification (&ise_selector_module_noti);
4451 #endif
4452 #endif
4453 }
4454
4455 #if ENABLE_MULTIWINDOW_SUPPORT
4456 static Eina_Bool ise_hide_timeout (void *data)
4457 {
4458     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4459
4460     delete_ise_hide_timer ();
4461     hide_ise ();
4462
4463     return ECORE_CALLBACK_CANCEL;
4464 }
4465 #endif
4466
4467 /**
4468  * @brief Insert data to ime_info table.
4469  *
4470  * @param list The list to store uuid
4471  *
4472  * @return true if it is successful, otherwise return false.
4473  */
4474 static bool update_ise_list (std::vector<String> &list)
4475 {
4476     std::vector<String> uuids;
4477     std::vector<TOOLBAR_MODE_T>  modes;
4478     std::vector<ImeInfoDB>::iterator iter;
4479     bool result = true;
4480
4481     if (_ime_info.size() == 0) {
4482         if (isf_pkg_select_all_ime_info_db(_ime_info) == 0)
4483             result = false;
4484     }
4485
4486     /* Update _groups */
4487     _groups.clear();
4488     std::vector<String> ise_langs;
4489     for (size_t i = 0; i < _ime_info.size (); ++i) {
4490         scim_split_string_list(ise_langs, _ime_info[i].languages);
4491         for (size_t j = 0; j < ise_langs.size (); j++) {
4492             if (std::find (_groups[ise_langs[j]].begin (), _groups[ise_langs[j]].end (), i) == _groups[ise_langs[j]].end ())
4493             _groups[ise_langs[j]].push_back (i);
4494         }
4495         ise_langs.clear ();
4496     }
4497
4498     for (iter = _ime_info.begin(); iter != _ime_info.end(); iter++) {
4499         uuids.push_back(iter->appid);
4500         modes.push_back(iter->mode);
4501     }
4502
4503     if (uuids.size() > 0) {
4504         list.clear ();
4505         list = uuids;
4506
4507         _info_manager->update_ise_list (list);
4508
4509         if (_initial_ise_uuid.length () > 0) {
4510             String active_uuid   = _initial_ise_uuid;
4511             String default_uuid  = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), String (""));
4512             if (std::find (uuids.begin (), uuids.end (), default_uuid) == uuids.end ()) {
4513                 if ((_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) && (modes[get_ise_index (_initial_ise_uuid)] != TOOLBAR_KEYBOARD_MODE)) {
4514                     active_uuid = String (SCIM_COMPOSE_KEY_FACTORY_UUID);
4515                 }
4516
4517                 if (set_active_ise (active_uuid, _soft_keyboard_launched) == false) {
4518                     if (_initial_ise_uuid.compare (active_uuid)) {
4519                         LOGD ("Trying to launch initial IME (%s)", _initial_ise_uuid.c_str ());
4520                         set_active_ise (_initial_ise_uuid, _soft_keyboard_launched);
4521                     }
4522                 }
4523             } else if (_info_manager->get_current_toolbar_mode () == TOOLBAR_HELPER_MODE) {    // Check whether keyboard engine is installed
4524                 String IMENGINE_KEY  = String (SCIM_CONFIG_DEFAULT_IMENGINE_FACTORY) + String ("/") + String ("~other");
4525                 String keyboard_uuid = _config->read (IMENGINE_KEY, String (""));
4526                 if (std::find (uuids.begin (), uuids.end (), keyboard_uuid) == uuids.end ()) {
4527                     active_uuid = String (SCIM_COMPOSE_KEY_FACTORY_UUID);
4528                     _info_manager->change_factory (active_uuid);
4529                     _config->write (IMENGINE_KEY, active_uuid);
4530                     _config->flush ();
4531                 }
4532             }
4533         }
4534
4535 #ifdef HAVE_VCONF
4536         char *lang_str = vconf_get_str (VCONFKEY_LANGSET);
4537         if (lang_str) {
4538             if (_ime_info.size () > 0 && _ime_info[0].display_lang.compare(lang_str) == 0)
4539                 _locale_string = String (lang_str);
4540             free (lang_str);
4541         }
4542 #endif
4543     }
4544     else
4545         LOGW ("No IME list");
4546
4547 #ifdef HAVE_PKGMGR_INFO
4548     if (!pkgmgr) {
4549         int ret = package_manager_create (&pkgmgr);
4550         if (ret == PACKAGE_MANAGER_ERROR_NONE) {
4551             ret = package_manager_set_event_cb (pkgmgr, _package_manager_event_cb, NULL);
4552             if (ret == PACKAGE_MANAGER_ERROR_NONE) {
4553                 LOGD ("package_manager_set_event_cb succeeded.");
4554             }
4555             else {
4556                 LOGE ("package_manager_set_event_cb failed(%d)", ret);
4557             }
4558         }
4559         else {
4560             LOGE ("package_manager_create failed(%d)", ret);
4561         }
4562     }
4563 #endif
4564
4565     return result;
4566 }
4567
4568 /**
4569  * @brief Focus in slot function for PanelAgent.
4570  */
4571 static void slot_focus_in (void)
4572 {
4573     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4574
4575     _focus_in = true;
4576     if ((_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE)) {
4577         if (_launch_ise_on_request && !_soft_keyboard_launched) {
4578             String uuid = _config->read (SCIM_CONFIG_DEFAULT_HELPER_ISE, String (""));
4579             if (uuid.length () > 0 && (_ime_info[get_ise_index(uuid)].options & ISM_HELPER_PROCESS_KEYBOARD_KEYEVENT)) {
4580                 LOGD ("Start helper (%s)", uuid.c_str ());
4581
4582                 set_keyboard_engine (String (SCIM_COMPOSE_KEY_FACTORY_UUID));
4583                 if (_info_manager->start_helper (uuid))
4584                     _soft_keyboard_launched = true;
4585             }
4586         }
4587     }
4588
4589 #if ISF_BUILD_CANDIDATE_UI
4590     ui_candidate_delete_destroy_timer ();
4591 #endif /* CANDIDATE */
4592 }
4593
4594 /**
4595  * @brief Focus out slot function for PanelAgent.
4596  */
4597 static void slot_focus_out (void)
4598 {
4599     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4600
4601     _focus_in = false;
4602
4603 #if ISF_BUILD_CANDIDATE_UI
4604     ui_candidate_delete_destroy_timer ();
4605     _destroy_timer = ecore_timer_add (ISF_CANDIDATE_DESTROY_DELAY, ui_candidate_destroy_timeout, NULL);
4606 #endif /* CANDIDATE */
4607 }
4608
4609 /**
4610  * @brief Expand candidate slot function for PanelAgent.
4611  */
4612 static void slot_expand_candidate (void)
4613 {
4614     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4615     if (_candidate_mode == SOFT_CANDIDATE_WINDOW)
4616         return;
4617
4618 #if ISF_BUILD_CANDIDATE_UI
4619     if (_candidate_area_2 && !_candidate_area_2_visible)
4620         ui_candidate_window_more_button_cb (NULL, NULL, NULL, NULL);
4621 #endif /* CANDIDATE */
4622 }
4623
4624 /**
4625  * @brief Contract candidate slot function for PanelAgent.
4626  */
4627 static void slot_contract_candidate (void)
4628 {
4629     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4630
4631     if (_candidate_mode == SOFT_CANDIDATE_WINDOW)
4632         return;
4633
4634 #if ISF_BUILD_CANDIDATE_UI
4635     ui_candidate_window_close_button_cb (NULL, NULL, NULL, NULL);
4636 #endif /* CANDIDATE */
4637 }
4638
4639 /**
4640  * @brief Set candidate style slot function for PanelAgent.
4641  *
4642  * @param portrait_line The displayed line number for portrait.
4643  * @param mode The candidate mode.
4644  */
4645 static void slot_set_candidate_style (int portrait_line, int mode)
4646 {
4647     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " display_line:" << portrait_line << " mode:" << mode << "\n";
4648 #if ISF_BUILD_CANDIDATE_UI
4649     if ((portrait_line != _candidate_port_line) || (mode != _candidate_mode)) {
4650         _candidate_mode      = (ISF_CANDIDATE_MODE_T)mode;
4651         _candidate_port_line = (ISF_CANDIDATE_PORTRAIT_LINE_T)portrait_line;
4652         _soft_candidate_width = 0;
4653         _soft_candidate_height = 0;
4654
4655         if (_candidate_mode == SOFT_CANDIDATE_WINDOW) {
4656             if (_candidate_window)
4657                 ui_destroy_candidate_window ();
4658
4659             return;
4660         }
4661
4662         if (_candidate_window)
4663             ui_create_candidate_window ();
4664     }
4665 #endif /* CANDIDATE */
4666 }
4667
4668 #if defined(HAVE_NOTIFICATION) || defined(HAVE_ECOREX)
4669 static unsigned int get_ise_count (TOOLBAR_MODE_T mode, bool valid_helper)
4670 {
4671     unsigned int ise_count = 0;
4672     for (unsigned int i = 0; i < _ime_info.size (); i++) {
4673         if (mode == _ime_info[i].mode) {
4674             if (mode == TOOLBAR_KEYBOARD_MODE || !valid_helper)
4675                 ise_count++;
4676             else if (_ime_info[i].is_enabled)
4677                 ise_count++;
4678         }
4679     }
4680
4681     return ise_count;
4682 }
4683 #endif
4684
4685 /**
4686  * @brief Update keyboard ISE information slot function for PanelAgent.
4687  *
4688  * @param info The information of current Keyboard ISE.
4689  */
4690 static void slot_update_factory_info (const PanelFactoryInfo &info)
4691 {
4692     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4693
4694     String ise_name = info.name;
4695
4696     String old_ise = _info_manager->get_current_ise_name ();
4697 #if ISF_BUILD_CANDIDATE_UI
4698     if (old_ise != ise_name) {
4699         if ((_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) && _candidate_window) {
4700             ui_destroy_candidate_window ();
4701         }
4702     }
4703 #endif /* CANDIDATE */
4704
4705     TOOLBAR_MODE_T mode = _info_manager->get_current_toolbar_mode ();
4706
4707     if (TOOLBAR_HELPER_MODE == mode)
4708         ise_name = _ime_info[get_ise_index (_info_manager->get_current_helper_uuid())].label;
4709
4710     if (ise_name.length () > 0)
4711         _info_manager->set_current_ise_name (ise_name);
4712
4713 #ifdef HAVE_NOTIFICATION
4714     if (_MOBILE) {
4715         if (old_ise != ise_name) {
4716             if (TOOLBAR_KEYBOARD_MODE == mode) {
4717                 char noti_msg[256] = {0};
4718                 unsigned int keyboard_ise_count = get_ise_count (TOOLBAR_KEYBOARD_MODE, false);
4719                 if (keyboard_ise_count == 0) {
4720                     LOGD ("the number of keyboard ise is %d", keyboard_ise_count);
4721                     return;
4722                 }
4723                 else if (keyboard_ise_count >= 2) {
4724                     snprintf (noti_msg, sizeof (noti_msg), _("%s selected"), ise_name.c_str ());
4725                 }
4726                 else if (keyboard_ise_count == 1) {
4727                     snprintf (noti_msg, sizeof (noti_msg), _("Only %s available"), ise_name.c_str ());
4728                 }
4729
4730                 notification_status_message_post (noti_msg);
4731                 LOGD ("%s", noti_msg);
4732             }
4733         }
4734     }
4735 #endif
4736 }
4737
4738 /**
4739  * @brief Update cursor position slot function for PanelAgent.
4740  *
4741  * @param x The x position of current cursor.
4742  * @param y The bottom y position of current cursor.
4743  * @param top_y The top y position of current cursor.
4744  */
4745 static void slot_update_spot_location (int x, int y, int top_y)
4746 {
4747     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4748
4749 #if ISF_BUILD_CANDIDATE_UI
4750     if (x >= 0 && x < _screen_height && y >= 0 && y < _screen_height) {
4751         _spot_location_x = x;
4752         _spot_location_y = y;
4753         _spot_location_top_y = top_y;
4754
4755         ui_settle_candidate_window ();
4756     }
4757 #endif /* CANDIDATE */
4758 }
4759
4760 /**
4761  * @brief The input context of ISE is changed.
4762  *
4763  * @param type  The event type.
4764  * @param value The event value.
4765  */
4766 static void slot_update_input_context (int type, int value)
4767 {
4768 }
4769
4770 /**
4771  * @brief Update ise geometry.
4772  *
4773  * @param x      The x position in screen.
4774  * @param y      The y position in screen.
4775  * @param width  The ISE window width.
4776  * @param height The ISE window height.
4777  */
4778 static void slot_update_ise_geometry (int x, int y, int width, int height)
4779 {
4780     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " x:" << x << " y:" << y << " width:" << width << " height:" << height << "...\n";
4781
4782     LOGD ("x : %d , y : %d , width : %d , height : %d, _ise_state : %d", x, y, width, height, _ise_state);
4783
4784     if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) {
4785         if (_candidate_mode == SOFT_CANDIDATE_WINDOW) {
4786             /*IF ISE sent the ise_geometry information when the current_keyboard_mode is H/W mode and candidate_mode is SOFT_CANDIDATE,
4787              It means that given geometry information is for the candidate window */
4788             set_soft_candidate_geometry (x, y, width, height);
4789         }
4790         return;
4791     }
4792
4793     _ise_x = x;
4794     _ise_y = y;
4795     _ise_width  = width;
4796     _ise_height = height;
4797
4798 #if ISF_BUILD_CANDIDATE_UI
4799     if (_candidate_window && _candidate_state == WINDOW_STATE_SHOW) {
4800         ui_settle_candidate_window ();
4801     }
4802 #endif /* CANDIDATE */
4803
4804     if (_ise_state == WINDOW_STATE_SHOW || _ise_state == WINDOW_STATE_WILL_SHOW) {
4805         _ise_reported_geometry.valid = true;
4806         _ise_reported_geometry.angle = efl_get_ise_window_angle ();
4807         _ise_reported_geometry.geometry.pos_x = x;
4808         _ise_reported_geometry.geometry.pos_y = y;
4809         _ise_reported_geometry.geometry.width = width;
4810         _ise_reported_geometry.geometry.height = height;
4811         if (_ise_state == WINDOW_STATE_SHOW) {
4812 #ifdef HAVE_ECOREX
4813             set_keyboard_geometry_atom_info (_app_window, _ise_reported_geometry.geometry);
4814 #endif
4815             _info_manager->update_input_panel_event (ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
4816         }
4817     }
4818 }
4819
4820 /**
4821  * @brief Show preedit slot function for PanelAgent.
4822  */
4823 static void slot_show_preedit_string (void)
4824 {
4825     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4826
4827     if (_candidate_mode == SOFT_CANDIDATE_WINDOW)
4828         return;
4829
4830 #if ISF_BUILD_CANDIDATE_UI
4831     if (_preedit_window == NULL) {
4832         ui_create_preedit_window ();
4833
4834         /* Move preedit window according to candidate window position */
4835         if (_candidate_window) {
4836             /* Get candidate window position */
4837             int x, y, width, height;
4838             ecore_evas_geometry_get (ecore_evas_ecore_evas_get (evas_object_evas_get (_candidate_window)), &x, &y, &width, &height);
4839
4840             int height2 = ui_candidate_get_valid_height ();
4841             int angle = efl_get_app_window_angle ();
4842
4843             if (angle == 90) {
4844                 x -= _preedit_height;
4845                 y = _screen_height - _preedit_width;
4846             } else if (_candidate_angle == 270) {
4847                 x += height2;
4848             } else if (_candidate_angle == 180) {
4849                 x = _screen_width - _preedit_width;
4850                 y += height2;
4851             } else {
4852                 y -= _preedit_height;
4853             }
4854
4855             if (_preedit_window)
4856                 evas_object_move (_preedit_window, x, y);
4857         }
4858     }
4859
4860     if (_preedit_window && evas_object_visible_get (_preedit_window))
4861         return;
4862
4863     slot_show_candidate_table ();
4864
4865     if (_preedit_window)
4866         evas_object_show (_preedit_window);
4867 #endif /* CANDIDATE */
4868 }
4869
4870 /**
4871  * @brief Show aux slot function for PanelAgent.
4872  */
4873 static void slot_show_aux_string (void)
4874 {
4875     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4876
4877 #if ISF_BUILD_CANDIDATE_UI
4878     if (_candidate_window == NULL)
4879         ui_create_candidate_window ();
4880
4881     if (_aux_area == NULL || _aux_area_visible)
4882         return;
4883
4884     evas_object_show (_aux_area);
4885     _aux_area_visible = true;
4886     ui_candidate_window_adjust ();
4887
4888     LOGD ("calling ui_candidate_show ()");
4889     ui_candidate_show ();
4890     ui_settle_candidate_window ();
4891     ui_candidate_delete_destroy_timer ();
4892 #endif /* CANDIDATE */
4893 }
4894
4895 /**
4896  * @brief Show candidate table slot function for PanelAgent.
4897  */
4898 static void slot_show_candidate_table (void)
4899 {
4900     if (_candidate_mode == SOFT_CANDIDATE_WINDOW) {
4901         _info_manager->helper_candidate_show ();
4902         return;
4903     }
4904
4905 #if ISF_BUILD_CANDIDATE_UI
4906     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4907     if (_candidate_window == NULL)
4908         ui_create_candidate_window ();
4909
4910 #ifdef HAVE_ECOREX
4911     if (_candidate_state == WINDOW_STATE_SHOW &&
4912         (_candidate_area_1_visible || _candidate_area_2_visible)) {
4913         efl_set_transient_for_app_window (elm_win_xwindow_get (_candidate_window));
4914         return;
4915     }
4916 #endif
4917
4918     evas_object_show (_candidate_area_1);
4919     _candidate_area_1_visible = true;
4920     ui_candidate_window_adjust ();
4921
4922     LOGD ("calling ui_candidate_show ()");
4923     ui_candidate_show ();
4924     ui_settle_candidate_window ();
4925     ui_candidate_delete_destroy_timer ();
4926
4927 #ifdef HAVE_FEEDBACK
4928     int feedback_result = feedback_initialize ();
4929
4930     if (FEEDBACK_ERROR_NONE == feedback_result) {
4931         LOGD ("Feedback initialize successful");
4932         feedback_initialized = true;
4933     } else {
4934         LOGW ("Feedback initialize fail : %d", feedback_result);
4935         feedback_initialized = false;
4936     }
4937 #endif /* HAVE_FEEDBACK */
4938 #endif /* CANDIDATE */
4939 }
4940
4941 /**
4942  * @brief Hide preedit slot function for PanelAgent.
4943  */
4944 static void slot_hide_preedit_string (void)
4945 {
4946     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4947
4948 #if ISF_BUILD_CANDIDATE_UI
4949     if (!_preedit_window || !evas_object_visible_get (_preedit_window))
4950         return;
4951
4952     evas_object_hide (_preedit_window);
4953 #endif /* CANDIDATE */
4954 }
4955
4956 /**
4957  * @brief Hide aux slot function for PanelAgent.
4958  */
4959 static void slot_hide_aux_string (void)
4960 {
4961     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4962
4963 #if ISF_BUILD_CANDIDATE_UI
4964     if (!_aux_area || !_aux_area_visible)
4965         return;
4966
4967     evas_object_hide (_aux_area);
4968     _aux_area_visible = false;
4969     elm_scroller_region_show (_aux_area, 0, 0, 10, 10);
4970     ui_candidate_window_adjust ();
4971
4972     LOGD ("calling ui_candidate_hide (false, true, true)");
4973     ui_candidate_hide (false, true, true);
4974     ui_settle_candidate_window ();
4975
4976     if (ui_candidate_can_be_hide ()) {
4977         _candidate_show_requested = false;
4978         LOGD ("setting _show_candidate_requested to FALSE");
4979     }
4980 #endif /* CANDIDATE */
4981 }
4982
4983 /**
4984  * @brief Hide candidate table slot function for PanelAgent.
4985  */
4986 static void slot_hide_candidate_table (void)
4987 {
4988     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
4989
4990     if (_candidate_mode == SOFT_CANDIDATE_WINDOW) {
4991         _info_manager->helper_candidate_hide ();
4992         return;
4993     }
4994
4995 #if ISF_BUILD_CANDIDATE_UI
4996     if (!_candidate_area_1 || _candidate_state == WINDOW_STATE_WILL_HIDE)
4997         return;
4998
4999     if (_candidate_area_1_visible || _candidate_area_2_visible) {
5000         bool bForce = false;
5001         if (_candidate_area_1_visible) {
5002             if (_aux_area_visible) {
5003                 evas_object_hide (_candidate_area_1);
5004                 _candidate_area_1_visible = false;
5005                 evas_object_hide (_more_btn);
5006             } else {
5007                 /* Let's not actually hide the _candidate_area_1 object, for the case that
5008                    even if the application replies CANDIDATE_WILL_HIDE_ACK a little late,
5009                    it is better to display the previous candidates instead of blank screen */
5010                 _candidate_area_1_visible = false;
5011                 bForce = true;
5012             }
5013         }
5014         if (_candidate_area_2_visible) {
5015             evas_object_hide (_candidate_area_2);
5016             _candidate_area_2_visible = false;
5017             evas_object_hide (_scroller_bg);
5018             evas_object_hide (_close_btn);
5019             _info_manager->candidate_more_window_hide ();
5020         }
5021         ui_candidate_window_adjust ();
5022
5023         LOGD ("calling ui_candidate_hide (%d, true, true)", bForce);
5024         ui_candidate_hide (bForce, true, true);
5025         ui_settle_candidate_window ();
5026     }
5027
5028 #ifdef HAVE_FEEDBACK
5029     int feedback_result = feedback_deinitialize ();
5030
5031     if (FEEDBACK_ERROR_NONE == feedback_result)
5032         LOGD ("Feedback deinitialize successful");
5033     else
5034         LOGW ("Feedback deinitialize fail : %d", feedback_result);
5035
5036     feedback_initialized = false;
5037 #endif
5038
5039     if (ui_candidate_can_be_hide ()) {
5040         _candidate_show_requested = false;
5041         LOGD ("setting _show_candidate_requested to FALSE");
5042     }
5043 #endif /* CANDIDATE */
5044 }
5045
5046 /**
5047  * @brief Update preedit slot function for PanelAgent.
5048  *
5049  * @param str The new preedit string.
5050  * @param attrs The attribute list of new preedit string.
5051  */
5052 static void slot_update_preedit_string (const String &str, const AttributeList &attrs, int caret)
5053 {
5054     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " string=" << str << "\n";
5055
5056 #if ISF_BUILD_CANDIDATE_UI
5057     if (str.length () <= 0)
5058         return;
5059
5060     if (_preedit_window == NULL || !evas_object_visible_get (_preedit_window)) {
5061         slot_show_preedit_string ();
5062     }
5063
5064     int x, y, width, height, candidate_width;
5065     evas_object_text_text_set (_tmp_preedit_text, str.c_str ());
5066     evas_object_geometry_get (_tmp_preedit_text, &x, &y, &width, &height);
5067     ecore_evas_geometry_get (ecore_evas_ecore_evas_get (evas_object_evas_get (_candidate_window)), &x, &y, &candidate_width, &height);
5068     _preedit_width = (width + ISF_PREEDIT_BORDER * 2) < candidate_width ? (width + ISF_PREEDIT_BORDER * 2) : candidate_width;
5069
5070     /* Resize preedit window and avoid text blink */
5071     int old_width, old_height;
5072     evas_object_geometry_get (_preedit_window, &x, &y, &old_width, &old_height);
5073     if (old_width < _preedit_width) {
5074         evas_object_resize (_preedit_window, _preedit_width, _preedit_height);
5075         edje_object_part_text_set (_preedit_text, "preedit", str.c_str ());
5076     } else {
5077         edje_object_part_text_set (_preedit_text, "preedit", str.c_str ());
5078         evas_object_resize (_preedit_window, _preedit_width, _preedit_height);
5079     }
5080
5081     /* Move preedit window */
5082     if (_candidate_angle == 90 || _candidate_angle == 180) {
5083         ecore_evas_geometry_get (ecore_evas_ecore_evas_get (evas_object_evas_get (_preedit_window)), &x, &y, &width, &height);
5084         if (_candidate_angle == 90) {
5085             y = _screen_height - _preedit_width;
5086         } else if (_candidate_angle == 180) {
5087             x = _screen_width - _preedit_width;
5088         }
5089         evas_object_move (_preedit_window, x, y);
5090     }
5091 #endif /* CANDIDATE */
5092 }
5093
5094 /**
5095  * @brief Update caret slot function for PanelAgent.
5096  *
5097  * @param caret The caret position.
5098  */
5099 static void slot_update_preedit_caret (int caret)
5100 {
5101     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " caret=" << caret << "\n";
5102 }
5103
5104 #if ISF_BUILD_CANDIDATE_UI
5105 /**
5106  * @brief Set highlight text color and background color for edje object.
5107  *
5108  * @param item The edje object pointer.
5109  * @param nForeGround The text color.
5110  * @param nBackGround The background color.
5111  * @param bSetBack The flag for background color.
5112  */
5113 static void set_highlight_color (Evas_Object *item, uint32 nForeGround, uint32 nBackGround, bool bSetBack)
5114 {
5115     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
5116
5117     int r, g, b, a, r2, g2, b2, a2, r3, g3, b3, a3;
5118     if (edje_object_color_class_get (item, "text_color", &r, &g, &b, &a, &r2, &g2, &b2, &a2, &r3, &g3, &b3, &a3)) {
5119         r = SCIM_RGB_COLOR_RED (nForeGround);
5120         g = SCIM_RGB_COLOR_GREEN (nForeGround);
5121         b = SCIM_RGB_COLOR_BLUE (nForeGround);
5122         edje_object_color_class_set (item, "text_color", r, g, b, a, r2, g2, b2, a2, r3, g3, b3, a3);
5123     }
5124     if (bSetBack && edje_object_color_class_get (item, "rect_color", &r, &g, &b, &a, &r2, &g2, &b2, &a2, &r3, &g3, &b3, &a3)) {
5125         r = SCIM_RGB_COLOR_RED (nBackGround);
5126         g = SCIM_RGB_COLOR_GREEN (nBackGround);
5127         b = SCIM_RGB_COLOR_BLUE (nBackGround);
5128         edje_object_color_class_set (item, "rect_color", r, g, b, 255, r2, g2, b2, a2, r3, g3, b3, a3);
5129     }
5130 }
5131 #endif /* CANDIDATE */
5132
5133 /**
5134  * @brief Update aux slot function for PanelAgent.
5135  *
5136  * @param str The new aux string.
5137  * @param attrs The attribute list of new aux string.
5138  */
5139 static void slot_update_aux_string (const String &str, const AttributeList &attrs)
5140 {
5141     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
5142 #if ISF_BUILD_CANDIDATE_UI
5143     if (_candidate_window == NULL)
5144         ui_create_candidate_window ();
5145
5146     if (!_aux_area || (str.length () <= 0))
5147         return;
5148
5149     if (!_aux_area_visible) {
5150         LOGD ("calling ui_candidate_show ()");
5151         ui_candidate_show ();
5152         slot_show_aux_string ();
5153     }
5154
5155     int x, y, width, height, item_width = 0;
5156     unsigned int window_width = 0, count = 0, i;
5157
5158     Evas_Object *aux_edje = NULL;
5159
5160     /* Get highlight item index */
5161     int    aux_index = -1, aux_start = 0, aux_end = 0;
5162     String strAux      = str;
5163     bool   bSetBack    = false;
5164     uint32 nForeGround = SCIM_RGB_COLOR (62, 207, 255);
5165     uint32 nBackGround = SCIM_RGB_COLOR (0, 0, 0);
5166     for (AttributeList::const_iterator ait = attrs.begin (); ait != attrs.end (); ++ait) {
5167         if (aux_index == -1 && ait->get_type () == SCIM_ATTR_DECORATE) {
5168             aux_index = ait->get_value ();
5169         } else if (ait->get_type () == SCIM_ATTR_FOREGROUND) {
5170             nForeGround = ait->get_value ();
5171         } else if (ait->get_type () == SCIM_ATTR_BACKGROUND) {
5172             nBackGround = ait->get_value ();
5173             bSetBack = true;
5174         }
5175     }
5176
5177     std::vector<String> aux_list;
5178     scim_split_string_list (aux_list, strAux, '|');
5179
5180     if (_aux_items.size () > 0) {
5181         for (i = 0; i < _aux_items.size (); i++)
5182             evas_object_del (_aux_items [i]);
5183         _aux_items.clear ();
5184     }
5185     if (_aux_seperates.size () > 0) {
5186         for (i = 0; i < _aux_seperates.size (); i++)
5187             evas_object_del (_aux_seperates [i]);
5188         _aux_seperates.clear ();
5189     }
5190
5191     int   seperate_width  = 4;
5192     int   seperate_height = 52 * _height_rate;
5193     Evas *evas = evas_object_evas_get (_candidate_window);
5194     for (i = 0; i < aux_list.size (); i++) {
5195         if (i > 0) {
5196             Evas_Object *seperate_item = edje_object_add (evas);
5197             edje_object_file_set (seperate_item, _candidate_edje_file.c_str (), "seperate_line");
5198             evas_object_size_hint_min_set (seperate_item, seperate_width, seperate_height);
5199             elm_table_pack (_aux_table, seperate_item, 2 * i - 1, 0, 1, 1);
5200             evas_object_show (seperate_item);
5201             _aux_seperates.push_back (seperate_item);
5202         }
5203
5204         count++;
5205         aux_edje = edje_object_add (evas);
5206         edje_object_file_set (aux_edje, _candidate_edje_file.c_str (), "aux");
5207         edje_object_part_text_set (aux_edje, "aux", aux_list [i].c_str ());
5208         edje_object_text_class_set (aux_edje, "tizen", _candidate_font_name.c_str (), _aux_font_size);
5209         elm_table_pack (_aux_table, aux_edje, 2 * i, 0, 1, 1);
5210         evas_object_event_callback_add (aux_edje, EVAS_CALLBACK_MOUSE_DOWN, ui_mouse_button_pressed_cb, GINT_TO_POINTER ((i << 8) + ISF_EFL_AUX));
5211         evas_object_event_callback_add (aux_edje, EVAS_CALLBACK_MOUSE_UP, ui_mouse_button_released_cb, GINT_TO_POINTER (i));
5212         evas_object_event_callback_add (aux_edje, EVAS_CALLBACK_MOUSE_MOVE, ui_mouse_moved_cb, GINT_TO_POINTER (ISF_EFL_AUX));
5213         evas_object_show (aux_edje);
5214         _aux_items.push_back (aux_edje);
5215 /*      if (i == (unsigned int)aux_index)
5216             edje_object_signal_emit (aux_edje, "aux,state,selected", "aux");
5217         else
5218             edje_object_signal_emit (aux_edje, "aux,state,unselected", "aux");
5219 */
5220         evas_object_text_text_set (_tmp_aux_text, aux_list [i].c_str ());
5221         evas_object_geometry_get (_tmp_aux_text, &x, &y, &width, &height);
5222         item_width = width + 2*_blank_width;
5223         item_width = item_width > _item_min_width ? item_width : _item_min_width;
5224         evas_object_size_hint_min_set (aux_edje, item_width, _aux_height);
5225         if (aux_index == (int)i || (aux_index == -1 && i == 0)) {
5226             aux_start = window_width;
5227             aux_end   = window_width + item_width;
5228         }
5229         window_width = window_width + item_width + 4;
5230     }
5231
5232     // Set highlight item
5233     for (AttributeList::const_iterator ait = attrs.begin (); ait != attrs.end (); ++ait) {
5234         if (ait->get_type () == SCIM_ATTR_DECORATE) {
5235             unsigned int index = ait->get_value ();
5236             if (index < _aux_items.size ())
5237                 set_highlight_color (_aux_items [index], nForeGround, nBackGround, bSetBack);
5238         }
5239     }
5240
5241     int w, h;
5242     elm_scroller_region_get (_aux_area, &x, &y, &w, &h);
5243     item_width = aux_end - aux_start;
5244     if (item_width > 0) {
5245         if (item_width >= w)
5246             elm_scroller_region_show (_aux_area, aux_end - w, y, w, h);
5247         else if (aux_end > x + w)
5248             elm_scroller_region_show (_aux_area, aux_end - w, y, w, h);
5249         else if (aux_start < x)
5250             elm_scroller_region_show (_aux_area, aux_start, y, w, h);
5251     }
5252     flush_memory ();
5253 #endif /* CANDIDATE */
5254 }
5255
5256 #if ISF_BUILD_CANDIDATE_UI
5257 /**
5258  * @brief Update candidate/associate table.
5259  *
5260  * @param table_type The table type.
5261  * @param table The lookup table for candidate or associate.
5262  */
5263 static void update_table (int table_type, const LookupTable &table)
5264 {
5265     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " (" << table.get_current_page_size () << ")\n";
5266
5267     int item_num = table.get_current_page_size ();
5268     if (item_num < 0)
5269         return;
5270
5271     String     mbs;
5272     WideString wcs;
5273
5274     AttributeList attrs;
5275     int i, x, y, item_0_width = 0;
5276
5277     int nLast = 0;
5278
5279     int seperate_width  = 2;
5280     int seperate_height = 52 * _height_rate;
5281     int line_width      = _candidate_scroll_width;
5282     int line_height     = _v_padding;
5283     int total_width     = 0;
5284     int current_width   = 0;
5285     int line_0          = 0;
5286     int line_count      = 0;
5287     int more_item_count = 0;
5288     int scroll_0_width  = _candidate_scroll_0_width_min;
5289     int cursor_pos      = table.get_cursor_pos ();
5290     int cursor_line     = 0;
5291
5292     if (_candidate_angle == 90 || _candidate_angle == 270)
5293         scroll_0_width = _screen_height - _more_btn_width - _h_padding;
5294     else
5295         scroll_0_width = _screen_width - _more_btn_width - _h_padding;
5296
5297     _candidate_image_count = 0;
5298     _candidate_text_count = 0;
5299     _candidate_pop_image_count = 0;
5300     _candidate_display_number = 0;
5301     _candidate_row_items.clear ();
5302
5303     Evas *evas = evas_object_evas_get (_candidate_window);
5304     for (i = 0; i < SCIM_LOOKUP_TABLE_MAX_PAGESIZE; ++i) {
5305         if (_candidate_0 [i]) {
5306             evas_object_del (_candidate_0 [i]);
5307             _candidate_0 [i] = NULL;
5308         }
5309         if (_seperate_0 [i]) {
5310             evas_object_del (_seperate_0 [i]);
5311             _seperate_0 [i] = NULL;
5312         }
5313         if (_seperate_items [i]) {
5314             evas_object_del (_seperate_items [i]);
5315             _seperate_items [i] = NULL;
5316         }
5317         if (_line_0 [i]) {
5318             evas_object_del (_line_0 [i]);
5319             _line_0 [i] = NULL;
5320         }
5321         if (_line_items [i]) {
5322             evas_object_del (_line_items [i]);
5323             _line_items [i] = NULL;
5324         }
5325     }
5326
5327     for (i = 0; i < SCIM_LOOKUP_TABLE_MAX_PAGESIZE; ++i) {
5328         if (i < item_num) {
5329             bool   bHighLight  = false;
5330             bool   bSetBack    = false;
5331             uint32 nForeGround = SCIM_RGB_COLOR (249, 249, 249);
5332             uint32 nBackGround = SCIM_RGB_COLOR (0, 0, 0);
5333             attrs = table.get_attributes_in_current_page (i);
5334             for (AttributeList::const_iterator ait = attrs.begin (); ait != attrs.end (); ++ait) {
5335                 if (ait->get_type () == SCIM_ATTR_DECORATE && ait->get_value () == SCIM_ATTR_DECORATE_HIGHLIGHT) {
5336                     bHighLight  = true;
5337                     nForeGround = SCIM_RGB_COLOR (62, 207, 255);
5338                 } else if (ait->get_type () == SCIM_ATTR_FOREGROUND) {
5339                     bHighLight  = true;
5340                     nForeGround = ait->get_value ();
5341                 } else if (ait->get_type () == SCIM_ATTR_BACKGROUND) {
5342                     bSetBack    = true;
5343                     nBackGround = ait->get_value ();
5344                 }
5345             }
5346
5347             wcs = table.get_candidate_in_current_page (i);
5348             mbs = utf8_wcstombs (wcs);
5349
5350             if (!_candidate_0 [i] && total_width <= scroll_0_width) {
5351                 _candidate_0 [i] = get_candidate (mbs, _candidate_window, &item_0_width, nForeGround, nBackGround, bHighLight, bSetBack, item_num, i);
5352                 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));
5353                 evas_object_event_callback_add (_candidate_0 [i], EVAS_CALLBACK_MOUSE_UP, ui_mouse_button_released_cb, GINT_TO_POINTER (i));
5354                 evas_object_event_callback_add (_candidate_0 [i], EVAS_CALLBACK_MOUSE_MOVE, ui_mouse_moved_cb, GINT_TO_POINTER (ISF_EFL_CANDIDATE_0));
5355
5356                 /* Check whether this item is the last one */
5357                 if (i == item_num - 1) {
5358                     if (_candidate_angle == 90 || _candidate_angle == 270)
5359                         scroll_0_width = _candidate_land_width;
5360                     else
5361                         scroll_0_width = _candidate_port_width;
5362                 }
5363
5364                 /* Add first item */
5365                 if (i == 0) {
5366                     item_0_width = item_0_width > scroll_0_width ? scroll_0_width : item_0_width;
5367                     evas_object_show (_candidate_0 [i]);
5368                     evas_object_size_hint_min_set (_candidate_0 [i], item_0_width, _item_min_height);
5369                     elm_table_pack (_candidate_0_table, _candidate_0 [i], 0, 0, item_0_width, _item_min_height);
5370                     total_width += item_0_width;
5371                     _candidate_display_number++;
5372                     continue;
5373                 } else {
5374                     total_width += (item_0_width + seperate_width);
5375                     if (total_width <= scroll_0_width) {
5376                         _seperate_0 [i] = edje_object_add (evas);
5377                         edje_object_file_set (_seperate_0 [i], _candidate_edje_file.c_str (), "seperate_line");
5378                         evas_object_size_hint_min_set (_seperate_0 [i], seperate_width, seperate_height);
5379                         elm_table_pack (_candidate_0_table, _seperate_0 [i],
5380                                 total_width - item_0_width - seperate_width,
5381                                 line_0*(_item_min_height+line_height) + (_item_min_height - seperate_height)/2,
5382                                 seperate_width, seperate_height);
5383                         evas_object_show (_seperate_0 [i]);
5384                         evas_object_show (_candidate_0 [i]);
5385                         evas_object_size_hint_min_set (_candidate_0 [i], item_0_width, _item_min_height);
5386                         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);
5387                         _candidate_display_number++;
5388                         continue;
5389                     } else if ((_candidate_angle == 0 || _candidate_angle == 180) &&
5390                             (_candidate_port_line > 1 && (line_0 + 1) < _candidate_port_line)) {
5391                         line_0++;
5392                         scroll_0_width = _candidate_scroll_0_width_min;
5393                         item_0_width = item_0_width > scroll_0_width ? scroll_0_width : item_0_width;
5394                         evas_object_show (_candidate_0 [i]);
5395                         evas_object_size_hint_min_set (_candidate_0 [i], item_0_width, _item_min_height);
5396                         elm_table_pack (_candidate_0_table, _candidate_0 [i], 0, line_0*(_item_min_height+line_height), item_0_width, _item_min_height);
5397                         total_width = item_0_width;
5398                         _candidate_display_number++;
5399
5400                         _candidate_row_items.push_back (i - nLast);
5401                         nLast = i;
5402                         continue;
5403                     } else {
5404                         _candidate_row_items.push_back (i - nLast);
5405                         nLast = i;
5406                     }
5407                 }
5408             }
5409
5410             if (!_candidate_0 [i]) {
5411                 _candidate_0 [i] = get_candidate (mbs, _candidate_window, &item_0_width, nForeGround, nBackGround, bHighLight, bSetBack, item_num, i);
5412                 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));
5413                 evas_object_event_callback_add (_candidate_0 [i], EVAS_CALLBACK_MOUSE_UP, ui_mouse_button_released_cb, GINT_TO_POINTER (i));
5414                 evas_object_event_callback_add (_candidate_0 [i], EVAS_CALLBACK_MOUSE_MOVE, ui_mouse_moved_cb, GINT_TO_POINTER (ISF_EFL_CANDIDATE_ITEMS));
5415             }
5416             if (current_width > 0 && current_width + item_0_width > _candidate_scroll_width) {
5417                 current_width = 0;
5418                 line_count++;
5419
5420                 _candidate_row_items.push_back (i - nLast);
5421                 nLast = i;
5422                 if (cursor_pos >= i)
5423                     cursor_line++;
5424             }
5425             if (current_width == 0 && !_line_items [i]) {
5426                 _line_items [i] = edje_object_add (evas);
5427                 edje_object_file_set (_line_items [i], _candidate_edje_file.c_str (), "popup_line");
5428                 evas_object_size_hint_min_set (_line_items [i], line_width, line_height);
5429                 x = 0;
5430                 y = line_count*(_item_min_height+line_height);
5431                 elm_table_pack (_candidate_table, _line_items [i], x, y, line_width, line_height);
5432                 evas_object_show (_line_items [i]);
5433             }
5434             if (current_width != 0 && !_seperate_items [i]) {
5435                 _seperate_items [i] = edje_object_add (evas);
5436                 edje_object_file_set (_seperate_items [i], _candidate_edje_file.c_str (), "seperate_line");
5437                 evas_object_size_hint_min_set (_seperate_items [i], seperate_width, seperate_height);
5438                 x = current_width;
5439                 y = line_count*(_item_min_height+line_height) + line_height + (_item_min_height - seperate_height)/2;
5440                 elm_table_pack (_candidate_table, _seperate_items [i], x, y, seperate_width, seperate_height);
5441                 evas_object_show (_seperate_items [i]);
5442                 current_width += seperate_width;
5443             }
5444             x = current_width;
5445             y = line_count*(_item_min_height+line_height) + line_height;
5446             evas_object_size_hint_min_set (_candidate_0 [i], item_0_width, _item_min_height);
5447             evas_object_show (_candidate_0 [i]);
5448             elm_table_pack (_candidate_table, _candidate_0 [i], x, y, item_0_width, _item_min_height);
5449             current_width += item_0_width;
5450             more_item_count++;
5451             if (candidate_expanded == false && !bHighLight)
5452                 break;
5453             else
5454                 candidate_expanded = true;
5455         }
5456     }
5457
5458     for (i = 1; i < _candidate_port_line; i++) {
5459         if ((_candidate_angle == 0 || _candidate_angle == 180)) {
5460             if (_line_0 [i] == NULL) {
5461                 _line_0 [i] = edje_object_add (evas);
5462                 edje_object_file_set (_line_0 [i], _candidate_edje_file.c_str (), "popup_line");
5463                 evas_object_size_hint_min_set (_line_0 [i], line_width, line_height);
5464                 x = 0;
5465                 y = i * (_item_min_height + line_height) - line_height;
5466                 elm_table_pack (_candidate_0_table, _line_0 [i], x, y, line_width, line_height);
5467                 evas_object_show (_line_0 [i]);
5468             }
5469
5470             // Create blank line
5471             if (line_0 + 1 < _candidate_port_line && i > line_0) {
5472                 int nIndex = item_num + i;
5473                 nIndex = nIndex < SCIM_LOOKUP_TABLE_MAX_PAGESIZE ? nIndex : SCIM_LOOKUP_TABLE_MAX_PAGESIZE - 1;
5474                 _seperate_0 [nIndex] = edje_object_add (evas);
5475                 edje_object_file_set (_seperate_0 [nIndex], _candidate_edje_file.c_str (), "seperate_line");
5476                 evas_object_size_hint_min_set (_seperate_0 [nIndex], seperate_width, _item_min_height);
5477                 elm_table_pack (_candidate_0_table, _seperate_0 [nIndex],
5478                         0, i*(_item_min_height+line_height), seperate_width, _item_min_height);
5479             }
5480         } else if (_line_0 [i]) {
5481             evas_object_del (_line_0 [i]);
5482             _line_0 [i] = NULL;
5483         }
5484     }
5485
5486     _candidate_row_items.push_back (item_num - nLast);     /* Add the number of last row */
5487     _info_manager->update_displayed_candidate_number (_candidate_display_number);
5488     _info_manager->update_candidate_item_layout (_candidate_row_items);
5489     if (more_item_count == 0) {
5490         ui_candidate_window_close_button_cb (NULL, NULL, NULL, NULL);
5491         evas_object_hide (_more_btn);
5492         evas_object_hide (_close_btn);
5493     } else if (!_candidate_area_2_visible) {
5494         evas_object_show (_more_btn);
5495         evas_object_hide (_close_btn);
5496     } else {
5497         evas_object_hide (_more_btn);
5498         evas_object_show (_close_btn);
5499     }
5500
5501     int w, h;
5502     elm_scroller_region_get (_candidate_area_2, &x, &y, &w, &h);
5503
5504     int line_h   = _item_min_height + _v_padding;
5505     int cursor_y = cursor_line * line_h;
5506     if (cursor_y < y) {
5507         elm_scroller_region_bring_in (_candidate_area_2, 0, cursor_y, w, h);
5508     } else if (cursor_y >= y + h) {
5509         elm_scroller_region_bring_in (_candidate_area_2, 0, cursor_y + line_h - h, w, h);
5510     }
5511
5512     flush_memory ();
5513 }
5514 #endif /* CANDIDATE */
5515
5516 /**
5517  * @brief Update candidate table slot function for PanelAgent.
5518  *
5519  * @param table The lookup table for candidate.
5520  */
5521 static void slot_update_candidate_table (const LookupTable &table)
5522 {
5523     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
5524
5525     if (_candidate_mode == SOFT_CANDIDATE_WINDOW) {
5526         _info_manager->update_helper_lookup_table (table);
5527         return ;
5528     }
5529
5530 #if ISF_BUILD_CANDIDATE_UI
5531     if (_candidate_window == NULL)
5532         ui_create_candidate_window ();
5533
5534     if (!_candidate_window || table.get_current_page_size () < 0)
5535         return;
5536
5537     if (evas_object_visible_get (_candidate_area_2)) {
5538         candidate_expanded = true;
5539     } else {
5540         candidate_expanded = false;
5541     }
5542
5543     update_table (ISF_CANDIDATE_TABLE, table);
5544     _candidate_tts_focus_index = INVALID_TTS_FOCUS_INDEX;
5545     ui_tts_focus_rect_hide ();
5546 #endif /* CANDIDATE */
5547 }
5548
5549 /**
5550  * @brief Send selected candidate index.
5551  *
5552  * @param selected candidate string index number.
5553  */
5554 static void slot_select_candidate (int index)
5555 {
5556     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
5557     _info_manager->select_candidate (index);
5558 }
5559
5560 /**
5561  * @brief Get candidate geometry slot function for PanelAgent.
5562  *
5563  * @param info The data is used to store candidate position and size.
5564  */
5565 static void slot_get_candidate_geometry (struct rectinfo &info)
5566 {
5567     int x      = 0;
5568     int y      = 0;
5569     int width  = 0;
5570     int height = 0;
5571
5572     if (_candidate_mode == SOFT_CANDIDATE_WINDOW) {
5573         info.pos_x  = x;
5574         info.pos_y  = y;
5575         info.width  = width;
5576         info.height = height;
5577         return;
5578     }
5579
5580 #if ISF_BUILD_CANDIDATE_UI
5581     if (_candidate_window && _candidate_state == WINDOW_STATE_SHOW) {
5582         /* Get candidate window position */
5583         /*ecore_evas_geometry_get (ecore_evas_ecore_evas_get (evas_object_evas_get (_candidate_window)), &x, &y, &width, &height);*/
5584         /* Get exact candidate window size */
5585         /*int x2, y2;
5586           evas_object_geometry_get (_candidate_window, &x2, &y2, &width, &height);*/
5587
5588         x      = _candidate_x;
5589         y      = _candidate_y;
5590         width  = _candidate_width;
5591         height = _candidate_height;
5592     }
5593 #endif /* CANDIDATE */
5594
5595     info.pos_x  = x;
5596     info.pos_y  = y;
5597     info.width  = width;
5598     info.height = height;
5599
5600     LOGD ("%d %d %d %d", info.pos_x, info.pos_y, info.width, info.height);
5601     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " x:" << info.pos_x << " y:" << info.pos_y
5602                         << " width:" << info.width << " height:" << info.height << "\n";
5603 }
5604
5605 /**
5606  * @brief Get input panel geometry slot function for PanelAgent.
5607  *
5608  * @param info The data is used to store input panel position and size.
5609  */
5610 static void slot_get_input_panel_geometry (struct rectinfo &info)
5611 {
5612     if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) {
5613         info.pos_x = 0;
5614         info.width = 0;
5615         info.height = 0;
5616
5617 #if ISF_BUILD_CANDIDATE_UI
5618         if (_candidate_mode == FIXED_CANDIDATE_WINDOW) {
5619             if (_candidate_window && _candidate_state == WINDOW_STATE_SHOW) {
5620                 info.width  = _candidate_width;
5621                 info.height = _candidate_height;
5622             }
5623         } else if (_candidate_mode == SOFT_CANDIDATE_WINDOW) {
5624             info.width  = _soft_candidate_width;
5625             info.height = _soft_candidate_height;
5626         }
5627         int angle = efl_get_app_window_angle ();
5628         if (angle == 90 || angle == 270)
5629             info.pos_y = _screen_width - info.height;
5630         else
5631             info.pos_y = _screen_height - info.height;
5632     } else {
5633         info = get_ise_geometry ();
5634         if (_ise_state != WINDOW_STATE_SHOW) {
5635             info.width = 0;
5636             info.height = 0;
5637         } else {
5638             if (_candidate_mode == FIXED_CANDIDATE_WINDOW) {
5639                 if (_candidate_window && _candidate_state == WINDOW_STATE_SHOW) {
5640                     int height = ui_candidate_get_valid_height ();
5641
5642                     if ((_candidate_height - height) > _ise_height) {
5643                         info.pos_y  = info.pos_y + info.height - _candidate_height;
5644                         info.height = _candidate_height;
5645                     } else {
5646                         info.pos_y  -= height;
5647                         info.height += height;
5648                     }
5649                 }
5650             }
5651         }
5652 #endif /* CANDIDATE */
5653     }
5654
5655     LOGD ("%d %d %d %d", info.pos_x, info.pos_y, info.width, info.height);
5656     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " x:" << info.pos_x << " y:" << info.pos_y
5657                         << " width:" << info.width << " height:" << info.height << "\n";
5658 }
5659
5660 /**
5661  * @brief Get the recent input panel geometry slot function for PanelAgent.
5662  *
5663  * @param angle the rotation angle of application window.
5664  * @param info The data is used to store input panel position and size.
5665  */
5666 static void slot_get_recent_ise_geometry (int angle, struct rectinfo &info)
5667 {
5668     LOGD ("slot_get_recent_ise_geometry");
5669
5670     /* If we have geometry reported by ISE, use the geometry information */
5671     if (angle < 0) {
5672         angle = _ise_angle;
5673     }
5674
5675     if (angle == 0 || angle == 180) {
5676         if (_portrait_recent_ise_geometry.valid) {
5677             info = _portrait_recent_ise_geometry.geometry;
5678             return;
5679         }
5680     }
5681     else {
5682         if (_landscape_recent_ise_geometry.valid) {
5683             info = _landscape_recent_ise_geometry.geometry;
5684             return;
5685         }
5686     }
5687
5688     info.pos_x = -1;
5689     info.pos_y = -1;
5690     info.width = -1;
5691     info.height = -1;
5692 }
5693
5694 static bool slot_check_privilege_by_sockfd (int client_id, String privilege)
5695 {
5696     PrivilegeChecker privilegeChecker (client_id);
5697
5698     bool priv_ret = privilegeChecker.checkPrivilege (privilege.c_str ());
5699
5700     if (priv_ret == false)
5701         LOGW ("Failed to check privilege (%s)", privilege.c_str ());
5702     else
5703         LOGD ("Succeeded to check privilege (%s)", privilege.c_str ());
5704
5705     return priv_ret;
5706 }
5707
5708 /**
5709  * @brief Set active ISE slot function for PanelAgent.
5710  *
5711  * @param uuid The active ISE's uuid.
5712  * @param changeDefault The flag for changing default ISE.
5713  */
5714 static void slot_set_active_ise (const String &uuid, bool changeDefault)
5715 {
5716     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " (" << uuid << ")\n";
5717
5718     bool invalid = false;
5719
5720 #ifdef HAVE_PKGMGR_INFO
5721     /* When changing the active (default) keyboard, initialize ime_info DB if appid is invalid.
5722        This may be necessary if IME packages are changed while panel process is terminated. */
5723     pkgmgrinfo_appinfo_h handle = NULL;
5724     /* Try to get in global packages */
5725     int ret = pkgmgr_get_appinfo (uuid.c_str (), &handle);
5726     if (ret != PMINFO_R_OK) {
5727         LOGW ("appid \"%s\" is invalid.", uuid.c_str ());
5728         /* This might happen if IME is uninstalled while the panel process is inactive.
5729            The variable uuid would be invalid, so set_active_ise() would return false. */
5730         invalid = true;
5731     }
5732
5733     if (handle)
5734         pkgmgrinfo_appinfo_destroy_appinfo (handle);
5735 #endif
5736
5737     if (invalid) {
5738         _initialize_ime_info ();
5739         set_active_ise (_initial_ise_uuid, _soft_keyboard_launched);
5740     }
5741     else if (set_active_ise (uuid, _soft_keyboard_launched) == false) {
5742         if (_initial_ise_uuid.compare (uuid))
5743             set_active_ise (_initial_ise_uuid, _soft_keyboard_launched);
5744     }
5745 }
5746
5747 /**
5748  * @brief Get all ISEs list slot function for PanelAgent.
5749  *
5750  * @param list The list is used to store all ISEs.
5751  *
5752  * @return true if this operation is successful, otherwise return false.
5753  */
5754 static bool slot_get_ise_list (std::vector<String> &list)
5755 {
5756     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
5757
5758     bool result = false;
5759
5760     std::vector<String> uuids;
5761     for (std::vector<ImeInfoDB>::iterator iter = _ime_info.begin(); iter != _ime_info.end(); iter++) {
5762         uuids.push_back(iter->appid);
5763     }
5764     if (_ime_info.size () > 0) {
5765         list =  uuids;
5766         result = true;
5767     }
5768     else {
5769         result = update_ise_list (list);
5770     }
5771
5772     return result;
5773 }
5774
5775 /**
5776  * @brief Get all Helper ISE information from ime_info DB.
5777  *
5778  * @param info This is used to store all Helper ISE information.
5779  *
5780  * @return true if this operation is successful, otherwise return false.
5781  */
5782 static bool slot_get_all_helper_ise_info (HELPER_ISE_INFO &info)
5783 {
5784     bool result = false;
5785     String active_ime_appid;
5786
5787     info.appid.clear ();
5788     info.label.clear ();
5789     info.is_enabled.clear ();
5790     info.is_preinstalled.clear ();
5791     info.has_option.clear ();
5792
5793     if (_ime_info.size() == 0)
5794         isf_pkg_select_all_ime_info_db (_ime_info);
5795
5796     //active_ime_appid = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), String (""));
5797     if (_info_manager) {
5798         active_ime_appid = _info_manager->get_current_helper_uuid ();
5799     }
5800
5801     if (_ime_info.size () > 0) {
5802         for (std::vector<ImeInfoDB>::iterator iter = _ime_info.begin (); iter != _ime_info.end (); iter++) {
5803             if (iter->mode == TOOLBAR_HELPER_MODE) {
5804                 info.appid.push_back (iter->appid);
5805                 info.label.push_back (iter->label);
5806                 info.is_enabled.push_back (iter->is_enabled);
5807                 info.is_preinstalled.push_back (iter->is_preinstalled);
5808                 info.has_option.push_back (static_cast<uint32>(iter->has_option));
5809                 result = true;
5810             }
5811         }
5812     }
5813
5814     return result;
5815 }
5816
5817 /**
5818  * @brief Update "has_option" column of ime_info DB by Application ID
5819  *
5820  * @param[in] appid Application ID of IME to enable or disable
5821  * @param[in] has_option @c true to have IME option(setting), otherwise @c false
5822  */
5823 static void slot_set_has_option_helper_ise_info (const String &appid, bool has_option)
5824 {
5825     if (appid.length() == 0) {
5826         LOGW ("Invalid appid");
5827         return;
5828     }
5829
5830     if (_ime_info.size() == 0)
5831         isf_pkg_select_all_ime_info_db(_ime_info);
5832
5833     if (isf_db_update_has_option_by_appid(appid.c_str(), has_option)) {    // Update ime_info DB
5834         for (unsigned int i = 0; i < _ime_info.size (); i++) {
5835             if (appid == _ime_info[i].appid) {
5836                 _ime_info[i].has_option = static_cast<uint32>(has_option);  // Update global variable
5837             }
5838         }
5839     }
5840 }
5841
5842 /**
5843  * @brief Update "is_enable" column of ime_info DB by Application ID
5844  *
5845  * @param[in] appid Application ID of IME to enable or disable
5846  * @param[in] is_enabled @c true to enable the IME, otherwise @c false
5847  */
5848 static void slot_set_enable_helper_ise_info (const String &appid, bool is_enabled)
5849 {
5850     if (appid.length() == 0) {
5851         LOGW ("Invalid appid");
5852         return;
5853     }
5854
5855     if (_ime_info.size() == 0)
5856         isf_pkg_select_all_ime_info_db(_ime_info);
5857
5858     if (isf_db_update_is_enabled_by_appid(appid.c_str(), is_enabled)) {    // Update ime_info DB
5859         for (unsigned int i = 0; i < _ime_info.size (); i++) {
5860             if (appid == _ime_info[i].appid) {
5861                 _ime_info[i].is_enabled = static_cast<uint32>(is_enabled);  // Update global variable
5862             }
5863         }
5864     }
5865 }
5866
5867 #ifdef HAVE_PKGMGR_INFO
5868 /**
5869  * @brief Finds appid with specific category
5870  *
5871  * @return 0 if success, negative value(<0) if fail. Callback is not called if return value is negative
5872  */
5873 static int _find_appid_from_category (const pkgmgrinfo_appinfo_h handle, void *user_data)
5874 {
5875     if (user_data) {
5876         char **result = static_cast<char **>(user_data);
5877         char *appid = NULL;
5878         int ret = 0;
5879
5880         /* Get appid */
5881         ret = pkgmgrinfo_appinfo_get_appid (handle, &appid);
5882         if (ret == PMINFO_R_OK) {
5883             *result = strdup (appid);
5884         }
5885         else {
5886             LOGW ("pkgmgrinfo_appinfo_get_appid failed!");
5887         }
5888     }
5889     else {
5890         LOGW ("user_data is null!");
5891     }
5892
5893     return -1;  // This callback is no longer called.
5894 }
5895 #endif
5896
5897 /**
5898  * @brief Requests to open the installed IME list application.
5899  */
5900 static void slot_show_helper_ise_list (void)
5901 {
5902     // Launch IME List application; e.g., org.tizen.inputmethod-setting-list
5903     char *app_id = NULL;
5904 #ifdef HAVE_PKGMGR_INFO
5905     pkgmgrinfo_appinfo_filter_h handle;
5906     int ret;
5907
5908     if (ime_list_app.length() < 1) {
5909         ret = pkgmgrinfo_appinfo_filter_create (&handle);
5910         if (ret == PMINFO_R_OK) {
5911             ret = pkgmgrinfo_appinfo_filter_add_string (handle, PMINFO_APPINFO_PROP_APP_CATEGORY, "http://tizen.org/category/ime-list");
5912             if (ret == PMINFO_R_OK) {
5913                 pkgmgrinfo_appinfo_filter_foreach_appinfo (handle, _find_appid_from_category, &app_id);
5914             }
5915             pkgmgrinfo_appinfo_filter_destroy (handle);
5916
5917             if (app_id)
5918                 ime_list_app = String (app_id);
5919         }
5920     }
5921     else
5922         app_id = strdup (ime_list_app.c_str());
5923 #endif
5924
5925     if (app_id) {
5926         app_control_launch (app_id);
5927         free(app_id);
5928     }
5929     else {
5930       SECURE_LOGW ("AppID with http://tizen.org/category/ime-list category is not available.");
5931     }
5932 }
5933
5934 /**
5935  * @brief Requests to open the installed IME selector application.
5936  */
5937 static void slot_show_helper_ise_selector (void)
5938 {
5939     // Launch IME Selector application; e.g., org.tizen.inputmethod-setting-selector
5940     char *app_id = NULL;
5941 #ifdef HAVE_PKGMGR_INFO
5942     pkgmgrinfo_appinfo_filter_h handle;
5943     int ret;
5944
5945     if (ime_selector_app.length() < 1) {
5946         ret = pkgmgrinfo_appinfo_filter_create(&handle);
5947         if (ret == PMINFO_R_OK) {
5948             ret = pkgmgrinfo_appinfo_filter_add_string(handle, PMINFO_APPINFO_PROP_APP_CATEGORY, "http://tizen.org/category/ime-selector");
5949             if (ret == PMINFO_R_OK) {
5950                 pkgmgrinfo_appinfo_filter_foreach_appinfo(handle, _find_appid_from_category, &app_id);
5951             }
5952             pkgmgrinfo_appinfo_filter_destroy(handle);
5953
5954             if (app_id)
5955                 ime_selector_app = String(app_id);
5956         }
5957     }
5958     else
5959         app_id = strdup(ime_selector_app.c_str());
5960 #endif
5961
5962     if (app_id) {
5963         app_control_launch (app_id);
5964         free(app_id);
5965     }
5966     else {
5967         SECURE_LOGW ("AppID with http://tizen.org/category/ime-selector category is not available.");
5968     }
5969 }
5970
5971 static bool slot_is_helper_ise_enabled (String appid, int &enabled)
5972 {
5973     bool is_enabled = false;
5974
5975     if (appid.length() == 0) {
5976         LOGW ("Invalid appid.");
5977         return false;
5978     }
5979
5980     if (_ime_info.size() == 0)
5981         isf_pkg_select_all_ime_info_db(_ime_info);
5982
5983     if (isf_db_select_is_enabled_by_appid(appid.c_str(), &is_enabled)) {
5984         enabled = static_cast<int>(is_enabled);
5985     }
5986     else
5987         return false;
5988
5989     return true;
5990 }
5991
5992 /**
5993  * @brief Get the ISE's information.
5994  *
5995  * @param uuid The ISE's uuid.
5996  * @param name The ISE's name.
5997  * @param language The ISE's language.
5998  * @param type The ISE's type.
5999  * @param option The ISE's option.
6000  *
6001  * @return true if this operation is successful, otherwise return false.
6002  */
6003 static bool slot_get_ise_information (String uuid, String &name, String &language, int &type, int &option, String &module_name)
6004 {
6005     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6006
6007     if (uuid.length () > 0) {
6008         // update all ISE names according to the display languages
6009         // sometimes get_ise_information is called before vconf display language changed callback is called.
6010         update_ise_locale ();
6011
6012         for (unsigned int i = 0; i < _ime_info.size (); i++) {
6013             if (uuid == _ime_info[i].appid) {
6014                 name = _ime_info[i].label;
6015                 language = _ime_info[i].languages;
6016                 type  = _ime_info[i].mode;
6017                 option = _ime_info[i].options;
6018                 module_name = _ime_info[i].module_name;
6019                 return true;
6020             }
6021         }
6022     }
6023
6024     std::cerr << __func__ << " is failed!!!\n";
6025     return false;
6026 }
6027
6028 /**
6029  * @brief Get keyboard ISEs list slot function for PanelAgent.
6030  *
6031  * @param name_list The list is used to store keyboard ISEs.
6032  *
6033  * @return true if this operation is successful, otherwise return false.
6034  */
6035 static bool slot_get_keyboard_ise_list (std::vector<String> &name_list)
6036 {
6037     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6038
6039     isf_load_ise_information (ALL_ISE, _config);
6040
6041     std::vector<String> lang_list, uuid_list;
6042     isf_get_all_languages (lang_list);
6043     isf_get_keyboard_ises_in_languages (lang_list, uuid_list, name_list, false);
6044
6045     _info_manager->update_ise_list (uuid_list);
6046     return true;
6047 }
6048
6049 /**
6050  * @brief Get enable languages list slot function for PanelAgent.
6051  *
6052  * @param list The list is used to store languages.
6053  */
6054 static void slot_get_language_list (std::vector<String> &list)
6055 {
6056     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6057
6058     String lang_name;
6059     MapStringVectorSizeT::iterator iter = _groups.begin ();
6060
6061     for (; iter != _groups.end (); iter++) {
6062         lang_name = scim_get_language_name (iter->first);
6063         list.push_back (lang_name);
6064     }
6065 }
6066
6067 /**
6068  * @brief Get all languages list slot function for PanelAgent.
6069  *
6070  * @param lang The list is used to store languages.
6071  */
6072 static void slot_get_all_language (std::vector<String> &lang)
6073 {
6074     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6075
6076     isf_get_all_languages (lang);
6077 }
6078
6079 /**
6080  * @brief Get specific ISE language list slot function for PanelAgent.
6081  *
6082  * @param name The ISE name.
6083  * @param list The list is used to store ISE languages.
6084  */
6085 static void slot_get_ise_language (char *name, std::vector<String> &list)
6086 {
6087     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6088
6089     if (name == NULL)
6090         return;
6091
6092     std::vector<String> list_tmp;
6093     list_tmp.clear ();
6094     for (unsigned int i = 0; i < _ime_info.size(); i++) {
6095         if (!strcmp (_ime_info[i].label.c_str (), name)) {
6096             scim_split_string_list (list_tmp, _ime_info[i].languages, ',');
6097             for (i = 0; i < list_tmp.size (); i++)
6098                 list.push_back (scim_get_language_name (list_tmp[i]));
6099             return;
6100         }
6101     }
6102 }
6103
6104 /**
6105  * @brief Get ISE information slot function for PanelAgent.
6106  *
6107  * @param uuid The ISE uuid.
6108  * @param info The variable is used to store ISE information.
6109  *
6110  * @return true if this operation is successful, otherwise return false.
6111  */
6112 static bool slot_get_ise_info (const String &uuid, ISE_INFO &info)
6113 {
6114     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6115
6116     for (unsigned int i = 0; i < _ime_info.size (); i++) {
6117         if (!uuid.compare (_ime_info[i].appid)) {
6118             info.uuid   = _ime_info[i].appid;
6119             info.name   = _ime_info[i].label;
6120             info.icon   = _ime_info[i].iconpath;
6121             info.lang   = _ime_info[i].languages;
6122             info.option = _ime_info[i].options;
6123             info.type   = _ime_info[i].mode;
6124             return true;
6125         }
6126     }
6127
6128     return false;
6129 }
6130
6131 /**
6132  * @brief Set keyboard ISE slot function for PanelAgent.
6133  *
6134  * @param uuid The variable is ISE uuid.
6135  */
6136 static void slot_set_keyboard_ise (const String &uuid)
6137 {
6138     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " uuid = " << uuid << "\n";
6139
6140     std::vector<String> uuids;
6141     std::vector<ImeInfoDB>::iterator iter;
6142     for (iter = _ime_info.begin(); iter != _ime_info.end(); iter++) {
6143         uuids.push_back(iter->appid);
6144     }
6145
6146     if (uuid.length () <= 0 || std::find (uuids.begin (), uuids.end (), uuid) == uuids.end ())
6147         return;
6148
6149     String default_uuid = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), String (""));
6150     if (_ime_info[get_ise_index (default_uuid)].mode == TOOLBAR_KEYBOARD_MODE)
6151         return;
6152
6153     uint32 ise_option = 0;
6154     String ise_uuid, ise_name;
6155     isf_get_keyboard_ise (_config, ise_uuid, ise_name, ise_option);
6156     if (ise_uuid == uuid)
6157         return;
6158
6159     String language = String ("~other");/*scim_get_locale_language (scim_get_current_locale ());*/
6160     _config->write (String (SCIM_CONFIG_DEFAULT_IMENGINE_FACTORY) + String ("/") + language, uuid);
6161     _config->flush ();
6162     _config->reload ();
6163
6164     _info_manager->change_factory (uuid);
6165 }
6166
6167 /**
6168  * @brief Get current keyboard ISE name and uuid slot function for PanelAgent.
6169  *
6170  * @param ise_name The variable is used to store ISE name.
6171  * @param ise_uuid The variable is used to store ISE uuid.
6172  */
6173 static void slot_get_keyboard_ise (String &ise_name, String &ise_uuid)
6174 {
6175     uint32 ise_option = 0;
6176     isf_get_keyboard_ise (_config, ise_uuid, ise_name, ise_option);
6177
6178     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " uuid = " << ise_uuid << "\n";
6179 }
6180
6181 /**
6182  * @brief Accept connection slot function for PanelAgent.
6183  *
6184  * @param fd The file descriptor to connect.
6185  */
6186 static void slot_accept_connection (int fd)
6187 {
6188     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6189
6190 #ifdef HAVE_ECOREX
6191     get_input_window ();
6192 #endif
6193 }
6194
6195 /**
6196  * @brief Close connection slot function for PanelAgent.
6197  *
6198  * @param fd The file descriptor to connect.
6199  */
6200 static void slot_close_connection (int fd)
6201 {
6202     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6203 }
6204
6205 /**
6206  * @brief Exit panel process slot function for PanelAgent.
6207  */
6208 static void slot_exit (void)
6209 {
6210     std::cerr << __FUNCTION__ << "...\n";
6211     ISF_SAVE_LOG ("exit");
6212
6213 #if ISF_BUILD_CANDIDATE_UI
6214     elm_exit ();
6215 #else
6216     ecore_main_loop_quit ();
6217 #endif /* CANDIDATE */
6218 }
6219
6220 static void delete_ise_check_pid_alive_timer(void)
6221 {
6222     LOGD("deleting ise_check_alive_timer");
6223     if (_ise_check_pid_alive_timer) {
6224         ecore_timer_del(_ise_check_pid_alive_timer);
6225         _ise_check_pid_alive_timer = NULL;
6226     }
6227 }
6228
6229 static Eina_Bool ise_check_pid_alive_timer(void *data)
6230 {
6231     Eina_Bool ret = ECORE_CALLBACK_RENEW;
6232     Eina_Bool retry = EINA_FALSE;
6233
6234     int status = aul_app_get_status (_ise_check_pid_alive_uuid.c_str ());
6235     LOGD ("STATUS : %d", status);
6236     if (status >= STATUS_LAUNCHING) {
6237         /* If the status is not one of STATUS_LAUNCHING, STATUS_VISIBLE, STATUS_BG */
6238         if (status >= STATUS_DYING) {
6239             LOGE ("aul_app_get_status reports %d", status);
6240             retry = EINA_TRUE;
6241         }
6242     }
6243     else {
6244         /* Status query not successful, the ISE could have failed launching */
6245         LOGE ("aul_app_get_status failed. %d", status);
6246         retry = EINA_TRUE;
6247     }
6248
6249     if (retry) {
6250         _soft_keyboard_launched = false;
6251         String uuid = _config->read (SCIM_CONFIG_DEFAULT_HELPER_ISE, String(""));
6252         /* The start_helper() function below will going to call slot_run_helper,
6253            which will going to assign a new timer handle to the _ise_check_pid_alive_timer variable.
6254         */
6255         LOGW ("The previous attempt to launch %s seems to be failed, restarting",
6256             _ise_check_pid_alive_uuid.c_str ());
6257         if (_info_manager->start_helper (uuid))
6258             _soft_keyboard_launched = true;
6259         ret = ECORE_CALLBACK_CANCEL;
6260     }
6261
6262     return ret;
6263 }
6264
6265 static void slot_register_helper(int id, const HelperInfo& info)
6266 {
6267     LOGD ("app id : %s", info.uuid.c_str ());
6268     /* Do we need to check whether the pid of this helper is the one we are watching? */
6269     if (info.uuid.compare(_ise_check_pid_alive_uuid) == 0) {
6270         delete_ise_check_pid_alive_timer();
6271     }
6272 }
6273
6274 static void slot_register_helper_properties (int id, const PropertyList &props)
6275 {
6276     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6277 #ifdef HAVE_ECOREX
6278     /* WMSYNC, #2 Receiving X window ID from ISE */
6279     /* FIXME : We should add an API to set window id of ISE */
6280     Property prop = props[0];
6281     if (prop.get_label ().compare ("XID") == 0) {
6282         Ecore_X_Window xwindow = atoi (prop.get_key ().c_str ());
6283         _ise_window = xwindow;
6284         LOGD ("ISE XID : %x", _ise_window);
6285
6286         /* Just in case for the helper sent this message later than show_ise request */
6287         if (_ise_state == WINDOW_STATE_SHOW || _ise_state == WINDOW_STATE_WILL_SHOW) {
6288             efl_set_transient_for_app_window (_ise_window);
6289         }
6290
6291         Ecore_X_Atom atom = ecore_x_atom_get ("_ISF_ISE_WINDOW");
6292         if (atom && _control_window && _ise_window) {
6293             ecore_x_window_prop_xid_set (_control_window, atom, ECORE_X_ATOM_WINDOW, &_ise_window, 1);
6294         }
6295 #ifdef HAVE_NOTIFICATION
6296         delete_notification (&ise_selector_module_noti);
6297 #endif
6298     }
6299 #endif
6300 }
6301
6302 #if ENABLE_REMOTE_INPUT
6303 static void slot_send_remote_input_message (const String &msg, bool len)
6304 {
6305     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6306
6307     String con = msg.c_str ();
6308     ISE_MESSAGE message = CISEMessageSerializer::deserialize(con);
6309
6310     if (remote_input_impl == NULL) {
6311         remote_input_impl = Remote_Input::get_instance();
6312     }
6313
6314     if (remote_input_impl)
6315         remote_input_impl->handle_websocket_message(message);
6316 }
6317
6318 static void slot_recv_remote_surrounding_text (int cursor, const String &text)
6319 {
6320     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6321
6322     if (remote_input_impl == NULL) {
6323         remote_input_impl = Remote_Input::get_instance();
6324     }
6325
6326     if (remote_input_impl)
6327         remote_input_impl->handle_recv_panel_message(3, text.c_str (), cursor);
6328 }
6329 #endif
6330
6331 static void slot_show_ise (void)
6332 {
6333     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6334
6335     /* If the current toolbar mode is not HELPER_MODE, do not proceed */
6336     if (_info_manager->get_current_toolbar_mode () != TOOLBAR_HELPER_MODE) {
6337         LOGD ("Current toolbar mode should be TOOLBAR_HELPER_MODE but is %d, returning",
6338             _info_manager->get_current_toolbar_mode ());
6339         return;
6340     }
6341
6342     LOGD ("slot_show_ise ()");
6343
6344     delete_ise_hide_timer ();
6345 #ifdef HAVE_ECOREX
6346     /* WMSYNC, #3 Clear the existing application's conformant area and set transient_for */
6347     // Unset conformant area
6348     Ecore_X_Window current_app_window = efl_get_app_window ();
6349     if (_app_window != current_app_window) {
6350         struct rectinfo info = {0, 0, 0, 0};
6351         info.pos_y = _screen_width > _screen_height ? _screen_width : _screen_height;
6352         set_keyboard_geometry_atom_info (_app_window, info);
6353         ecore_x_event_mask_unset (_app_window, ECORE_X_EVENT_MASK_WINDOW_FOCUS_CHANGE);
6354         LOGD ("Conformant reset for window %x", _app_window);
6355         _app_window = current_app_window;
6356
6357         /* If the target window has changed but our ISE is still in visible state,
6358            update the keyboard geometry information */
6359         if (_ise_state == WINDOW_STATE_SHOW) {
6360             set_keyboard_geometry_atom_info (_app_window, get_ise_geometry ());
6361         }
6362     }
6363
6364     /* If the candidate was already in SHOW state, respect the current angle */
6365     if (_candidate_state != WINDOW_STATE_SHOW) {
6366         /* FIXME : Need to check if candidate_angle and window_angle should be left as separated */
6367         _candidate_angle = efl_get_app_window_angle ();
6368     }
6369     /* If the ise was already in SHOW state, respect the current angle */
6370     if (_ise_state != WINDOW_STATE_SHOW) {
6371         _ise_angle = efl_get_app_window_angle ();
6372     }
6373
6374     ecore_x_event_mask_set (_app_window, ECORE_X_EVENT_MASK_WINDOW_FOCUS_CHANGE);
6375     efl_set_transient_for_app_window (_ise_window);
6376
6377     /* Make clipboard window to have transient_for information on ISE window,
6378        so that the clipboard window will always be above ISE window */
6379     Ecore_X_Window clipboard_window = efl_get_clipboard_window ();
6380     if (_ise_window && clipboard_window) {
6381         ecore_x_icccm_transient_for_set (clipboard_window, _ise_window);
6382     }
6383
6384     /* If our ISE was already in SHOW state, skip state transition to WILL_SHOW */
6385     if (_ise_state != WINDOW_STATE_SHOW) {
6386         _ise_state = WINDOW_STATE_WILL_SHOW;
6387     }
6388 #else
6389     _ise_angle = 0;
6390 #if ISF_BUILD_CANDIDATE_UI
6391     _candidate_angle = 0;
6392 #endif /* CANDIDATE */
6393     _ise_state = WINDOW_STATE_SHOW;
6394
6395 #ifdef HAVE_NOTIFICATION
6396     if (_info_manager->get_current_toolbar_mode () == TOOLBAR_HELPER_MODE) {
6397         if (get_ise_count (TOOLBAR_HELPER_MODE, true) >= 2) {
6398             show_ime_selector_notification ();
6399         }
6400     }
6401 #endif
6402 #endif
6403 }
6404
6405 static void slot_hide_ise (void)
6406 {
6407     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6408
6409     LOGD ("slot_hide_ise ()");
6410
6411     if (!_ise_hide_timer)
6412         hide_ise ();
6413 }
6414
6415 static void slot_will_hide_ack (void)
6416 {
6417     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6418 #ifdef HAVE_ECOREX
6419     /* WMSYNC, #8 Let the Window Manager to actually hide keyboard window */
6420     // WILL_HIDE_REQUEST_DONE Ack to WM
6421     Ecore_X_Window root_window = ecore_x_window_root_get (_control_window);
6422     //ecore_x_e_virtual_keyboard_off_prepare_done_send (root_window, _control_window);
6423     LOGD ("_ecore_x_e_virtual_keyboard_off_prepare_done_send (%x, %x)",
6424             root_window, _control_window);
6425     if (_info_manager->get_current_toolbar_mode () == TOOLBAR_HELPER_MODE) {
6426         LOGD ("calling ui_candidate_hide (true, false)");
6427         ui_candidate_hide (true, false);
6428     }
6429
6430     /* WILL_HIDE_ACK means that the application finished redrawing the autoscroll area,
6431        now hide the candidate window right away if it is also in WILL_HIDE state */
6432     if (_candidate_state == WINDOW_STATE_WILL_HIDE) {
6433         candidate_window_hide ();
6434     }
6435
6436     if (_off_prepare_done_timer) {
6437         ecore_timer_del (_off_prepare_done_timer);
6438         _off_prepare_done_timer = NULL;
6439     }
6440 #endif
6441 }
6442
6443 static void slot_candidate_will_hide_ack (void)
6444 {
6445     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6446 #ifdef HAVE_ECOREX
6447     LOGD ("candidate_will_hide_ack");
6448     if (_candidate_state == WINDOW_STATE_WILL_HIDE) {
6449         candidate_window_hide ();
6450     }
6451 #endif
6452 }
6453
6454 static void slot_set_keyboard_mode (int mode)
6455 {
6456     LOGD ("slot_set_keyboard_mode called (TOOLBAR_MODE : %d)", mode);
6457
6458     change_keyboard_mode ((TOOLBAR_MODE_T)mode);
6459 }
6460
6461 static void slot_get_ise_state (int &state)
6462 {
6463     if (_ise_state == WINDOW_STATE_SHOW ||
6464         ((_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) && (_candidate_state == WINDOW_STATE_SHOW))) {
6465         state = ECORE_IMF_INPUT_PANEL_STATE_SHOW;
6466     } else {
6467         /* Currently we don't have WILL_HIDE / HIDE state distinction in Ecore_IMF */
6468         switch (_ise_state) {
6469             case WINDOW_STATE_SHOW :
6470                 state = ECORE_IMF_INPUT_PANEL_STATE_SHOW;
6471                 break;
6472             case WINDOW_STATE_WILL_SHOW :
6473                 state = ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW;
6474                 break;
6475             case WINDOW_STATE_WILL_HIDE :
6476                 state = ECORE_IMF_INPUT_PANEL_STATE_HIDE;
6477                 break;
6478             case WINDOW_STATE_HIDE :
6479                 state = ECORE_IMF_INPUT_PANEL_STATE_HIDE;
6480                 break;
6481             default :
6482                 state = ECORE_IMF_INPUT_PANEL_STATE_HIDE;
6483         };
6484     }
6485     LOGD ("state = %d", state);
6486     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " state = " << state << "\n";
6487 }
6488
6489 static void slot_start_default_ise (void)
6490 {
6491     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6492
6493     if ((_info_manager->get_current_toolbar_mode () == TOOLBAR_HELPER_MODE)) {
6494         String uuid  = _config->read (SCIM_CONFIG_DEFAULT_HELPER_ISE, String (""));
6495         int pid = aul_app_get_pid (uuid.c_str ());
6496         if (pid >= 0) {
6497             if (STATUS_DYING == aul_app_get_status (uuid.c_str ()))
6498                 pid = -1;
6499         }
6500         if (_launch_ise_on_request && !_soft_keyboard_launched && pid < 0) {
6501             LOGD ("Start helper (%s)", uuid.c_str ());
6502             set_keyboard_engine (String (SCIM_COMPOSE_KEY_FACTORY_UUID));
6503
6504             if (_info_manager->start_helper (uuid))
6505                 _soft_keyboard_launched = true;
6506             else
6507                 LOGW ("Failed to start helper (%s)", uuid.c_str ());
6508         }
6509     }
6510 }
6511
6512 static void slot_stop_default_ise (bool is_exist)
6513 {
6514     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6515
6516     if (is_exist) {
6517         if (_launch_ise_on_request && _auto_destroy_ise && _soft_keyboard_launched) {
6518             String uuid = _info_manager->get_current_helper_uuid ();
6519
6520             if (uuid.length () > 0) {
6521                 _info_manager->hide_helper (uuid);
6522                 _info_manager->stop_helper (uuid);
6523                 _soft_keyboard_launched = false;
6524                 LOGD ("stop helper (%s)", uuid.c_str ());
6525             }
6526         }
6527     } else {
6528         if (_soft_keyboard_launched)
6529             _soft_keyboard_launched = false;
6530     }
6531 }
6532
6533 static void launch_helper (const char* exec, const char *name, const char *appid, const char *config, const char *display)
6534 {
6535     int pid;
6536
6537     pid = fork ();
6538
6539     if (pid < 0) return;
6540
6541     if (pid == 0) {
6542         const char *argv [] = { exec,
6543                            "--daemon",
6544                            "--config", config,
6545                            "--display", display,
6546                            const_cast<char*> (name),
6547                            const_cast<char*> (appid),
6548                            0};
6549
6550         SCIM_DEBUG_MAIN (2) << " Call scim-helper-launcher.\n";
6551         ISF_SAVE_LOG ("Exec scim_helper_launcher(%s %s)", name, appid);
6552
6553         unsetenv ("ELM_THEME");
6554         unsetenv ("ELM_SCALE");
6555
6556         setsid ();
6557         LOGD ("launch execpath : %s", exec);
6558         execv (exec, const_cast<char **>(argv));
6559 #if ISF_BUILD_CANDIDATE_UI
6560         elm_exit ();
6561 #else
6562         ecore_main_loop_quit ();
6563 #endif /* CANDIDATE */
6564     }
6565 }
6566
6567 static bool app_control_launch (const char *app_id)
6568 {
6569     app_control_h app_control;
6570     int ret;
6571
6572     ret = app_control_create (&app_control);
6573     if (ret != APP_CONTROL_ERROR_NONE) {
6574         LOGW ("app_control_create returned %08x", ret);
6575         return false;
6576     }
6577
6578     ret = app_control_set_operation (app_control, APP_CONTROL_OPERATION_DEFAULT);
6579     if (ret != APP_CONTROL_ERROR_NONE) {
6580         LOGW ("app_control_set_operation returned %08x", ret);
6581         app_control_destroy (app_control);
6582         return false;
6583     }
6584
6585     ret = app_control_set_app_id (app_control, app_id);
6586     if (ret != APP_CONTROL_ERROR_NONE) {
6587         LOGW ("app_control_set_app_id returned %08x", ret);
6588         app_control_destroy (app_control);
6589         return false;
6590     }
6591
6592     int tries = 0;
6593     do {
6594         if (tries != 0) usleep(1000000); /* If we are retrying to launch, pause for a while */
6595         ret = app_control_send_launch_request(app_control, NULL, NULL);
6596         LOGW ("app_control_send_launch_request returned %08x, app_id=%s", ret, app_id);
6597     } while (ret != APP_CONTROL_ERROR_NONE && (++tries) < 3);
6598
6599     app_control_destroy (app_control);
6600
6601     if (ret != APP_CONTROL_ERROR_NONE) {
6602         LOGW ("Failed to launch IME (%s)", app_id);
6603     } else {
6604         LOGD ("Succeeded to launch IME (%s)", app_id);
6605     }
6606
6607     return (ret == APP_CONTROL_ERROR_NONE);
6608 }
6609
6610 static void add_ise_check_pid_alive_timer(const String &uuid) {
6611     delete_ise_check_pid_alive_timer ();
6612     LOGD ("Register check_alive timer for uuid : %s", uuid.c_str ());
6613     _ise_check_pid_alive_uuid = uuid;
6614     _ise_check_pid_alive_timer = ecore_timer_add (_ise_check_pid_alive_time,
6615         ise_check_pid_alive_timer, NULL);
6616 }
6617
6618 static void slot_run_helper (const String &uuid, const String &config, const String &display)
6619 {
6620     ISF_SAVE_LOG ("time:%ld  pid:%d  %s  %s  uuid(%s)",
6621         time (0), getpid (), __FILE__, __func__, uuid.c_str ());
6622
6623     String scim_helper_path;
6624
6625     delete_ise_check_pid_alive_timer ();
6626
6627 #ifdef HAVE_PKGMGR_INFO
6628     char *execpath = NULL;
6629     int ret;
6630     pkgmgrinfo_appinfo_h appinfo_handle;
6631
6632     /* get app info handle */
6633     /* Try to get in global packages */
6634     ret = pkgmgr_get_appinfo (uuid.c_str (), &appinfo_handle);
6635     if (ret != PMINFO_R_OK) {
6636         LOGE ("pkgmgr_get_appinfo failed. appid : %s, ret : %d ", uuid.c_str (), ret);
6637         add_ise_check_pid_alive_timer (uuid);
6638         return;
6639     }
6640
6641     /* Get exec path */
6642     ret = pkgmgrinfo_appinfo_get_exec (appinfo_handle, &execpath);
6643     if (ret != PMINFO_R_OK) {
6644         LOGE ("pkgmgrinfo_appinfo_get_exec failed. appid : %s, ret : %d ", uuid.c_str (), ret);
6645         pkgmgrinfo_appinfo_destroy_appinfo (appinfo_handle);
6646         add_ise_check_pid_alive_timer (uuid);
6647         return;
6648     }
6649
6650     LOGD ("exec path : %s %d", execpath, _ime_info.size ());
6651     scim_helper_path = String (execpath);
6652
6653     if (appinfo_handle) {
6654         pkgmgrinfo_appinfo_destroy_appinfo (appinfo_handle);
6655         appinfo_handle = NULL;
6656     }
6657 #else
6658     scim_helper_path = String (SCIM_HELPER_LAUNCHER_PROGRAM);
6659 #endif
6660
6661     for (size_t i = 0; i < _ime_info.size (); ++i) {
6662         if (_ime_info[i].appid == uuid && _ime_info[i].module_name.length ()) {
6663             if (scim_helper_path != String (SCIM_HELPER_LAUNCHER_PROGRAM)) {
6664                 /* Check if IME with the same AppID is alive */
6665                 int status_ret = aul_app_get_status (uuid.c_str ());
6666                 if (status_ret >= STATUS_LAUNCHING) {
6667                     /* Request to terminate IME */
6668                     int ime_pid = aul_app_get_pid (uuid.c_str ());
6669                     status_ret = aul_terminate_pid (ime_pid);
6670                     if (status_ret < AUL_R_OK) {
6671                         LOGE ("aul_terminate_pid(%d) failed: %d", ime_pid, status_ret);
6672                     }
6673                     else {
6674                         LOGD ("Requested to terminate IME(%s)", uuid.c_str ());
6675                         usleep (1000000);
6676                     }
6677                 }
6678                 /* execute type IME */
6679                 LOGD ("Try to launch IME (%s)", uuid.c_str ());
6680                 app_control_launch (uuid.c_str ());
6681
6682                 /* ISE check alive only works for AUL based IMEs */
6683                 add_ise_check_pid_alive_timer (uuid);
6684             }
6685             else {
6686                 /* shared object (so) type IME */
6687                 launch_helper (scim_helper_path.c_str(), _ime_info[i].module_name.c_str (), uuid.c_str (), config.c_str (), display.c_str ());
6688             }
6689
6690             break;
6691         }
6692     }
6693
6694     SCIM_DEBUG_MAIN (2) << " exit run_helper ().\n";
6695 }
6696
6697 static bool slot_launch_option_application (String ime_appid)
6698 {
6699     String ime_setting_app = isf_pkg_get_setting_app (ime_appid);
6700
6701     LOGD ("IME appid : %s, IME setting app id : %s", ime_appid.c_str (), ime_setting_app.c_str ());
6702
6703     if (ime_setting_app.length () > 0) {
6704         app_control_launch (ime_setting_app.c_str ());
6705         return true;
6706     }
6707
6708     return false;
6709 }
6710
6711 //////////////////////////////////////////////////////////////////////
6712 // End of PanelAgent-Functions
6713 //////////////////////////////////////////////////////////////////////
6714
6715
6716 /**
6717  * @brief Callback function for abnormal signal.
6718  *
6719  * @param sig The signal.
6720  */
6721 static void signalhandler (int sig)
6722 {
6723     std::cerr << __FUNCTION__ << " Signal=" << sig << "\n";
6724     ISF_SAVE_LOG ("Signal=%d", sig);
6725
6726 #if ISF_BUILD_CANDIDATE_UI
6727     elm_exit ();
6728 #else
6729     ecore_main_loop_quit ();
6730 #endif /* CANDIDATE */
6731 }
6732
6733 #ifdef HAVE_VCONF
6734 static void update_ise_locale (const char *language)
6735 {
6736     String strLang;
6737
6738     if (language) {
6739         strLang = String (language);
6740     }
6741     else {
6742         char *lang_str = vconf_get_str (VCONFKEY_LANGSET);
6743         if (lang_str) {
6744             if (_locale_string.compare(lang_str) == 0) {
6745                 free (lang_str);
6746                 return;
6747             }
6748
6749             strLang = String (lang_str);
6750
6751             free (lang_str);
6752         }
6753     }
6754
6755     LOGD ("update all ISE names according to display language : %s", strLang.c_str ());
6756     set_language_and_locale (strLang.c_str ());
6757
6758     bool need_to_init_db = false;
6759 #ifdef HAVE_PKGMGR_INFO
6760     int ret = 0;
6761     bool exist = false;
6762     char *label = NULL;
6763     pkgmgrinfo_appinfo_h handle = NULL;
6764
6765     /* Read DB from ime_info table */
6766     isf_load_ise_information(ALL_ISE, _config);
6767
6768     for (unsigned int i = 0; i < _ime_info.size (); i++) {
6769         ret = pkgmgr_get_appinfo (_ime_info[i].appid.c_str(), &handle);
6770
6771         if (ret == PMINFO_R_OK) {
6772             ret = pkgmgrinfo_appinfo_is_category_exist(handle, "http://tizen.org/category/ime", &exist);
6773             if (ret == PMINFO_R_OK && exist) {
6774                 ret = pkgmgrinfo_appinfo_get_label(handle, &label);
6775                 if (ret == PMINFO_R_OK && label) {
6776                     _ime_info[i].label = String(label);
6777                     /* Update label column in ime_info db table */
6778                     if (isf_db_update_label_by_appid(_ime_info[i].appid.c_str(), label)) {
6779                         _ime_info[i].label = label;
6780                     }
6781                 }
6782             }
6783             else {
6784                 // The appid is invalid.. Need to initialize ime_info DB.
6785                 need_to_init_db = true;
6786             }
6787             pkgmgrinfo_appinfo_destroy_appinfo(handle);
6788         }
6789         else {
6790             // The appid is invalid.. Need to initialize ime_info DB.
6791             need_to_init_db = true;
6792         }
6793     }
6794 #endif
6795
6796     if (need_to_init_db) {
6797         _initialize_ime_info ();
6798     }
6799
6800     if (strLang.length () > 0) {
6801         isf_db_update_disp_lang (strLang.c_str ());
6802         _locale_string = strLang;
6803     }
6804 }
6805
6806 /**
6807  * @brief Set language and locale.
6808  *
6809  * @return void
6810  */
6811 static void set_language_and_locale (const char *lang_str)
6812 {
6813     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6814
6815     char language[256];
6816
6817     if (lang_str) {
6818         LOGD ("language : %s", lang_str);
6819 #if ISF_BUILD_CANDIDATE_UI
6820         elm_language_set (lang_str);
6821 #endif /* CANDIDATE */
6822
6823         snprintf (language, sizeof (language), "%s:en_US:en_GB:en", lang_str);
6824         setenv ("LANGUAGE", language, 1);
6825         setenv ("LANG", lang_str, 1);
6826         setlocale (LC_MESSAGES, lang_str);
6827     } else {
6828         setenv ("LANG", "en_US.utf8", 1);
6829         setlocale (LC_MESSAGES, "en_US.utf8");
6830     }
6831 }
6832
6833 /**
6834  * @brief Callback function for display language change.
6835  *
6836  * @param key The key node.
6837  * @param data The data to pass to this callback.
6838  *
6839  * @return void
6840  */
6841 static void display_language_changed_cb (keynode_t *key, void* data)
6842 {
6843     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6844
6845     char *lang_str = vconf_keynode_get_str (key);
6846     LOGD ("lang : %s", lang_str);
6847     set_language_and_locale (lang_str);
6848
6849     /* Update all ISE names according to display language */
6850     update_ise_locale ();
6851
6852     String default_uuid = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), _initial_ise_uuid);
6853     unsigned int ise_idx = get_ise_index (default_uuid);
6854
6855     if (ise_idx < _ime_info.size ()) {
6856         String default_name = _ime_info[ise_idx].label;
6857         _info_manager->set_current_ise_name (default_name);
6858         _config->reload ();
6859     }
6860 }
6861
6862 /**
6863  * @brief Callback function for keyboard mode change.
6864  *
6865  * @param key The key node.
6866  * @param data The data to pass to this callback.
6867  *
6868  * @return void
6869  */
6870 static void keyboard_mode_changed_cb (keynode_t *key, void* data)
6871 {
6872     bool val = vconf_keynode_get_bool (key);
6873
6874     if (val == 0) {
6875         _info_manager->reset_keyboard_ise ();
6876         change_keyboard_mode (TOOLBAR_HELPER_MODE);
6877         _info_manager->update_input_panel_event (ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
6878     }
6879 }
6880 #endif
6881
6882 /**
6883  * @brief Change keyboard mode.
6884  *
6885  * @param mode The keyboard mode.
6886  *
6887  * @return void
6888  */
6889 static void change_keyboard_mode (TOOLBAR_MODE_T mode)
6890 {
6891     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
6892     uint32 option = 0;
6893     String uuid, name;
6894     bool _support_hw_keyboard_mode = false;
6895 #ifdef HAVE_ECOREX
6896     unsigned int val = 0;
6897 #endif
6898
6899 #ifdef HAVE_VCONF
6900     int input_detect = false;
6901 #endif
6902
6903     String helper_uuid = _config->read (SCIM_CONFIG_DEFAULT_HELPER_ISE, String (""));
6904     String default_uuid = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), String (""));
6905     _support_hw_keyboard_mode = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_SUPPORT_HW_KEYBOARD_MODE), _support_hw_keyboard_mode);
6906
6907     if (mode == TOOLBAR_KEYBOARD_MODE && _support_hw_keyboard_mode) {
6908         if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) {
6909             LOGD ("HARDWARE_KEYBOARD_MODE return");
6910             return;
6911         }
6912
6913         LOGD ("HARDWARE KEYBOARD MODE");
6914         _config->write (ISF_CONFIG_HARDWARE_KEYBOARD_DETECT, 1);
6915         _config->flush ();
6916
6917         if (_ime_info[get_ise_index(default_uuid)].mode == TOOLBAR_HELPER_MODE) {
6918             /* Get the keyboard ISE */
6919             isf_get_keyboard_ise (_config, uuid, name, option);
6920             if (option & SCIM_IME_NOT_SUPPORT_HARDWARE_KEYBOARD) {
6921                 uuid = String (SCIM_COMPOSE_KEY_FACTORY_UUID);
6922                 std::cerr << __FUNCTION__ << ": Keyboard ISE (" << name << ") can not support hardware keyboard!!!\n";
6923             }
6924             /* Try to find reasonable keyboard ISE according to helper ISE language */
6925             if (uuid == String (SCIM_COMPOSE_KEY_FACTORY_UUID)) {
6926                 String helper_language = _ime_info[get_ise_index(default_uuid)].languages;
6927                 if (helper_language.length () > 0) {
6928                     std::vector<String> ise_langs;
6929                     scim_split_string_list (ise_langs, helper_language);
6930                     for (size_t i = 0; i < _groups[ise_langs[0]].size (); ++i) {
6931                         int j = _groups[ise_langs[0]][i];
6932                         if (_ime_info[j].appid != uuid && _ime_info[j].mode == TOOLBAR_KEYBOARD_MODE) {
6933                             uuid = _ime_info[j].appid;
6934                             break;
6935                         }
6936                     }
6937                 }
6938             }
6939         }
6940         else {
6941             uuid = default_uuid;
6942         }
6943 #if ISF_BUILD_CANDIDATE_UI
6944         _soft_candidate_width = 0;
6945         _soft_candidate_height = 0;
6946 #endif /* CANDIDATE */
6947         _ise_state = WINDOW_STATE_HIDE;
6948         _info_manager->set_current_toolbar_mode (TOOLBAR_KEYBOARD_MODE);
6949         _info_manager->hide_helper (helper_uuid);
6950
6951         /* Check whether stop soft keyboard */
6952         if (_focus_in && (_ime_info[get_ise_index (helper_uuid)].options & ISM_HELPER_PROCESS_KEYBOARD_KEYEVENT)) {
6953             /* If focus in and soft keyboard can support hardware key event, then don't stop it */
6954             ;
6955         } else if (_launch_ise_on_request && _soft_keyboard_launched) {
6956             _info_manager->stop_helper (helper_uuid);
6957             _soft_keyboard_launched = false;
6958         }
6959 #ifdef HAVE_ECOREX
6960         ecore_x_event_mask_set (efl_get_quickpanel_window (), ECORE_X_EVENT_MASK_WINDOW_PROPERTY);
6961 #endif
6962
6963 #ifdef HAVE_NOTIFICATION
6964         if (_MOBILE) {
6965             notification_status_message_post (_("Input detected from hardware keyboard"));
6966
6967             /* Read configuations for notification app (isf-kbd-mode-changer) */
6968             String kbd_mode_changer = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_DEFAULT_KBD_MODE_CHANGER_PROGRAM), String (""));
6969             hwkbd_module_noti.launch_app = kbd_mode_changer;
6970             LOGD ("Create kbd_mode_changer notification with : %s", kbd_mode_changer.c_str ());
6971             create_notification (&hwkbd_module_noti);
6972         }
6973 #endif
6974
6975 #ifdef HAVE_VCONF
6976         vconf_get_bool (VCONFKEY_ISF_HW_KEYBOARD_INPUT_DETECTED, &input_detect);
6977
6978         if (!input_detect) {
6979             if (vconf_set_bool (VCONFKEY_ISF_HW_KEYBOARD_INPUT_DETECTED, 1) != 0)
6980                 LOGW ("Failed to set vconf key");
6981             else
6982                 LOGD ("Succeeded to set vconf key");
6983         }
6984 #endif
6985     } else if (mode == TOOLBAR_HELPER_MODE) {
6986         LOGD ("SOFTWARE KEYBOARD MODE");
6987         /* When switching back to S/W keyboard mode, let's hide candidate window first */
6988 #if ISF_BUILD_CANDIDATE_UI
6989         LOGD ("calling ui_candidate_hide (true, true, true)");
6990         ui_candidate_hide (true, true, true);
6991 #endif /* CANDIDATE */
6992         _config->write (ISF_CONFIG_HARDWARE_KEYBOARD_DETECT, 0);
6993         _config->flush ();
6994         if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) {
6995             uuid = helper_uuid.length () > 0 ? helper_uuid : _initial_ise_uuid;
6996             if (_launch_ise_on_request) {
6997                 if (set_active_ise (uuid, false) == false) {
6998                     if (_initial_ise_uuid.compare(uuid))
6999                         set_active_ise (_initial_ise_uuid, false);
7000                 }
7001             }
7002             else {
7003                 if (set_active_ise (uuid, true) == false) {
7004                     if (_initial_ise_uuid.compare(uuid)) {
7005                         LOGD ("Trying to launch initial IME (%s)", _initial_ise_uuid.c_str ());
7006                         set_active_ise (_initial_ise_uuid, true);
7007                     }
7008                 }
7009             }
7010         }
7011
7012 #ifdef HAVE_NOTIFICATION
7013         delete_notification (&hwkbd_module_noti);
7014 #endif
7015
7016 #ifdef HAVE_VCONF
7017         vconf_get_bool (VCONFKEY_ISF_HW_KEYBOARD_INPUT_DETECTED, &input_detect);
7018
7019         if (input_detect) {
7020             if (vconf_set_bool (VCONFKEY_ISF_HW_KEYBOARD_INPUT_DETECTED, 0) != 0)
7021                 LOGW ("Failed to set vconf key");
7022             else
7023                 LOGD ("Succeeded to set vconf key");
7024         }
7025 #endif
7026     }
7027     _config->reload ();
7028 }
7029
7030 #ifdef HAVE_BLUETOOTH
7031 /**
7032  * @brief Callback function for the connection state of Bluetooth Keyboard
7033  *
7034  * @param result The result of changing the connection state
7035  * @param connected The state to be changed. true means connected state, Otherwise, false.
7036  * @param remote_address The remote address
7037  * @param user_data The user data passed from the callback registration function
7038  *
7039  * @return void
7040  */
7041 static void _bt_cb_hid_state_changed (int result, bool connected, const char *remote_address, void *user_data)
7042 {
7043     if (connected == false) {
7044        LOGD ("Bluetooth keyboard disconnected");
7045        if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) {
7046            change_keyboard_mode (TOOLBAR_HELPER_MODE);
7047         }
7048     }
7049 }
7050 #endif
7051
7052 #ifdef HAVE_NOTIFICATION
7053 static void show_ime_selector_notification ()
7054 {
7055     String ise_name;
7056
7057     if (!_MOBILE) return;
7058
7059     unsigned int idx = get_ise_index (_info_manager->get_current_helper_uuid ());
7060     if (idx < _ime_info.size ())
7061         ise_name = _ime_info[idx].label;
7062
7063     String noti_icon_path = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_QUICK_PANEL_ICON_PATH), String (SCIM_ICONDIR));
7064     noti_icon_path += ISF_ISE_SELECTOR_ICON_FILE;
7065
7066     LOGD("IME selector icon path : %s", noti_icon_path.c_str ());
7067
7068     ise_selector_module_noti.icon = noti_icon_path;
7069     ise_selector_module_noti.content = ise_name;
7070
7071     /* Find IME Selector appid for notification */
7072     if (ime_selector_app.length () < 1) {
7073         char *app_id = NULL;
7074         pkgmgrinfo_appinfo_filter_h handle;
7075         int ret = pkgmgrinfo_appinfo_filter_create (&handle);
7076         if (ret == PMINFO_R_OK) {
7077             ret = pkgmgrinfo_appinfo_filter_add_string (handle, PMINFO_APPINFO_PROP_APP_CATEGORY, "http://tizen.org/category/ime-selector");
7078             if (ret == PMINFO_R_OK) {
7079                 pkgmgrinfo_appinfo_filter_foreach_appinfo (handle, _find_appid_from_category, &app_id);
7080             }
7081             pkgmgrinfo_appinfo_filter_destroy (handle);
7082
7083             if (app_id) {
7084                 ime_selector_app = String (app_id);
7085                 free (app_id);
7086                 app_id = NULL;
7087             }
7088         }
7089     }
7090
7091     if (ime_selector_app.length () > 0) {
7092         ise_selector_module_noti.launch_app = ime_selector_app;
7093         LOGD ("Create ise_selector notification with : %s", ime_selector_app.c_str ());
7094         create_notification (&ise_selector_module_noti);
7095     }
7096     else
7097         LOGW ("AppID with http://tizen.org/category/ime-selector category is not available");
7098 }
7099 #endif
7100
7101 #ifdef HAVE_ECOREX
7102 /**
7103  * @brief Callback function for ECORE_X_EVENT_WINDOW_PROPERTY.
7104  *
7105  * @param data Data to pass when it is called.
7106  * @param ev_type The event type.
7107  * @param ev The information for current message.
7108  *
7109  * @return ECORE_CALLBACK_PASS_ON
7110  */
7111 static Eina_Bool x_event_window_property_cb (void *data, int ev_type, void *event)
7112 {
7113     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
7114
7115     Ecore_X_Event_Window_Property *ev = (Ecore_X_Event_Window_Property *)event;
7116
7117     if (ev == NULL)
7118         return ECORE_CALLBACK_PASS_ON;
7119
7120     if (ev->atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE) {
7121         if (ev->win == _control_window) {
7122             /* WMSYNC, #6 The keyboard window is displayed fully so set the conformant geometry */
7123             LOGD ("ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE : win : %p, atom : %d", ev->win, ev->atom);
7124             Ecore_X_Virtual_Keyboard_State state;
7125             state = ecore_x_e_virtual_keyboard_state_get (ev->win);
7126             if (state == ECORE_X_VIRTUAL_KEYBOARD_STATE_ON) {
7127                 LOGD ("ECORE_X_VIRTUAL_KEYBOARD_STATE_ON");
7128                 _ise_state = WINDOW_STATE_SHOW;
7129
7130                 /* Make sure that we have the same rotation angle with the keyboard window */
7131                 if (_ise_window) {
7132                     _candidate_angle = efl_get_ise_window_angle ();
7133                     _ise_angle = efl_get_ise_window_angle ();
7134                 }
7135
7136                 if (_candidate_show_requested) {
7137                     LOGD ("calling ui_candidate_show (true)");
7138                     ui_candidate_show (true);
7139                 } else {
7140                     if (_candidate_area_1_visible) {
7141                         LOGD ("calling ui_candidate_show (false)");
7142                         ui_candidate_show (false);
7143                     }
7144                 }
7145
7146                 set_keyboard_geometry_atom_info (_app_window, get_ise_geometry ());
7147                 _info_manager->update_input_panel_event (ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
7148                 _info_manager->update_input_panel_event (
7149                         ECORE_IMF_INPUT_PANEL_STATE_EVENT, ECORE_IMF_INPUT_PANEL_STATE_SHOW);
7150
7151 #ifdef HAVE_VCONF
7152                 vconf_set_int (VCONFKEY_ISF_INPUT_PANEL_STATE, VCONFKEY_ISF_INPUT_PANEL_STATE_SHOW);
7153 #endif
7154
7155                 if (_info_manager->get_current_toolbar_mode () == TOOLBAR_HELPER_MODE) {
7156                     if (get_ise_count (TOOLBAR_HELPER_MODE, true) >= 2) {
7157                         ecore_x_event_mask_set (efl_get_quickpanel_window (), ECORE_X_EVENT_MASK_WINDOW_PROPERTY);
7158
7159 #ifdef HAVE_NOTIFICATION
7160                         show_ime_selector_notification ();
7161 #endif
7162                     }
7163                 }
7164
7165                 _updated_hide_state_geometry = false;
7166
7167                 ecore_x_e_virtual_keyboard_state_set (_ise_window, ECORE_X_VIRTUAL_KEYBOARD_STATE_ON);
7168             } else if (state == ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF) {
7169                 /* WMSYNC, #9 The keyboard window is hidden fully so send HIDE state */
7170                 LOGD ("ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF");
7171                 // For now don't send HIDE signal here
7172                 //_info_manager->update_input_panel_event (
7173                 //    ECORE_IMF_INPUT_PANEL_STATE_EVENT, ECORE_IMF_INPUT_PANEL_STATE_HIDE);
7174                 _ise_state = WINDOW_STATE_HIDE;
7175                 _ise_angle = -1;
7176                 if (!_updated_hide_state_geometry) {
7177                     /* When the ISE gets hidden by the window manager forcefully without OFF_PREPARE,
7178                        the application might not have updated its autoscroll area */
7179                     set_keyboard_geometry_atom_info (_app_window, get_ise_geometry ());
7180                     _info_manager->update_input_panel_event (ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
7181                     _info_manager->update_input_panel_event (
7182                             ECORE_IMF_INPUT_PANEL_STATE_EVENT, ECORE_IMF_INPUT_PANEL_STATE_HIDE);
7183
7184                     _updated_hide_state_geometry = true;
7185                 }
7186                 if (_info_manager->get_current_toolbar_mode () == TOOLBAR_HELPER_MODE) {
7187                     LOGD ("calling ui_candidate_hide (true, false)");
7188                     ui_candidate_hide (true, false);
7189                 } else {
7190                     ui_settle_candidate_window ();
7191                 }
7192
7193 #ifdef HAVE_VCONF
7194                 vconf_set_int (VCONFKEY_ISF_INPUT_PANEL_STATE, VCONFKEY_ISF_INPUT_PANEL_STATE_HIDE);
7195 #endif
7196
7197 #ifdef HAVE_NOTIFICATION
7198                 delete_notification (&ise_selector_module_noti);
7199 #endif
7200
7201                 _ise_reported_geometry.valid = false;
7202
7203                 ecore_x_e_virtual_keyboard_state_set (_ise_window, ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF);
7204             }
7205             ui_settle_candidate_window ();
7206         }
7207     } else if (ev->atom == ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE) {
7208         if (ev->win == efl_get_quickpanel_window ()) {
7209             int angle = efl_get_quickpanel_window_angle ();
7210             LOGD ("ev->win : %p, change window angle : %d", ev->win, angle);
7211         }
7212     }
7213
7214     return ECORE_CALLBACK_PASS_ON;
7215 }
7216
7217 /**
7218  * @brief Callback function for X event client message.
7219  *
7220  * @param data Data to pass when it is called.
7221  * @param type The event type.
7222  * @param event The information for current message.
7223  *
7224  * @return ECORE_CALLBACK_RENEW
7225  */
7226 static Eina_Bool x_event_client_message_cb (void *data, int type, void *event)
7227 {
7228     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
7229
7230     Ecore_X_Event_Client_Message *ev = (Ecore_X_Event_Client_Message *)event;
7231
7232     if (ev == NULL)
7233         return ECORE_CALLBACK_RENEW;
7234
7235 #if 0
7236     if ((ev->win == _control_window)) {
7237         if (ev->message_type == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ON_PREPARE_REQUEST) {
7238             /* WMSYNC, #4 Send WILL_SHOW event when the keyboard window is about to displayed */
7239             LOGD ("_ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ON_PREPARE_REQUEST");
7240
7241             /* WMSYNC, #5 Let the Window Manager to actually show keyboard window */
7242             // WILL_SHOW_REQUEST_DONE Ack to WM
7243             Ecore_X_Window root_window = ecore_x_window_root_get (_control_window);
7244             ecore_x_e_virtual_keyboard_on_prepare_done_send (root_window, _control_window);
7245             LOGD ("_ecore_x_e_virtual_keyboard_on_prepare_done_send (%x, %x)",
7246                     root_window, _control_window);
7247
7248             _info_manager->update_input_panel_event (
7249                     ECORE_IMF_INPUT_PANEL_STATE_EVENT, ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW);
7250             ui_create_candidate_window ();
7251
7252             vconf_set_int (VCONFKEY_ISF_INPUT_PANEL_STATE, VCONFKEY_ISF_INPUT_PANEL_STATE_WILL_SHOW);
7253         } else if (ev->message_type == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_OFF_PREPARE_REQUEST) {
7254             _ise_state = WINDOW_STATE_WILL_HIDE;
7255             /* WMSYNC, #7 Send WILL_HIDE event when the keyboard window is about to hidden */
7256             LOGD ("_ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_OFF_PREPARE_REQUEST");
7257             // Clear conformant geometry information first
7258
7259             if (_off_prepare_done_timer) {
7260                 ecore_timer_del (_off_prepare_done_timer);
7261                 _off_prepare_done_timer = NULL;
7262             }
7263             _off_prepare_done_timer = ecore_timer_add (1.0, off_prepare_done_timeout, NULL);
7264
7265             _ise_reported_geometry.valid = false;
7266             set_keyboard_geometry_atom_info (_app_window, get_ise_geometry ());
7267             _info_manager->update_input_panel_event (ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
7268             _updated_hide_state_geometry = true;
7269
7270             /* If the input panel is getting hidden because of hw keyboard mode while
7271                the candidate window is still opened, it is considered to be an
7272                "input panel being resized" event instead of "input panel being hidden",
7273                since the candidate window will work as an "input panel" afterwards */
7274             bool send_input_panel_hide_event = true;
7275             if (_info_manager->get_current_toolbar_mode () == TOOLBAR_KEYBOARD_MODE) {
7276                 LOGD ("_candidate_state : %d", _candidate_state);
7277                 if (_candidate_state == WINDOW_STATE_SHOW) {
7278                     send_input_panel_hide_event = false;
7279                 }
7280             }
7281             if (send_input_panel_hide_event) {
7282                 _info_manager->update_input_panel_event (
7283                         ECORE_IMF_INPUT_PANEL_STATE_EVENT, ECORE_IMF_INPUT_PANEL_STATE_HIDE);
7284             }
7285             // For now don't send WILL_HIDE signal here
7286             //_info_manager->update_input_panel_event (
7287             //    ECORE_IMF_INPUT_PANEL_STATE_EVENT, ECORE_IMF_INPUT_PANEL_STATE_WILL_HIDE);
7288             // Instead send HIDE signal
7289             vconf_set_int (VCONFKEY_ISF_INPUT_PANEL_STATE, VCONFKEY_ISF_INPUT_PANEL_STATE_WILL_HIDE);
7290         } else if (ev->message_type == ECORE_X_ATOM_E_WINDOW_ROTATION_CHANGE_PREPARE) {
7291             /* WMSYNC, #10 Register size hints for candidate window and set conformant geometry */
7292             // PRE_ROTATE_DONE Ack to WM
7293             _candidate_angle = ev->data.l[1];
7294             _ise_angle = ev->data.l[1];
7295             LOGD ("ECORE_X_ATOM_E_WINDOW_ROTATION_CHANGE_PREPARE : %d", _candidate_angle);
7296
7297             if (_candidate_angle == 90 || _candidate_angle == 270) {
7298                 ui_candidate_window_resize (_candidate_land_width, _candidate_land_height_min);
7299             } else {
7300                 ui_candidate_window_resize (_candidate_port_width, _candidate_port_height_min);
7301             }
7302             if (_ise_state == WINDOW_STATE_SHOW) {
7303                 set_keyboard_geometry_atom_info (_app_window, get_ise_geometry ());
7304                 _info_manager->update_input_panel_event (ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
7305             }
7306             ui_settle_candidate_window ();
7307             ui_candidate_window_rotate (_candidate_angle);
7308             Ecore_X_Window root_window = ecore_x_window_root_get (_control_window);
7309             LOGD ("ecore_x_e_window_rotation_change_prepare_done_send (%d)", _candidate_angle);
7310             ecore_x_e_window_rotation_change_prepare_done_send (root_window,
7311                     _control_window, _candidate_angle);
7312         } else if (ev->message_type == ECORE_X_ATOM_E_WINDOW_ROTATION_CHANGE_REQUEST) {
7313             int ise_angle = (int)ev->data.l[1];
7314             LOGD ("ECORE_X_ATOM_E_WINDOW_ROTATION_CHANGE_REQUEST for ISE WINDOW : ISE angle : %d, Candidate angle : %d", ise_angle, _candidate_angle);
7315             _candidate_angle = ise_angle;
7316             _ise_angle = ise_angle;
7317             if (_ise_state == WINDOW_STATE_SHOW) {
7318                 set_keyboard_geometry_atom_info (_app_window, get_ise_geometry ());
7319                 _info_manager->update_input_panel_event (ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
7320                 ui_settle_candidate_window ();
7321             }
7322         }
7323     } else if (ev->win == elm_win_xwindow_get (_candidate_window)) {
7324         if (ev->message_type == ECORE_X_ATOM_E_WINDOW_ROTATION_CHANGE_REQUEST || ev->message_type == ECORE_X_ATOM_E_ILLUME_ROTATE_ROOT_ANGLE) {
7325             /* WMSYNC, #11 Actual rotate the candidate window */
7326             if (ev->message_type == ECORE_X_ATOM_E_WINDOW_ROTATION_CHANGE_REQUEST) {
7327                 _candidate_angle = (int)ev->data.l[1];
7328                 ui_candidate_window_rotate (_candidate_angle);
7329                 LOGD ("ECORE_X_ATOM_E_WINDOW_ROTATION_CHANGE_REQUEST : %d", _candidate_angle);
7330             } else if (ev->message_type == ECORE_X_ATOM_E_ILLUME_ROTATE_ROOT_ANGLE &&
7331                 _ise_state != WINDOW_STATE_SHOW) {
7332                 ecore_x_e_window_rotation_app_set (elm_win_xwindow_get (_candidate_window), EINA_TRUE);
7333                 _candidate_angle = (int)ev->data.l[0];
7334                 if (_candidate_angle == 90 || _candidate_angle == 270) {
7335                     evas_object_resize (_candidate_window, _candidate_land_width, _candidate_land_height_min);
7336                 } else {
7337                     evas_object_resize (_candidate_window, _candidate_port_width, _candidate_port_height_min);
7338                 }
7339                 ui_candidate_window_rotate (_candidate_angle);
7340                 ui_settle_candidate_window ();
7341                 ecore_x_e_window_rotation_app_set (elm_win_xwindow_get (_candidate_window), EINA_FALSE);
7342                 LOGD ("ECORE_X_ATOM_E_ILLUME_ROTATE_ROOT_ANGLE : %d", _candidate_angle);
7343             }
7344             SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " : ANGLE (" << _candidate_angle << ")\n";
7345         }
7346     }
7347 #endif
7348
7349     /* Screen reader feature */
7350     if (ev->message_type == ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL) {
7351         static int last_pos_x = -10000;
7352         static int last_pos_y = -10000;
7353
7354         if (_candidate_window) {
7355             if ((unsigned int)ev->data.l[0] == elm_win_xwindow_get (_candidate_window)) {
7356                 if ((unsigned int)ev->data.l[1] == ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_ACTIVATE) {
7357                     // 1 finger double tap
7358                     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "    1 finger double tap focus index = " << _candidate_tts_focus_index << "\n";
7359                     ui_mouse_click (_candidate_tts_focus_index);
7360                 } else if ((unsigned int)ev->data.l[1] == ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ) {
7361                     // 1 finger tap
7362                     // 1 finger touch & move
7363                     last_pos_x = ev->data.l[2];
7364                     last_pos_y = ev->data.l[3];
7365                     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "    1 finger touch & move (" << last_pos_x << ", " << last_pos_y << ")\n";
7366                     ui_mouse_over (last_pos_x, last_pos_y);
7367                 } else if ((unsigned int)ev->data.l[1] == ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ_NEXT ||
7368                            (unsigned int)ev->data.l[1] == ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ_PREV) {
7369                     if ((unsigned int)ev->data.l[1] == ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ_NEXT) {
7370                         // flick right
7371                         SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "    1 finger flick right\n";
7372                         if (evas_object_visible_get (_more_btn) && _candidate_tts_focus_index == (int)(_candidate_display_number - 1))
7373                             _candidate_tts_focus_index = _candidate_display_number == _candidate_row_items[0] ? MORE_BUTTON_INDEX : 0;
7374                         else if (evas_object_visible_get (_more_btn) && _candidate_tts_focus_index == (int)(_candidate_row_items[0] - 1))
7375                             _candidate_tts_focus_index = MORE_BUTTON_INDEX;
7376                         else if (evas_object_visible_get (_close_btn) && _candidate_tts_focus_index == (int)(_candidate_row_items[0] - 1))
7377                             _candidate_tts_focus_index = CLOSE_BUTTON_INDEX;
7378                         else if (_candidate_tts_focus_index == MORE_BUTTON_INDEX)
7379                             _candidate_tts_focus_index = _candidate_display_number == _candidate_row_items[0] ? 0 : _candidate_row_items[0];
7380                         else if (_candidate_tts_focus_index == CLOSE_BUTTON_INDEX)
7381                             _candidate_tts_focus_index = _candidate_row_items[0];
7382                         else if (_candidate_tts_focus_index >= 0 && _candidate_tts_focus_index < (g_isf_candidate_table.get_current_page_size () - 1))
7383                             _candidate_tts_focus_index++;
7384                         else if (_candidate_tts_focus_index == (g_isf_candidate_table.get_current_page_size () - 1))
7385                             _candidate_tts_focus_index = 0;
7386                     } else {
7387                         // flick left
7388                         SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "    1 finger flick left\n";
7389                         if (evas_object_visible_get (_more_btn) && _candidate_tts_focus_index == 0)
7390                             _candidate_tts_focus_index = _candidate_display_number == _candidate_row_items[0] ? MORE_BUTTON_INDEX : _candidate_display_number - 1;
7391                         else if (evas_object_visible_get (_more_btn) && _candidate_tts_focus_index == (int)_candidate_row_items[0])
7392                             _candidate_tts_focus_index = MORE_BUTTON_INDEX;
7393                         else if (evas_object_visible_get (_close_btn) && _candidate_tts_focus_index == (int)_candidate_row_items[0])
7394                             _candidate_tts_focus_index = CLOSE_BUTTON_INDEX;
7395                         else if (_candidate_tts_focus_index == MORE_BUTTON_INDEX)
7396                             _candidate_tts_focus_index = _candidate_row_items[0] - 1;
7397                         else if (_candidate_tts_focus_index == CLOSE_BUTTON_INDEX)
7398                             _candidate_tts_focus_index = _candidate_row_items[0] - 1;
7399                         else if (_candidate_tts_focus_index > 0 && _candidate_tts_focus_index < g_isf_candidate_table.get_current_page_size ())
7400                             _candidate_tts_focus_index--;
7401                         else if (_candidate_tts_focus_index == 0)
7402                             _candidate_tts_focus_index = g_isf_candidate_table.get_current_page_size () - 1;
7403                     }
7404
7405                     int x = 0, y = 0, w = 0, h = 0;
7406                     _wait_stop_event = false;
7407                     if (candidate_expanded) {
7408                         int total = 0;
7409                         int cursor_line = 0;
7410                         for (unsigned int i = 0; i < _candidate_row_items.size (); i++) {
7411                             total += _candidate_row_items [i];
7412                             if (total > (int)_candidate_display_number && _candidate_tts_focus_index >= total)
7413                                 cursor_line++;
7414                         }
7415
7416                         elm_scroller_region_get (_candidate_area_2, &x, &y, &w, &h);
7417
7418                         int line_h   = _item_min_height + _v_padding;
7419                         int cursor_y = cursor_line * line_h;
7420                         if (cursor_y < y) {
7421                             elm_scroller_region_bring_in (_candidate_area_2, 0, cursor_y, w, h);
7422                             _wait_stop_event = true;
7423                         } else if (cursor_y >= y + h) {
7424                             elm_scroller_region_bring_in (_candidate_area_2, 0, cursor_y + line_h - h, w, h);
7425                             _wait_stop_event = true;
7426                         }
7427                     }
7428
7429                     x = y = w = h = 0;
7430                     String strTts = String ("");
7431                     if (_candidate_tts_focus_index >= 0 && _candidate_tts_focus_index < g_isf_candidate_table.get_current_page_size ()) {
7432                         strTts = utf8_wcstombs (g_isf_candidate_table.get_candidate_in_current_page (_candidate_tts_focus_index));
7433                         if (_candidate_0 [_candidate_tts_focus_index])
7434                             evas_object_geometry_get (_candidate_0 [_candidate_tts_focus_index], &x, &y, &w, &h);
7435                     } else if (_candidate_tts_focus_index == MORE_BUTTON_INDEX) {
7436                         strTts = String (_("more button"));
7437                         evas_object_geometry_get (_more_btn, &x, &y, &w, &h);
7438                     } else if (_candidate_tts_focus_index == CLOSE_BUTTON_INDEX) {
7439                         strTts = String (_("close button"));
7440                         evas_object_geometry_get (_close_btn, &x, &y, &w, &h);
7441                     } else {
7442                         LOGW ("TTS focus index = %d", _candidate_tts_focus_index);
7443                         ui_tts_focus_rect_hide ();
7444                     }
7445
7446 #ifdef HAVE_TTS
7447                     if (strTts.length () > 0)
7448                         ui_play_tts (strTts.c_str ());
7449 #endif
7450                     if (w > 0 && h > 0) {
7451                         if (!_wait_stop_event)
7452                             ui_tts_focus_rect_show (x, y, w, h);
7453                         else
7454                             ui_tts_focus_rect_hide ();
7455                     }
7456                 }
7457             }
7458         }
7459     }
7460
7461     return ECORE_CALLBACK_RENEW;
7462 }
7463 #endif
7464
7465 Eina_Bool check_focus_out_by_popup_win ()
7466 {
7467     Eina_Bool ret = EINA_FALSE;
7468 #ifdef HAVE_ECOREX
7469     Ecore_X_Window focus_win = ecore_x_window_focus_get ();
7470     Ecore_X_Window_Type win_type = ECORE_X_WINDOW_TYPE_UNKNOWN;
7471
7472     if (!ecore_x_netwm_window_type_get (focus_win, &win_type))
7473         return EINA_FALSE;
7474
7475     LOGD ("win type : %d", win_type);
7476
7477     if (win_type == ECORE_X_WINDOW_TYPE_POPUP_MENU ||
7478         win_type == ECORE_X_WINDOW_TYPE_NOTIFICATION) {
7479         ret = EINA_TRUE;
7480     }
7481 #endif
7482     return ret;
7483 }
7484
7485 #ifdef HAVE_ECOREX
7486 /**
7487  * @brief Callback function for focus out event of application window
7488  *
7489  * @param data Data to pass when it is called.
7490  *
7491  * @return ECORE_CALLBACK_RENEW
7492  */
7493 static Eina_Bool x_event_window_focus_out_cb (void *data, int ev_type, void *event)
7494 {
7495     Ecore_X_Event_Window_Focus_Out *e = (Ecore_X_Event_Window_Focus_Out*)event;
7496
7497     if (e && e->win == _app_window) {
7498         if (_info_manager->get_current_toolbar_mode () == TOOLBAR_HELPER_MODE) {
7499             if (check_focus_out_by_popup_win ())
7500                 return ECORE_CALLBACK_RENEW;
7501
7502 #if ENABLE_MULTIWINDOW_SUPPORT
7503             unsigned int layout = 0;
7504             LOGD ("Application window focus OUT!");
7505             delete_ise_hide_timer ();
7506
7507             // Check multi window mode
7508             if (ecore_x_window_prop_card32_get (efl_get_app_window (), ECORE_X_ATOM_E_WINDOW_DESKTOP_LAYOUT, &layout, 1) != -1) {
7509                 if (layout == 0 || layout == 1) {
7510                     // Split mode
7511                     LOGD ("Multi window mode. start timer to hide IME");
7512
7513                     // Use timer not to hide and show IME again in focus-out and focus-in event between applications
7514                     _ise_hide_timer = ecore_timer_add (ISF_ISE_HIDE_DELAY, ise_hide_timeout, NULL);
7515                 }
7516             }
7517
7518             if (!_ise_hide_timer) {
7519                 LOGD ("Panel hides ISE");
7520                 _info_manager->hide_helper (_info_manager->get_current_helper_uuid ());
7521                 slot_hide_ise ();
7522                 ui_candidate_hide (true, false, false);
7523             }
7524 #else
7525             LOGD ("Application window focus OUT! Panel hides ISE");
7526             _info_manager->hide_helper (_info_manager->get_current_helper_uuid ());
7527             slot_hide_ise ();
7528             ui_candidate_hide (true, false, false);
7529 #endif
7530         }
7531     }
7532
7533     return ECORE_CALLBACK_RENEW;
7534 }
7535 #endif
7536
7537 static void restore_config ()
7538 {
7539     if (!_config.null ()) {
7540         String uuid = _initial_ise_uuid;
7541
7542         String global_uuid = scim_global_config_read (String(SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), String(""));
7543         if (global_uuid.length () > 0) uuid = global_uuid;
7544
7545         String default_uuid = _config->read (SCIM_CONFIG_DEFAULT_HELPER_ISE, String(""));
7546         if (default_uuid.length() > 0) uuid = default_uuid;
7547
7548         if (global_uuid.length() == 0) {
7549             scim_global_config_write (String(SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), uuid);
7550         }
7551         if (default_uuid.length() == 0) {
7552             _config->write (SCIM_CONFIG_DEFAULT_HELPER_ISE, uuid);
7553         }
7554
7555         scim_global_config_flush ();
7556         _config->flush();
7557
7558         scim_global_config_reload ();
7559         _config->reload ();
7560     }
7561 }
7562
7563 /**
7564  * @brief : Launches default soft keyboard for performance enhancement (It's not mandatory)
7565  */
7566 static void launch_default_soft_keyboard (keynode_t *key, void* data)
7567 {
7568     SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
7569
7570     String helper_uuid;
7571     if (!_config.null()) {
7572         helper_uuid = _config->read(SCIM_CONFIG_DEFAULT_HELPER_ISE, String(""));
7573     }
7574     if (helper_uuid.length () > 0) {
7575         /* Start default ISE */
7576         change_keyboard_mode (TOOLBAR_HELPER_MODE);
7577     } else {
7578         if (!_launch_ise_on_request) {
7579             set_temporary_ise (_initial_ise_uuid);
7580             restore_config();
7581         }
7582     }
7583 }
7584
7585 static String sanitize_string (const char *str, int maxlen = 32)
7586 {
7587     String ret;
7588     static char acceptables[] =
7589         "abcdefghijklmnopqrstuvwxyz"
7590         "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
7591         "1234567890_-.@:";
7592
7593     char *newstr = NULL;
7594     if (maxlen > 0) {
7595         newstr = new char[maxlen + 1];
7596     }
7597     int len = 0;
7598     if (newstr) {
7599         memset (newstr, 0x00, sizeof (char) * (maxlen + 1));
7600
7601         if (str) {
7602             while (len < maxlen && str[len] != '\0' && strchr (acceptables, str[len]) != NULL) {
7603                 newstr[len] = str[len];
7604                 len++;
7605             }
7606             ret = newstr;
7607         }
7608         delete [] newstr;
7609     }
7610     return ret;
7611 }
7612
7613 static Eina_Bool monitor_user_data_path_timer(void *data)
7614 {
7615     const char *path = static_cast<const char*>(data);
7616     bool user_data_path_exists = ecore_file_exists (path);
7617     bool user_data_path_is_dir = ecore_file_is_dir (path);
7618     if (user_data_path_exists && user_data_path_is_dir) {
7619         LOGW ("'%s' exists : %d, is_dir : %d", path,
7620              (user_data_path_exists ? 1 : 0), (user_data_path_is_dir ? 1 : 0));
7621
7622         scim_global_config_reload (true);
7623
7624         load_config ();
7625
7626         /* Read all ime info from db */
7627         _ime_info.clear ();
7628         isf_pkg_select_all_ime_info_db (_ime_info);
7629
7630         bool launch = true;
7631         if (_info_manager->get_current_toolbar_mode () != TOOLBAR_HELPER_MODE) {
7632             launch = false;
7633         }
7634         if (_launch_ise_on_request) {
7635             launch = false;
7636         }
7637         String default_ise_uuid = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), _initial_ise_uuid);
7638
7639         set_active_ise (default_ise_uuid, launch);
7640
7641         restore_config ();
7642
7643         g_monitor_user_data_path_timer = NULL;
7644         return ECORE_CALLBACK_CANCEL;
7645     }
7646
7647     return ECORE_CALLBACK_RENEW;
7648 }
7649
7650 int main (int argc, char *argv [])
7651 {
7652     struct tms    tiks_buf;
7653     _clock_start = times (&tiks_buf);
7654
7655     int           i;
7656     int           ret             = 0;
7657
7658     bool          daemon          = false;
7659     bool          should_resident = true;
7660
7661     int           new_argc        = 0;
7662     char        **new_argv        = new char * [40];
7663     int           display_name_c  = 0;
7664     ConfigModule *config_module   = NULL;
7665     String        config_name     = String ("simple");
7666     String        display_name    = String ();
7667     char          buf[256]        = {0};
7668
7669     String        user_data_path  = String ();
7670     bool          user_data_path_exists = false;
7671     bool          user_data_path_is_dir = false;
7672
7673 #ifdef HAVE_ECOREX
7674     Ecore_Event_Handler *xclient_message_handler  = NULL;
7675     Ecore_Event_Handler *xwindow_property_handler = NULL;
7676     Ecore_Event_Handler *xwindow_focus_out_handler = NULL;
7677 #endif
7678
7679     check_time ("\nStarting ISF Panel EFL...... ");
7680     ISF_SAVE_LOG ("Starting ISF Panel EFL......");
7681
7682     DebugOutput::disable_debug (SCIM_DEBUG_AllMask);
7683     DebugOutput::enable_debug (SCIM_DEBUG_MainMask);
7684
7685     /* Parse command options */
7686     i = 0;
7687     while (i < argc) {
7688         if (++i >= argc)
7689             break;
7690
7691         if (String ("-c") == argv [i] || String ("--config") == argv [i]) {
7692             if (++i >= argc) {
7693                 std::cerr << "no argument for option " << argv [i-1] << "\n";
7694                 ret = -1;
7695                 goto cleanup;
7696             }
7697             config_name = argv [i];
7698             continue;
7699         }
7700
7701         if (String ("-h") == argv [i] || String ("--help") == argv [i]) {
7702             std::cout << "Usage: " << argv [0] << " [option]...\n\n"
7703                  << "The options are: \n"
7704                  << "  --display DISPLAY    Run on display DISPLAY.\n"
7705                  << "  -c, --config NAME    Uses specified Config module.\n"
7706                  << "  -d, --daemon         Run " << argv [0] << " as a daemon.\n"
7707                  << "  -ns, --no-stay       Quit if no connected client.\n"
7708 #if ENABLE_DEBUG
7709                  << "  -v, --verbose LEVEL  Enable debug info, to specific LEVEL.\n"
7710                  << "  -o, --output FILE    Output debug information into FILE.\n"
7711 #endif
7712                  << "  -h, --help           Show this help message.\n";
7713             delete []new_argv;
7714             return 0;
7715         }
7716
7717         if (String ("-d") == argv [i] || String ("--daemon") == argv [i]) {
7718             daemon = true;
7719             continue;
7720         }
7721
7722         if (String ("-ns") == argv [i] || String ("--no-stay") == argv [i]) {
7723             should_resident = false;
7724             continue;
7725         }
7726
7727         if (String ("-v") == argv [i] || String ("--verbose") == argv [i]) {
7728             if (++i >= argc) {
7729                 std::cerr << "no argument for option " << argv [i-1] << "\n";
7730                 ret = -1;
7731                 goto cleanup;
7732             }
7733             DebugOutput::set_verbose_level (atoi (argv [i]));
7734             continue;
7735         }
7736
7737         if (String ("-o") == argv [i] || String ("--output") == argv [i]) {
7738             if (++i >= argc) {
7739                 std::cerr << "No argument for option " << argv [i-1] << "\n";
7740                 ret = -1;
7741                 goto cleanup;
7742             }
7743             DebugOutput::set_output (sanitize_string (argv [i]));
7744             continue;
7745         }
7746
7747         if (String ("--display") == argv [i]) {
7748             if (++i >= argc) {
7749                 std::cerr << "No argument for option " << argv [i-1] << "\n";
7750                 ret = -1;
7751                 goto cleanup;
7752             }
7753             display_name = sanitize_string (argv [i]);
7754             continue;
7755         }
7756
7757         if (String ("--") == argv [i])
7758             break;
7759
7760         std::cerr << "Invalid command line option: " << argv [i] << "\n";
7761         delete []new_argv;
7762         return 0;
7763     } /* End of command line parsing. */
7764
7765     if (new_argv) {
7766         new_argv [new_argc ++] = argv [0];
7767
7768         /* Store the rest argvs into new_argv. */
7769         for (++i; i < argc && new_argc < 37; ++i) {
7770             new_argv [new_argc ++] = argv [i];
7771         }
7772
7773         /* Make up DISPLAY env. */
7774         if (display_name.length ()) {
7775             new_argv [new_argc ++] = const_cast <char*> ("--display");
7776             display_name_c = new_argc;
7777             new_argv [new_argc ++] = strdup (display_name.c_str ());
7778
7779             setenv ("DISPLAY", display_name.c_str (), 1);
7780         }
7781
7782         new_argv [new_argc] = 0;
7783     }
7784
7785     if (!config_name.length ()) {
7786         std::cerr << "No Config module is available!\n";
7787         ret = -1;
7788         goto cleanup;
7789     }
7790
7791     /* Get current display. */
7792     {
7793         const char *p = getenv ("DISPLAY");
7794         if (p)
7795             display_name = String (p);
7796     }
7797
7798     snprintf (buf, sizeof (buf), "config_name=%s display_name=%s", config_name.c_str (), display_name.c_str ());
7799     check_time (buf);
7800
7801     if (daemon) {
7802         check_time ("ISF Panel EFL run as daemon");
7803         scim_daemon ();
7804     }
7805
7806     /* No loading default theme to reduce heap memory */
7807     setenv ("ELM_THEME", "", 1);
7808
7809 #if ISF_BUILD_CANDIDATE_UI
7810     elm_init (argc, argv);
7811 #else
7812     ecore_init ();
7813     ecore_app_args_set(argc, (const char **)argv);
7814 #endif /* CANDIDATE */
7815
7816     check_time ("elm_init");
7817
7818     flush_memory ();
7819
7820 #if ISF_BUILD_CANDIDATE_UI
7821     elm_policy_set (ELM_POLICY_THROTTLE, ELM_POLICY_THROTTLE_NEVER);
7822 #endif /* CANDIDATE */
7823
7824     if (config_name != "dummy") {
7825         /* Load config module */
7826         config_module = new ConfigModule (config_name);
7827
7828         if (!config_module || !config_module->valid ()) {
7829             std::cerr << "Can not load " << config_name << " Config module.\n";
7830             ret = -1;
7831             goto cleanup;
7832         }
7833     } else {
7834         _config = new DummyConfig ();
7835     }
7836
7837     /* Create config instance */
7838     if (_config.null () && config_module && config_module->valid ())
7839         _config = config_module->create_config ();
7840     if (_config.null ()) {
7841         std::cerr << "Failed to create Config instance from " << config_name << " Config module.\n";
7842         ret = -1;
7843         goto cleanup;
7844     }
7845     ConfigBase::set (_config);
7846     check_time ("create config instance");
7847
7848     try {
7849         if (!initialize_panel_agent (_config, display_name, should_resident)) {
7850             check_time ("Failed to initialize Panel Agent!");
7851             std::cerr << "Failed to initialize Panel Agent!\n";
7852             LOGE ("Failed to initialize Panel Agent!");
7853             ret = -1;
7854             goto cleanup;
7855         }
7856     } catch (scim::Exception & e) {
7857         std::cerr << e.what () << "\n";
7858         LOGD("");
7859         ret = -1;
7860         goto cleanup;
7861     }
7862     check_time ("initialize_panel_agent");
7863
7864 #if ISF_BUILD_CANDIDATE_UI
7865     /* Initialize global variables and pointers for candidate items and etc. */
7866     for (i = 0; i < SCIM_LOOKUP_TABLE_MAX_PAGESIZE; i++) {
7867         _candidate_0 [i]     = NULL;
7868         _seperate_0 [i]      = NULL;
7869         _seperate_items [i]  = NULL;
7870         _line_0 [i]          = NULL;
7871         _line_items [i]      = NULL;
7872         _candidate_text [i]  = NULL;
7873         _candidate_image [i] = NULL;
7874         _candidate_pop_image [i] = NULL;
7875     }
7876 #endif /* CANDIDATE */
7877
7878     /* Connect the configuration reload signal. */
7879     _config_connection = _config->signal_connect_reload (slot (config_reload_cb));
7880
7881 #ifdef HAVE_ECOREX
7882     if (!efl_create_control_window ()) {
7883         LOGW ("Failed to create control window");
7884         goto cleanup;
7885     }
7886 #endif
7887
7888 #if ISF_BUILD_CANDIDATE_UI
7889     efl_get_screen_resolution (_screen_width, _screen_height);
7890
7891     _width_rate       = (float)(_screen_width / 720.0);
7892     _height_rate      = (float)(_screen_height / 1280.0);
7893     _blank_width      = (int)(_blank_width * _width_rate);
7894     _item_min_width   = (int)(_item_min_width * _width_rate);
7895     _item_min_height  = (int)(_item_min_height * _height_rate);
7896     _candidate_width  = (int)(_candidate_port_width * _width_rate);
7897     _candidate_height = (int)(_candidate_port_height_min * _height_rate);
7898     _indicator_height = (int)(_indicator_height * _height_rate);
7899
7900     _aux_font_size       = (int)(_aux_font_size * (_width_rate < _height_rate ? _width_rate : _height_rate));
7901     _candidate_font_size = (int)(_candidate_font_size * (_width_rate < _height_rate ? _width_rate : _height_rate));
7902 #endif /* CANDIDATE */
7903
7904     /* Load ISF configuration */
7905     user_data_path = scim_get_user_data_dir ();
7906     user_data_path_exists = ecore_file_exists (user_data_path.c_str ());
7907     user_data_path_is_dir = ecore_file_is_dir (user_data_path.c_str ());
7908     _launch_ise_on_request = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_LAUNCH_ISE_ON_REQUEST), _launch_ise_on_request);
7909     if (user_data_path_exists && user_data_path_is_dir) {
7910         load_config ();
7911     } else {
7912         LOGW ("'%s' exists : %d, is_dir : %d", user_data_path.c_str (),
7913             (user_data_path_exists ? 1 : 0), (user_data_path_is_dir ? 1 : 0));
7914         g_monitor_user_data_path_timer = ecore_timer_add (1.0, monitor_user_data_path_timer, user_data_path.c_str ());
7915     }
7916     check_time("load_config");
7917
7918 #ifdef HAVE_VCONF
7919     char *lang_str;
7920     lang_str = vconf_get_str (VCONFKEY_LANGSET);
7921     set_language_and_locale (lang_str);
7922     if (lang_str)
7923         free (lang_str);
7924
7925     /* Add callback function for input language and display language */
7926     vconf_notify_key_changed (VCONFKEY_LANGSET, display_language_changed_cb, NULL);
7927     vconf_notify_key_changed (VCONFKEY_ISF_HW_KEYBOARD_INPUT_DETECTED, keyboard_mode_changed_cb, NULL);
7928 #endif
7929
7930 #ifdef HAVE_EDBUS
7931     if (0 != register_edbus_signal_handler ())
7932         LOGW ("register edbus signal fail");
7933 #endif
7934
7935     try {
7936         /* Update ISE list */
7937         std::vector<String> list;
7938         update_ise_list (list);
7939
7940         /* Load initial ISE information */
7941         _initial_ise_uuid = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_INITIAL_ISE_UUID), String (SCIM_COMPOSE_KEY_FACTORY_UUID));
7942
7943         /* Check if SCIM_CONFIG_DEFAULT_HELPER_ISE is available. If it's not, set it as _initial_ise_uuid.
7944            e.g., This might be necessary when the platform is upgraded from 2.3 to 2.4. */
7945         String helper_uuid = _config->read (SCIM_CONFIG_DEFAULT_HELPER_ISE, String (""));
7946         if (_initial_ise_uuid.length() > 0 && helper_uuid != _initial_ise_uuid) {
7947             bool match = false;
7948             for (unsigned int u = 0; u < _ime_info.size (); u++) {
7949                 if (_ime_info[u].mode == TOOLBAR_HELPER_MODE && helper_uuid == _ime_info[u].appid) {
7950                     match = true;
7951                     break;
7952                 }
7953             }
7954             if (!match) {
7955                 _config->write (String (SCIM_CONFIG_DEFAULT_HELPER_ISE), _initial_ise_uuid);
7956             }
7957         }
7958
7959         /* Launches default soft keyboard when all conditions are satisfied */
7960         launch_default_soft_keyboard ();
7961
7962         /* Update the name of each ISE according to display language */
7963         update_ise_locale ();
7964     } catch (scim::Exception & e) {
7965         std::cerr << e.what () << "\n";
7966     } catch (std::logic_error & e) {
7967         std::cerr << e.what () << "\n";
7968     }
7969 #ifdef HAVE_ECOREX
7970     xclient_message_handler  = ecore_event_handler_add (ECORE_X_EVENT_CLIENT_MESSAGE, x_event_client_message_cb, NULL);
7971     xwindow_property_handler = ecore_event_handler_add (ECORE_X_EVENT_WINDOW_PROPERTY, x_event_window_property_cb, NULL);
7972     xwindow_focus_out_handler = ecore_event_handler_add (ECORE_X_EVENT_WINDOW_FOCUS_OUT, x_event_window_focus_out_cb, NULL);
7973 #endif
7974
7975 #ifdef HAVE_BLUETOOTH
7976     /* Register the callback function of Bluetooth connection */
7977      ret = bt_initialize ();
7978      if (ret != BT_ERROR_NONE)
7979          LOGW ("Fail to init Bluetooth");
7980
7981      ret = bt_hid_host_initialize (_bt_cb_hid_state_changed, NULL);
7982      if (ret != BT_ERROR_NONE)
7983          LOGW ("bt_hid_host_initialize failed");
7984 #endif
7985
7986     if (_TV) {
7987         launch_remote_input = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_LAUNCH_REMOTE_INPUT), launch_remote_input);
7988
7989          /* Create remote input */
7990         if (launch_remote_input) {
7991              LOGD("remote input start");
7992              remote_input_impl = new Remote_Input();
7993              if (remote_input_impl) {
7994                  remote_input_impl->init(_info_manager);
7995              }
7996         }
7997     }
7998
7999 #if ISF_BUILD_CANDIDATE_UI
8000     _system_scale = elm_config_scale_get ();
8001
8002     /* Set elementary scale */
8003     if (_screen_width) {
8004         _app_scale = _screen_width / 720.0;
8005         elm_config_scale_set (_app_scale);
8006         char buf[16] = {0};
8007         snprintf (buf, sizeof (buf), "%4.3f", _app_scale);
8008         setenv ("ELM_SCALE", buf, 1);
8009     }
8010 #endif /* CANDIDATE */
8011
8012     signal (SIGQUIT, signalhandler);
8013     signal (SIGTERM, signalhandler);
8014     signal (SIGINT,  signalhandler);
8015     signal (SIGHUP,  signalhandler);
8016
8017     check_time ("EFL Panel launch time");
8018
8019     if (!isf_cynara_initialize())
8020         LOGW ("Failed to initialize cynara");
8021
8022 #if ISF_BUILD_CANDIDATE_UI
8023     elm_run ();
8024 #else
8025     ecore_main_loop_begin ();
8026 #endif /* CANDIDATE */
8027
8028     LOGW("out of loop");
8029
8030     isf_cynara_finish();
8031
8032     _config->flush ();
8033     ret = 0;
8034
8035     if (g_monitor_user_data_path_timer) {
8036         ecore_timer_del (g_monitor_user_data_path_timer);
8037         g_monitor_user_data_path_timer = NULL;
8038     }
8039
8040 #ifdef HAVE_BLUETOOTH
8041     /* deinitialize the callback function of Bluetooth connection */
8042     ret = bt_hid_host_deinitialize ();
8043     if (ret != BT_ERROR_NONE)
8044         LOGW ("bt_hid_host_deinitialize failed: %d", ret);
8045
8046     ret = bt_deinitialize ();
8047     if (ret != BT_ERROR_NONE)
8048         LOGW ("bt_deinitialize failed: %d", ret);
8049 #endif
8050
8051 #ifdef HAVE_ECOREX
8052     if (xclient_message_handler) {
8053         ecore_event_handler_del (xclient_message_handler);
8054         xclient_message_handler = NULL;
8055     }
8056
8057     if (xwindow_property_handler) {
8058         ecore_event_handler_del (xwindow_property_handler);
8059         xwindow_property_handler = NULL;
8060     }
8061
8062     if (xwindow_focus_out_handler) {
8063         ecore_event_handler_del (xwindow_focus_out_handler);
8064         xwindow_focus_out_handler = NULL;
8065     }
8066 #endif
8067
8068 #ifdef HAVE_VCONF
8069     /* Remove callback function for input language and display language */
8070     vconf_ignore_key_changed (VCONFKEY_LANGSET, display_language_changed_cb);
8071     vconf_ignore_key_changed (VCONFKEY_ISF_HW_KEYBOARD_INPUT_DETECTED, keyboard_mode_changed_cb);
8072 #endif
8073
8074 cleanup:
8075 #if ISF_BUILD_CANDIDATE_UI
8076     ui_destroy_candidate_window ();
8077     ui_candidate_delete_check_size_timer ();
8078     ui_candidate_delete_longpress_timer ();
8079     ui_candidate_delete_destroy_timer ();
8080 #endif /* CANDIDATE */
8081 #ifdef HAVE_PKGMGR_INFO
8082     if (pkgmgr) {
8083         package_manager_destroy (pkgmgr);
8084         pkgmgr = NULL;
8085     }
8086 #endif
8087     delete_ise_check_pid_alive_timer();
8088
8089 #if ISF_BUILD_CANDIDATE_UI
8090 #ifdef HAVE_TTS
8091     ui_close_tts ();
8092 #endif
8093 #endif
8094
8095 #ifdef HAVE_EDBUS
8096     unregister_edbus_signal_handler ();
8097 #endif
8098
8099     if (_info_manager) {
8100         try {
8101             _info_manager->stop ();
8102         } catch (scim::Exception & e) {
8103             std::cerr << "Exception is thrown from _info_manager->stop (), error is " << e.what () << "\n";
8104         }
8105         delete _info_manager;
8106     }
8107     _config_connection.disconnect ();
8108     if (!_config.null ())
8109         _config.reset ();
8110     ConfigBase::set (0);
8111
8112     if (config_module)
8113         delete config_module;
8114
8115 #if ISF_BUILD_CANDIDATE_UI
8116     elm_shutdown ();
8117 #else
8118     ecore_shutdown ();
8119 #endif /* CANDIDATE */
8120
8121     if (new_argv) {
8122         if ((display_name_c > 0) && new_argv [display_name_c]) {
8123             free (new_argv [display_name_c]);
8124         }
8125         delete []new_argv;
8126     }
8127
8128     ISF_SAVE_LOG ("ret=%d", ret);
8129     if (ret == 0) {
8130         std::cerr << "Successfully exited.\n";
8131         return 0;
8132     } else {
8133         std::cerr << "Abnormally exited.\n";
8134         return -1;
8135     }
8136 }
8137
8138 /*
8139 vi:ts=4:nowrap:expandtab
8140 */