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