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