d085ec043b87caca5153485770f23c4f57d37e42
[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->locks & ECORE_IMF_KEYBOARD_LOCK_CAPS) key.mask |=SCIM_KEY_CapsLockMask;
1393         if (ev->locks & ECORE_IMF_KEYBOARD_LOCK_NUM) key.mask |=SCIM_KEY_NumLockMask;
1394      }
1395    else if (type == ECORE_IMF_EVENT_KEY_UP)
1396      {
1397         Ecore_IMF_Event_Key_Up *ev = (Ecore_IMF_Event_Key_Up *)event;
1398         scim_string_to_key(key, ev->key);
1399         key.mask = SCIM_KEY_ReleaseMask;
1400         if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_SHIFT) key.mask |=SCIM_KEY_ShiftMask;
1401         if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_CTRL) key.mask |=SCIM_KEY_ControlMask;
1402         if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_ALT) key.mask |=SCIM_KEY_AltMask;
1403         if (ev->locks & ECORE_IMF_KEYBOARD_LOCK_CAPS) key.mask |=SCIM_KEY_CapsLockMask;
1404         if (ev->locks & ECORE_IMF_KEYBOARD_LOCK_NUM) key.mask |=SCIM_KEY_NumLockMask;
1405      }
1406    else
1407      {
1408         return ret;
1409      }
1410
1411    key.mask &= _valid_key_mask;
1412
1413    _panel_client.prepare(ic->id);
1414
1415    ret = EINA_TRUE;
1416    if (!filter_hotkeys(ic, key))
1417      {
1418         if (!_focused_ic || !_focused_ic->impl->is_on ||
1419             !_focused_ic->impl->si->process_key_event(key))
1420           ret = EINA_FALSE;
1421      }
1422
1423    _panel_client.send();
1424
1425    return ret;
1426 }
1427
1428 EAPI void
1429 isf_imf_context_input_panel_show(Ecore_IMF_Context *ctx)
1430 {
1431    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1432
1433    EcoreIMFContextISF *ic = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
1434    if (ic == NULL || ic->impl == NULL)
1435      return;
1436
1437    ecore_x_e_virtual_keyboard_state_set
1438         (ic->impl->client_window, ECORE_X_VIRTUAL_KEYBOARD_STATE_ON);
1439 }
1440
1441 EAPI void
1442 isf_imf_context_input_panel_hide(Ecore_IMF_Context *ctx)
1443 {
1444    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1445
1446    EcoreIMFContextISF *ic = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
1447    if (ic == NULL || ic->impl == NULL)
1448      return;
1449
1450    ecore_x_e_virtual_keyboard_state_set
1451         (ic->impl->client_window, ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF);
1452 }
1453
1454 /* Panel Slot functions */
1455 static void
1456 panel_slot_reload_config(int context __UNUSED__)
1457 {
1458    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1459    _config->reload();
1460 }
1461
1462 static void
1463 panel_slot_exit(int /* context */)
1464 {
1465    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1466
1467    finalize();
1468 }
1469
1470 static void
1471 panel_slot_update_lookup_table_page_size(int context, int page_size)
1472 {
1473    EcoreIMFContextISF *ic = find_ic(context);
1474    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " page_size=" << page_size << " ic=" << ic << "\n";
1475    if (ic && ic->impl)
1476      {
1477         _panel_client.prepare(ic->id);
1478         ic->impl->si->update_lookup_table_page_size(page_size);
1479         _panel_client.send();
1480      }
1481 }
1482
1483 static void
1484 panel_slot_lookup_table_page_up(int context)
1485 {
1486    EcoreIMFContextISF *ic = find_ic(context);
1487    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n";
1488    if (ic && ic->impl)
1489      {
1490         _panel_client.prepare(ic->id);
1491         ic->impl->si->lookup_table_page_up();
1492         _panel_client.send();
1493      }
1494 }
1495
1496 static void
1497 panel_slot_lookup_table_page_down(int context)
1498 {
1499    EcoreIMFContextISF *ic = find_ic(context);
1500    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n";
1501    if (ic && ic->impl)
1502      {
1503         _panel_client.prepare(ic->id);
1504         ic->impl->si->lookup_table_page_down();
1505         _panel_client.send();
1506      }
1507 }
1508
1509 static void
1510 panel_slot_trigger_property(int context, const String &property)
1511 {
1512    EcoreIMFContextISF *ic = find_ic(context);
1513    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " property=" << property << " ic=" << ic << "\n";
1514    if (ic && ic->impl)
1515      {
1516         _panel_client.prepare(ic->id);
1517         ic->impl->si->trigger_property(property);
1518         _panel_client.send();
1519      }
1520 }
1521
1522 static void
1523 panel_slot_process_helper_event(int context, const String &target_uuid, const String &helper_uuid, const Transaction &trans)
1524 {
1525    EcoreIMFContextISF *ic = find_ic(context);
1526    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " target=" << target_uuid
1527       << " helper=" << helper_uuid << " ic=" << ic << " ic->impl=" << (ic ? ic->impl : 0) << " ic-uuid="
1528       << ((ic && ic->impl) ? ic->impl->si->get_factory_uuid() : "" ) << "\n";
1529    if (ic && ic->impl && ic->impl->si->get_factory_uuid() == target_uuid)
1530      {
1531         _panel_client.prepare(ic->id);
1532         SCIM_DEBUG_FRONTEND(2) << "call process_helper_event\n";
1533         ic->impl->si->process_helper_event(helper_uuid, trans);
1534         _panel_client.send();
1535      }
1536 }
1537
1538 static void
1539 panel_slot_move_preedit_caret(int context, int caret_pos)
1540 {
1541    EcoreIMFContextISF *ic = find_ic(context);
1542    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " caret=" << caret_pos << " ic=" << ic << "\n";
1543    if (ic && ic->impl)
1544      {
1545         _panel_client.prepare(ic->id);
1546         ic->impl->si->move_preedit_caret(caret_pos);
1547         _panel_client.send();
1548      }
1549 }
1550
1551 static void
1552 panel_slot_select_candidate(int context, int cand_index)
1553 {
1554    EcoreIMFContextISF *ic = find_ic(context);
1555    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " candidate=" << cand_index << " ic=" << ic << "\n";
1556    if (ic && ic->impl)
1557      {
1558         _panel_client.prepare(ic->id);
1559         ic->impl->si->select_candidate(cand_index);
1560         _panel_client.send();
1561      }
1562 }
1563
1564 static void
1565 panel_slot_process_key_event(int context, const KeyEvent &key)
1566 {
1567    EcoreIMFContextISF *ic = find_ic(context);
1568    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " key=" << key.get_key_string() << " ic=" << ic << "\n";
1569
1570    if (key.is_key_press())
1571      ecore_x_test_fake_key_press(key.get_key_string().c_str());
1572 }
1573
1574 static void
1575 panel_slot_commit_string(int context, const WideString &wstr)
1576 {
1577    EcoreIMFContextISF *ic = find_ic(context);
1578    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " str=" << utf8_wcstombs(wstr) << " ic=" << ic << "\n";
1579
1580    if (ic && ic->impl)
1581      {
1582         if (_focused_ic != ic)
1583           return;
1584
1585         ecore_imf_context_commit_event_add(ic->ctx, utf8_wcstombs(wstr).c_str());
1586         ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(wstr).c_str());
1587      }
1588 }
1589
1590 static void
1591 panel_slot_forward_key_event(int context, const KeyEvent &key)
1592 {
1593    EcoreIMFContextISF *ic = find_ic(context);
1594    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " key=" << key.get_key_string() << " ic=" << ic << "\n";
1595
1596    if (ic && ic->impl && ic->impl->client_canvas)
1597      feed_key_event(ic->impl->client_canvas, key.get_key_string().c_str(), EINA_TRUE);
1598 }
1599
1600 static void
1601 panel_slot_request_help(int context)
1602 {
1603    EcoreIMFContextISF *ic = find_ic(context);
1604    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n";
1605
1606    if (ic && ic->impl)
1607      {
1608         _panel_client.prepare(ic->id);
1609         panel_req_show_help(ic);
1610         _panel_client.send();
1611      }
1612 }
1613
1614 static void
1615 panel_slot_request_factory_menu(int context)
1616 {
1617    EcoreIMFContextISF *ic = find_ic(context);
1618    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n";
1619
1620    if (ic && ic->impl)
1621      {
1622         _panel_client.prepare(ic->id);
1623         panel_req_show_factory_menu(ic);
1624         _panel_client.send();
1625      }
1626 }
1627
1628 static void
1629 panel_slot_change_factory(int context, const String &uuid)
1630 {
1631    EcoreIMFContextISF *ic = find_ic(context);
1632    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " factory=" << uuid << " ic=" << ic << "\n";
1633
1634    if (ic && ic->impl)
1635      {
1636         ic->impl->si->reset();
1637         _panel_client.prepare(ic->id);
1638         open_specific_factory(ic, uuid);
1639         _panel_client.send();
1640      }
1641 }
1642
1643 /* Panel Requestion functions. */
1644 static void
1645 panel_req_show_help(EcoreIMFContextISF *ic)
1646 {
1647    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1648
1649    String help;
1650
1651    help =  String("Smart Common Input Method platform ") +
1652       //String(SCIM_VERSION) +
1653       String("\n(C) 2002-2005 James Su <suzhe@tsinghua.org.cn>\n\n");
1654
1655    if (ic && ic->impl)
1656      {
1657         IMEngineFactoryPointer sf = _backend->get_factory(ic->impl->si->get_factory_uuid());
1658         if (sf)
1659           {
1660              help += utf8_wcstombs(sf->get_name());
1661              help += String(":\n\n");
1662
1663              help += utf8_wcstombs(sf->get_help());
1664              help += String("\n\n");
1665
1666              help += utf8_wcstombs(sf->get_credits());
1667           }
1668         _panel_client.show_help(ic->id, help);
1669      }
1670 }
1671
1672 static void
1673 panel_req_show_factory_menu(EcoreIMFContextISF *ic)
1674 {
1675    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1676
1677    std::vector<IMEngineFactoryPointer> factories;
1678    std::vector <PanelFactoryInfo> menu;
1679
1680    _backend->get_factories_for_encoding(factories, "UTF-8");
1681
1682    for (size_t i = 0; i < factories.size(); ++ i)
1683      {
1684         menu.push_back(PanelFactoryInfo(
1685               factories [i]->get_uuid(),
1686               utf8_wcstombs(factories [i]->get_name()),
1687               factories [i]->get_language(),
1688               factories [i]->get_icon_file()));
1689      }
1690
1691    if (menu.size())
1692      _panel_client.show_factory_menu(ic->id, menu);
1693 }
1694
1695 static void
1696 panel_req_update_factory_info(EcoreIMFContextISF *ic)
1697 {
1698    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1699
1700    if (ic && ic->impl && ic == _focused_ic)
1701      {
1702         PanelFactoryInfo info;
1703         if (ic->impl->is_on)
1704           {
1705              IMEngineFactoryPointer sf = _backend->get_factory(ic->impl->si->get_factory_uuid());
1706              if (sf)
1707                info = PanelFactoryInfo(sf->get_uuid(), utf8_wcstombs(sf->get_name()), sf->get_language(), sf->get_icon_file());
1708           }
1709         else
1710           {
1711              info = PanelFactoryInfo(String(""), String("English/Keyboard"), String("C"), "");
1712           }
1713         _panel_client.update_factory_info(ic->id, info);
1714      }
1715 }
1716
1717 static void
1718 panel_req_focus_in(EcoreIMFContextISF *ic)
1719 {
1720    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1721
1722    _panel_client.focus_in(ic->id, ic->impl->si->get_factory_uuid());
1723 }
1724
1725 static void
1726 panel_req_update_spot_location(EcoreIMFContextISF *ic)
1727 {
1728    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1729
1730    _panel_client.update_spot_location(ic->id, ic->impl->cursor_x, ic->impl->cursor_y);
1731 }
1732
1733 static bool
1734 filter_hotkeys(EcoreIMFContextISF *ic, const KeyEvent &key)
1735 {
1736    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1737
1738    bool ret = false;
1739
1740    _frontend_hotkey_matcher.push_key_event(key);
1741    _imengine_hotkey_matcher.push_key_event(key);
1742
1743    FrontEndHotkeyAction hotkey_action = _frontend_hotkey_matcher.get_match_result();
1744
1745    if (hotkey_action == SCIM_FRONTEND_HOTKEY_TRIGGER)
1746      {
1747         if (!ic->impl->is_on)
1748           turn_on_ic(ic);
1749         else
1750           turn_off_ic(ic);
1751         ret = true;
1752      }
1753    else if (hotkey_action == SCIM_FRONTEND_HOTKEY_ON)
1754      {
1755         if (!ic->impl->is_on)
1756           turn_on_ic(ic);
1757         ret = true;
1758      }
1759    else if (hotkey_action == SCIM_FRONTEND_HOTKEY_OFF)
1760      {
1761         if (ic->impl->is_on)
1762           turn_off_ic(ic);
1763         ret = true;
1764      }
1765    else if (hotkey_action == SCIM_FRONTEND_HOTKEY_NEXT_FACTORY)
1766      {
1767         open_next_factory(ic);
1768         ret = true;
1769      }
1770    else if (hotkey_action == SCIM_FRONTEND_HOTKEY_PREVIOUS_FACTORY)
1771      {
1772         open_previous_factory(ic);
1773         ret = true;
1774      }
1775    else if (hotkey_action == SCIM_FRONTEND_HOTKEY_SHOW_FACTORY_MENU)
1776      {
1777         panel_req_show_factory_menu(ic);
1778         ret = true;
1779      }
1780    else if (_imengine_hotkey_matcher.is_matched())
1781      {
1782         String sfid = _imengine_hotkey_matcher.get_match_result();
1783         open_specific_factory(ic, sfid);
1784         ret = true;
1785      }
1786    return ret;
1787 }
1788
1789 static bool
1790 panel_initialize(void)
1791 {
1792    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1793
1794    String display_name;
1795      {
1796         const char *p = getenv("DISPLAY");
1797         if (p) display_name = String(p);
1798      }
1799
1800    if (_panel_client.open_connection(_config->get_name(), display_name) >= 0)
1801      {
1802         int fd = _panel_client.get_connection_number();
1803
1804         _panel_iochannel_read_handler = ecore_main_fd_handler_add(fd, ECORE_FD_READ, panel_iochannel_handler, NULL, NULL, NULL);
1805
1806         SCIM_DEBUG_FRONTEND(2) << " Panel FD= " << fd << "\n";
1807
1808         return true;
1809    }
1810    std::cerr << "panel_initialize() failed!!!\n";
1811    return false;
1812 }
1813
1814 static void
1815 panel_finalize(void)
1816 {
1817    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1818
1819    _panel_client.close_connection();
1820
1821    if (_panel_iochannel_read_handler)
1822      {
1823         ecore_main_fd_handler_del(_panel_iochannel_read_handler);
1824         _panel_iochannel_read_handler = 0;
1825      }
1826
1827    if (_panel_iochannel_err_handler)
1828      {
1829         ecore_main_fd_handler_del(_panel_iochannel_err_handler);
1830         _panel_iochannel_err_handler = 0;
1831      }
1832 }
1833
1834 static Eina_Bool
1835 panel_iochannel_handler(void *data __UNUSED__, Ecore_Fd_Handler *fd_handler)
1836 {
1837    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1838
1839    if (fd_handler == _panel_iochannel_read_handler)
1840      {
1841         if (!_panel_client.filter_event())
1842           {
1843              panel_finalize();
1844              panel_initialize();
1845              return ECORE_CALLBACK_CANCEL;
1846           }
1847      }
1848    else if (fd_handler == _panel_iochannel_err_handler)
1849      {
1850         panel_finalize();
1851         panel_initialize();
1852         return ECORE_CALLBACK_CANCEL;
1853      }
1854    return ECORE_CALLBACK_RENEW;
1855 }
1856
1857 static void
1858 turn_on_ic(EcoreIMFContextISF *ic)
1859 {
1860    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1861
1862    if (ic && ic->impl && !ic->impl->is_on)
1863      {
1864         ic->impl->is_on = true;
1865
1866         if (ic == _focused_ic)
1867           {
1868              panel_req_focus_in(ic);
1869              panel_req_update_spot_location(ic);
1870              panel_req_update_factory_info(ic);
1871              _panel_client.turn_on(ic->id);
1872              _panel_client.hide_preedit_string(ic->id);
1873              _panel_client.hide_aux_string(ic->id);
1874              _panel_client.hide_lookup_table(ic->id);
1875              ic->impl->si->focus_in();
1876           }
1877
1878         //Record the IC on/off status
1879         if (_shared_input_method)
1880           _config->write(String(SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), true);
1881
1882         if (ic->impl->use_preedit && ic->impl->preedit_string.length())
1883           {
1884              ecore_imf_context_preedit_start_event_add(ic->ctx);
1885              ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
1886              ecore_imf_context_preedit_changed_event_add(ic->ctx);
1887              ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
1888              ic->impl->preedit_started = true;
1889           }
1890      }
1891 }
1892
1893 static void
1894 turn_off_ic(EcoreIMFContextISF *ic)
1895 {
1896    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1897
1898    if (ic && ic->impl && ic->impl->is_on)
1899      {
1900         ic->impl->is_on = false;
1901
1902         if (ic == _focused_ic)
1903           {
1904              ic->impl->si->focus_out();
1905
1906              panel_req_update_factory_info(ic);
1907              _panel_client.turn_off(ic->id);
1908           }
1909
1910         //Record the IC on/off status
1911         if (_shared_input_method)
1912           _config->write(String(SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), false);
1913
1914         if (ic->impl->use_preedit && ic->impl->preedit_string.length())
1915           {
1916              ecore_imf_context_preedit_changed_event_add(ic->ctx);
1917              ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
1918              ecore_imf_context_preedit_end_event_add(ic->ctx);
1919              ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
1920              ic->impl->preedit_started = false;
1921           }
1922      }
1923 }
1924
1925 static void
1926 set_ic_capabilities(EcoreIMFContextISF *ic)
1927 {
1928    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1929
1930    if (ic && ic->impl)
1931      {
1932         unsigned int cap = SCIM_CLIENT_CAP_ALL_CAPABILITIES;
1933
1934         if (!_on_the_spot || !ic->impl->use_preedit)
1935           cap -= SCIM_CLIENT_CAP_ONTHESPOT_PREEDIT;
1936
1937         ic->impl->si->update_client_capabilities(cap);
1938      }
1939 }
1940
1941 static bool
1942 check_socket_frontend(void)
1943 {
1944    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1945
1946    SocketAddress address;
1947    SocketClient client;
1948
1949    uint32 magic;
1950
1951    address.set_address(scim_get_default_socket_frontend_address());
1952
1953    if (!client.connect(address))
1954      return false;
1955
1956    if (!scim_socket_open_connection(magic,
1957                                     String("ConnectionTester"),
1958                                     String("SocketFrontEnd"),
1959                                     client,
1960                                     1000))
1961         return false;
1962
1963    return true;
1964 }
1965
1966 void
1967 initialize(void)
1968 {
1969    std::vector<String>     config_list;
1970    std::vector<String>     engine_list;
1971    std::vector<String>     load_engine_list;
1972
1973    std::vector<String>::iterator it;
1974
1975    bool                    manual = false;
1976
1977    bool                    socket = true;
1978
1979    String                  config_module_name = "simple";
1980
1981    printf("Initializing Ecore SCIM IMModule...\n");
1982
1983    SCIM_DEBUG_FRONTEND(1) << "Initializing Ecore SCIM IMModule...\n";
1984
1985    // Get system language.
1986    _language = scim_get_locale_language(scim_get_current_locale());
1987
1988    if (socket)
1989      {
1990         // If no Socket FrontEnd is running, then launch one.
1991         // And set manual to false.
1992         bool check_result = check_socket_frontend();
1993         if (!check_result)
1994           {
1995              std::cerr << "Launching a SCIM daemon with Socket FrontEnd...\n";
1996              //get modules list
1997              scim_get_imengine_module_list(engine_list);
1998
1999              for (it = engine_list.begin(); it != engine_list.end(); it++)
2000                {
2001                   if (*it != "socket")
2002                     load_engine_list.push_back(*it);
2003                }
2004
2005              const char *new_argv [] = { "--no-stay", 0 };
2006              scim_launch(true,
2007                          config_module_name,
2008                          (load_engine_list.size() ? scim_combine_string_list(load_engine_list, ',') : "none"),
2009                          "socket",
2010                          (char **)new_argv);
2011              manual = false;
2012           }
2013
2014         // If there is one Socket FrontEnd running and it's not manual mode,
2015         // then just use this Socket Frontend.
2016         if (!manual)
2017           {
2018              for (int i = 0; i < 200; ++i)
2019                {
2020                   if (check_result)
2021                     {
2022                        config_module_name = "socket";
2023                        load_engine_list.clear();
2024                        load_engine_list.push_back("socket");
2025                        break;
2026                     }
2027                   scim_usleep(50000);
2028                   check_result = check_socket_frontend();
2029                }
2030           }
2031      }
2032
2033    if (config_module_name != "dummy")
2034      {
2035         //load config module
2036         SCIM_DEBUG_FRONTEND(1) << "Loading Config module: " << config_module_name << "...\n";
2037         _config_module = new ConfigModule(config_module_name);
2038
2039         //create config instance
2040         if (_config_module != NULL && _config_module->valid())
2041           _config = _config_module->create_config();
2042      }
2043
2044    if (_config.null())
2045      {
2046         SCIM_DEBUG_FRONTEND(1) << "Config module cannot be loaded, using dummy Config.\n";
2047
2048         if (_config_module) delete _config_module;
2049         _config_module = NULL;
2050
2051         _config = new DummyConfig();
2052         config_module_name = "dummy";
2053      }
2054
2055    reload_config_callback(_config);
2056    _config->signal_connect_reload(slot(reload_config_callback));
2057
2058    // create backend
2059    _backend = new CommonBackEnd(_config, load_engine_list.size() ? load_engine_list : engine_list);
2060
2061    if (_backend.null())
2062      std::cerr << "Cannot create BackEnd Object!\n";
2063    else
2064      _fallback_factory = _backend->get_factory(SCIM_COMPOSE_KEY_FACTORY_UUID);
2065
2066    if (_fallback_factory.null())
2067      _fallback_factory = new DummyIMEngineFactory();
2068
2069    _fallback_instance = _fallback_factory->create_instance(String("UTF-8"), 0);
2070    _fallback_instance->signal_connect_commit_string(slot(fallback_commit_string_cb));
2071
2072    // Attach Panel Client signal.
2073    _panel_client.signal_connect_reload_config                (slot(panel_slot_reload_config));
2074    _panel_client.signal_connect_exit                         (slot(panel_slot_exit));
2075    _panel_client.signal_connect_update_lookup_table_page_size(slot(panel_slot_update_lookup_table_page_size));
2076    _panel_client.signal_connect_lookup_table_page_up         (slot(panel_slot_lookup_table_page_up));
2077    _panel_client.signal_connect_lookup_table_page_down       (slot(panel_slot_lookup_table_page_down));
2078    _panel_client.signal_connect_trigger_property             (slot(panel_slot_trigger_property));
2079    _panel_client.signal_connect_process_helper_event         (slot(panel_slot_process_helper_event));
2080    _panel_client.signal_connect_move_preedit_caret           (slot(panel_slot_move_preedit_caret));
2081    _panel_client.signal_connect_select_candidate             (slot(panel_slot_select_candidate));
2082    _panel_client.signal_connect_process_key_event            (slot(panel_slot_process_key_event));
2083    _panel_client.signal_connect_commit_string                (slot(panel_slot_commit_string));
2084    _panel_client.signal_connect_forward_key_event            (slot(panel_slot_forward_key_event));
2085    _panel_client.signal_connect_request_help                 (slot(panel_slot_request_help));
2086    _panel_client.signal_connect_request_factory_menu         (slot(panel_slot_request_factory_menu));
2087    _panel_client.signal_connect_change_factory               (slot(panel_slot_change_factory));
2088
2089    if (!panel_initialize())
2090      std::cerr << "Ecore IM Module: Cannot connect to Panel!\n";
2091 }
2092
2093 static void
2094 finalize(void)
2095 {
2096    SCIM_DEBUG_FRONTEND(1) << "Finalizing Ecore ISF IMModule...\n";
2097
2098    // Reset this first so that the shared instance could be released correctly afterwards.
2099    _default_instance.reset();
2100
2101    SCIM_DEBUG_FRONTEND(2) << "Finalize all IC partially.\n";
2102    while (_used_ic_impl_list)
2103      {
2104         // In case in "shared input method" mode,
2105         // all contexts share only one instance,
2106         // so we need point the reference pointer correctly before finalizing.
2107         _used_ic_impl_list->si->set_frontend_data(static_cast <void*>(_used_ic_impl_list->parent));
2108         isf_imf_context_del(_used_ic_impl_list->parent->ctx);
2109      }
2110
2111    delete_all_ic_impl();
2112
2113    _fallback_instance.reset();
2114    _fallback_factory.reset();
2115
2116    SCIM_DEBUG_FRONTEND(2) << " Releasing BackEnd...\n";
2117    _backend.reset();
2118
2119    SCIM_DEBUG_FRONTEND(2) << " Releasing Config...\n";
2120    _config.reset();
2121
2122    if (_config_module)
2123      {
2124         SCIM_DEBUG_FRONTEND(2) << " Deleting _config_module...\n";
2125         delete _config_module;
2126         _config_module = 0;
2127      }
2128
2129    _focused_ic = NULL;
2130    _ic_list = NULL;
2131
2132    _scim_initialized = false;
2133
2134    panel_finalize();
2135 }
2136
2137 static void
2138 open_next_factory(EcoreIMFContextISF *ic)
2139 {
2140    SCIM_DEBUG_FRONTEND(2) << __FUNCTION__ << " context=" << ic->id << "\n";
2141    IMEngineFactoryPointer sf = _backend->get_next_factory("", "UTF-8", ic->impl->si->get_factory_uuid());
2142
2143    if (!sf.null())
2144      {
2145         turn_off_ic(ic);
2146         ic->impl->si = sf->create_instance("UTF-8", ic->impl->si->get_id());
2147         ic->impl->si->set_frontend_data(static_cast <void*>(ic));
2148         ic->impl->preedit_string = WideString();
2149         ic->impl->preedit_caret = 0;
2150         attach_instance(ic->impl->si);
2151         _backend->set_default_factory(_language, sf->get_uuid());
2152         _panel_client.register_input_context(ic->id, sf->get_uuid());
2153         set_ic_capabilities(ic);
2154         turn_on_ic(ic);
2155
2156         if (_shared_input_method)
2157           {
2158              _default_instance = ic->impl->si;
2159              ic->impl->shared_si = true;
2160           }
2161      }
2162 }
2163
2164 static void
2165 open_previous_factory(EcoreIMFContextISF *ic)
2166 {
2167    if (ic == NULL)
2168      return;
2169
2170    SCIM_DEBUG_FRONTEND(2) << __FUNCTION__ << " context=" << ic->id << "\n";
2171    IMEngineFactoryPointer sf = _backend->get_previous_factory("", "UTF-8", ic->impl->si->get_factory_uuid());
2172
2173    if (!sf.null())
2174      {
2175         turn_off_ic(ic);
2176         ic->impl->si = sf->create_instance("UTF-8", ic->impl->si->get_id());
2177         ic->impl->si->set_frontend_data(static_cast <void*>(ic));
2178         ic->impl->preedit_string = WideString();
2179         ic->impl->preedit_caret = 0;
2180         attach_instance(ic->impl->si);
2181         _backend->set_default_factory(_language, sf->get_uuid());
2182         _panel_client.register_input_context(ic->id, sf->get_uuid());
2183         set_ic_capabilities(ic);
2184         turn_on_ic(ic);
2185
2186         if (_shared_input_method)
2187           {
2188              _default_instance = ic->impl->si;
2189              ic->impl->shared_si = true;
2190           }
2191      }
2192 }
2193
2194 static void
2195 open_specific_factory(EcoreIMFContextISF *ic,
2196                        const String     &uuid)
2197 {
2198    if (ic == NULL)
2199      return;
2200
2201    SCIM_DEBUG_FRONTEND(2) << __FUNCTION__ << " context=" << ic->id << "\n";
2202
2203    // The same input method is selected, just turn on the IC.
2204    if (ic->impl->si->get_factory_uuid() == uuid)
2205      {
2206         turn_on_ic(ic);
2207         return;
2208      }
2209
2210    IMEngineFactoryPointer sf = _backend->get_factory(uuid);
2211
2212    if (uuid.length() && !sf.null())
2213      {
2214         turn_off_ic(ic);
2215         ic->impl->si = sf->create_instance("UTF-8", ic->impl->si->get_id());
2216         ic->impl->si->set_frontend_data(static_cast <void*>(ic));
2217         ic->impl->preedit_string = WideString();
2218         ic->impl->preedit_caret = 0;
2219         attach_instance(ic->impl->si);
2220         _backend->set_default_factory(_language, sf->get_uuid());
2221         _panel_client.register_input_context(ic->id, sf->get_uuid());
2222         set_ic_capabilities(ic);
2223         turn_on_ic(ic);
2224
2225         if (_shared_input_method)
2226           {
2227              _default_instance = ic->impl->si;
2228              ic->impl->shared_si = true;
2229           }
2230      }
2231    else
2232      {
2233         // turn_off_ic comment out panel_req_update_factory_info()
2234         turn_off_ic(ic);
2235         if (ic && ic->impl->is_on)
2236           {
2237              ic->impl->is_on = false;
2238
2239              if (ic == _focused_ic)
2240                {
2241                   ic->impl->si->focus_out();
2242
2243                   panel_req_update_factory_info(ic);
2244                   _panel_client.turn_off(ic->id);
2245                }
2246
2247              //Record the IC on/off status
2248              if (_shared_input_method)
2249                _config->write(String(SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), false);
2250
2251              if (ic->impl->use_preedit && ic->impl->preedit_string.length())
2252                {
2253                   ecore_imf_context_preedit_changed_event_add(ic->ctx);
2254                   ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
2255                   ecore_imf_context_preedit_end_event_add(ic->ctx);
2256                   ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
2257                   ic->impl->preedit_started = false;
2258                }
2259           }
2260      }
2261 }
2262
2263 static void initialize_modifier_bits(Display *display)
2264 {
2265    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2266
2267    if (__current_display == display)
2268      return;
2269
2270    __current_display = display;
2271
2272    if (display == 0)
2273      {
2274         __current_alt_mask     = Mod1Mask;
2275         __current_meta_mask    = ShiftMask | Mod1Mask;
2276         __current_super_mask   = 0;
2277         __current_hyper_mask   = 0;
2278         __current_numlock_mask = Mod2Mask;
2279         return;
2280      }
2281
2282    XModifierKeymap *mods = NULL;
2283
2284    ::KeyCode ctrl_l  = XKeysymToKeycode(display, XK_Control_L);
2285    ::KeyCode ctrl_r  = XKeysymToKeycode(display, XK_Control_R);
2286    ::KeyCode meta_l  = XKeysymToKeycode(display, XK_Meta_L);
2287    ::KeyCode meta_r  = XKeysymToKeycode(display, XK_Meta_R);
2288    ::KeyCode alt_l   = XKeysymToKeycode(display, XK_Alt_L);
2289    ::KeyCode alt_r   = XKeysymToKeycode(display, XK_Alt_R);
2290    ::KeyCode super_l = XKeysymToKeycode(display, XK_Super_L);
2291    ::KeyCode super_r = XKeysymToKeycode(display, XK_Super_R);
2292    ::KeyCode hyper_l = XKeysymToKeycode(display, XK_Hyper_L);
2293    ::KeyCode hyper_r = XKeysymToKeycode(display, XK_Hyper_R);
2294    ::KeyCode numlock = XKeysymToKeycode(display, XK_Num_Lock);
2295
2296    int i, j;
2297
2298    mods = XGetModifierMapping(display);
2299    if (mods == NULL)
2300      return;
2301
2302    __current_alt_mask     = 0;
2303    __current_meta_mask    = 0;
2304    __current_super_mask   = 0;
2305    __current_hyper_mask   = 0;
2306    __current_numlock_mask = 0;
2307
2308    /* We skip the first three sets for Shift, Lock, and Control.  The
2309       remaining sets are for Mod1, Mod2, Mod3, Mod4, and Mod5.  */
2310    for (i = 3; i < 8; i++)
2311      {
2312         for (j = 0; j < mods->max_keypermod; j++)
2313           {
2314              ::KeyCode code = mods->modifiermap [i * mods->max_keypermod + j];
2315              if (! code) continue;
2316              if (code == alt_l || code == alt_r)
2317                __current_alt_mask |= (1 << i);
2318              else if (code == meta_l || code == meta_r)
2319                __current_meta_mask |= (1 << i);
2320              else if (code == super_l || code == super_r)
2321                __current_super_mask |= (1 << i);
2322              else if (code == hyper_l || code == hyper_r)
2323                __current_hyper_mask |= (1 << i);
2324              else if (code == numlock)
2325                __current_numlock_mask |= (1 << i);
2326           }
2327      }
2328
2329    /* Check whether there is a combine keys mapped to Meta */
2330    if (__current_meta_mask == 0)
2331      {
2332         char buf [32];
2333         XKeyEvent xkey;
2334         KeySym keysym_l, keysym_r;
2335
2336         xkey.type = KeyPress;
2337         xkey.display = display;
2338         xkey.serial = 0L;
2339         xkey.send_event = False;
2340         xkey.x = xkey.y = xkey.x_root = xkey.y_root = 0;
2341         xkey.time = 0;
2342         xkey.same_screen = False;
2343         xkey.subwindow = None;
2344         xkey.window = None;
2345         xkey.root = DefaultRootWindow(display);
2346         xkey.state = ShiftMask;
2347
2348         xkey.keycode = meta_l;
2349         XLookupString(&xkey, buf, 32, &keysym_l, 0);
2350         xkey.keycode = meta_r;
2351         XLookupString(&xkey, buf, 32, &keysym_r, 0);
2352
2353         if ((meta_l == alt_l && keysym_l == XK_Meta_L) || (meta_r == alt_r && keysym_r == XK_Meta_R))
2354           __current_meta_mask = ShiftMask + __current_alt_mask;
2355         else if ((meta_l == ctrl_l && keysym_l == XK_Meta_L) || (meta_r == ctrl_r && keysym_r == XK_Meta_R))
2356           __current_meta_mask = ShiftMask + ControlMask;
2357      }
2358
2359    XFreeModifiermap(mods);
2360 }
2361
2362 static unsigned int scim_x11_keymask_scim_to_x11(Display *display, uint16 scimkeymask)
2363 {
2364    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2365
2366    unsigned int state = 0;
2367
2368    initialize_modifier_bits(display);
2369
2370    if (scimkeymask & SCIM_KEY_ShiftMask)    state |= ShiftMask;
2371    if (scimkeymask & SCIM_KEY_CapsLockMask) state |= LockMask;
2372    if (scimkeymask & SCIM_KEY_ControlMask)  state |= ControlMask;
2373    if (scimkeymask & SCIM_KEY_AltMask)      state |= __current_alt_mask;
2374    if (scimkeymask & SCIM_KEY_MetaMask)     state |= __current_meta_mask;
2375    if (scimkeymask & SCIM_KEY_SuperMask)    state |= __current_super_mask;
2376    if (scimkeymask & SCIM_KEY_HyperMask)    state |= __current_hyper_mask;
2377    if (scimkeymask & SCIM_KEY_NumLockMask)  state |= __current_numlock_mask;
2378
2379    return state;
2380 }
2381
2382 static XKeyEvent createKeyEvent(Display *display, Window &win,
2383                                 Window &winRoot, bool press,
2384                                 int keycode, int modifiers)
2385 {
2386    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2387
2388    XKeyEvent event;
2389
2390    event.display     = display;
2391    event.window      = win;
2392    event.root        = winRoot;
2393    event.subwindow   = None;
2394    event.time        = CurrentTime;
2395    event.x           = 1;
2396    event.y           = 1;
2397    event.x_root      = 1;
2398    event.y_root      = 1;
2399    event.same_screen = EINA_TRUE;
2400    event.state       = modifiers;
2401    event.keycode     = XKeysymToKeycode(display, keycode);
2402    if (press)
2403      event.type = KeyPress;
2404    else
2405      event.type = KeyRelease;
2406    event.send_event  = EINA_FALSE;
2407    event.serial = 0;
2408
2409    return event;
2410 }
2411
2412 static void _x_send_key_event(const KeyEvent &key)
2413 {
2414    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2415
2416    // Obtain the X11 display.
2417    Display *display = XOpenDisplay(NULL);
2418    if (display == NULL)
2419      {
2420         std::cerr << "XOpenDisplay failed\n";
2421         return;
2422      }
2423
2424    // Get the root window for the current display.
2425    Window winRoot = 0;
2426
2427    // Find the window which has the current keyboard focus.
2428    Window winFocus = 0;
2429    int revert = RevertToParent;
2430
2431    XGetInputFocus(display, &winFocus, &revert);
2432
2433    // Send a fake key press event to the window.
2434    XSelectInput(display, winFocus, FocusChangeMask|KeyPressMask|KeyReleaseMask);
2435    XMapWindow(display, winFocus);
2436
2437    unsigned int modifier = scim_x11_keymask_scim_to_x11(display, key.mask);
2438    XKeyEvent event;
2439    if (key.is_key_press())
2440      {
2441         event = createKeyEvent(display, winFocus, winRoot, true, key.code, modifier);
2442         XSendEvent(event.display, event.window, True, KeyPressMask, (XEvent *)&event);
2443      }
2444    else
2445      {
2446         event = createKeyEvent(display, winFocus, winRoot, false, key.code, modifier);
2447         XSendEvent(event.display, event.window, True, KeyReleaseMask, (XEvent *)&event);
2448      }
2449
2450    XCloseDisplay(display);
2451 }
2452
2453 static void
2454 attach_instance(const IMEngineInstancePointer &si)
2455 {
2456    si->signal_connect_show_preedit_string(
2457       slot(slot_show_preedit_string));
2458    si->signal_connect_show_aux_string(
2459       slot(slot_show_aux_string));
2460    si->signal_connect_show_lookup_table(
2461       slot(slot_show_lookup_table));
2462
2463    si->signal_connect_hide_preedit_string(
2464       slot(slot_hide_preedit_string));
2465    si->signal_connect_hide_aux_string(
2466       slot(slot_hide_aux_string));
2467    si->signal_connect_hide_lookup_table(
2468       slot(slot_hide_lookup_table));
2469
2470    si->signal_connect_update_preedit_caret(
2471       slot(slot_update_preedit_caret));
2472    si->signal_connect_update_preedit_string(
2473       slot(slot_update_preedit_string));
2474    si->signal_connect_update_aux_string(
2475       slot(slot_update_aux_string));
2476    si->signal_connect_update_lookup_table(
2477       slot(slot_update_lookup_table));
2478
2479    si->signal_connect_commit_string(
2480       slot(slot_commit_string));
2481
2482    si->signal_connect_forward_key_event(
2483       slot(slot_forward_key_event));
2484
2485    si->signal_connect_register_properties(
2486       slot(slot_register_properties));
2487
2488    si->signal_connect_update_property(
2489       slot(slot_update_property));
2490
2491    si->signal_connect_beep(
2492       slot(slot_beep));
2493
2494    si->signal_connect_start_helper(
2495       slot(slot_start_helper));
2496
2497    si->signal_connect_stop_helper(
2498       slot(slot_stop_helper));
2499
2500    si->signal_connect_send_helper_event(
2501       slot(slot_send_helper_event));
2502
2503    si->signal_connect_get_surrounding_text(
2504       slot(slot_get_surrounding_text));
2505
2506    si->signal_connect_delete_surrounding_text(
2507       slot(slot_delete_surrounding_text));
2508 }
2509
2510 // Implementation of slot functions
2511 static void
2512 slot_show_preedit_string(IMEngineInstanceBase *si)
2513 {
2514    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2515
2516    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2517
2518    if (ic && ic->impl && _focused_ic == ic)
2519      {
2520         if (ic->impl->use_preedit)
2521           {
2522              if (!ic->impl->preedit_started)
2523                {
2524                   ecore_imf_context_preedit_start_event_add(_focused_ic->ctx);
2525                   ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
2526                   ic->impl->preedit_started = true;
2527                }
2528           }
2529         else
2530           _panel_client.show_preedit_string(ic->id);
2531      }
2532 }
2533
2534 static void
2535 slot_show_aux_string(IMEngineInstanceBase *si)
2536 {
2537    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2538
2539    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2540
2541    if (ic && ic->impl && _focused_ic == ic)
2542      _panel_client.show_aux_string(ic->id);
2543 }
2544
2545 static void
2546 slot_show_lookup_table(IMEngineInstanceBase *si)
2547 {
2548    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2549
2550    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2551
2552    if (ic && ic->impl && _focused_ic == ic)
2553      _panel_client.show_lookup_table(ic->id);
2554 }
2555
2556 static void
2557 slot_hide_preedit_string(IMEngineInstanceBase *si)
2558 {
2559    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2560
2561    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2562
2563    if (ic && ic->impl && _focused_ic == ic)
2564      {
2565         bool emit = false;
2566         if (ic->impl->preedit_string.length())
2567           {
2568              ic->impl->preedit_string = WideString();
2569              ic->impl->preedit_caret = 0;
2570              ic->impl->preedit_attrlist.clear();
2571              emit = true;
2572           }
2573         if (ic->impl->use_preedit)
2574           {
2575              if (emit)
2576                {
2577                   ecore_imf_context_preedit_changed_event_add(ic->ctx);
2578                   ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
2579                }
2580              if (ic->impl->preedit_started)
2581                {
2582                   ecore_imf_context_preedit_end_event_add(ic->ctx);
2583                   ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
2584                   ic->impl->preedit_started = false;
2585                }
2586           }
2587         else
2588           _panel_client.hide_preedit_string(ic->id);
2589      }
2590 }
2591
2592 static void
2593 slot_hide_aux_string(IMEngineInstanceBase *si)
2594 {
2595    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2596
2597    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2598
2599    if (ic && ic->impl && _focused_ic == ic)
2600      _panel_client.hide_aux_string(ic->id);
2601 }
2602
2603 static void
2604 slot_hide_lookup_table(IMEngineInstanceBase *si)
2605 {
2606    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2607
2608    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2609
2610    if (ic && ic->impl && _focused_ic == ic)
2611      _panel_client.hide_lookup_table(ic->id);
2612 }
2613
2614 static void
2615 slot_update_preedit_caret(IMEngineInstanceBase *si, int caret)
2616 {
2617    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2618
2619    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2620
2621    if (ic && ic->impl && _focused_ic == ic && ic->impl->preedit_caret != caret)
2622      {
2623         ic->impl->preedit_caret = caret;
2624         if (ic->impl->use_preedit)
2625           {
2626              if (!ic->impl->preedit_started)
2627                {
2628                   ecore_imf_context_preedit_start_event_add(ic->ctx);
2629                   ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
2630                   ic->impl->preedit_started = true;
2631                }
2632              ecore_imf_context_preedit_changed_event_add(ic->ctx);
2633              ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
2634           }
2635         else
2636           _panel_client.update_preedit_caret(ic->id, caret);
2637      }
2638 }
2639
2640 static void
2641 slot_update_preedit_string(IMEngineInstanceBase *si,
2642                             const WideString & str,
2643                             const AttributeList & attrs)
2644 {
2645    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2646
2647    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2648
2649    if (ic && ic->impl && _focused_ic == ic && (ic->impl->preedit_string != str || str.length()))
2650      {
2651         ic->impl->preedit_string   = str;
2652         ic->impl->preedit_attrlist = attrs;
2653         if (ic->impl->use_preedit)
2654           {
2655              if (!ic->impl->preedit_started)
2656                {
2657                   ecore_imf_context_preedit_start_event_add(_focused_ic->ctx);
2658                   ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
2659                   ic->impl->preedit_started = true;
2660                }
2661              ic->impl->preedit_caret    = str.length();
2662              ic->impl->preedit_updating = true;
2663              ecore_imf_context_preedit_changed_event_add(ic->ctx);
2664              ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
2665              ic->impl->preedit_updating = false;
2666           }
2667         else
2668           {
2669              _panel_client.update_preedit_string(ic->id, str, attrs);
2670           }
2671      }
2672 }
2673
2674 static void
2675 slot_update_aux_string(IMEngineInstanceBase *si,
2676                         const WideString & str,
2677                         const AttributeList & attrs)
2678 {
2679    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2680
2681    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2682
2683    if (ic && ic->impl && _focused_ic == ic)
2684      _panel_client.update_aux_string(ic->id, str, attrs);
2685 }
2686
2687 static void
2688 slot_commit_string(IMEngineInstanceBase *si,
2689                     const WideString & str)
2690 {
2691    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2692
2693    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2694
2695    if (ic && ic->ctx)
2696      {
2697         ecore_imf_context_commit_event_add(ic->ctx, utf8_wcstombs(str).c_str());
2698         ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(str).c_str());
2699      }
2700 }
2701
2702 static void
2703 slot_forward_key_event(IMEngineInstanceBase *si,
2704                         const KeyEvent & key)
2705 {
2706    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2707
2708    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2709
2710    if (ic && _focused_ic == ic)
2711      {
2712         if (!_fallback_instance->process_key_event(key))
2713           _x_send_key_event(key);
2714      }
2715 }
2716
2717 static void
2718 slot_update_lookup_table(IMEngineInstanceBase *si,
2719                           const LookupTable & table)
2720 {
2721    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2722
2723    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2724
2725    if (ic && ic->impl && _focused_ic == ic)
2726      _panel_client.update_lookup_table(ic->id, table);
2727 }
2728
2729 static void
2730 slot_register_properties(IMEngineInstanceBase *si,
2731                          const PropertyList & properties)
2732 {
2733    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2734
2735    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2736
2737    if (ic && ic->impl && _focused_ic == ic)
2738      _panel_client.register_properties(ic->id, properties);
2739 }
2740
2741 static void
2742 slot_update_property(IMEngineInstanceBase *si,
2743                      const Property & property)
2744 {
2745    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2746
2747    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2748
2749    if (ic && ic->impl && _focused_ic == ic)
2750      _panel_client.update_property(ic->id, property);
2751 }
2752
2753 static void
2754 slot_beep(IMEngineInstanceBase *si __UNUSED__)
2755 {
2756    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2757 }
2758
2759 static void
2760 slot_start_helper(IMEngineInstanceBase *si,
2761                   const String &helper_uuid)
2762 {
2763    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2764
2765    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " helper= " << helper_uuid << " context="
2766       << (ic ? ic->id : -1) << " ic=" << ic
2767       << " ic-uuid=" << ((ic ) ? ic->impl->si->get_factory_uuid() : "") << "...\n";
2768
2769    if (ic && ic->impl)
2770      _panel_client.start_helper(ic->id, helper_uuid);
2771 }
2772
2773 static void
2774 slot_stop_helper(IMEngineInstanceBase *si,
2775                  const String &helper_uuid)
2776 {
2777    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2778
2779    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " helper= " << helper_uuid << " context=" << (ic ? ic->id : -1) << " ic=" << ic << "...\n";
2780
2781    if (ic && ic->impl)
2782      _panel_client.stop_helper(ic->id, helper_uuid);
2783 }
2784
2785 static void
2786 slot_send_helper_event(IMEngineInstanceBase *si,
2787                        const String      &helper_uuid,
2788                        const Transaction &trans)
2789 {
2790    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2791
2792    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " helper= " << helper_uuid << " context="
2793       << (ic ? ic->id : -1) << " ic=" << ic
2794       << " ic-uuid=" << ((ic) ? ic->impl->si->get_factory_uuid() : "") << "...\n";
2795
2796    if (ic && ic->impl)
2797      _panel_client.send_helper_event(ic->id, helper_uuid, trans);
2798 }
2799
2800 static bool
2801 slot_get_surrounding_text(IMEngineInstanceBase *si,
2802                           WideString            &text,
2803                           int                   &cursor,
2804                           int                    maxlen_before,
2805                           int                    maxlen_after)
2806 {
2807    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2808
2809    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2810
2811    if (ic && ic->impl && _focused_ic == ic)
2812      {
2813         char *surrounding = NULL;
2814         int   cursor_index;
2815         if (ecore_imf_context_surrounding_get(_focused_ic->ctx, &surrounding, &cursor_index))
2816           {
2817              SCIM_DEBUG_FRONTEND(2) << "Surrounding text: " << surrounding <<"\n";
2818              SCIM_DEBUG_FRONTEND(2) << "Cursor Index    : " << cursor_index <<"\n";
2819              WideString before(utf8_mbstowcs(String(surrounding, surrounding + cursor_index)));
2820              WideString after(utf8_mbstowcs(String(surrounding + cursor_index)));
2821              if (maxlen_before > 0 && ((unsigned int)maxlen_before) < before.length())
2822                before = WideString(before.begin() + (before.length() - maxlen_before), before.end());
2823              else if (maxlen_before == 0) before = WideString();
2824              if (maxlen_after > 0 && ((unsigned int)maxlen_after) < after.length())
2825                after = WideString(after.begin(), after.begin() + maxlen_after);
2826              else if (maxlen_after == 0) after = WideString();
2827              text = before + after;
2828              cursor = before.length();
2829              return true;
2830           }
2831      }
2832    return false;
2833 }
2834
2835 static bool
2836 slot_delete_surrounding_text(IMEngineInstanceBase *si,
2837                              int                   offset,
2838                              int                   len)
2839 {
2840    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2841
2842    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2843
2844    if (ic && ic->impl && _focused_ic == ic)
2845      {
2846         Ecore_IMF_Event_Delete_Surrounding ev;
2847         ev.ctx = _focused_ic->ctx;
2848         ev.n_chars = len;
2849         ev.offset = offset;
2850         ecore_imf_context_delete_surrounding_event_add(_focused_ic->ctx, offset, len);
2851         ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, &ev);
2852         return true;
2853      }
2854    return false;
2855 }
2856
2857 static void
2858 reload_config_callback(const ConfigPointer &config)
2859 {
2860    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2861
2862    _frontend_hotkey_matcher.load_hotkeys(config);
2863    _imengine_hotkey_matcher.load_hotkeys(config);
2864
2865    KeyEvent key;
2866
2867    scim_string_to_key(key,
2868                       config->read(String(SCIM_CONFIG_HOTKEYS_FRONTEND_VALID_KEY_MASK),
2869                                      String("Shift+Control+Alt+Lock")));
2870
2871    _valid_key_mask = (key.mask > 0)?(key.mask):0xFFFF;
2872    _valid_key_mask |= SCIM_KEY_ReleaseMask;
2873    // Special treatment for two backslash keys on jp106 keyboard.
2874    _valid_key_mask |= SCIM_KEY_QuirkKanaRoMask;
2875
2876    _on_the_spot = config->read(String(SCIM_CONFIG_FRONTEND_ON_THE_SPOT), _on_the_spot);
2877    _shared_input_method = config->read(String(SCIM_CONFIG_FRONTEND_SHARED_INPUT_METHOD), _shared_input_method);
2878
2879    // Get keyboard layout setting
2880    // Flush the global config first, in order to load the new configs from disk.
2881    scim_global_config_flush();
2882
2883    _keyboard_layout = scim_get_default_keyboard_layout();
2884 }
2885
2886 static void
2887 fallback_commit_string_cb(IMEngineInstanceBase  *si __UNUSED__,
2888                           const WideString      &str)
2889 {
2890    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2891
2892    if (_focused_ic && _focused_ic->impl)
2893      {
2894         ecore_imf_context_commit_event_add(_focused_ic->ctx, utf8_wcstombs(str).c_str());
2895         ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(str).c_str());
2896      }
2897 }
2898