Tizen 2.1 base
[framework/uifw/ecore.git] / src / modules / immodules / ibus / ibus_imcontext.c
1 #ifdef HAVE_CONFIG_H
2 #include <config.h>
3 #endif
4
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <sys/time.h>
8 #include <sys/un.h>
9 #include <string.h>
10 #include <stdlib.h>
11 #include <glib.h>
12
13 #include <X11/Xlib.h>
14 #include <Ecore_X.h>
15 #include <Ecore_Evas.h>
16
17 #include <ibus.h>
18 #include "ibus_imcontext.h"
19
20 struct _IBusIMContext
21 {
22    /* instance members */
23    Ecore_IMF_Context *ctx;
24
25    /* enabled */
26    Eina_Bool        enable;
27    IBusInputContext *ibuscontext;
28
29    /* preedit status */
30    char            *preedit_string;
31    Eina_List       *preedit_attrs;
32    int              preedit_cursor_pos;
33    Eina_Bool        preedit_visible;
34
35    int              cursor_x;
36    int              cursor_y;
37    int              cursor_w;
38    int              cursor_h;
39
40    Eina_Bool        has_focus;
41
42    Ecore_X_Window   client_window;
43    Evas            *client_canvas;
44
45    int              caps;
46 };
47
48 typedef struct _KeyEvent KeyEvent;
49
50 struct _KeyEvent
51 {
52    int keysym;
53    int state;
54 };
55
56 static Eina_Bool _use_sync_mode = EINA_FALSE;
57
58 static Ecore_IMF_Context *_focus_im_context = NULL;
59 static IBusBus           *_bus = NULL;
60
61 /* functions prototype */
62 /* static methods*/
63 static void     _create_input_context       (IBusIMContext      *context);
64 static void     _set_cursor_location_internal
65 (Ecore_IMF_Context  *ctx);
66 static void     _bus_connected_cb           (IBusBus            *bus,
67                                              IBusIMContext      *context);
68 static XKeyEvent createXKeyEvent            (Window win, Eina_Bool press, int keysym, int modifiers);
69
70 static void
71 _window_to_screen_geometry_get(Ecore_X_Window client_win, int *x, int *y)
72 {
73    Ecore_X_Window root_window, win;
74    int win_x, win_y;
75    int sum_x = 0, sum_y = 0;
76
77    root_window = ecore_x_window_root_get(client_win);
78    win = client_win;
79
80    while (root_window != win)
81      {
82         ecore_x_window_geometry_get(win, &win_x, &win_y, NULL, NULL);
83         sum_x += win_x;
84         sum_y += win_y;
85         win = ecore_x_window_parent_get(win);
86      }
87
88    if (x)
89      *x = sum_x;
90    if (y)
91      *y = sum_y;
92 }
93
94 static unsigned int
95 _ecore_imf_modifier_to_ibus_modifier(unsigned int modifier)
96 {
97    unsigned int state = 0;
98
99    /**< "Control" is pressed */
100    if (modifier & ECORE_IMF_KEYBOARD_MODIFIER_CTRL)
101      state |= IBUS_CONTROL_MASK;
102
103    /**< "Alt" is pressed */
104    if (modifier & ECORE_IMF_KEYBOARD_MODIFIER_ALT)
105      state |= IBUS_MOD1_MASK;
106
107    /**< "Shift" is pressed */
108    if (modifier & ECORE_IMF_KEYBOARD_MODIFIER_SHIFT)
109      state |= IBUS_SHIFT_MASK;
110
111    /**< "Win" (between "Ctrl" and "Alt") */
112    if (modifier & ECORE_IMF_KEYBOARD_MODIFIER_WIN)
113      state |= IBUS_SUPER_MASK;
114
115    /**< "AltGr" is pressed */
116    if (modifier & ECORE_IMF_KEYBOARD_MODIFIER_ALTGR)
117      state |= IBUS_MOD5_MASK;
118
119    return state;
120 }
121
122 static void
123 key_event_put(int keysym, int state)
124 {
125    // Find the window which has the current keyboard focus.
126    Window winFocus = 0;
127    int revert = RevertToParent;
128
129    XGetInputFocus(ecore_x_display_get(), &winFocus, &revert);
130
131    XKeyEvent event;
132    if (state & IBUS_RELEASE_MASK)
133      {
134         event = createXKeyEvent(winFocus, EINA_FALSE, keysym, state);
135         XSendEvent(event.display, event.window, True, KeyReleaseMask, (XEvent *)&event);
136      }
137    else
138      {
139         event = createXKeyEvent(winFocus, EINA_TRUE, keysym, state);
140         XSendEvent(event.display, event.window, True, KeyPressMask, (XEvent *)&event);
141      }
142 }
143
144 static KeyEvent *
145 key_event_copy(int keysym, int state)
146 {
147    KeyEvent *kev = calloc(1, sizeof(KeyEvent));
148    kev->keysym = keysym;
149    kev->state = state;
150
151    return kev;
152 }
153
154 IBusIMContext *
155 ibus_im_context_new(void)
156 {
157    EINA_LOG_DBG("%s", __FUNCTION__);
158
159    IBusIMContext *context = calloc(1, sizeof(IBusIMContext));
160
161    /* init bus object */
162    if (_bus == NULL)
163      {
164         char *display_name = NULL;
165
166         if ((display_name = getenv("DISPLAY")))
167           ibus_set_display(display_name);
168         else
169           ibus_set_display(":0.0");
170
171         _bus = ibus_bus_new();
172      }
173
174    return context;
175 }
176
177 static void
178 _process_key_event_done (GObject      *object,
179                          GAsyncResult *res,
180                          gpointer      user_data)
181 {
182     IBusInputContext *context = (IBusInputContext *)object;
183     KeyEvent *event = (KeyEvent *)user_data;
184
185     GError *error = NULL;
186     Eina_Bool retval = ibus_input_context_process_key_event_async_finish(context,
187                                                                          res,
188                                                                          &error);
189
190     if (error != NULL)
191       {
192          g_warning("Process Key Event failed: %s.", error->message);
193          g_error_free(error);
194       }
195
196     if (retval == EINA_FALSE)
197       {
198          key_event_put(event->keysym, event->state);
199       }
200     free(event);
201 }
202
203 EAPI void
204 ibus_im_context_add(Ecore_IMF_Context *ctx)
205 {
206    EINA_LOG_DBG("%s", __FUNCTION__);
207
208    char *s = NULL;
209    IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx);
210    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
211
212    ibusimcontext->client_window = 0;
213
214    // Init ibus status
215    ibusimcontext->enable = EINA_FALSE;
216
217    // Init preedit status
218    ibusimcontext->preedit_string = NULL;
219    ibusimcontext->preedit_attrs = NULL;
220    ibusimcontext->preedit_cursor_pos = 0;
221    ibusimcontext->preedit_visible = EINA_FALSE;
222
223    // Init cursor area
224    ibusimcontext->cursor_x = -1;
225    ibusimcontext->cursor_y = -1;
226    ibusimcontext->cursor_w = 0;
227    ibusimcontext->cursor_h = 0;
228
229    ibusimcontext->ibuscontext = NULL;
230    ibusimcontext->has_focus = EINA_FALSE;
231    ibusimcontext->caps = IBUS_CAP_PREEDIT_TEXT | IBUS_CAP_FOCUS | IBUS_CAP_SURROUNDING_TEXT;
232    ibusimcontext->ctx = ctx;
233
234    s = getenv("IBUS_ENABLE_SYNC_MODE");
235    if (s)
236      _use_sync_mode = !!atoi(s);
237
238    if (ibus_bus_is_connected(_bus))
239      _create_input_context (ibusimcontext);
240
241    g_signal_connect(_bus, "connected", G_CALLBACK (_bus_connected_cb), ctx);
242 }
243
244 EAPI void
245 ibus_im_context_del(Ecore_IMF_Context *ctx)
246 {
247    EINA_LOG_DBG("%s", __FUNCTION__);
248
249    IBusIMContext *ibusimcontext = (IBusIMContext*)ecore_imf_context_data_get(ctx);
250    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
251
252    g_signal_handlers_disconnect_by_func(_bus, G_CALLBACK(_bus_connected_cb), ctx);
253
254    if (ibusimcontext->ibuscontext)
255      ibus_proxy_destroy((IBusProxy *)ibusimcontext->ibuscontext);
256
257    // release preedit
258    if (ibusimcontext->preedit_string)
259      free(ibusimcontext->preedit_string);
260    if (_focus_im_context == ctx)
261      _focus_im_context = NULL;
262 }
263
264 EAPI Eina_Bool
265 ibus_im_context_filter_event(Ecore_IMF_Context *ctx, Ecore_IMF_Event_Type type, Ecore_IMF_Event *event)
266 {
267    IBusIMContext *ibusimcontext = (IBusIMContext*)ecore_imf_context_data_get(ctx);
268    EINA_SAFETY_ON_NULL_RETURN_VAL(ibusimcontext, EINA_FALSE);
269
270    if (type != ECORE_IMF_EVENT_KEY_UP && type != ECORE_IMF_EVENT_KEY_DOWN)
271      return EINA_FALSE;
272
273    EINA_LOG_DBG("%s", __FUNCTION__);
274
275    if (G_LIKELY(ibusimcontext->ibuscontext && ibusimcontext->has_focus))
276      {
277         /* If context does not have focus, ibus will process key event in sync mode.
278          * It is a workaround for increase search in treeview.
279          */
280         Eina_Bool retval = EINA_FALSE;
281         int keycode;
282         int keysym;
283         unsigned int state = 0;
284
285         if (type == ECORE_IMF_EVENT_KEY_UP)
286           {
287              Ecore_IMF_Event_Key_Up *ev = (Ecore_IMF_Event_Key_Up *)event;
288              if (ev->timestamp == 0)
289                return EINA_FALSE;
290
291              keycode = ecore_x_keysym_keycode_get(ev->key);
292              keysym = XStringToKeysym(ev->key);
293              state = _ecore_imf_modifier_to_ibus_modifier(ev->modifiers) | IBUS_RELEASE_MASK;
294
295              if (_use_sync_mode)
296                {
297                   retval = ibus_input_context_process_key_event(ibusimcontext->ibuscontext,
298                                                                 keysym,
299                                                                 keycode - 8,
300                                                                 state);
301                }
302              else
303                {
304                   ibus_input_context_process_key_event_async(ibusimcontext->ibuscontext,
305                                                              keysym,
306                                                              keycode - 8,
307                                                              state,
308                                                              -1,
309                                                              NULL,
310                                                              _process_key_event_done,
311                                                              key_event_copy(keysym, state));
312                   retval = EINA_TRUE;
313                }
314           }
315         else if (type == ECORE_IMF_EVENT_KEY_DOWN)
316           {
317              Ecore_IMF_Event_Key_Down *ev = (Ecore_IMF_Event_Key_Down *)event;
318              if (ev->timestamp == 0)
319                return EINA_FALSE;
320
321              keycode = ecore_x_keysym_keycode_get(ev->key);
322              keysym = XStringToKeysym(ev->key);
323              state = _ecore_imf_modifier_to_ibus_modifier(ev->modifiers);
324              if (_use_sync_mode)
325                {
326                   retval = ibus_input_context_process_key_event(ibusimcontext->ibuscontext,
327                                                                 keysym,
328                                                                 keycode - 8,
329                                                                 state);
330                }
331              else
332                {
333                   ibus_input_context_process_key_event_async(ibusimcontext->ibuscontext,
334                                                              keysym,
335                                                              keycode - 8,
336                                                              state,
337                                                              -1,
338                                                              NULL,
339                                                              _process_key_event_done,
340                                                              key_event_copy(keysym, state));
341                   retval = EINA_TRUE;
342                }
343           }
344         else
345           retval = EINA_FALSE;
346
347         if (retval)
348           return EINA_TRUE;
349         else
350           return EINA_FALSE;
351      }
352    else
353      return EINA_FALSE;
354 }
355
356 EAPI void
357 ibus_im_context_focus_in(Ecore_IMF_Context *ctx)
358 {
359    EINA_LOG_DBG("ctx : %p", ctx);
360
361    IBusIMContext *ibusimcontext = (IBusIMContext*)ecore_imf_context_data_get(ctx);
362    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
363
364    if (ibusimcontext->has_focus)
365      return;
366
367    if (_focus_im_context != NULL)
368      ecore_imf_context_focus_out(_focus_im_context);
369
370    ibusimcontext->has_focus = EINA_TRUE;
371    if (ibusimcontext->ibuscontext)
372      ibus_input_context_focus_in(ibusimcontext->ibuscontext);
373
374    if (_focus_im_context != ctx)
375      _focus_im_context = ctx;
376 }
377
378 EAPI void
379 ibus_im_context_focus_out(Ecore_IMF_Context *ctx)
380 {
381    EINA_LOG_DBG("ctx : %p", ctx);
382
383    IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx);
384    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
385
386    if (ibusimcontext->has_focus == EINA_FALSE)
387      return;
388
389    if (_focus_im_context == ctx)
390      _focus_im_context = NULL;
391
392    ibusimcontext->has_focus = EINA_FALSE;
393    if (ibusimcontext->ibuscontext)
394      ibus_input_context_focus_out(ibusimcontext->ibuscontext);
395 }
396
397 EAPI void
398 ibus_im_context_reset(Ecore_IMF_Context *ctx)
399 {
400    IBusIMContext *ibusimcontext = (IBusIMContext*)ecore_imf_context_data_get(ctx);
401    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
402
403    if (ibusimcontext->ibuscontext)
404      ibus_input_context_reset(ibusimcontext->ibuscontext);
405 }
406
407 EAPI void
408 ibus_im_context_preedit_string_get(Ecore_IMF_Context *ctx,
409                                    char          **str,
410                                    int            *cursor_pos)
411 {
412    IBusIMContext *ibusimcontext = (IBusIMContext*)ecore_imf_context_data_get(ctx);
413    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
414
415    if (ibusimcontext->enable && ibusimcontext->preedit_visible)
416      {
417         if (str)
418           *str = strdup(ibusimcontext->preedit_string ? ibusimcontext->preedit_string: "");
419
420         if (cursor_pos)
421           *cursor_pos = ibusimcontext->preedit_cursor_pos;
422      }
423    else
424      {
425         if (str)
426           *str = strdup("");
427
428         if (cursor_pos)
429           *cursor_pos = 0;
430      }
431    EINA_LOG_DBG("str : %s, cursor_pos : %d", *str, *cursor_pos);
432 }
433
434 EAPI void
435 ibus_im_context_preedit_string_with_attributes_get(Ecore_IMF_Context   *ctx,
436                                                    char          **str,
437                                                    Eina_List     **attr __UNUSED__,
438                                                    int            *cursor_pos)
439 {
440    IBusIMContext *ibusimcontext = (IBusIMContext*)ecore_imf_context_data_get(ctx);
441    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
442
443    if (ibusimcontext->enable && ibusimcontext->preedit_visible)
444      {
445         if (str)
446           *str = strdup(ibusimcontext->preedit_string ? ibusimcontext->preedit_string: "");
447
448         if (cursor_pos)
449           *cursor_pos = ibusimcontext->preedit_cursor_pos;
450      }
451    else
452      {
453         if (str)
454           *str = strdup("");
455
456         if (cursor_pos)
457           *cursor_pos = 0;
458      }
459    EINA_LOG_DBG("str : %s, cursor_pos : %d", *str, *cursor_pos);
460 }
461
462 EAPI void
463 ibus_im_context_client_window_set(Ecore_IMF_Context *ctx, void *window)
464 {
465    EINA_LOG_DBG("canvas : %p", window);
466    IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx);
467    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
468
469    if (window != NULL)
470      ibusimcontext->client_window = (Ecore_X_Window)(Ecore_Window)window;
471 }
472
473 EAPI void
474 ibus_im_context_client_canvas_set(Ecore_IMF_Context *ctx, void *canvas)
475 {
476    EINA_LOG_DBG("canvas : %p", canvas);
477    IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx);
478    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
479
480    if (canvas != NULL)
481      ibusimcontext->client_canvas = canvas;
482 }
483
484 static void
485 _set_cursor_location_internal(Ecore_IMF_Context *ctx)
486 {
487    IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx);
488    Ecore_Evas *ee;
489    int canvas_x, canvas_y;
490
491    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
492
493    if (ibusimcontext->ibuscontext == NULL)
494      return;
495
496    if (ibusimcontext->client_canvas)
497      {
498         ee = ecore_evas_ecore_evas_get(ibusimcontext->client_canvas);
499         if (!ee) return;
500
501         ecore_evas_geometry_get(ee, &canvas_x, &canvas_y, NULL, NULL);
502      }
503    else
504      {
505         if (ibusimcontext->client_window)
506           _window_to_screen_geometry_get(ibusimcontext->client_window, &canvas_x, &canvas_y);
507         else
508           return;
509      }
510
511    ibus_input_context_set_cursor_location(ibusimcontext->ibuscontext,
512                                           ibusimcontext->cursor_x + canvas_x,
513                                           ibusimcontext->cursor_y + canvas_y,
514                                           ibusimcontext->cursor_w,
515                                           ibusimcontext->cursor_h);
516 }
517
518 EAPI void
519 ibus_im_context_cursor_location_set(Ecore_IMF_Context *ctx, int x, int y, int w, int h)
520 {
521    EINA_LOG_DBG("x : %d, y : %d, w, %d, h :%d", x, y, w, h);
522    IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx);
523    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
524
525    if (ibusimcontext->cursor_x != x ||
526        ibusimcontext->cursor_y != y ||
527        ibusimcontext->cursor_w != w ||
528        ibusimcontext->cursor_h != h)
529      {
530         ibusimcontext->cursor_x = x;
531         ibusimcontext->cursor_y = y;
532         ibusimcontext->cursor_w = w;
533         ibusimcontext->cursor_h = h;
534
535         _set_cursor_location_internal(ctx);
536      }
537 }
538
539 EAPI void
540 ibus_im_context_use_preedit_set(Ecore_IMF_Context *ctx, Eina_Bool use_preedit)
541 {
542    EINA_LOG_DBG("preedit : %d", use_preedit);
543    IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx);
544    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
545
546    if (ibusimcontext->ibuscontext)
547      {
548         if (use_preedit)
549           ibusimcontext->caps |= IBUS_CAP_PREEDIT_TEXT;
550         else
551           ibusimcontext->caps &= ~IBUS_CAP_PREEDIT_TEXT;
552
553         ibus_input_context_set_capabilities(ibusimcontext->ibuscontext, ibusimcontext->caps);
554      }
555 }
556
557 static void
558 _bus_connected_cb(IBusBus          *bus __UNUSED__,
559                   IBusIMContext    *ibusimcontext)
560 {
561    EINA_LOG_DBG("ibus is connected");
562
563    if (ibusimcontext)
564      _create_input_context(ibusimcontext);
565 }
566
567 static void
568 _ibus_context_commit_text_cb(IBusInputContext *ibuscontext __UNUSED__,
569                              IBusText         *text,
570                              IBusIMContext    *ibusimcontext)
571 {
572    if (!ibusimcontext || !text) return;
573    char *commit_str = text->text ? text->text : "";
574
575    EINA_LOG_DBG("commit string : %s", commit_str);
576
577    if (ibusimcontext->ctx)
578      {
579         ecore_imf_context_commit_event_add(ibusimcontext->ctx, text->text);
580         ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)commit_str);
581      }
582 }
583
584 static XKeyEvent createXKeyEvent(Window win, Eina_Bool press, int keysym, int modifiers)
585 {
586    XKeyEvent event;
587    Display *display = ecore_x_display_get();
588
589    event.display     = display;
590    event.window      = win;
591    event.root        = ecore_x_window_root_get(win);
592    event.subwindow   = None;
593    event.time        = 0;
594    event.x           = 1;
595    event.y           = 1;
596    event.x_root      = 1;
597    event.y_root      = 1;
598    event.same_screen = EINA_TRUE;
599    event.state       = modifiers;
600    event.keycode     = XKeysymToKeycode(display, keysym);
601    if (press)
602      event.type = KeyPress;
603    else
604      event.type = KeyRelease;
605    event.send_event  = EINA_FALSE;
606    event.serial = 0;
607
608    return event;
609 }
610
611 static void
612 _ibus_context_forward_key_event_cb(IBusInputContext  *ibuscontext __UNUSED__,
613                                    guint              keyval,
614                                    guint              state,
615                                    IBusIMContext     *ibusimcontext __UNUSED__)
616 {
617    EINA_LOG_DBG("keyval : %d, state : %d", keyval, state);
618
619    key_event_put(keyval, state);
620 }
621
622 static void
623 _ibus_context_update_preedit_text_cb(IBusInputContext  *ibuscontext __UNUSED__,
624                                      IBusText          *text,
625                                      gint               cursor_pos,
626                                      gboolean           visible,
627                                      IBusIMContext     *ibusimcontext)
628 {
629    if (!ibusimcontext || !text) return;
630
631    const char *str;
632    gboolean flag;
633
634    if (ibusimcontext->preedit_string)
635      free (ibusimcontext->preedit_string);
636
637    str = text->text;
638
639    if (str)
640      ibusimcontext->preedit_string = strdup(str);
641    else
642      ibusimcontext->preedit_string = strdup("");
643
644    ibusimcontext->preedit_cursor_pos = cursor_pos;
645
646    EINA_LOG_DBG("string : %s, cursor : %d", ibusimcontext->preedit_string, ibusimcontext->preedit_cursor_pos);
647
648    flag = ibusimcontext->preedit_visible != visible;
649    ibusimcontext->preedit_visible = visible;
650
651    if (ibusimcontext->preedit_visible)
652      {
653         if (flag)
654           {
655              ecore_imf_context_preedit_start_event_add(ibusimcontext->ctx);
656              ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
657           }
658
659         ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx);
660         ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
661      }
662    else
663      {
664         if (flag)
665           {
666              ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx);
667              ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
668           }
669
670         ecore_imf_context_preedit_end_event_add(ibusimcontext->ctx);
671         ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
672      }
673 }
674
675 static void
676 _ibus_context_show_preedit_text_cb(IBusInputContext *ibuscontext __UNUSED__,
677                                    IBusIMContext    *ibusimcontext)
678 {
679    EINA_LOG_DBG("preedit visible : %d", ibusimcontext->preedit_visible);
680    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
681
682    if (ibusimcontext->preedit_visible == EINA_TRUE)
683      return;
684
685    ibusimcontext->preedit_visible = EINA_TRUE;
686
687    // call preedit start
688    ecore_imf_context_preedit_start_event_add(ibusimcontext->ctx);
689    ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
690
691    // call preedit changed
692    ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx);
693    ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
694 }
695
696 static void
697 _ibus_context_hide_preedit_text_cb(IBusInputContext *ibuscontext __UNUSED__,
698                                    IBusIMContext    *ibusimcontext)
699 {
700    EINA_LOG_DBG("%s", __FUNCTION__);
701    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
702
703    if (ibusimcontext->preedit_visible == EINA_FALSE)
704      return;
705
706    ibusimcontext->preedit_visible = EINA_FALSE;
707
708    // call preedit changed
709    ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx);
710    ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
711
712    // call preedit end
713    ecore_imf_context_preedit_end_event_add(ibusimcontext->ctx);
714    ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
715 }
716
717 static void
718 _ibus_context_enabled_cb(IBusInputContext *ibuscontext __UNUSED__,
719                          IBusIMContext    *ibusimcontext)
720 {
721    EINA_LOG_DBG("%s", __FUNCTION__);
722    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
723
724    ibusimcontext->enable = EINA_TRUE;
725 }
726
727 static void
728 _ibus_context_disabled_cb(IBusInputContext *ibuscontext __UNUSED__,
729                           IBusIMContext    *ibusimcontext)
730 {
731    EINA_LOG_DBG("%s", __FUNCTION__);
732    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
733
734    ibusimcontext->enable = EINA_FALSE;
735
736    /* clear preedit */
737    ibusimcontext->preedit_visible = EINA_FALSE;
738    ibusimcontext->preedit_cursor_pos = 0;
739    free (ibusimcontext->preedit_string);
740    ibusimcontext->preedit_string = NULL;
741
742    // call preedit changed
743    ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx);
744    ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
745
746    // call preedit end
747    ecore_imf_context_preedit_end_event_add(ibusimcontext->ctx);
748    ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
749 }
750
751 static void
752 _ibus_context_destroy_cb(IBusInputContext *ibuscontext __UNUSED__,
753                          IBusIMContext    *ibusimcontext)
754 {
755    EINA_LOG_DBG("%s", __FUNCTION__);
756    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
757
758    ibusimcontext->ibuscontext = NULL;
759    ibusimcontext->enable = EINA_FALSE;
760
761    /* clear preedit */
762    ibusimcontext->preedit_visible = EINA_FALSE;
763    ibusimcontext->preedit_cursor_pos = 0;
764    free (ibusimcontext->preedit_string);
765    ibusimcontext->preedit_string = NULL;
766
767    // call preedit changed
768    ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx);
769    ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
770
771    // call preedit end
772    ecore_imf_context_preedit_end_event_add(ibusimcontext->ctx);
773    ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
774 }
775
776 static void
777 _create_input_context(IBusIMContext *ibusimcontext)
778 {
779    EINA_LOG_DBG("%s", __FUNCTION__);
780    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
781
782    ibusimcontext->ibuscontext = ibus_bus_create_input_context(_bus, "ecore");
783
784    g_return_if_fail(ibusimcontext->ibuscontext != NULL);
785
786    g_signal_connect(ibusimcontext->ibuscontext,
787                     "commit-text",
788                     G_CALLBACK (_ibus_context_commit_text_cb),
789                     ibusimcontext);
790    g_signal_connect(ibusimcontext->ibuscontext,
791                     "forward-key-event",
792                     G_CALLBACK (_ibus_context_forward_key_event_cb),
793                     ibusimcontext);
794    g_signal_connect(ibusimcontext->ibuscontext,
795                     "update-preedit-text",
796                     G_CALLBACK (_ibus_context_update_preedit_text_cb),
797                     ibusimcontext);
798    g_signal_connect(ibusimcontext->ibuscontext,
799                     "show-preedit-text",
800                     G_CALLBACK (_ibus_context_show_preedit_text_cb),
801                     ibusimcontext);
802    g_signal_connect(ibusimcontext->ibuscontext,
803                     "hide-preedit-text",
804                     G_CALLBACK (_ibus_context_hide_preedit_text_cb),
805                     ibusimcontext);
806    g_signal_connect(ibusimcontext->ibuscontext,
807                     "enabled",
808                     G_CALLBACK (_ibus_context_enabled_cb),
809                     ibusimcontext);
810    g_signal_connect(ibusimcontext->ibuscontext,
811                     "disabled",
812                     G_CALLBACK (_ibus_context_disabled_cb),
813                     ibusimcontext);
814    g_signal_connect(ibusimcontext->ibuscontext, "destroy",
815                     G_CALLBACK (_ibus_context_destroy_cb),
816                     ibusimcontext);
817
818    ibus_input_context_set_capabilities(ibusimcontext->ibuscontext, ibusimcontext->caps);
819
820    if (ibusimcontext->has_focus)
821      ibus_input_context_focus_in(ibusimcontext->ibuscontext);
822 }