Tizen 2.1 base
[framework/uifw/ecore.git] / src / modules / immodules / scim / scim_imcontext.cpp
1 #ifdef HAVE_CONFIG_H
2 #include <config.h>
3 #endif
4
5 #define Uses_SCIM_DEBUG
6 #define Uses_SCIM_BACKEND
7 #define Uses_SCIM_IMENGINE_MODULE
8 #define Uses_SCIM_HOTKEY
9 #define Uses_SCIM_PANEL_CLIENT
10
11 #include <sys/types.h>
12 #include <sys/wait.h>
13 #include <sys/time.h>
14 #include <sys/times.h>
15 #include <unistd.h>
16 #include <pthread.h>
17 #include <Ecore_Evas.h>
18 #include <Ecore_X.h>
19 #include <Ecore.h>
20 #include <Evas.h>
21
22 #include <X11/Xlib.h>
23 #include <X11/keysym.h>
24 #include <X11/Xutil.h>
25
26 #include <scim.h>
27 #include "scim_imcontext.h"
28
29 using namespace scim;
30
31 struct _EcoreIMFContextISFImpl
32 {
33     EcoreIMFContextISF      *parent;
34     IMEngineInstancePointer  si;
35     Ecore_X_Window           client_window;
36     Evas                    *client_canvas;
37     Ecore_IMF_Input_Mode     input_mode;
38     WideString               preedit_string;
39     AttributeList            preedit_attrlist;
40     Ecore_IMF_Autocapital_Type autocapital_type;
41     int                      preedit_caret;
42     int                      cursor_x;
43     int                      cursor_y;
44     int                      cursor_pos;
45     bool                     use_preedit;
46     bool                     is_on;
47     bool                     shared_si;
48     bool                     preedit_started;
49     bool                     preedit_updating;
50     bool                     need_commit_preedit;
51     bool                     uppercase;
52     bool                     prediction_allow;
53
54     EcoreIMFContextISFImpl  *next;
55 };
56
57 /* Input Context handling functions. */
58 static EcoreIMFContextISFImpl *new_ic_impl              (EcoreIMFContextISF     *parent);
59 static void                    delete_ic_impl           (EcoreIMFContextISFImpl *impl);
60 static void                    delete_all_ic_impl       (void);
61
62 static EcoreIMFContextISF     *find_ic                  (int                     id);
63
64
65 /* private functions */
66 static void     panel_slot_reload_config                (int                     context);
67 static void     panel_slot_exit                         (int                     context);
68 static void     panel_slot_update_lookup_table_page_size(int                     context,
69                                                          int                     page_size);
70 static void     panel_slot_lookup_table_page_up         (int                     context);
71 static void     panel_slot_lookup_table_page_down       (int                     context);
72 static void     panel_slot_trigger_property             (int                     context,
73                                                          const String           &property);
74 static void     panel_slot_process_helper_event         (int                     context,
75                                                          const String           &target_uuid,
76                                                          const String           &helper_uuid,
77                                                          const Transaction      &trans);
78 static void     panel_slot_move_preedit_caret           (int                     context,
79                                                          int                     caret_pos);
80 static void     panel_slot_select_candidate             (int                     context,
81                                                          int                     cand_index);
82 static void     panel_slot_process_key_event            (int                     context,
83                                                          const KeyEvent         &key);
84 static void     panel_slot_commit_string                (int                     context,
85                                                          const WideString       &wstr);
86 static void     panel_slot_forward_key_event            (int                     context,
87                                                          const KeyEvent         &key);
88 static void     panel_slot_request_help                 (int                     context);
89 static void     panel_slot_request_factory_menu         (int                     context);
90 static void     panel_slot_change_factory               (int                     context,
91                                                          const String           &uuid);
92
93 static void     panel_req_focus_in                      (EcoreIMFContextISF     *ic);
94 static void     panel_req_update_factory_info           (EcoreIMFContextISF     *ic);
95 static void     panel_req_update_spot_location          (EcoreIMFContextISF     *ic);
96 static void     panel_req_show_help                     (EcoreIMFContextISF     *ic);
97 static void     panel_req_show_factory_menu             (EcoreIMFContextISF     *ic);
98
99 /* Panel iochannel handler*/
100 static bool     panel_initialize                        (void);
101 static void     panel_finalize                          (void);
102 static Eina_Bool panel_iochannel_handler                (void                   *data,
103                                                          Ecore_Fd_Handler       *fd_handler);
104
105 /* utility functions */
106 static bool     filter_hotkeys                          (EcoreIMFContextISF     *ic,
107                                                          const KeyEvent         &key);
108 static void     turn_on_ic                              (EcoreIMFContextISF     *ic);
109 static void     turn_off_ic                             (EcoreIMFContextISF     *ic);
110 static void     set_ic_capabilities                     (EcoreIMFContextISF     *ic);
111
112 static void     initialize                              (void);
113 static void     finalize                                (void);
114
115 static void     open_next_factory                       (EcoreIMFContextISF     *ic);
116 static void     open_previous_factory                   (EcoreIMFContextISF     *ic);
117 static void     open_specific_factory                   (EcoreIMFContextISF     *ic,
118                                                          const String           &uuid);
119 static void     initialize_modifier_bits                (Display *display);
120 static unsigned int scim_x11_keymask_scim_to_x11        (Display *display, uint16 scimkeymask);
121 static XKeyEvent createKeyEvent                         (Display *display, Window &win,
122                                                          Window &winRoot, bool press,
123                                                          int keycode, int modifiers);
124 static void     _x_send_key_event                       (const KeyEvent &key);
125
126 static void     attach_instance                         (const IMEngineInstancePointer &si);
127
128 /* slot functions */
129 static void     slot_show_preedit_string                (IMEngineInstanceBase   *si);
130 static void     slot_show_aux_string                    (IMEngineInstanceBase   *si);
131 static void     slot_show_lookup_table                  (IMEngineInstanceBase   *si);
132
133 static void     slot_hide_preedit_string                (IMEngineInstanceBase   *si);
134 static void     slot_hide_aux_string                    (IMEngineInstanceBase   *si);
135 static void     slot_hide_lookup_table                  (IMEngineInstanceBase   *si);
136
137 static void     slot_update_preedit_caret               (IMEngineInstanceBase   *si,
138                                                          int                     caret);
139 static void     slot_update_preedit_string              (IMEngineInstanceBase   *si,
140                                                          const WideString       &str,
141                                                          const AttributeList    &attrs);
142 static void     slot_update_aux_string                  (IMEngineInstanceBase   *si,
143                                                          const WideString       &str,
144                                                          const AttributeList    &attrs);
145 static void     slot_commit_string                      (IMEngineInstanceBase   *si,
146                                                          const WideString       &str);
147 static void     slot_forward_key_event                  (IMEngineInstanceBase   *si,
148                                                          const KeyEvent         &key);
149 static void     slot_update_lookup_table                (IMEngineInstanceBase   *si,
150                                                          const LookupTable      &table);
151
152 static void     slot_register_properties                (IMEngineInstanceBase   *si,
153                                                          const PropertyList     &properties);
154 static void     slot_update_property                    (IMEngineInstanceBase   *si,
155                                                          const Property         &property);
156 static void     slot_beep                               (IMEngineInstanceBase   *si);
157 static void     slot_start_helper                       (IMEngineInstanceBase   *si,
158                                                          const String           &helper_uuid);
159 static void     slot_stop_helper                        (IMEngineInstanceBase   *si,
160                                                          const String           &helper_uuid);
161 static void     slot_send_helper_event                  (IMEngineInstanceBase   *si,
162                                                          const String           &helper_uuid,
163                                                          const Transaction      &trans);
164 static bool     slot_get_surrounding_text               (IMEngineInstanceBase   *si,
165                                                          WideString             &text,
166                                                          int                    &cursor,
167                                                          int                     maxlen_before,
168                                                          int                     maxlen_after);
169 static bool     slot_delete_surrounding_text            (IMEngineInstanceBase   *si,
170                                                          int                     offset,
171                                                          int                     len);
172
173 static void     reload_config_callback                  (const ConfigPointer    &config);
174
175 static void     fallback_commit_string_cb               (IMEngineInstanceBase   *si,
176                                                          const WideString       &str);
177
178 static void     caps_mode_check                         (Ecore_IMF_Context *ctx, Eina_Bool force);
179
180 /* Local variables declaration */
181 static String                                           _language;
182 static EcoreIMFContextISFImpl                          *_used_ic_impl_list          = 0;
183 static EcoreIMFContextISFImpl                          *_free_ic_impl_list          = 0;
184 static EcoreIMFContextISF                              *_ic_list                    = 0;
185
186 static KeyboardLayout                                   _keyboard_layout            = SCIM_KEYBOARD_Default;
187 static int                                              _valid_key_mask             = SCIM_KEY_AllMasks;
188
189 static FrontEndHotkeyMatcher                            _frontend_hotkey_matcher;
190 static IMEngineHotkeyMatcher                            _imengine_hotkey_matcher;
191
192 static IMEngineInstancePointer                          _default_instance;
193
194 static ConfigModule                                    *_config_module              = 0;
195 static ConfigPointer                                    _config;
196 static BackEndPointer                                   _backend;
197
198 static EcoreIMFContextISF                              *_focused_ic                 = 0;
199
200 static bool                                             _scim_initialized           = false;
201
202 static int                                              _instance_count             = 0;
203 static int                                              _context_count              = 0;
204
205 static IMEngineFactoryPointer                           _fallback_factory;
206 static IMEngineInstancePointer                          _fallback_instance;
207 static PanelClient                                      _panel_client;
208
209 static Ecore_Fd_Handler                                *_panel_iochannel_read_handler = 0;
210 static Ecore_Fd_Handler                                *_panel_iochannel_err_handler  = 0;
211
212 static Ecore_X_Window                                  _client_window               = 0;
213
214 static bool                                             _on_the_spot                = true;
215 static bool                                             _shared_input_method        = false;
216
217 static Eina_Bool                                        autocap_allow = EINA_FALSE;
218
219 static Display *__current_display      = 0;
220 static int      __current_alt_mask     = Mod1Mask;
221 static int      __current_meta_mask    = 0;
222 static int      __current_super_mask   = 0;
223 static int      __current_hyper_mask   = 0;
224 static int      __current_numlock_mask = Mod2Mask;
225
226 // A hack to shutdown the immodule cleanly even if im_module_exit() is not called when exiting.
227 class FinalizeHandler
228 {
229 public:
230    FinalizeHandler()
231      {
232         SCIM_DEBUG_FRONTEND(1) << "FinalizeHandler::FinalizeHandler()\n";
233      }
234    ~FinalizeHandler()
235      {
236         SCIM_DEBUG_FRONTEND(1) << "FinalizeHandler::~FinalizeHandler()\n";
237         isf_imf_context_shutdown();
238      }
239 };
240
241 static FinalizeHandler                                  _finalize_handler;
242
243 static unsigned int
244 utf8_offset_to_index(const char *str, int offset)
245 {
246    int index = 0;
247    int i;
248    for (i = 0; i < offset; i++)
249      {
250         eina_unicode_utf8_get_next(str, &index);
251      }
252
253    return index;
254 }
255
256 static unsigned int
257 get_time(void)
258 {
259    unsigned int tint;
260    struct timeval tv;
261    struct timezone tz;           /* is not used since ages */
262    gettimeofday(&tv, &tz);
263    tint = tv.tv_sec * 1000;
264    tint = tint / 1000 * 1000;
265    tint = tint + tv.tv_usec / 1000;
266    return tint;
267 }
268
269 /* Function Implementations */
270 static EcoreIMFContextISFImpl *
271 new_ic_impl(EcoreIMFContextISF *parent)
272 {
273    EcoreIMFContextISFImpl *impl = NULL;
274
275    if (_free_ic_impl_list != NULL)
276      {
277         impl = _free_ic_impl_list;
278         _free_ic_impl_list = _free_ic_impl_list->next;
279      }
280    else
281      {
282         impl = new EcoreIMFContextISFImpl;
283         if (impl == NULL)
284           return NULL;
285      }
286
287    impl->uppercase = false;
288    impl->autocapital_type = ECORE_IMF_AUTOCAPITAL_TYPE_NONE;
289    impl->next = _used_ic_impl_list;
290    _used_ic_impl_list = impl;
291
292    impl->parent = parent;
293
294    return impl;
295 }
296
297 static void
298 delete_ic_impl(EcoreIMFContextISFImpl *impl)
299 {
300    EcoreIMFContextISFImpl *rec = _used_ic_impl_list, *last = 0;
301
302    for (; rec != 0; last = rec, rec = rec->next)
303      {
304         if (rec == impl)
305           {
306              if (last != 0)
307                last->next = rec->next;
308              else
309                _used_ic_impl_list = rec->next;
310
311              rec->next = _free_ic_impl_list;
312              _free_ic_impl_list = rec;
313
314              rec->parent = 0;
315              rec->si.reset();
316              rec->client_window = 0;
317              rec->preedit_string = WideString();
318              rec->preedit_attrlist.clear();
319
320              return;
321           }
322      }
323 }
324
325 static void
326 delete_all_ic_impl(void)
327 {
328    EcoreIMFContextISFImpl *it = _used_ic_impl_list;
329
330    while (it != 0)
331      {
332         _used_ic_impl_list = it->next;
333         delete it;
334         it = _used_ic_impl_list;
335      }
336
337    it = _free_ic_impl_list;
338    while (it != 0)
339      {
340         _free_ic_impl_list = it->next;
341         delete it;
342         it = _free_ic_impl_list;
343      }
344 }
345
346 static EcoreIMFContextISF *
347 find_ic(int id)
348 {
349    EcoreIMFContextISFImpl *rec = _used_ic_impl_list;
350
351    while (rec != 0)
352      {
353         if (rec->parent && rec->parent->id == id)
354           return rec->parent;
355         rec = rec->next;
356      }
357
358    return 0;
359 }
360
361 static Eina_Bool
362 analyze_surrounding_text(Ecore_IMF_Context *ctx)
363 {
364    char *plain_str = NULL;
365    char *markup_str = NULL;
366    const char *puncs[] = {". ", "! ", "? "};
367    Eina_Bool ret = EINA_FALSE;
368    int cursor_pos = 0;
369    int i = 0;
370    Eina_Unicode *tail = NULL;
371    Eina_Unicode *ustr = NULL;
372    const int punc_num = sizeof(puncs) / sizeof(puncs[0]);
373    Eina_Unicode *uni_puncs[punc_num];
374    EcoreIMFContextISF *context_scim;
375
376    if (!ctx) return EINA_FALSE;
377    context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
378    if (!context_scim || !context_scim->impl) return EINA_FALSE;
379
380    switch (context_scim->impl->autocapital_type)
381      {
382       case ECORE_IMF_AUTOCAPITAL_TYPE_NONE:
383          return EINA_FALSE;
384       case ECORE_IMF_AUTOCAPITAL_TYPE_ALLCHARACTER:
385          return EINA_TRUE;
386       default:
387          break;
388      }
389
390    for (i = 0; i < punc_num; i++)
391      uni_puncs[i] = eina_unicode_utf8_to_unicode(puncs[i], NULL);
392
393    ecore_imf_context_surrounding_get(ctx, &markup_str, &cursor_pos);
394    if (!markup_str) goto done;
395
396    if (cursor_pos == 0)
397      {
398         ret = EINA_TRUE;
399         goto done;
400      }
401
402    // Convert into plain string
403    plain_str = evas_textblock_text_markup_to_utf8(NULL, markup_str);
404    if (!plain_str) goto done;
405
406    // Convert string from UTF-8 to unicode
407    ustr = eina_unicode_utf8_to_unicode(plain_str, NULL);
408    if (!ustr) goto done;
409
410    if (cursor_pos >= 1)
411      {
412         if (context_scim->impl->autocapital_type == ECORE_IMF_AUTOCAPITAL_TYPE_WORD)
413           {
414              if (ustr[cursor_pos-1] == ' ')
415                {
416                   ret = EINA_TRUE;
417                   goto done;
418                }
419           }
420
421         // Check paragraph separator <PS> and carriage return  <br>
422         if ((ustr[cursor_pos-1] == 0x2029) || (ustr[cursor_pos-1] == '\n'))
423           {
424              ret = EINA_TRUE;
425              goto done;
426           }
427      }
428
429    // check punctuation
430    if (cursor_pos >= 2)
431      {
432         tail = eina_unicode_strndup(ustr+cursor_pos-2, 2);
433
434         if (tail)
435           {
436              for (i = 0; i < punc_num; i++)
437                {
438                   if (!eina_unicode_strcmp(tail, uni_puncs[i]))
439                     {
440                        ret = EINA_TRUE;
441                        break;
442                     }
443                }
444              free(tail);
445              tail = NULL;
446           }
447      }
448
449 done:
450    if (ustr) free(ustr);
451    if (markup_str) free(markup_str);
452    if (plain_str) free(plain_str);
453
454    for (i = 0; i < punc_num; i++)
455      if (uni_puncs[i]) free(uni_puncs[i]);
456
457    return ret;
458 }
459
460 static void
461 caps_mode_check(Ecore_IMF_Context *ctx, Eina_Bool force)
462 {
463    Eina_Bool uppercase;
464    EcoreIMFContextISF *context_scim;
465
466    if (!ctx) return;
467    context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
468
469    if (autocap_allow == EINA_FALSE)
470      return;
471
472    // Check autocapital type
473    if (!context_scim || !context_scim->impl)
474      return;
475
476    if (analyze_surrounding_text(ctx))
477      uppercase = EINA_TRUE;
478    else
479      uppercase = EINA_FALSE;
480
481    if (force)
482      context_scim->impl->uppercase = uppercase;
483    else
484      if (context_scim->impl->uppercase != uppercase)
485        context_scim->impl->uppercase = uppercase;
486 }
487
488 static void
489 feed_key_event(Evas *evas, const char *str, Eina_Bool fake)
490 {
491    char key_string[128] = {0};
492    unsigned int timestamp = 0;
493
494    if (!fake)
495      timestamp = get_time();
496
497    if (strncmp(str, "KeyRelease+", 11) == 0)
498      {
499         strncpy(key_string, str + 11, strlen(str)-11);
500         evas_event_feed_key_up(evas, key_string, key_string, NULL, NULL, timestamp, NULL);
501         SCIM_DEBUG_FRONTEND(1) << "    evas_event_feed_key_up()...\n";
502      }
503    else
504      {
505         strncpy(key_string, str, strlen(str));
506         evas_event_feed_key_down(evas, key_string, key_string, NULL, NULL, timestamp, NULL);
507         SCIM_DEBUG_FRONTEND(1) << "    evas_event_feed_key_down()...\n";
508      }
509 }
510
511 static void
512 window_to_screen_geometry_get(Ecore_X_Window client_win, int *x, int *y)
513 {
514    Ecore_X_Window root_window, win;
515    int win_x, win_y;
516    int sum_x = 0, sum_y = 0;
517
518    root_window = ecore_x_window_root_get(client_win);
519    win = client_win;
520
521    while (root_window != win)
522      {
523         ecore_x_window_geometry_get(win, &win_x, &win_y, NULL, NULL);
524         sum_x += win_x;
525         sum_y += win_y;
526         win = ecore_x_window_parent_get(win);
527      }
528
529    if (x)
530      *x = sum_x;
531    if (y)
532      *y = sum_y;
533 }
534
535 /* Public functions */
536 /**
537  * isf_imf_context_new
538  *
539  * This function will be called by Ecore IMF.
540  * Create a instance of type EcoreIMFContextISF.
541  *
542  * Return value: A pointer to the newly created EcoreIMFContextISF instance
543  */
544 EAPI EcoreIMFContextISF *
545 isf_imf_context_new(void)
546 {
547    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
548    char *env;
549
550    EcoreIMFContextISF *context_scim = new EcoreIMFContextISF;
551    if (context_scim == NULL)
552      {
553         std::cerr << "memory allocation failed in " << __FUNCTION__ << "\n";
554         return NULL;
555      }
556
557    context_scim->id = _context_count++;
558
559    if (!_scim_initialized)
560      {
561         initialize();
562         _scim_initialized = true;
563      }
564
565    env = getenv("ECORE_IMF_AUTOCAPITAL_ALLOW");
566    if (env)
567      autocap_allow = !!atoi(env);
568
569    return context_scim;
570 }
571
572 /**
573  * isf_imf_context_shutdown
574  *
575  * It will be called when the scim im module is unloaded by ecore. It will do some
576  * cleanup job.
577  */
578 EAPI void
579 isf_imf_context_shutdown(void)
580 {
581    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
582
583    if (_scim_initialized)
584      {
585         _scim_initialized = false;
586         finalize();
587      }
588 }
589
590 EAPI void
591 isf_imf_context_add(Ecore_IMF_Context *ctx)
592 {
593    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
594
595    EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
596
597    if (!context_scim) return;
598
599    context_scim->impl = NULL;
600
601    if (_backend.null())
602      return;
603
604    IMEngineInstancePointer si;
605
606    // Use the default instance if "shared input method" mode is enabled.
607    if (_shared_input_method && !_default_instance.null())
608      {
609         si = _default_instance;
610         SCIM_DEBUG_FRONTEND(2) << "use default instance: " << si->get_id() << " " << si->get_factory_uuid() << "\n";
611      }
612
613    // Not in "shared input method" mode, or no default instance, create an instance.
614    if (si.null())
615      {
616         IMEngineFactoryPointer factory = _backend->get_default_factory(_language, "UTF-8");
617         if (factory.null()) return;
618         si = factory->create_instance("UTF-8", _instance_count++);
619         if (si.null()) return;
620         attach_instance(si);
621         SCIM_DEBUG_FRONTEND(2) << "create new instance: " << si->get_id() << " " << si->get_factory_uuid() << "\n";
622      }
623
624    // If "shared input method" mode is enabled, and there is no default instance,
625    // then store this instance as default one.
626    if (_shared_input_method && _default_instance.null())
627      {
628         SCIM_DEBUG_FRONTEND(2) << "update default instance.\n";
629         _default_instance = si;
630      }
631
632    context_scim->ctx                       = ctx;
633    context_scim->impl                      = new_ic_impl(context_scim);
634    if (context_scim->impl == NULL)
635      {
636         std::cerr << "memory allocation failed in " << __FUNCTION__ << "\n";
637         return;
638      }
639
640    context_scim->impl->si                  = si;
641    context_scim->impl->client_window       = 0;
642    context_scim->impl->client_canvas       = NULL;
643    context_scim->impl->preedit_caret       = 0;
644    context_scim->impl->cursor_x            = 0;
645    context_scim->impl->cursor_y            = 0;
646    context_scim->impl->cursor_pos          = -1;
647    context_scim->impl->is_on               = false;
648    context_scim->impl->shared_si           = _shared_input_method;
649    context_scim->impl->use_preedit         = _on_the_spot;
650    context_scim->impl->preedit_started     = false;
651    context_scim->impl->preedit_updating    = false;
652    context_scim->impl->need_commit_preedit = false;
653
654    if (!_ic_list)
655      context_scim->next = NULL;
656    else
657      context_scim->next = _ic_list;
658    _ic_list = context_scim;
659
660    if (_shared_input_method)
661      context_scim->impl->is_on = _config->read(String(SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), context_scim->impl->is_on);
662
663    _panel_client.prepare(context_scim->id);
664    _panel_client.register_input_context(context_scim->id, si->get_factory_uuid());
665    set_ic_capabilities(context_scim);
666    _panel_client.send();
667
668    SCIM_DEBUG_FRONTEND(2) << "input context created: id = " << context_scim->id << "\n";
669 }
670
671 EAPI void
672 isf_imf_context_del(Ecore_IMF_Context *ctx)
673 {
674    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
675
676    if (!_ic_list) return;
677
678    EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
679
680    if (context_scim)
681      {
682         if (context_scim->id != _ic_list->id)
683           {
684              EcoreIMFContextISF * pre = _ic_list;
685              EcoreIMFContextISF * cur = _ic_list->next;
686              while (cur != NULL)
687                {
688                   if (cur->id == context_scim->id)
689                     {
690                        pre->next = cur->next;
691                        break;
692                     }
693                   pre = cur;
694                   cur = cur->next;
695                }
696           }
697         else
698           _ic_list = _ic_list->next;
699      }
700
701    if (context_scim && context_scim->impl)
702      {
703         _panel_client.prepare(context_scim->id);
704
705         if (context_scim == _focused_ic)
706           context_scim->impl->si->focus_out();
707
708         // Delete the instance.
709         EcoreIMFContextISF *old_focused = _focused_ic;
710         _focused_ic = context_scim;
711         context_scim->impl->si.reset();
712         _focused_ic = old_focused;
713
714         if (context_scim == _focused_ic)
715           {
716              _panel_client.turn_off(context_scim->id);
717              _panel_client.focus_out(context_scim->id);
718           }
719
720         _panel_client.remove_input_context(context_scim->id);
721         _panel_client.send();
722
723         if (context_scim->impl->client_window)
724           isf_imf_context_client_window_set(ctx, NULL);
725
726         if (context_scim->impl)
727           {
728              delete_ic_impl(context_scim->impl);
729              context_scim->impl = 0;
730           }
731      }
732
733    if (context_scim == _focused_ic)
734      _focused_ic = 0;
735
736    if (context_scim)
737      {
738         delete context_scim;
739         context_scim = 0;
740      }
741 }
742
743 /**
744  * isf_imf_context_client_canvas_set
745  * @ctx: a #Ecore_IMF_Context
746  * @canvas: the client canvas
747  *
748  * This function will be called by Ecore IMF.
749  *
750  * Set the client canvas for the Input Method Context; this is the canvas
751  * in which the input appears.
752  *
753  * The canvas type can be determined by using the context canvas type.
754  * Actually only canvas with type "evas" (Evas *) is supported. This canvas
755  * may be used in order to correctly position status windows, and may also
756  * be used for purposes internal to the Input Method Context.
757  */
758 EAPI void
759 isf_imf_context_client_canvas_set(Ecore_IMF_Context *ctx, void *canvas)
760 {
761    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
762
763    EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
764
765    if (context_scim && context_scim->impl && context_scim->impl->client_canvas != (Evas*) canvas)
766      context_scim->impl->client_canvas = (Evas*)canvas;
767 }
768
769 /**
770  * isf_imf_context_client_window_set
771  * @ctx: a #Ecore_IMF_Context
772  * @window: the client window
773  *
774  * This function will be called by Ecore IMF.
775  *
776  * Set the client window for the Input Method Context; this is the Ecore_X_Window
777  * when using X11, Ecore_Win32_Window when using Win32, etc.
778  *
779  * This window is used in order to correctly position status windows,
780  * and may also be used for purposes internal to the Input Method Context.
781  */
782 EAPI void
783 isf_imf_context_client_window_set(Ecore_IMF_Context *ctx, void *window)
784 {
785    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
786
787    EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
788
789    if (context_scim && context_scim->impl && context_scim->impl->client_window != (Ecore_X_Window)((Ecore_Window)window))
790      {
791         context_scim->impl->client_window = (Ecore_X_Window)((Ecore_Window)window);
792
793         if ((context_scim->impl->client_window != 0) &&
794             (context_scim->impl->client_window != _client_window))
795           _client_window = context_scim->impl->client_window;
796      }
797 }
798
799 /**
800  * isf_imf_context_reset
801  * @ctx: a #Ecore_IMF_Context
802  *
803  * This function will be called by Ecore IMF.
804  *
805  * Notify the Input Method Context that a change such as a change in cursor
806  * position has been made. This will typically cause the Input Method Context
807  * to clear the preedit state.
808  */
809 EAPI void
810 isf_imf_context_reset(Ecore_IMF_Context *ctx)
811 {
812    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
813
814    EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
815
816    if (context_scim && context_scim->impl && context_scim == _focused_ic)
817      {
818         WideString wstr = context_scim->impl->preedit_string;
819
820         _panel_client.prepare(context_scim->id);
821         context_scim->impl->si->reset();
822         _panel_client.send();
823
824         if (context_scim->impl->need_commit_preedit)
825           {
826              if (wstr.length())
827                {
828                   ecore_imf_context_commit_event_add(context_scim->ctx, utf8_wcstombs(wstr).c_str());
829                   ecore_imf_context_event_callback_call(context_scim->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(wstr).c_str());
830                }
831              _panel_client.prepare(context_scim->id);
832              _panel_client.send();
833           }
834      }
835 }
836
837 /**
838  * isf_imf_context_focus_in
839  * @ctx: a #Ecore_IMF_Context
840  *
841  * This function will be called by Ecore IMF.
842  *
843  * Notify the Input Method Context that the widget to which its correspond has gained focus.
844  */
845 EAPI void
846 isf_imf_context_focus_in(Ecore_IMF_Context *ctx)
847 {
848    EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
849
850    if (!context_scim)
851      return;
852
853    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__<< "(" << context_scim->id << ")...\n";
854
855    if (_focused_ic)
856      {
857         if (_focused_ic == context_scim)
858           {
859              SCIM_DEBUG_FRONTEND(1) << "It's already focused.\n";
860              return;
861           }
862         SCIM_DEBUG_FRONTEND(1) << "Focus out previous IC first: " << _focused_ic->id << "\n";
863         if (_focused_ic->ctx)
864           isf_imf_context_focus_out(_focused_ic->ctx);
865      }
866
867    bool need_cap   = false;
868    bool need_reset = false;
869    bool need_reg   = false;
870
871    if (context_scim && context_scim->impl)
872      {
873         _focused_ic = context_scim;
874         _panel_client.prepare(context_scim->id);
875
876         // Handle the "Shared Input Method" mode.
877         if (_shared_input_method)
878           {
879              SCIM_DEBUG_FRONTEND(2) << "shared input method.\n";
880              IMEngineFactoryPointer factory = _backend->get_default_factory(_language, "UTF-8");
881              if (!factory.null())
882                {
883                   if (_default_instance.null() || _default_instance->get_factory_uuid() != factory->get_uuid())
884                     {
885                        _default_instance = factory->create_instance("UTF-8", _default_instance.null() ? _instance_count++ : _default_instance->get_id());
886                        attach_instance(_default_instance);
887                        SCIM_DEBUG_FRONTEND(2) << "create new default instance: " << _default_instance->get_id() << " " << _default_instance->get_factory_uuid() << "\n";
888                     }
889
890                   context_scim->impl->shared_si = true;
891                   context_scim->impl->si = _default_instance;
892
893                   context_scim->impl->is_on = _config->read(String(SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), context_scim->impl->is_on);
894                   context_scim->impl->preedit_string.clear();
895                   context_scim->impl->preedit_attrlist.clear();
896                   context_scim->impl->preedit_caret = 0;
897                   context_scim->impl->preedit_started = false;
898                   need_cap = true;
899                   need_reset = true;
900                   need_reg = true;
901                }
902           }
903         else if (context_scim->impl->shared_si)
904           {
905              SCIM_DEBUG_FRONTEND(2) << "exit shared input method.\n";
906              IMEngineFactoryPointer factory = _backend->get_default_factory(_language, "UTF-8");
907              if (!factory.null())
908                {
909                   context_scim->impl->si = factory->create_instance("UTF-8", _instance_count++);
910                   context_scim->impl->preedit_string.clear();
911                   context_scim->impl->preedit_attrlist.clear();
912                   context_scim->impl->preedit_caret = 0;
913                   context_scim->impl->preedit_started = false;
914                   attach_instance(context_scim->impl->si);
915                   need_cap = true;
916                   need_reg = true;
917                   context_scim->impl->shared_si = false;
918                   SCIM_DEBUG_FRONTEND(2) << "create new instance: " << context_scim->impl->si->get_id() << " " << context_scim->impl->si->get_factory_uuid() << "\n";
919                }
920           }
921
922         context_scim->impl->si->set_frontend_data(static_cast <void*>(context_scim));
923
924         if (need_reg) _panel_client.register_input_context(context_scim->id, context_scim->impl->si->get_factory_uuid());
925         if (need_cap) set_ic_capabilities(context_scim);
926         if (need_reset) context_scim->impl->si->reset();
927
928         panel_req_focus_in(context_scim);
929         panel_req_update_spot_location(context_scim);
930         panel_req_update_factory_info(context_scim);
931
932         if (context_scim->impl->is_on)
933           {
934              _panel_client.turn_on(context_scim->id);
935              _panel_client.hide_preedit_string(context_scim->id);
936              _panel_client.hide_aux_string(context_scim->id);
937              _panel_client.hide_lookup_table(context_scim->id);
938              context_scim->impl->si->focus_in();
939           }
940         else
941           {
942              _panel_client.turn_off(context_scim->id);
943           }
944
945         _panel_client.send();
946      }
947
948    if (ecore_imf_context_input_panel_enabled_get(ctx))
949      ecore_imf_context_input_panel_show(ctx);
950 }
951
952 /**
953  * isf_imf_context_focus_out
954  * @ctx: a #Ecore_IMF_Context
955  *
956  * This function will be called by Ecore IMF.
957  *
958  * Notify the Input Method Context that the widget to which its correspond has lost focus.
959  */
960 EAPI void
961 isf_imf_context_focus_out(Ecore_IMF_Context *ctx)
962 {
963    EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
964
965    if (!context_scim) return;
966
967    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "(" << context_scim->id << ")...\n";
968
969    if (context_scim && context_scim->impl && context_scim == _focused_ic)
970      {
971         WideString wstr = context_scim->impl->preedit_string;
972
973         if (context_scim->impl->need_commit_preedit)
974           {
975              if (wstr.length())
976                {
977                   ecore_imf_context_commit_event_add(context_scim->ctx, utf8_wcstombs(wstr).c_str());
978                   ecore_imf_context_event_callback_call(context_scim->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(wstr).c_str());
979                }
980              _panel_client.prepare(context_scim->id);
981              _panel_client.send();
982           }
983
984         _panel_client.prepare(context_scim->id);
985         context_scim->impl->si->focus_out();
986         context_scim->impl->si->reset();
987         _panel_client.turn_off(context_scim->id);
988         _panel_client.focus_out(context_scim->id);
989         _panel_client.send();
990         _focused_ic = 0;
991      }
992
993    if (ecore_imf_context_input_panel_enabled_get(ctx))
994      ecore_imf_context_input_panel_hide(ctx);
995 }
996
997 /**
998  * isf_imf_context_cursor_location_set
999  * @ctx: a #Ecore_IMF_Context
1000  * @x: x position of New cursor.
1001  * @y: y position of New cursor.
1002  * @w: the width of New cursor.
1003  * @h: the height of New cursor.
1004  *
1005  * This function will be called by Ecore IMF.
1006  *
1007  * Notify the Input Method Context that a change in the cursor location has been made.
1008  */
1009 EAPI void
1010 isf_imf_context_cursor_location_set(Ecore_IMF_Context *ctx, int cx, int cy, int cw, int ch)
1011 {
1012    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1013
1014    EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
1015    Ecore_Evas *ee;
1016    int canvas_x, canvas_y;
1017    int new_cursor_x, new_cursor_y;
1018
1019    if (cw == 0 && ch == 0)
1020      return;
1021
1022    if (context_scim && context_scim->impl && context_scim == _focused_ic)
1023      {
1024         if (context_scim->impl->client_canvas)
1025           {
1026              ee = ecore_evas_ecore_evas_get(context_scim->impl->client_canvas);
1027              if (!ee) return;
1028
1029              ecore_evas_geometry_get(ee, &canvas_x, &canvas_y, NULL, NULL);
1030           }
1031         else
1032           {
1033              if (context_scim->impl->client_window)
1034                window_to_screen_geometry_get(context_scim->impl->client_window, &canvas_x, &canvas_y);
1035              else
1036                return;
1037           }
1038
1039         new_cursor_x = canvas_x + cx;
1040         new_cursor_y = canvas_y + cy + ch;
1041
1042         // Don't update spot location while updating preedit string.
1043         if (context_scim->impl->preedit_updating && (context_scim->impl->cursor_y == new_cursor_y))
1044           return;
1045
1046         if (context_scim->impl->cursor_x != new_cursor_x || context_scim->impl->cursor_y != new_cursor_y)
1047           {
1048              context_scim->impl->cursor_x     = new_cursor_x;
1049              context_scim->impl->cursor_y     = new_cursor_y;
1050              _panel_client.prepare(context_scim->id);
1051              panel_req_update_spot_location(context_scim);
1052              _panel_client.send();
1053              SCIM_DEBUG_FRONTEND(2) << "new cursor location = " << context_scim->impl->cursor_x << "," << context_scim->impl->cursor_y << "\n";
1054           }
1055      }
1056 }
1057
1058 /**
1059  * isf_imf_context_use_preedit_set
1060  * @ctx: a #Ecore_IMF_Context
1061  * @use_preedit: Whether the IM context should use the preedit string.
1062  *
1063  * This function will be called by Ecore IMF.
1064  *
1065  * Set whether the IM context should use the preedit string to display feedback.
1066  * If is 0 (default is 1), then the IM context may use some other method to
1067  * display feedback, such as displaying it in a child of the root window.
1068  */
1069 EAPI void
1070 isf_imf_context_use_preedit_set(Ecore_IMF_Context* ctx, Eina_Bool use_preedit)
1071 {
1072    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " = " << (use_preedit ? "true" : "false") << "...\n";
1073
1074    EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
1075
1076    if (!_on_the_spot) return;
1077
1078    if (context_scim && context_scim->impl)
1079      {
1080         bool old = context_scim->impl->use_preedit;
1081         context_scim->impl->use_preedit = use_preedit;
1082         if (context_scim == _focused_ic)
1083           {
1084              _panel_client.prepare(context_scim->id);
1085
1086              if (old != use_preedit)
1087                set_ic_capabilities(context_scim);
1088
1089              if (context_scim->impl->preedit_string.length())
1090                slot_show_preedit_string(context_scim->impl->si);
1091
1092              _panel_client.send();
1093           }
1094      }
1095 }
1096
1097 EAPI void
1098 isf_imf_context_preedit_string_with_attributes_get(Ecore_IMF_Context *ctx, char** str, Eina_List **attrs, int *cursor_pos)
1099 {
1100    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1101
1102    EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
1103
1104    if (context_scim && context_scim->impl && context_scim->impl->is_on)
1105      {
1106         String mbs = utf8_wcstombs(context_scim->impl->preedit_string);
1107
1108         if (str)
1109           {
1110              if (mbs.length())
1111                *str = strdup(mbs.c_str());
1112              else
1113                *str = strdup("");
1114           }
1115
1116         if (cursor_pos)
1117           {
1118              *cursor_pos = context_scim->impl->preedit_caret;
1119           }
1120
1121         if (attrs)
1122           {
1123              if (mbs.length())
1124                {
1125                   int start_index, end_index;
1126                   int wlen = context_scim->impl->preedit_string.length();
1127
1128                   Ecore_IMF_Preedit_Attr *attr = NULL;
1129                   AttributeList::const_iterator i;
1130                   bool *attrs_flag = new bool [mbs.length()];
1131                   memset(attrs_flag, 0, mbs.length() *sizeof(bool));
1132
1133                   for (i = context_scim->impl->preedit_attrlist.begin();
1134                        i != context_scim->impl->preedit_attrlist.end(); ++i)
1135                     {
1136                        start_index = i->get_start();
1137                        end_index = i->get_end();
1138
1139                        if (end_index <= wlen && start_index < end_index && i->get_type() != SCIM_ATTR_DECORATE_NONE)
1140                          {
1141                             start_index = utf8_offset_to_index(mbs.c_str(), i->get_start());
1142                             end_index = utf8_offset_to_index(mbs.c_str(), i->get_end());
1143
1144                             if (i->get_type() == SCIM_ATTR_DECORATE)
1145                               {
1146                                  attr = (Ecore_IMF_Preedit_Attr *)calloc(1, sizeof(Ecore_IMF_Preedit_Attr));
1147                                  if (attr == NULL)
1148                                    continue;
1149                                  attr->start_index = start_index;
1150                                  attr->end_index = end_index;
1151
1152                                  if (i->get_value() == SCIM_ATTR_DECORATE_UNDERLINE)
1153                                    {
1154                                       attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB1;
1155                                       *attrs = eina_list_append(*attrs, (void *)attr);
1156                                    }
1157                                  else if (i->get_value() == SCIM_ATTR_DECORATE_REVERSE)
1158                                    {
1159                                       attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB2;
1160                                       *attrs = eina_list_append(*attrs, (void *)attr);
1161                                    }
1162                                  else if (i->get_value() == SCIM_ATTR_DECORATE_HIGHLIGHT)
1163                                    {
1164                                       attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB3;
1165                                       *attrs = eina_list_append(*attrs, (void *)attr);
1166                                    }
1167                                  else
1168                                    {
1169                                       free(attr);
1170                                    }
1171
1172                                  switch(i->get_value())
1173                                    {
1174                                     case SCIM_ATTR_DECORATE_UNDERLINE:
1175                                     case SCIM_ATTR_DECORATE_REVERSE:
1176                                     case SCIM_ATTR_DECORATE_HIGHLIGHT:
1177                                        // Record which character has attribute.
1178                                        for (int pos = start_index; pos < end_index; ++pos)
1179                                          attrs_flag [pos] = 1;
1180                                        break;
1181                                     default:
1182                                        break;
1183                                    }
1184                             }
1185                             else if (i->get_type() == SCIM_ATTR_FOREGROUND)
1186                               {
1187                                  SCIM_DEBUG_FRONTEND(4) << "SCIM_ATTR_FOREGROUND\n";
1188                               }
1189                             else if (i->get_type() == SCIM_ATTR_BACKGROUND)
1190                               {
1191                                  SCIM_DEBUG_FRONTEND(4) << "SCIM_ATTR_BACKGROUND\n";
1192                               }
1193                          }
1194                     }
1195
1196                   // Add underline for all characters which don't have attribute.
1197                   for (unsigned int pos = 0; pos < mbs.length(); ++pos)
1198                     {
1199                        if (!attrs_flag [pos])
1200                          {
1201                             int begin_pos = pos;
1202
1203                             while (pos < mbs.length() && !attrs_flag[pos])
1204                               ++pos;
1205
1206                             // use REVERSE style as default
1207                             attr = (Ecore_IMF_Preedit_Attr *)calloc(1, sizeof(Ecore_IMF_Preedit_Attr));
1208                             if (attr == NULL)
1209                               continue;
1210                             attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB2;
1211                             attr->start_index = begin_pos;
1212                             attr->end_index = pos;
1213                             *attrs = eina_list_append(*attrs, (void *)attr);
1214                          }
1215                     }
1216
1217                   delete [] attrs_flag;
1218                }
1219           }
1220      }
1221    else
1222      {
1223         if (str)
1224           *str = strdup("");
1225
1226         if (cursor_pos)
1227           *cursor_pos = 0;
1228
1229         if (attrs)
1230           *attrs = NULL;
1231      }
1232 }
1233
1234 /**
1235  * isf_imf_context_preedit_string_get
1236  * @ctx: a #Ecore_IMF_Context
1237  * @str: the preedit string
1238  * @cursor_pos: the cursor position
1239  *
1240  * This function will be called by Ecore IMF.
1241  *
1242  * To get the preedit string of the input method.
1243  */
1244 EAPI void
1245 isf_imf_context_preedit_string_get(Ecore_IMF_Context *ctx, char** str, int *cursor_pos)
1246 {
1247    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1248
1249    EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
1250
1251    if (context_scim && context_scim->impl && context_scim->impl->is_on)
1252      {
1253         String mbs = utf8_wcstombs(context_scim->impl->preedit_string);
1254
1255         if (str)
1256           {
1257              if (mbs.length())
1258                *str = strdup(mbs.c_str());
1259              else
1260                *str = strdup("");
1261           }
1262
1263         if (cursor_pos)
1264           *cursor_pos = context_scim->impl->preedit_caret;
1265      }
1266    else
1267      {
1268         if (str)
1269           *str = strdup("");
1270
1271         if (cursor_pos)
1272           *cursor_pos = 0;
1273      }
1274 }
1275
1276 /**
1277  * isf_imf_context_cursor_position_set
1278  * @ctx: a #Ecore_IMF_Context
1279  * @cursor_pos: New cursor position in characters.
1280  *
1281  * This function will be called by Ecore IMF.
1282  *
1283  * Notify the Input Method Context that a change in the cursor position has been made.
1284  */
1285 EAPI void
1286 isf_imf_context_cursor_position_set(Ecore_IMF_Context *ctx, int cursor_pos)
1287 {
1288    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1289
1290    EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
1291
1292    if (context_scim && context_scim->impl && context_scim == _focused_ic)
1293      {
1294         // Don't update spot location while updating preedit string.
1295         if (context_scim->impl->preedit_updating)
1296           return;
1297
1298         if (context_scim->impl->cursor_pos != cursor_pos)
1299           {
1300              context_scim->impl->cursor_pos = cursor_pos;
1301              caps_mode_check(ctx, EINA_FALSE);
1302           }
1303      }
1304 }
1305
1306 /**
1307  * isf_imf_context_input_mode_set
1308  * @ctx: a #Ecore_IMF_Context
1309  * @input_mode: the input mode
1310  *
1311  * This function will be called by Ecore IMF.
1312  *
1313  * To set the input mode of input method. The definition of Ecore_IMF_Input_Mode
1314  * is in Ecore_IMF.h.
1315  */
1316 EAPI void
1317 isf_imf_context_input_mode_set(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Mode input_mode)
1318 {
1319    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1320
1321    EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
1322    if (context_scim && context_scim->impl)
1323      context_scim->impl->input_mode = input_mode;
1324 }
1325
1326 /**
1327  * isf_imf_context_prediction_allow_set
1328  * @ctx: a #Ecore_IMF_Context
1329  * @use_prediction: Whether the IM context should use the prediction.
1330  *
1331  * This function will be called by Ecore IMF.
1332  *
1333  * Set whether the IM context should use the prediction.
1334  */
1335 EAPI void
1336 isf_imf_context_prediction_allow_set(Ecore_IMF_Context* ctx, Eina_Bool prediction)
1337 {
1338    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " = " << (prediction ? "true" : "false") << "...\n";
1339
1340    EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
1341
1342    if (context_scim && context_scim->impl && context_scim->impl->prediction_allow != prediction)
1343      context_scim->impl->prediction_allow = prediction;
1344 }
1345
1346 EAPI void
1347 isf_imf_context_autocapital_type_set(Ecore_IMF_Context* ctx, Ecore_IMF_Autocapital_Type autocapital_type)
1348 {
1349    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " = " << autocapital_type << "...\n";
1350
1351    EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
1352
1353    if (context_scim && context_scim->impl && context_scim->impl->autocapital_type != autocapital_type)
1354      context_scim->impl->autocapital_type = autocapital_type;
1355 }
1356
1357 /**
1358  * isf_imf_context_filter_event
1359  * @ctx: a #Ecore_IMF_Context
1360  * @type: The type of event defined by Ecore_IMF_Event_Type.
1361  * @event: The event itself.
1362  * Return value: %TRUE if the input method handled the key event.
1363  *
1364  * This function will be called by Ecore IMF.
1365  *
1366  * Allow an Ecore Input Context to internally handle an event. If this function
1367  * returns 1, then no further processing should be done for this event. Input
1368  * methods must be able to accept all types of events (simply returning 0 if
1369  * the event was not handled), but there is no obligation of any events to be
1370  * submitted to this function.
1371  */
1372 EAPI Eina_Bool
1373 isf_imf_context_filter_event(Ecore_IMF_Context *ctx, Ecore_IMF_Event_Type type, Ecore_IMF_Event *event)
1374 {
1375    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1376
1377    EcoreIMFContextISF *ic = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
1378    Eina_Bool ret = EINA_FALSE;
1379
1380    if (ic == NULL || ic->impl == NULL)
1381      return ret;
1382
1383    KeyEvent key;
1384
1385    if (type == ECORE_IMF_EVENT_KEY_DOWN)
1386      {
1387         Ecore_IMF_Event_Key_Down *ev = (Ecore_IMF_Event_Key_Down *)event;
1388         scim_string_to_key(key, ev->key);
1389         if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_SHIFT) key.mask |=SCIM_KEY_ShiftMask;
1390         if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_CTRL) key.mask |=SCIM_KEY_ControlMask;
1391         if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_ALT) key.mask |=SCIM_KEY_AltMask;
1392         if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_ALTGR) key.mask |=SCIM_KEY_Mod5Mask;
1393         if (ev->locks & ECORE_IMF_KEYBOARD_LOCK_CAPS) key.mask |=SCIM_KEY_CapsLockMask;
1394         if (ev->locks & ECORE_IMF_KEYBOARD_LOCK_NUM) key.mask |=SCIM_KEY_NumLockMask;
1395      }
1396    else if (type == ECORE_IMF_EVENT_KEY_UP)
1397      {
1398         Ecore_IMF_Event_Key_Up *ev = (Ecore_IMF_Event_Key_Up *)event;
1399         scim_string_to_key(key, ev->key);
1400         key.mask = SCIM_KEY_ReleaseMask;
1401         if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_SHIFT) key.mask |=SCIM_KEY_ShiftMask;
1402         if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_CTRL) key.mask |=SCIM_KEY_ControlMask;
1403         if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_ALT) key.mask |=SCIM_KEY_AltMask;
1404         if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_ALTGR) key.mask |=SCIM_KEY_Mod5Mask;
1405         if (ev->locks & ECORE_IMF_KEYBOARD_LOCK_CAPS) key.mask |=SCIM_KEY_CapsLockMask;
1406         if (ev->locks & ECORE_IMF_KEYBOARD_LOCK_NUM) key.mask |=SCIM_KEY_NumLockMask;
1407      }
1408    else
1409      {
1410         return ret;
1411      }
1412
1413    key.mask &= _valid_key_mask;
1414
1415    _panel_client.prepare(ic->id);
1416
1417    ret = EINA_TRUE;
1418    if (!filter_hotkeys(ic, key))
1419      {
1420         if (!_focused_ic || !_focused_ic->impl->is_on ||
1421             !_focused_ic->impl->si->process_key_event(key))
1422           ret = EINA_FALSE;
1423      }
1424
1425    _panel_client.send();
1426
1427    return ret;
1428 }
1429
1430 EAPI void
1431 isf_imf_context_input_panel_show(Ecore_IMF_Context *ctx)
1432 {
1433    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1434
1435    EcoreIMFContextISF *ic = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
1436    if (ic == NULL || ic->impl == NULL)
1437      return;
1438
1439    ecore_x_e_virtual_keyboard_state_set
1440         (ic->impl->client_window, ECORE_X_VIRTUAL_KEYBOARD_STATE_ON);
1441 }
1442
1443 EAPI void
1444 isf_imf_context_input_panel_hide(Ecore_IMF_Context *ctx)
1445 {
1446    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1447
1448    EcoreIMFContextISF *ic = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
1449    if (ic == NULL || ic->impl == NULL)
1450      return;
1451
1452    ecore_x_e_virtual_keyboard_state_set
1453         (ic->impl->client_window, ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF);
1454 }
1455
1456 /* Panel Slot functions */
1457 static void
1458 panel_slot_reload_config(int context __UNUSED__)
1459 {
1460    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1461    _config->reload();
1462 }
1463
1464 static void
1465 panel_slot_exit(int /* context */)
1466 {
1467    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1468
1469    finalize();
1470 }
1471
1472 static void
1473 panel_slot_update_lookup_table_page_size(int context, int page_size)
1474 {
1475    EcoreIMFContextISF *ic = find_ic(context);
1476    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " page_size=" << page_size << " ic=" << ic << "\n";
1477    if (ic && ic->impl)
1478      {
1479         _panel_client.prepare(ic->id);
1480         ic->impl->si->update_lookup_table_page_size(page_size);
1481         _panel_client.send();
1482      }
1483 }
1484
1485 static void
1486 panel_slot_lookup_table_page_up(int context)
1487 {
1488    EcoreIMFContextISF *ic = find_ic(context);
1489    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n";
1490    if (ic && ic->impl)
1491      {
1492         _panel_client.prepare(ic->id);
1493         ic->impl->si->lookup_table_page_up();
1494         _panel_client.send();
1495      }
1496 }
1497
1498 static void
1499 panel_slot_lookup_table_page_down(int context)
1500 {
1501    EcoreIMFContextISF *ic = find_ic(context);
1502    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n";
1503    if (ic && ic->impl)
1504      {
1505         _panel_client.prepare(ic->id);
1506         ic->impl->si->lookup_table_page_down();
1507         _panel_client.send();
1508      }
1509 }
1510
1511 static void
1512 panel_slot_trigger_property(int context, const String &property)
1513 {
1514    EcoreIMFContextISF *ic = find_ic(context);
1515    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " property=" << property << " ic=" << ic << "\n";
1516    if (ic && ic->impl)
1517      {
1518         _panel_client.prepare(ic->id);
1519         ic->impl->si->trigger_property(property);
1520         _panel_client.send();
1521      }
1522 }
1523
1524 static void
1525 panel_slot_process_helper_event(int context, const String &target_uuid, const String &helper_uuid, const Transaction &trans)
1526 {
1527    EcoreIMFContextISF *ic = find_ic(context);
1528    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " target=" << target_uuid
1529       << " helper=" << helper_uuid << " ic=" << ic << " ic->impl=" << (ic ? ic->impl : 0) << " ic-uuid="
1530       << ((ic && ic->impl) ? ic->impl->si->get_factory_uuid() : "" ) << "\n";
1531    if (ic && ic->impl && ic->impl->si->get_factory_uuid() == target_uuid)
1532      {
1533         _panel_client.prepare(ic->id);
1534         SCIM_DEBUG_FRONTEND(2) << "call process_helper_event\n";
1535         ic->impl->si->process_helper_event(helper_uuid, trans);
1536         _panel_client.send();
1537      }
1538 }
1539
1540 static void
1541 panel_slot_move_preedit_caret(int context, int caret_pos)
1542 {
1543    EcoreIMFContextISF *ic = find_ic(context);
1544    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " caret=" << caret_pos << " ic=" << ic << "\n";
1545    if (ic && ic->impl)
1546      {
1547         _panel_client.prepare(ic->id);
1548         ic->impl->si->move_preedit_caret(caret_pos);
1549         _panel_client.send();
1550      }
1551 }
1552
1553 static void
1554 panel_slot_select_candidate(int context, int cand_index)
1555 {
1556    EcoreIMFContextISF *ic = find_ic(context);
1557    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " candidate=" << cand_index << " ic=" << ic << "\n";
1558    if (ic && ic->impl)
1559      {
1560         _panel_client.prepare(ic->id);
1561         ic->impl->si->select_candidate(cand_index);
1562         _panel_client.send();
1563      }
1564 }
1565
1566 static void
1567 panel_slot_process_key_event(int context, const KeyEvent &key)
1568 {
1569    EcoreIMFContextISF *ic = find_ic(context);
1570    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " key=" << key.get_key_string() << " ic=" << ic << "\n";
1571
1572    if (key.is_key_press())
1573      ecore_x_test_fake_key_press(key.get_key_string().c_str());
1574 }
1575
1576 static void
1577 panel_slot_commit_string(int context, const WideString &wstr)
1578 {
1579    EcoreIMFContextISF *ic = find_ic(context);
1580    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " str=" << utf8_wcstombs(wstr) << " ic=" << ic << "\n";
1581
1582    if (ic && ic->impl)
1583      {
1584         if (_focused_ic != ic)
1585           return;
1586
1587         ecore_imf_context_commit_event_add(ic->ctx, utf8_wcstombs(wstr).c_str());
1588         ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(wstr).c_str());
1589      }
1590 }
1591
1592 static void
1593 panel_slot_forward_key_event(int context, const KeyEvent &key)
1594 {
1595    EcoreIMFContextISF *ic = find_ic(context);
1596    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " key=" << key.get_key_string() << " ic=" << ic << "\n";
1597
1598    if (ic && ic->impl && ic->impl->client_canvas)
1599      feed_key_event(ic->impl->client_canvas, key.get_key_string().c_str(), EINA_TRUE);
1600 }
1601
1602 static void
1603 panel_slot_request_help(int context)
1604 {
1605    EcoreIMFContextISF *ic = find_ic(context);
1606    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n";
1607
1608    if (ic && ic->impl)
1609      {
1610         _panel_client.prepare(ic->id);
1611         panel_req_show_help(ic);
1612         _panel_client.send();
1613      }
1614 }
1615
1616 static void
1617 panel_slot_request_factory_menu(int context)
1618 {
1619    EcoreIMFContextISF *ic = find_ic(context);
1620    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n";
1621
1622    if (ic && ic->impl)
1623      {
1624         _panel_client.prepare(ic->id);
1625         panel_req_show_factory_menu(ic);
1626         _panel_client.send();
1627      }
1628 }
1629
1630 static void
1631 panel_slot_change_factory(int context, const String &uuid)
1632 {
1633    EcoreIMFContextISF *ic = find_ic(context);
1634    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " factory=" << uuid << " ic=" << ic << "\n";
1635
1636    if (ic && ic->impl)
1637      {
1638         ic->impl->si->reset();
1639         _panel_client.prepare(ic->id);
1640         open_specific_factory(ic, uuid);
1641         _panel_client.send();
1642      }
1643 }
1644
1645 /* Panel Requestion functions. */
1646 static void
1647 panel_req_show_help(EcoreIMFContextISF *ic)
1648 {
1649    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1650
1651    String help;
1652
1653    help =  String("Smart Common Input Method platform ") +
1654       //String(SCIM_VERSION) +
1655       String("\n(C) 2002-2005 James Su <suzhe@tsinghua.org.cn>\n\n");
1656
1657    if (ic && ic->impl)
1658      {
1659         IMEngineFactoryPointer sf = _backend->get_factory(ic->impl->si->get_factory_uuid());
1660         if (sf)
1661           {
1662              help += utf8_wcstombs(sf->get_name());
1663              help += String(":\n\n");
1664
1665              help += utf8_wcstombs(sf->get_help());
1666              help += String("\n\n");
1667
1668              help += utf8_wcstombs(sf->get_credits());
1669           }
1670         _panel_client.show_help(ic->id, help);
1671      }
1672 }
1673
1674 static void
1675 panel_req_show_factory_menu(EcoreIMFContextISF *ic)
1676 {
1677    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1678
1679    std::vector<IMEngineFactoryPointer> factories;
1680    std::vector <PanelFactoryInfo> menu;
1681
1682    _backend->get_factories_for_encoding(factories, "UTF-8");
1683
1684    for (size_t i = 0; i < factories.size(); ++ i)
1685      {
1686         menu.push_back(PanelFactoryInfo(
1687               factories [i]->get_uuid(),
1688               utf8_wcstombs(factories [i]->get_name()),
1689               factories [i]->get_language(),
1690               factories [i]->get_icon_file()));
1691      }
1692
1693    if (menu.size())
1694      _panel_client.show_factory_menu(ic->id, menu);
1695 }
1696
1697 static void
1698 panel_req_update_factory_info(EcoreIMFContextISF *ic)
1699 {
1700    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1701
1702    if (ic && ic->impl && ic == _focused_ic)
1703      {
1704         PanelFactoryInfo info;
1705         if (ic->impl->is_on)
1706           {
1707              IMEngineFactoryPointer sf = _backend->get_factory(ic->impl->si->get_factory_uuid());
1708              if (sf)
1709                info = PanelFactoryInfo(sf->get_uuid(), utf8_wcstombs(sf->get_name()), sf->get_language(), sf->get_icon_file());
1710           }
1711         else
1712           {
1713              info = PanelFactoryInfo(String(""), String("English/Keyboard"), String("C"), "");
1714           }
1715         _panel_client.update_factory_info(ic->id, info);
1716      }
1717 }
1718
1719 static void
1720 panel_req_focus_in(EcoreIMFContextISF *ic)
1721 {
1722    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1723
1724    _panel_client.focus_in(ic->id, ic->impl->si->get_factory_uuid());
1725 }
1726
1727 static void
1728 panel_req_update_spot_location(EcoreIMFContextISF *ic)
1729 {
1730    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1731
1732    _panel_client.update_spot_location(ic->id, ic->impl->cursor_x, ic->impl->cursor_y);
1733 }
1734
1735 static bool
1736 filter_hotkeys(EcoreIMFContextISF *ic, const KeyEvent &key)
1737 {
1738    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1739
1740    bool ret = false;
1741
1742    _frontend_hotkey_matcher.push_key_event(key);
1743    _imengine_hotkey_matcher.push_key_event(key);
1744
1745    FrontEndHotkeyAction hotkey_action = _frontend_hotkey_matcher.get_match_result();
1746
1747    if (hotkey_action == SCIM_FRONTEND_HOTKEY_TRIGGER)
1748      {
1749         if (!ic->impl->is_on)
1750           turn_on_ic(ic);
1751         else
1752           turn_off_ic(ic);
1753         ret = true;
1754      }
1755    else if (hotkey_action == SCIM_FRONTEND_HOTKEY_ON)
1756      {
1757         if (!ic->impl->is_on)
1758           turn_on_ic(ic);
1759         ret = true;
1760      }
1761    else if (hotkey_action == SCIM_FRONTEND_HOTKEY_OFF)
1762      {
1763         if (ic->impl->is_on)
1764           turn_off_ic(ic);
1765         ret = true;
1766      }
1767    else if (hotkey_action == SCIM_FRONTEND_HOTKEY_NEXT_FACTORY)
1768      {
1769         open_next_factory(ic);
1770         ret = true;
1771      }
1772    else if (hotkey_action == SCIM_FRONTEND_HOTKEY_PREVIOUS_FACTORY)
1773      {
1774         open_previous_factory(ic);
1775         ret = true;
1776      }
1777    else if (hotkey_action == SCIM_FRONTEND_HOTKEY_SHOW_FACTORY_MENU)
1778      {
1779         panel_req_show_factory_menu(ic);
1780         ret = true;
1781      }
1782    else if (_imengine_hotkey_matcher.is_matched())
1783      {
1784         String sfid = _imengine_hotkey_matcher.get_match_result();
1785         open_specific_factory(ic, sfid);
1786         ret = true;
1787      }
1788    return ret;
1789 }
1790
1791 static bool
1792 panel_initialize(void)
1793 {
1794    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1795
1796    String display_name;
1797      {
1798         const char *p = getenv("DISPLAY");
1799         if (p) display_name = String(p);
1800      }
1801
1802    if (_panel_client.open_connection(_config->get_name(), display_name) >= 0)
1803      {
1804         int fd = _panel_client.get_connection_number();
1805
1806         _panel_iochannel_read_handler = ecore_main_fd_handler_add(fd, ECORE_FD_READ, panel_iochannel_handler, NULL, NULL, NULL);
1807
1808         SCIM_DEBUG_FRONTEND(2) << " Panel FD= " << fd << "\n";
1809
1810         return true;
1811    }
1812    std::cerr << "panel_initialize() failed!!!\n";
1813    return false;
1814 }
1815
1816 static void
1817 panel_finalize(void)
1818 {
1819    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1820
1821    _panel_client.close_connection();
1822
1823    if (_panel_iochannel_read_handler)
1824      {
1825         ecore_main_fd_handler_del(_panel_iochannel_read_handler);
1826         _panel_iochannel_read_handler = 0;
1827      }
1828
1829    if (_panel_iochannel_err_handler)
1830      {
1831         ecore_main_fd_handler_del(_panel_iochannel_err_handler);
1832         _panel_iochannel_err_handler = 0;
1833      }
1834 }
1835
1836 static Eina_Bool
1837 panel_iochannel_handler(void *data __UNUSED__, Ecore_Fd_Handler *fd_handler)
1838 {
1839    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1840
1841    if (fd_handler == _panel_iochannel_read_handler)
1842      {
1843         if (!_panel_client.filter_event())
1844           {
1845              panel_finalize();
1846              panel_initialize();
1847              return ECORE_CALLBACK_CANCEL;
1848           }
1849      }
1850    else if (fd_handler == _panel_iochannel_err_handler)
1851      {
1852         panel_finalize();
1853         panel_initialize();
1854         return ECORE_CALLBACK_CANCEL;
1855      }
1856    return ECORE_CALLBACK_RENEW;
1857 }
1858
1859 static void
1860 turn_on_ic(EcoreIMFContextISF *ic)
1861 {
1862    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1863
1864    if (ic && ic->impl && !ic->impl->is_on)
1865      {
1866         ic->impl->is_on = true;
1867
1868         if (ic == _focused_ic)
1869           {
1870              panel_req_focus_in(ic);
1871              panel_req_update_spot_location(ic);
1872              panel_req_update_factory_info(ic);
1873              _panel_client.turn_on(ic->id);
1874              _panel_client.hide_preedit_string(ic->id);
1875              _panel_client.hide_aux_string(ic->id);
1876              _panel_client.hide_lookup_table(ic->id);
1877              ic->impl->si->focus_in();
1878           }
1879
1880         //Record the IC on/off status
1881         if (_shared_input_method)
1882           _config->write(String(SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), true);
1883
1884         if (ic->impl->use_preedit && ic->impl->preedit_string.length())
1885           {
1886              ecore_imf_context_preedit_start_event_add(ic->ctx);
1887              ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
1888              ecore_imf_context_preedit_changed_event_add(ic->ctx);
1889              ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
1890              ic->impl->preedit_started = true;
1891           }
1892      }
1893 }
1894
1895 static void
1896 turn_off_ic(EcoreIMFContextISF *ic)
1897 {
1898    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1899
1900    if (ic && ic->impl && ic->impl->is_on)
1901      {
1902         ic->impl->is_on = false;
1903
1904         if (ic == _focused_ic)
1905           {
1906              ic->impl->si->focus_out();
1907
1908              panel_req_update_factory_info(ic);
1909              _panel_client.turn_off(ic->id);
1910           }
1911
1912         //Record the IC on/off status
1913         if (_shared_input_method)
1914           _config->write(String(SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), false);
1915
1916         if (ic->impl->use_preedit && ic->impl->preedit_string.length())
1917           {
1918              ecore_imf_context_preedit_changed_event_add(ic->ctx);
1919              ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
1920              ecore_imf_context_preedit_end_event_add(ic->ctx);
1921              ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
1922              ic->impl->preedit_started = false;
1923           }
1924      }
1925 }
1926
1927 static void
1928 set_ic_capabilities(EcoreIMFContextISF *ic)
1929 {
1930    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1931
1932    if (ic && ic->impl)
1933      {
1934         unsigned int cap = SCIM_CLIENT_CAP_ALL_CAPABILITIES;
1935
1936         if (!_on_the_spot || !ic->impl->use_preedit)
1937           cap -= SCIM_CLIENT_CAP_ONTHESPOT_PREEDIT;
1938
1939         ic->impl->si->update_client_capabilities(cap);
1940      }
1941 }
1942
1943 static bool
1944 check_socket_frontend(void)
1945 {
1946    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1947
1948    SocketAddress address;
1949    SocketClient client;
1950
1951    uint32 magic;
1952
1953    address.set_address(scim_get_default_socket_frontend_address());
1954
1955    if (!client.connect(address))
1956      return false;
1957
1958    if (!scim_socket_open_connection(magic,
1959                                     String("ConnectionTester"),
1960                                     String("SocketFrontEnd"),
1961                                     client,
1962                                     1000))
1963         return false;
1964
1965    return true;
1966 }
1967
1968 void
1969 initialize(void)
1970 {
1971    std::vector<String>     config_list;
1972    std::vector<String>     engine_list;
1973    std::vector<String>     load_engine_list;
1974
1975    std::vector<String>::iterator it;
1976
1977    bool                    manual = false;
1978
1979    bool                    socket = true;
1980
1981    String                  config_module_name = "simple";
1982
1983    printf("Initializing Ecore SCIM IMModule...\n");
1984
1985    SCIM_DEBUG_FRONTEND(1) << "Initializing Ecore SCIM IMModule...\n";
1986
1987    // Get system language.
1988    _language = scim_get_locale_language(scim_get_current_locale());
1989
1990    if (socket)
1991      {
1992         // If no Socket FrontEnd is running, then launch one.
1993         // And set manual to false.
1994         bool check_result = check_socket_frontend();
1995         if (!check_result)
1996           {
1997              std::cerr << "Launching a SCIM daemon with Socket FrontEnd...\n";
1998              //get modules list
1999              scim_get_imengine_module_list(engine_list);
2000
2001              for (it = engine_list.begin(); it != engine_list.end(); it++)
2002                {
2003                   if (*it != "socket")
2004                     load_engine_list.push_back(*it);
2005                }
2006
2007              const char *new_argv [] = { "--no-stay", 0 };
2008              scim_launch(true,
2009                          config_module_name,
2010                          (load_engine_list.size() ? scim_combine_string_list(load_engine_list, ',') : "none"),
2011                          "socket",
2012                          (char **)new_argv);
2013              manual = false;
2014           }
2015
2016         // If there is one Socket FrontEnd running and it's not manual mode,
2017         // then just use this Socket Frontend.
2018         if (!manual)
2019           {
2020              for (int i = 0; i < 200; ++i)
2021                {
2022                   if (check_result)
2023                     {
2024                        config_module_name = "socket";
2025                        load_engine_list.clear();
2026                        load_engine_list.push_back("socket");
2027                        break;
2028                     }
2029                   scim_usleep(50000);
2030                   check_result = check_socket_frontend();
2031                }
2032           }
2033      }
2034
2035    if (config_module_name != "dummy")
2036      {
2037         //load config module
2038         SCIM_DEBUG_FRONTEND(1) << "Loading Config module: " << config_module_name << "...\n";
2039         _config_module = new ConfigModule(config_module_name);
2040
2041         //create config instance
2042         if (_config_module != NULL && _config_module->valid())
2043           _config = _config_module->create_config();
2044      }
2045
2046    if (_config.null())
2047      {
2048         SCIM_DEBUG_FRONTEND(1) << "Config module cannot be loaded, using dummy Config.\n";
2049
2050         if (_config_module) delete _config_module;
2051         _config_module = NULL;
2052
2053         _config = new DummyConfig();
2054         config_module_name = "dummy";
2055      }
2056
2057    reload_config_callback(_config);
2058    _config->signal_connect_reload(slot(reload_config_callback));
2059
2060    // create backend
2061    _backend = new CommonBackEnd(_config, load_engine_list.size() ? load_engine_list : engine_list);
2062
2063    if (_backend.null())
2064      std::cerr << "Cannot create BackEnd Object!\n";
2065    else
2066      _fallback_factory = _backend->get_factory(SCIM_COMPOSE_KEY_FACTORY_UUID);
2067
2068    if (_fallback_factory.null())
2069      _fallback_factory = new DummyIMEngineFactory();
2070
2071    _fallback_instance = _fallback_factory->create_instance(String("UTF-8"), 0);
2072    _fallback_instance->signal_connect_commit_string(slot(fallback_commit_string_cb));
2073
2074    // Attach Panel Client signal.
2075    _panel_client.signal_connect_reload_config                (slot(panel_slot_reload_config));
2076    _panel_client.signal_connect_exit                         (slot(panel_slot_exit));
2077    _panel_client.signal_connect_update_lookup_table_page_size(slot(panel_slot_update_lookup_table_page_size));
2078    _panel_client.signal_connect_lookup_table_page_up         (slot(panel_slot_lookup_table_page_up));
2079    _panel_client.signal_connect_lookup_table_page_down       (slot(panel_slot_lookup_table_page_down));
2080    _panel_client.signal_connect_trigger_property             (slot(panel_slot_trigger_property));
2081    _panel_client.signal_connect_process_helper_event         (slot(panel_slot_process_helper_event));
2082    _panel_client.signal_connect_move_preedit_caret           (slot(panel_slot_move_preedit_caret));
2083    _panel_client.signal_connect_select_candidate             (slot(panel_slot_select_candidate));
2084    _panel_client.signal_connect_process_key_event            (slot(panel_slot_process_key_event));
2085    _panel_client.signal_connect_commit_string                (slot(panel_slot_commit_string));
2086    _panel_client.signal_connect_forward_key_event            (slot(panel_slot_forward_key_event));
2087    _panel_client.signal_connect_request_help                 (slot(panel_slot_request_help));
2088    _panel_client.signal_connect_request_factory_menu         (slot(panel_slot_request_factory_menu));
2089    _panel_client.signal_connect_change_factory               (slot(panel_slot_change_factory));
2090
2091    if (!panel_initialize())
2092      std::cerr << "Ecore IM Module: Cannot connect to Panel!\n";
2093 }
2094
2095 static void
2096 finalize(void)
2097 {
2098    SCIM_DEBUG_FRONTEND(1) << "Finalizing Ecore ISF IMModule...\n";
2099
2100    // Reset this first so that the shared instance could be released correctly afterwards.
2101    _default_instance.reset();
2102
2103    SCIM_DEBUG_FRONTEND(2) << "Finalize all IC partially.\n";
2104    while (_used_ic_impl_list)
2105      {
2106         // In case in "shared input method" mode,
2107         // all contexts share only one instance,
2108         // so we need point the reference pointer correctly before finalizing.
2109         _used_ic_impl_list->si->set_frontend_data(static_cast <void*>(_used_ic_impl_list->parent));
2110         isf_imf_context_del(_used_ic_impl_list->parent->ctx);
2111      }
2112
2113    delete_all_ic_impl();
2114
2115    _fallback_instance.reset();
2116    _fallback_factory.reset();
2117
2118    SCIM_DEBUG_FRONTEND(2) << " Releasing BackEnd...\n";
2119    _backend.reset();
2120
2121    SCIM_DEBUG_FRONTEND(2) << " Releasing Config...\n";
2122    _config.reset();
2123
2124    if (_config_module)
2125      {
2126         SCIM_DEBUG_FRONTEND(2) << " Deleting _config_module...\n";
2127         delete _config_module;
2128         _config_module = 0;
2129      }
2130
2131    _focused_ic = NULL;
2132    _ic_list = NULL;
2133
2134    _scim_initialized = false;
2135
2136    panel_finalize();
2137 }
2138
2139 static void
2140 open_next_factory(EcoreIMFContextISF *ic)
2141 {
2142    SCIM_DEBUG_FRONTEND(2) << __FUNCTION__ << " context=" << ic->id << "\n";
2143    IMEngineFactoryPointer sf = _backend->get_next_factory("", "UTF-8", ic->impl->si->get_factory_uuid());
2144
2145    if (!sf.null())
2146      {
2147         turn_off_ic(ic);
2148         ic->impl->si = sf->create_instance("UTF-8", ic->impl->si->get_id());
2149         ic->impl->si->set_frontend_data(static_cast <void*>(ic));
2150         ic->impl->preedit_string = WideString();
2151         ic->impl->preedit_caret = 0;
2152         attach_instance(ic->impl->si);
2153         _backend->set_default_factory(_language, sf->get_uuid());
2154         _panel_client.register_input_context(ic->id, sf->get_uuid());
2155         set_ic_capabilities(ic);
2156         turn_on_ic(ic);
2157
2158         if (_shared_input_method)
2159           {
2160              _default_instance = ic->impl->si;
2161              ic->impl->shared_si = true;
2162           }
2163      }
2164 }
2165
2166 static void
2167 open_previous_factory(EcoreIMFContextISF *ic)
2168 {
2169    if (ic == NULL)
2170      return;
2171
2172    SCIM_DEBUG_FRONTEND(2) << __FUNCTION__ << " context=" << ic->id << "\n";
2173    IMEngineFactoryPointer sf = _backend->get_previous_factory("", "UTF-8", ic->impl->si->get_factory_uuid());
2174
2175    if (!sf.null())
2176      {
2177         turn_off_ic(ic);
2178         ic->impl->si = sf->create_instance("UTF-8", ic->impl->si->get_id());
2179         ic->impl->si->set_frontend_data(static_cast <void*>(ic));
2180         ic->impl->preedit_string = WideString();
2181         ic->impl->preedit_caret = 0;
2182         attach_instance(ic->impl->si);
2183         _backend->set_default_factory(_language, sf->get_uuid());
2184         _panel_client.register_input_context(ic->id, sf->get_uuid());
2185         set_ic_capabilities(ic);
2186         turn_on_ic(ic);
2187
2188         if (_shared_input_method)
2189           {
2190              _default_instance = ic->impl->si;
2191              ic->impl->shared_si = true;
2192           }
2193      }
2194 }
2195
2196 static void
2197 open_specific_factory(EcoreIMFContextISF *ic,
2198                        const String     &uuid)
2199 {
2200    if (ic == NULL)
2201      return;
2202
2203    SCIM_DEBUG_FRONTEND(2) << __FUNCTION__ << " context=" << ic->id << "\n";
2204
2205    // The same input method is selected, just turn on the IC.
2206    if (ic->impl->si->get_factory_uuid() == uuid)
2207      {
2208         turn_on_ic(ic);
2209         return;
2210      }
2211
2212    IMEngineFactoryPointer sf = _backend->get_factory(uuid);
2213
2214    if (uuid.length() && !sf.null())
2215      {
2216         turn_off_ic(ic);
2217         ic->impl->si = sf->create_instance("UTF-8", ic->impl->si->get_id());
2218         ic->impl->si->set_frontend_data(static_cast <void*>(ic));
2219         ic->impl->preedit_string = WideString();
2220         ic->impl->preedit_caret = 0;
2221         attach_instance(ic->impl->si);
2222         _backend->set_default_factory(_language, sf->get_uuid());
2223         _panel_client.register_input_context(ic->id, sf->get_uuid());
2224         set_ic_capabilities(ic);
2225         turn_on_ic(ic);
2226
2227         if (_shared_input_method)
2228           {
2229              _default_instance = ic->impl->si;
2230              ic->impl->shared_si = true;
2231           }
2232      }
2233    else
2234      {
2235         // turn_off_ic comment out panel_req_update_factory_info()
2236         turn_off_ic(ic);
2237         if (ic && ic->impl->is_on)
2238           {
2239              ic->impl->is_on = false;
2240
2241              if (ic == _focused_ic)
2242                {
2243                   ic->impl->si->focus_out();
2244
2245                   panel_req_update_factory_info(ic);
2246                   _panel_client.turn_off(ic->id);
2247                }
2248
2249              //Record the IC on/off status
2250              if (_shared_input_method)
2251                _config->write(String(SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), false);
2252
2253              if (ic->impl->use_preedit && ic->impl->preedit_string.length())
2254                {
2255                   ecore_imf_context_preedit_changed_event_add(ic->ctx);
2256                   ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
2257                   ecore_imf_context_preedit_end_event_add(ic->ctx);
2258                   ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
2259                   ic->impl->preedit_started = false;
2260                }
2261           }
2262      }
2263 }
2264
2265 static void initialize_modifier_bits(Display *display)
2266 {
2267    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2268
2269    if (__current_display == display)
2270      return;
2271
2272    __current_display = display;
2273
2274    if (display == 0)
2275      {
2276         __current_alt_mask     = Mod1Mask;
2277         __current_meta_mask    = ShiftMask | Mod1Mask;
2278         __current_super_mask   = 0;
2279         __current_hyper_mask   = 0;
2280         __current_numlock_mask = Mod2Mask;
2281         return;
2282      }
2283
2284    XModifierKeymap *mods = NULL;
2285
2286    ::KeyCode ctrl_l  = XKeysymToKeycode(display, XK_Control_L);
2287    ::KeyCode ctrl_r  = XKeysymToKeycode(display, XK_Control_R);
2288    ::KeyCode meta_l  = XKeysymToKeycode(display, XK_Meta_L);
2289    ::KeyCode meta_r  = XKeysymToKeycode(display, XK_Meta_R);
2290    ::KeyCode alt_l   = XKeysymToKeycode(display, XK_Alt_L);
2291    ::KeyCode alt_r   = XKeysymToKeycode(display, XK_Alt_R);
2292    ::KeyCode super_l = XKeysymToKeycode(display, XK_Super_L);
2293    ::KeyCode super_r = XKeysymToKeycode(display, XK_Super_R);
2294    ::KeyCode hyper_l = XKeysymToKeycode(display, XK_Hyper_L);
2295    ::KeyCode hyper_r = XKeysymToKeycode(display, XK_Hyper_R);
2296    ::KeyCode numlock = XKeysymToKeycode(display, XK_Num_Lock);
2297
2298    int i, j;
2299
2300    mods = XGetModifierMapping(display);
2301    if (mods == NULL)
2302      return;
2303
2304    __current_alt_mask     = 0;
2305    __current_meta_mask    = 0;
2306    __current_super_mask   = 0;
2307    __current_hyper_mask   = 0;
2308    __current_numlock_mask = 0;
2309
2310    /* We skip the first three sets for Shift, Lock, and Control.  The
2311       remaining sets are for Mod1, Mod2, Mod3, Mod4, and Mod5.  */
2312    for (i = 3; i < 8; i++)
2313      {
2314         for (j = 0; j < mods->max_keypermod; j++)
2315           {
2316              ::KeyCode code = mods->modifiermap [i * mods->max_keypermod + j];
2317              if (! code) continue;
2318              if (code == alt_l || code == alt_r)
2319                __current_alt_mask |= (1 << i);
2320              else if (code == meta_l || code == meta_r)
2321                __current_meta_mask |= (1 << i);
2322              else if (code == super_l || code == super_r)
2323                __current_super_mask |= (1 << i);
2324              else if (code == hyper_l || code == hyper_r)
2325                __current_hyper_mask |= (1 << i);
2326              else if (code == numlock)
2327                __current_numlock_mask |= (1 << i);
2328           }
2329      }
2330
2331    /* Check whether there is a combine keys mapped to Meta */
2332    if (__current_meta_mask == 0)
2333      {
2334         char buf [32];
2335         XKeyEvent xkey;
2336         KeySym keysym_l, keysym_r;
2337
2338         xkey.type = KeyPress;
2339         xkey.display = display;
2340         xkey.serial = 0L;
2341         xkey.send_event = False;
2342         xkey.x = xkey.y = xkey.x_root = xkey.y_root = 0;
2343         xkey.time = 0;
2344         xkey.same_screen = False;
2345         xkey.subwindow = None;
2346         xkey.window = None;
2347         xkey.root = DefaultRootWindow(display);
2348         xkey.state = ShiftMask;
2349
2350         xkey.keycode = meta_l;
2351         XLookupString(&xkey, buf, 32, &keysym_l, 0);
2352         xkey.keycode = meta_r;
2353         XLookupString(&xkey, buf, 32, &keysym_r, 0);
2354
2355         if ((meta_l == alt_l && keysym_l == XK_Meta_L) || (meta_r == alt_r && keysym_r == XK_Meta_R))
2356           __current_meta_mask = ShiftMask + __current_alt_mask;
2357         else if ((meta_l == ctrl_l && keysym_l == XK_Meta_L) || (meta_r == ctrl_r && keysym_r == XK_Meta_R))
2358           __current_meta_mask = ShiftMask + ControlMask;
2359      }
2360
2361    XFreeModifiermap(mods);
2362 }
2363
2364 static unsigned int scim_x11_keymask_scim_to_x11(Display *display, uint16 scimkeymask)
2365 {
2366    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2367
2368    unsigned int state = 0;
2369
2370    initialize_modifier_bits(display);
2371
2372    if (scimkeymask & SCIM_KEY_ShiftMask)    state |= ShiftMask;
2373    if (scimkeymask & SCIM_KEY_CapsLockMask) state |= LockMask;
2374    if (scimkeymask & SCIM_KEY_ControlMask)  state |= ControlMask;
2375    if (scimkeymask & SCIM_KEY_AltMask)      state |= __current_alt_mask;
2376    if (scimkeymask & SCIM_KEY_MetaMask)     state |= __current_meta_mask;
2377    if (scimkeymask & SCIM_KEY_SuperMask)    state |= __current_super_mask;
2378    if (scimkeymask & SCIM_KEY_HyperMask)    state |= __current_hyper_mask;
2379    if (scimkeymask & SCIM_KEY_NumLockMask)  state |= __current_numlock_mask;
2380
2381    return state;
2382 }
2383
2384 static XKeyEvent createKeyEvent(Display *display, Window &win,
2385                                 Window &winRoot, bool press,
2386                                 int keycode, int modifiers)
2387 {
2388    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2389
2390    XKeyEvent event;
2391
2392    event.display     = display;
2393    event.window      = win;
2394    event.root        = winRoot;
2395    event.subwindow   = None;
2396    event.time        = CurrentTime;
2397    event.x           = 1;
2398    event.y           = 1;
2399    event.x_root      = 1;
2400    event.y_root      = 1;
2401    event.same_screen = EINA_TRUE;
2402    event.state       = modifiers;
2403    event.keycode     = XKeysymToKeycode(display, keycode);
2404    if (press)
2405      event.type = KeyPress;
2406    else
2407      event.type = KeyRelease;
2408    event.send_event  = EINA_FALSE;
2409    event.serial = 0;
2410
2411    return event;
2412 }
2413
2414 static void _x_send_key_event(const KeyEvent &key)
2415 {
2416    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2417
2418    // Obtain the X11 display.
2419    Display *display = XOpenDisplay(NULL);
2420    if (display == NULL)
2421      {
2422         std::cerr << "XOpenDisplay failed\n";
2423         return;
2424      }
2425
2426    // Get the root window for the current display.
2427    Window winRoot = 0;
2428
2429    // Find the window which has the current keyboard focus.
2430    Window winFocus = 0;
2431    int revert = RevertToParent;
2432
2433    XGetInputFocus(display, &winFocus, &revert);
2434
2435    // Send a fake key press event to the window.
2436    XSelectInput(display, winFocus, FocusChangeMask|KeyPressMask|KeyReleaseMask);
2437    XMapWindow(display, winFocus);
2438
2439    unsigned int modifier = scim_x11_keymask_scim_to_x11(display, key.mask);
2440    XKeyEvent event;
2441    if (key.is_key_press())
2442      {
2443         event = createKeyEvent(display, winFocus, winRoot, true, key.code, modifier);
2444         XSendEvent(event.display, event.window, True, KeyPressMask, (XEvent *)&event);
2445      }
2446    else
2447      {
2448         event = createKeyEvent(display, winFocus, winRoot, false, key.code, modifier);
2449         XSendEvent(event.display, event.window, True, KeyReleaseMask, (XEvent *)&event);
2450      }
2451
2452    XCloseDisplay(display);
2453 }
2454
2455 static void
2456 attach_instance(const IMEngineInstancePointer &si)
2457 {
2458    si->signal_connect_show_preedit_string(
2459       slot(slot_show_preedit_string));
2460    si->signal_connect_show_aux_string(
2461       slot(slot_show_aux_string));
2462    si->signal_connect_show_lookup_table(
2463       slot(slot_show_lookup_table));
2464
2465    si->signal_connect_hide_preedit_string(
2466       slot(slot_hide_preedit_string));
2467    si->signal_connect_hide_aux_string(
2468       slot(slot_hide_aux_string));
2469    si->signal_connect_hide_lookup_table(
2470       slot(slot_hide_lookup_table));
2471
2472    si->signal_connect_update_preedit_caret(
2473       slot(slot_update_preedit_caret));
2474    si->signal_connect_update_preedit_string(
2475       slot(slot_update_preedit_string));
2476    si->signal_connect_update_aux_string(
2477       slot(slot_update_aux_string));
2478    si->signal_connect_update_lookup_table(
2479       slot(slot_update_lookup_table));
2480
2481    si->signal_connect_commit_string(
2482       slot(slot_commit_string));
2483
2484    si->signal_connect_forward_key_event(
2485       slot(slot_forward_key_event));
2486
2487    si->signal_connect_register_properties(
2488       slot(slot_register_properties));
2489
2490    si->signal_connect_update_property(
2491       slot(slot_update_property));
2492
2493    si->signal_connect_beep(
2494       slot(slot_beep));
2495
2496    si->signal_connect_start_helper(
2497       slot(slot_start_helper));
2498
2499    si->signal_connect_stop_helper(
2500       slot(slot_stop_helper));
2501
2502    si->signal_connect_send_helper_event(
2503       slot(slot_send_helper_event));
2504
2505    si->signal_connect_get_surrounding_text(
2506       slot(slot_get_surrounding_text));
2507
2508    si->signal_connect_delete_surrounding_text(
2509       slot(slot_delete_surrounding_text));
2510 }
2511
2512 // Implementation of slot functions
2513 static void
2514 slot_show_preedit_string(IMEngineInstanceBase *si)
2515 {
2516    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2517
2518    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2519
2520    if (ic && ic->impl && _focused_ic == ic)
2521      {
2522         if (ic->impl->use_preedit)
2523           {
2524              if (!ic->impl->preedit_started)
2525                {
2526                   ecore_imf_context_preedit_start_event_add(_focused_ic->ctx);
2527                   ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
2528                   ic->impl->preedit_started = true;
2529                }
2530           }
2531         else
2532           _panel_client.show_preedit_string(ic->id);
2533      }
2534 }
2535
2536 static void
2537 slot_show_aux_string(IMEngineInstanceBase *si)
2538 {
2539    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2540
2541    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2542
2543    if (ic && ic->impl && _focused_ic == ic)
2544      _panel_client.show_aux_string(ic->id);
2545 }
2546
2547 static void
2548 slot_show_lookup_table(IMEngineInstanceBase *si)
2549 {
2550    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2551
2552    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2553
2554    if (ic && ic->impl && _focused_ic == ic)
2555      _panel_client.show_lookup_table(ic->id);
2556 }
2557
2558 static void
2559 slot_hide_preedit_string(IMEngineInstanceBase *si)
2560 {
2561    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2562
2563    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2564
2565    if (ic && ic->impl && _focused_ic == ic)
2566      {
2567         bool emit = false;
2568         if (ic->impl->preedit_string.length())
2569           {
2570              ic->impl->preedit_string = WideString();
2571              ic->impl->preedit_caret = 0;
2572              ic->impl->preedit_attrlist.clear();
2573              emit = true;
2574           }
2575         if (ic->impl->use_preedit)
2576           {
2577              if (emit)
2578                {
2579                   ecore_imf_context_preedit_changed_event_add(ic->ctx);
2580                   ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
2581                }
2582              if (ic->impl->preedit_started)
2583                {
2584                   ecore_imf_context_preedit_end_event_add(ic->ctx);
2585                   ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
2586                   ic->impl->preedit_started = false;
2587                }
2588           }
2589         else
2590           _panel_client.hide_preedit_string(ic->id);
2591      }
2592 }
2593
2594 static void
2595 slot_hide_aux_string(IMEngineInstanceBase *si)
2596 {
2597    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2598
2599    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2600
2601    if (ic && ic->impl && _focused_ic == ic)
2602      _panel_client.hide_aux_string(ic->id);
2603 }
2604
2605 static void
2606 slot_hide_lookup_table(IMEngineInstanceBase *si)
2607 {
2608    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2609
2610    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2611
2612    if (ic && ic->impl && _focused_ic == ic)
2613      _panel_client.hide_lookup_table(ic->id);
2614 }
2615
2616 static void
2617 slot_update_preedit_caret(IMEngineInstanceBase *si, int caret)
2618 {
2619    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2620
2621    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2622
2623    if (ic && ic->impl && _focused_ic == ic && ic->impl->preedit_caret != caret)
2624      {
2625         ic->impl->preedit_caret = caret;
2626         if (ic->impl->use_preedit)
2627           {
2628              if (!ic->impl->preedit_started)
2629                {
2630                   ecore_imf_context_preedit_start_event_add(ic->ctx);
2631                   ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
2632                   ic->impl->preedit_started = true;
2633                }
2634              ecore_imf_context_preedit_changed_event_add(ic->ctx);
2635              ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
2636           }
2637         else
2638           _panel_client.update_preedit_caret(ic->id, caret);
2639      }
2640 }
2641
2642 static void
2643 slot_update_preedit_string(IMEngineInstanceBase *si,
2644                             const WideString & str,
2645                             const AttributeList & attrs)
2646 {
2647    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2648
2649    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2650
2651    if (ic && ic->impl && _focused_ic == ic && (ic->impl->preedit_string != str || str.length()))
2652      {
2653         ic->impl->preedit_string   = str;
2654         ic->impl->preedit_attrlist = attrs;
2655         if (ic->impl->use_preedit)
2656           {
2657              if (!ic->impl->preedit_started)
2658                {
2659                   ecore_imf_context_preedit_start_event_add(_focused_ic->ctx);
2660                   ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
2661                   ic->impl->preedit_started = true;
2662                }
2663              ic->impl->preedit_caret    = str.length();
2664              ic->impl->preedit_updating = true;
2665              ecore_imf_context_preedit_changed_event_add(ic->ctx);
2666              ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
2667              ic->impl->preedit_updating = false;
2668           }
2669         else
2670           {
2671              _panel_client.update_preedit_string(ic->id, str, attrs);
2672           }
2673      }
2674 }
2675
2676 static void
2677 slot_update_aux_string(IMEngineInstanceBase *si,
2678                         const WideString & str,
2679                         const AttributeList & attrs)
2680 {
2681    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2682
2683    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2684
2685    if (ic && ic->impl && _focused_ic == ic)
2686      _panel_client.update_aux_string(ic->id, str, attrs);
2687 }
2688
2689 static void
2690 slot_commit_string(IMEngineInstanceBase *si,
2691                     const WideString & str)
2692 {
2693    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2694
2695    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2696
2697    if (ic && ic->ctx)
2698      {
2699         ecore_imf_context_commit_event_add(ic->ctx, utf8_wcstombs(str).c_str());
2700         ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(str).c_str());
2701      }
2702 }
2703
2704 static void
2705 slot_forward_key_event(IMEngineInstanceBase *si,
2706                         const KeyEvent & key)
2707 {
2708    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2709
2710    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2711
2712    if (ic && _focused_ic == ic)
2713      {
2714         if (!_fallback_instance->process_key_event(key))
2715           _x_send_key_event(key);
2716      }
2717 }
2718
2719 static void
2720 slot_update_lookup_table(IMEngineInstanceBase *si,
2721                           const LookupTable & table)
2722 {
2723    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2724
2725    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2726
2727    if (ic && ic->impl && _focused_ic == ic)
2728      _panel_client.update_lookup_table(ic->id, table);
2729 }
2730
2731 static void
2732 slot_register_properties(IMEngineInstanceBase *si,
2733                          const PropertyList & properties)
2734 {
2735    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2736
2737    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2738
2739    if (ic && ic->impl && _focused_ic == ic)
2740      _panel_client.register_properties(ic->id, properties);
2741 }
2742
2743 static void
2744 slot_update_property(IMEngineInstanceBase *si,
2745                      const Property & property)
2746 {
2747    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2748
2749    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2750
2751    if (ic && ic->impl && _focused_ic == ic)
2752      _panel_client.update_property(ic->id, property);
2753 }
2754
2755 static void
2756 slot_beep(IMEngineInstanceBase *si __UNUSED__)
2757 {
2758    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2759 }
2760
2761 static void
2762 slot_start_helper(IMEngineInstanceBase *si,
2763                   const String &helper_uuid)
2764 {
2765    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2766
2767    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " helper= " << helper_uuid << " context="
2768       << (ic ? ic->id : -1) << " ic=" << ic
2769       << " ic-uuid=" << ((ic ) ? ic->impl->si->get_factory_uuid() : "") << "...\n";
2770
2771    if (ic && ic->impl)
2772      _panel_client.start_helper(ic->id, helper_uuid);
2773 }
2774
2775 static void
2776 slot_stop_helper(IMEngineInstanceBase *si,
2777                  const String &helper_uuid)
2778 {
2779    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2780
2781    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " helper= " << helper_uuid << " context=" << (ic ? ic->id : -1) << " ic=" << ic << "...\n";
2782
2783    if (ic && ic->impl)
2784      _panel_client.stop_helper(ic->id, helper_uuid);
2785 }
2786
2787 static void
2788 slot_send_helper_event(IMEngineInstanceBase *si,
2789                        const String      &helper_uuid,
2790                        const Transaction &trans)
2791 {
2792    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2793
2794    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " helper= " << helper_uuid << " context="
2795       << (ic ? ic->id : -1) << " ic=" << ic
2796       << " ic-uuid=" << ((ic) ? ic->impl->si->get_factory_uuid() : "") << "...\n";
2797
2798    if (ic && ic->impl)
2799      _panel_client.send_helper_event(ic->id, helper_uuid, trans);
2800 }
2801
2802 static bool
2803 slot_get_surrounding_text(IMEngineInstanceBase *si,
2804                           WideString            &text,
2805                           int                   &cursor,
2806                           int                    maxlen_before,
2807                           int                    maxlen_after)
2808 {
2809    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2810
2811    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2812
2813    if (ic && ic->impl && _focused_ic == ic)
2814      {
2815         char *surrounding = NULL;
2816         int   cursor_index;
2817         if (ecore_imf_context_surrounding_get(_focused_ic->ctx, &surrounding, &cursor_index))
2818           {
2819              SCIM_DEBUG_FRONTEND(2) << "Surrounding text: " << surrounding <<"\n";
2820              SCIM_DEBUG_FRONTEND(2) << "Cursor Index    : " << cursor_index <<"\n";
2821              WideString before(utf8_mbstowcs(String(surrounding, surrounding + cursor_index)));
2822              WideString after(utf8_mbstowcs(String(surrounding + cursor_index)));
2823              if (maxlen_before > 0 && ((unsigned int)maxlen_before) < before.length())
2824                before = WideString(before.begin() + (before.length() - maxlen_before), before.end());
2825              else if (maxlen_before == 0) before = WideString();
2826              if (maxlen_after > 0 && ((unsigned int)maxlen_after) < after.length())
2827                after = WideString(after.begin(), after.begin() + maxlen_after);
2828              else if (maxlen_after == 0) after = WideString();
2829              text = before + after;
2830              cursor = before.length();
2831              return true;
2832           }
2833      }
2834    return false;
2835 }
2836
2837 static bool
2838 slot_delete_surrounding_text(IMEngineInstanceBase *si,
2839                              int                   offset,
2840                              int                   len)
2841 {
2842    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2843
2844    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2845
2846    if (ic && ic->impl && _focused_ic == ic)
2847      {
2848         Ecore_IMF_Event_Delete_Surrounding ev;
2849         ev.ctx = _focused_ic->ctx;
2850         ev.n_chars = len;
2851         ev.offset = offset;
2852         ecore_imf_context_delete_surrounding_event_add(_focused_ic->ctx, offset, len);
2853         ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, &ev);
2854         return true;
2855      }
2856    return false;
2857 }
2858
2859 static void
2860 reload_config_callback(const ConfigPointer &config)
2861 {
2862    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2863
2864    _frontend_hotkey_matcher.load_hotkeys(config);
2865    _imengine_hotkey_matcher.load_hotkeys(config);
2866
2867    KeyEvent key;
2868
2869    scim_string_to_key(key,
2870                       config->read(String(SCIM_CONFIG_HOTKEYS_FRONTEND_VALID_KEY_MASK),
2871                                      String("Shift+Control+Alt+Lock")));
2872
2873    _valid_key_mask = (key.mask > 0)?(key.mask):0xFFFF;
2874    _valid_key_mask |= SCIM_KEY_ReleaseMask;
2875    // Special treatment for two backslash keys on jp106 keyboard.
2876    _valid_key_mask |= SCIM_KEY_QuirkKanaRoMask;
2877
2878    _on_the_spot = config->read(String(SCIM_CONFIG_FRONTEND_ON_THE_SPOT), _on_the_spot);
2879    _shared_input_method = config->read(String(SCIM_CONFIG_FRONTEND_SHARED_INPUT_METHOD), _shared_input_method);
2880
2881    // Get keyboard layout setting
2882    // Flush the global config first, in order to load the new configs from disk.
2883    scim_global_config_flush();
2884
2885    _keyboard_layout = scim_get_default_keyboard_layout();
2886 }
2887
2888 static void
2889 fallback_commit_string_cb(IMEngineInstanceBase  *si __UNUSED__,
2890                           const WideString      &str)
2891 {
2892    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2893
2894    if (_focused_ic && _focused_ic->impl)
2895      {
2896         ecore_imf_context_commit_event_add(_focused_ic->ctx, utf8_wcstombs(str).c_str());
2897         ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(str).c_str());
2898      }
2899 }
2900