2c2e180c032698b1cbc11b0d2b0dbb8ec8ee34cc
[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 }
261
262 EAPI Eina_Bool
263 ibus_im_context_filter_event(Ecore_IMF_Context *ctx, Ecore_IMF_Event_Type type, Ecore_IMF_Event *event)
264 {
265    IBusIMContext *ibusimcontext = (IBusIMContext*)ecore_imf_context_data_get(ctx);
266    EINA_SAFETY_ON_NULL_RETURN_VAL(ibusimcontext, EINA_FALSE);
267
268    if (type != ECORE_IMF_EVENT_KEY_UP && type != ECORE_IMF_EVENT_KEY_DOWN)
269      return EINA_FALSE;
270
271    EINA_LOG_DBG("%s", __FUNCTION__);
272
273    if (G_LIKELY(ibusimcontext->ibuscontext && ibusimcontext->has_focus))
274      {
275         /* If context does not have focus, ibus will process key event in sync mode.
276          * It is a workaround for increase search in treeview.
277          */
278         Eina_Bool retval = EINA_FALSE;
279         int keycode;
280         int keysym;
281         unsigned int state = 0;
282
283         if (type == ECORE_IMF_EVENT_KEY_UP)
284           {
285              Ecore_IMF_Event_Key_Up *ev = (Ecore_IMF_Event_Key_Up *)event;
286              if (ev->timestamp == 0)
287                return EINA_FALSE;
288
289              keycode = ecore_x_keysym_keycode_get(ev->key);
290              keysym = XStringToKeysym(ev->key);
291              state = _ecore_imf_modifier_to_ibus_modifier(ev->modifiers) | IBUS_RELEASE_MASK;
292
293              if (_use_sync_mode)
294                {
295                   retval = ibus_input_context_process_key_event(ibusimcontext->ibuscontext,
296                                                                 keysym,
297                                                                 keycode - 8,
298                                                                 state);
299                }
300              else
301                {
302                   ibus_input_context_process_key_event_async(ibusimcontext->ibuscontext,
303                                                              keysym,
304                                                              keycode - 8,
305                                                              state,
306                                                              -1,
307                                                              NULL,
308                                                              _process_key_event_done,
309                                                              key_event_copy(keysym, state));
310                   retval = EINA_TRUE;
311                }
312           }
313         else if (type == ECORE_IMF_EVENT_KEY_DOWN)
314           {
315              Ecore_IMF_Event_Key_Down *ev = (Ecore_IMF_Event_Key_Down *)event;
316              if (ev->timestamp == 0)
317                return EINA_FALSE;
318
319              keycode = ecore_x_keysym_keycode_get(ev->key);
320              keysym = XStringToKeysym(ev->key);
321              state = _ecore_imf_modifier_to_ibus_modifier(ev->modifiers);
322              if (_use_sync_mode)
323                {
324                   retval = ibus_input_context_process_key_event(ibusimcontext->ibuscontext,
325                                                                 keysym,
326                                                                 keycode - 8,
327                                                                 state);
328                }
329              else
330                {
331                   ibus_input_context_process_key_event_async(ibusimcontext->ibuscontext,
332                                                              keysym,
333                                                              keycode - 8,
334                                                              state,
335                                                              -1,
336                                                              NULL,
337                                                              _process_key_event_done,
338                                                              key_event_copy(keysym, state));
339                   retval = EINA_TRUE;
340                }
341           }
342         else
343           retval = EINA_FALSE;
344
345         if (retval)
346           return EINA_TRUE;
347         else
348           return EINA_FALSE;
349      }
350    else
351      return EINA_FALSE;
352 }
353
354 EAPI void
355 ibus_im_context_focus_in(Ecore_IMF_Context *ctx)
356 {
357    EINA_LOG_DBG("ctx : %p", ctx);
358
359    IBusIMContext *ibusimcontext = (IBusIMContext*)ecore_imf_context_data_get(ctx);
360    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
361
362    if (ibusimcontext->has_focus)
363      return;
364
365    if (_focus_im_context != NULL)
366      ecore_imf_context_focus_out(_focus_im_context);
367
368    ibusimcontext->has_focus = EINA_TRUE;
369    if (ibusimcontext->ibuscontext)
370      ibus_input_context_focus_in(ibusimcontext->ibuscontext);
371
372    if (_focus_im_context != ctx)
373      _focus_im_context = ctx;
374 }
375
376 EAPI void
377 ibus_im_context_focus_out(Ecore_IMF_Context *ctx)
378 {
379    EINA_LOG_DBG("ctx : %p", ctx);
380
381    IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx);
382    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
383
384    if (ibusimcontext->has_focus == EINA_FALSE)
385      return;
386
387    if (_focus_im_context == ctx)
388      _focus_im_context = NULL;
389
390    ibusimcontext->has_focus = EINA_FALSE;
391    if (ibusimcontext->ibuscontext)
392      ibus_input_context_focus_out(ibusimcontext->ibuscontext);
393 }
394
395 EAPI void
396 ibus_im_context_reset(Ecore_IMF_Context *ctx)
397 {
398    IBusIMContext *ibusimcontext = (IBusIMContext*)ecore_imf_context_data_get(ctx);
399    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
400
401    if (ibusimcontext->ibuscontext)
402      ibus_input_context_reset(ibusimcontext->ibuscontext);
403 }
404
405 EAPI void
406 ibus_im_context_preedit_string_get(Ecore_IMF_Context *ctx,
407                                    char          **str,
408                                    int            *cursor_pos)
409 {
410    IBusIMContext *ibusimcontext = (IBusIMContext*)ecore_imf_context_data_get(ctx);
411    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
412
413    if (ibusimcontext->enable && ibusimcontext->preedit_visible)
414      {
415         if (str)
416           *str = strdup(ibusimcontext->preedit_string ? ibusimcontext->preedit_string: "");
417
418         if (cursor_pos)
419           *cursor_pos = ibusimcontext->preedit_cursor_pos;
420      }
421    else
422      {
423         if (str)
424           *str = strdup("");
425
426         if (cursor_pos)
427           *cursor_pos = 0;
428      }
429    EINA_LOG_DBG("str : %s, cursor_pos : %d", *str, *cursor_pos);
430 }
431
432 EAPI void
433 ibus_im_context_preedit_string_with_attributes_get(Ecore_IMF_Context   *ctx,
434                                                    char          **str,
435                                                    Eina_List     **attr __UNUSED__,
436                                                    int            *cursor_pos)
437 {
438    IBusIMContext *ibusimcontext = (IBusIMContext*)ecore_imf_context_data_get(ctx);
439    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
440
441    if (ibusimcontext->enable && ibusimcontext->preedit_visible)
442      {
443         if (str)
444           *str = strdup(ibusimcontext->preedit_string ? ibusimcontext->preedit_string: "");
445
446         if (cursor_pos)
447           *cursor_pos = ibusimcontext->preedit_cursor_pos;
448      }
449    else
450      {
451         if (str)
452           *str = strdup("");
453
454         if (cursor_pos)
455           *cursor_pos = 0;
456      }
457    EINA_LOG_DBG("str : %s, cursor_pos : %d", *str, *cursor_pos);
458 }
459
460 EAPI void
461 ibus_im_context_client_window_set(Ecore_IMF_Context *ctx, void *window)
462 {
463    EINA_LOG_DBG("canvas : %p", window);
464    IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx);
465    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
466
467    if (window != NULL)
468      ibusimcontext->client_window = (Ecore_X_Window)(Ecore_Window)window;
469 }
470
471 EAPI void
472 ibus_im_context_client_canvas_set(Ecore_IMF_Context *ctx, void *canvas)
473 {
474    EINA_LOG_DBG("canvas : %p", canvas);
475    IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx);
476    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
477
478    if (canvas != NULL)
479      ibusimcontext->client_canvas = canvas;
480 }
481
482 static void
483 _set_cursor_location_internal(Ecore_IMF_Context *ctx)
484 {
485    IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx);
486    Ecore_Evas *ee;
487    int canvas_x, canvas_y;
488
489    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
490
491    if (ibusimcontext->ibuscontext == NULL)
492      return;
493
494    if (ibusimcontext->client_canvas)
495      {
496         ee = ecore_evas_ecore_evas_get(ibusimcontext->client_canvas);
497         if (!ee) return;
498
499         ecore_evas_geometry_get(ee, &canvas_x, &canvas_y, NULL, NULL);
500      }
501    else
502      {
503         if (ibusimcontext->client_window)
504           _window_to_screen_geometry_get(ibusimcontext->client_window, &canvas_x, &canvas_y);
505         else
506           return;
507      }
508
509    ibus_input_context_set_cursor_location(ibusimcontext->ibuscontext,
510                                           ibusimcontext->cursor_x + canvas_x,
511                                           ibusimcontext->cursor_y + canvas_y,
512                                           ibusimcontext->cursor_w,
513                                           ibusimcontext->cursor_h);
514 }
515
516 EAPI void
517 ibus_im_context_cursor_location_set(Ecore_IMF_Context *ctx, int x, int y, int w, int h)
518 {
519    EINA_LOG_DBG("x : %d, y : %d, w, %d, h :%d", x, y, w, h);
520    IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx);
521    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
522
523    if (ibusimcontext->cursor_x != x ||
524        ibusimcontext->cursor_y != y ||
525        ibusimcontext->cursor_w != w ||
526        ibusimcontext->cursor_h != h)
527      {
528         ibusimcontext->cursor_x = x;
529         ibusimcontext->cursor_y = y;
530         ibusimcontext->cursor_w = w;
531         ibusimcontext->cursor_h = h;
532
533         _set_cursor_location_internal(ctx);
534      }
535 }
536
537 EAPI void
538 ibus_im_context_use_preedit_set(Ecore_IMF_Context *ctx, Eina_Bool use_preedit)
539 {
540    EINA_LOG_DBG("preedit : %d", use_preedit);
541    IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx);
542    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
543
544    if (ibusimcontext->ibuscontext)
545      {
546         if (use_preedit)
547           ibusimcontext->caps |= IBUS_CAP_PREEDIT_TEXT;
548         else
549           ibusimcontext->caps &= ~IBUS_CAP_PREEDIT_TEXT;
550
551         ibus_input_context_set_capabilities(ibusimcontext->ibuscontext, ibusimcontext->caps);
552      }
553 }
554
555 static void
556 _bus_connected_cb(IBusBus          *bus __UNUSED__,
557                   IBusIMContext    *ibusimcontext)
558 {
559    EINA_LOG_DBG("ibus is connected");
560
561    if (ibusimcontext)
562      _create_input_context(ibusimcontext);
563 }
564
565 static void
566 _ibus_context_commit_text_cb(IBusInputContext *ibuscontext __UNUSED__,
567                              IBusText         *text,
568                              IBusIMContext    *ibusimcontext)
569 {
570    if (!ibusimcontext || !text) return;
571    char *commit_str = text->text ? text->text : "";
572
573    EINA_LOG_DBG("commit string : %s", commit_str);
574
575    if (ibusimcontext->ctx)
576      {
577         ecore_imf_context_commit_event_add(ibusimcontext->ctx, text->text);
578         ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)commit_str);
579      }
580 }
581
582 static XKeyEvent createXKeyEvent(Window win, Eina_Bool press, int keysym, int modifiers)
583 {
584    XKeyEvent event;
585    Display *display = ecore_x_display_get();
586
587    event.display     = display;
588    event.window      = win;
589    event.root        = ecore_x_window_root_get(win);
590    event.subwindow   = None;
591    event.time        = 0;
592    event.x           = 1;
593    event.y           = 1;
594    event.x_root      = 1;
595    event.y_root      = 1;
596    event.same_screen = EINA_TRUE;
597    event.state       = modifiers;
598    event.keycode     = XKeysymToKeycode(display, keysym);
599    if (press)
600      event.type = KeyPress;
601    else
602      event.type = KeyRelease;
603    event.send_event  = EINA_FALSE;
604    event.serial = 0;
605
606    return event;
607 }
608
609 static void
610 _ibus_context_forward_key_event_cb(IBusInputContext  *ibuscontext __UNUSED__,
611                                    guint              keyval,
612                                    guint              state,
613                                    IBusIMContext     *ibusimcontext __UNUSED__)
614 {
615    EINA_LOG_DBG("keyval : %d, state : %d", keyval, state);
616
617    key_event_put(keyval, state);
618 }
619
620 static void
621 _ibus_context_update_preedit_text_cb(IBusInputContext  *ibuscontext __UNUSED__,
622                                      IBusText          *text,
623                                      gint               cursor_pos,
624                                      gboolean           visible,
625                                      IBusIMContext     *ibusimcontext)
626 {
627    if (!ibusimcontext || !text) return;
628
629    const char *str;
630    gboolean flag;
631
632    if (ibusimcontext->preedit_string)
633      free (ibusimcontext->preedit_string);
634
635    str = text->text;
636
637    if (str)
638      ibusimcontext->preedit_string = strdup(str);
639    else
640      ibusimcontext->preedit_string = strdup("");
641
642    ibusimcontext->preedit_cursor_pos = cursor_pos;
643
644    EINA_LOG_DBG("string : %s, cursor : %d", ibusimcontext->preedit_string, ibusimcontext->preedit_cursor_pos);
645
646    flag = ibusimcontext->preedit_visible != visible;
647    ibusimcontext->preedit_visible = visible;
648
649    if (ibusimcontext->preedit_visible)
650      {
651         if (flag)
652           {
653              ecore_imf_context_preedit_start_event_add(ibusimcontext->ctx);
654              ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
655           }
656
657         ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx);
658         ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
659      }
660    else
661      {
662         if (flag)
663           {
664              ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx);
665              ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
666           }
667
668         ecore_imf_context_preedit_end_event_add(ibusimcontext->ctx);
669         ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
670      }
671 }
672
673 static void
674 _ibus_context_show_preedit_text_cb(IBusInputContext *ibuscontext __UNUSED__,
675                                    IBusIMContext    *ibusimcontext)
676 {
677    EINA_LOG_DBG("preedit visible : %d", ibusimcontext->preedit_visible);
678    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
679
680    if (ibusimcontext->preedit_visible == EINA_TRUE)
681      return;
682
683    ibusimcontext->preedit_visible = EINA_TRUE;
684
685    // call preedit start
686    ecore_imf_context_preedit_start_event_add(ibusimcontext->ctx);
687    ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
688
689    // call preedit changed
690    ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx);
691    ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
692 }
693
694 static void
695 _ibus_context_hide_preedit_text_cb(IBusInputContext *ibuscontext __UNUSED__,
696                                    IBusIMContext    *ibusimcontext)
697 {
698    EINA_LOG_DBG("%s", __FUNCTION__);
699    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
700
701    if (ibusimcontext->preedit_visible == EINA_FALSE)
702      return;
703
704    ibusimcontext->preedit_visible = EINA_FALSE;
705
706    // call preedit changed
707    ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx);
708    ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
709
710    // call preedit end
711    ecore_imf_context_preedit_end_event_add(ibusimcontext->ctx);
712    ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
713 }
714
715 static void
716 _ibus_context_enabled_cb(IBusInputContext *ibuscontext __UNUSED__,
717                          IBusIMContext    *ibusimcontext)
718 {
719    EINA_LOG_DBG("%s", __FUNCTION__);
720    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
721
722    ibusimcontext->enable = EINA_TRUE;
723 }
724
725 static void
726 _ibus_context_disabled_cb(IBusInputContext *ibuscontext __UNUSED__,
727                           IBusIMContext    *ibusimcontext)
728 {
729    EINA_LOG_DBG("%s", __FUNCTION__);
730    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
731
732    ibusimcontext->enable = EINA_FALSE;
733
734    /* clear preedit */
735    ibusimcontext->preedit_visible = EINA_FALSE;
736    ibusimcontext->preedit_cursor_pos = 0;
737    free (ibusimcontext->preedit_string);
738    ibusimcontext->preedit_string = NULL;
739
740    // call preedit changed
741    ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx);
742    ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
743
744    // call preedit end
745    ecore_imf_context_preedit_end_event_add(ibusimcontext->ctx);
746    ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
747 }
748
749 static void
750 _ibus_context_destroy_cb(IBusInputContext *ibuscontext __UNUSED__,
751                          IBusIMContext    *ibusimcontext)
752 {
753    EINA_LOG_DBG("%s", __FUNCTION__);
754    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
755
756    ibusimcontext->ibuscontext = NULL;
757    ibusimcontext->enable = EINA_FALSE;
758
759    /* clear preedit */
760    ibusimcontext->preedit_visible = EINA_FALSE;
761    ibusimcontext->preedit_cursor_pos = 0;
762    free (ibusimcontext->preedit_string);
763    ibusimcontext->preedit_string = NULL;
764
765    // call preedit changed
766    ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx);
767    ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
768
769    // call preedit end
770    ecore_imf_context_preedit_end_event_add(ibusimcontext->ctx);
771    ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
772 }
773
774 static void
775 _create_input_context(IBusIMContext *ibusimcontext)
776 {
777    EINA_LOG_DBG("%s", __FUNCTION__);
778    EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
779
780    ibusimcontext->ibuscontext = ibus_bus_create_input_context(_bus, "ecore");
781
782    g_return_if_fail(ibusimcontext->ibuscontext != NULL);
783
784    g_signal_connect(ibusimcontext->ibuscontext,
785                     "commit-text",
786                     G_CALLBACK (_ibus_context_commit_text_cb),
787                     ibusimcontext);
788    g_signal_connect(ibusimcontext->ibuscontext,
789                     "forward-key-event",
790                     G_CALLBACK (_ibus_context_forward_key_event_cb),
791                     ibusimcontext);
792    g_signal_connect(ibusimcontext->ibuscontext,
793                     "update-preedit-text",
794                     G_CALLBACK (_ibus_context_update_preedit_text_cb),
795                     ibusimcontext);
796    g_signal_connect(ibusimcontext->ibuscontext,
797                     "show-preedit-text",
798                     G_CALLBACK (_ibus_context_show_preedit_text_cb),
799                     ibusimcontext);
800    g_signal_connect(ibusimcontext->ibuscontext,
801                     "hide-preedit-text",
802                     G_CALLBACK (_ibus_context_hide_preedit_text_cb),
803                     ibusimcontext);
804    g_signal_connect(ibusimcontext->ibuscontext,
805                     "enabled",
806                     G_CALLBACK (_ibus_context_enabled_cb),
807                     ibusimcontext);
808    g_signal_connect(ibusimcontext->ibuscontext,
809                     "disabled",
810                     G_CALLBACK (_ibus_context_disabled_cb),
811                     ibusimcontext);
812    g_signal_connect(ibusimcontext->ibuscontext, "destroy",
813                     G_CALLBACK (_ibus_context_destroy_cb),
814                     ibusimcontext);
815
816    ibus_input_context_set_capabilities(ibusimcontext->ibuscontext, ibusimcontext->caps);
817
818    if (ibusimcontext->has_focus)
819      ibus_input_context_focus_in(ibusimcontext->ibuscontext);
820 }