ec764ef2f4feec8ccc4b0e575cd6b04f0ba3ddde
[platform/upstream/ibus.git] / client / gtk2 / ibusimcontext.c
1 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
2 /* vim:set et sts=4: */
3 /* ibus - The Input Bus
4  * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
5  * Copyright (C) 2008-2010 Red Hat, Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #  include <config.h>
25 #endif
26
27 #include <string.h>
28 #include <gtk/gtk.h>
29 #include <gdk/gdkkeysyms.h>
30 #include <ibus.h>
31 #include "ibusimcontext.h"
32
33 #if !GTK_CHECK_VERSION (2, 91, 0)
34 #  define DEPRECATED_GDK_KEYSYMS 1
35 #endif
36
37 #ifdef DEBUG
38 #  define IDEBUG g_debug
39 #else
40 #  define IDEBUG(a...)
41 #endif
42
43 struct _IBusIMContext {
44     GtkIMContext parent;
45
46     /* instance members */
47     GtkIMContext *slave;
48     GdkWindow *client_window;
49
50     /* enabled */
51     gboolean        enable;
52     IBusInputContext *ibuscontext;
53
54     /* preedit status */
55     gchar           *preedit_string;
56     PangoAttrList   *preedit_attrs;
57     gint             preedit_cursor_pos;
58     gboolean         preedit_visible;
59
60     GdkRectangle     cursor_area;
61     gboolean         has_focus;
62
63     guint32          time;
64     gint             caps;
65
66     /* cancellable */
67     GCancellable    *cancellable;
68 };
69
70 struct _IBusIMContextClass {
71 GtkIMContextClass parent;
72     /* class members */
73 };
74
75 static guint    _signal_commit_id = 0;
76 static guint    _signal_preedit_changed_id = 0;
77 static guint    _signal_preedit_start_id = 0;
78 static guint    _signal_preedit_end_id = 0;
79 static guint    _signal_delete_surrounding_id = 0;
80 static guint    _signal_retrieve_surrounding_id = 0;
81
82 static const gchar *_no_snooper_apps = NO_SNOOPER_APPS;
83 static gboolean _use_key_snooper = ENABLE_SNOOPER;
84 static guint    _key_snooper_id = 0;
85
86 static gboolean _use_sync_mode = FALSE;
87
88 static GtkIMContext *_focus_im_context = NULL;
89 static IBusInputContext *_fake_context = NULL;
90 static GdkWindow *_input_window = NULL;
91 static GtkWidget *_input_widget = NULL;
92
93 /* functions prototype */
94 static void     ibus_im_context_class_init  (IBusIMContextClass    *class);
95 static void     ibus_im_context_class_fini  (IBusIMContextClass    *class);
96 static void     ibus_im_context_init        (GObject               *obj);
97 static void     ibus_im_context_finalize    (GObject               *obj);
98 static void     ibus_im_context_reset       (GtkIMContext          *context);
99 static gboolean ibus_im_context_filter_keypress
100                                             (GtkIMContext           *context,
101                                              GdkEventKey            *key);
102 static void     ibus_im_context_focus_in    (GtkIMContext          *context);
103 static void     ibus_im_context_focus_out   (GtkIMContext          *context);
104 static void     ibus_im_context_get_preedit_string
105                                             (GtkIMContext           *context,
106                                              gchar                  **str,
107                                              PangoAttrList          **attrs,
108                                              gint                   *cursor_pos);
109 static void     ibus_im_context_set_client_window
110                                             (GtkIMContext           *context,
111                                              GdkWindow              *client);
112 static void     ibus_im_context_set_cursor_location
113                                             (GtkIMContext           *context,
114                                              GdkRectangle           *area);
115 static void     ibus_im_context_set_use_preedit
116                                             (GtkIMContext           *context,
117                                              gboolean               use_preedit);
118 static void     ibus_im_context_set_surrounding
119                                             (GtkIMContext  *slave,
120                                              const gchar   *text,
121                                              gint           len,
122                                              gint           cursor_index);
123
124
125 /* static methods*/
126 static void     _create_input_context       (IBusIMContext      *context);
127 static gboolean _set_cursor_location_internal
128                                             (IBusIMContext      *context);
129
130 static void     _bus_connected_cb           (IBusBus            *bus,
131                                              IBusIMContext      *context);
132 /* callback functions for slave context */
133 static void     _slave_commit_cb            (GtkIMContext       *slave,
134                                              gchar              *string,
135                                              IBusIMContext       *context);
136 static void     _slave_preedit_changed_cb   (GtkIMContext       *slave,
137                                              IBusIMContext       *context);
138 static void     _slave_preedit_start_cb     (GtkIMContext       *slave,
139                                              IBusIMContext       *context);
140 static void     _slave_preedit_end_cb       (GtkIMContext       *slave,
141                                              IBusIMContext       *context);
142 static gboolean _slave_retrieve_surrounding_cb
143                                             (GtkIMContext       *slave,
144                                              IBusIMContext      *context);
145 static gboolean _slave_delete_surrounding_cb
146                                             (GtkIMContext       *slave,
147                                              gint                offset_from_cursor,
148                                              guint               nchars,
149                                              IBusIMContext      *context);
150 static void     _request_surrounding_text   (IBusIMContext      *context,
151                                              gboolean            force);
152 static void     _create_fake_input_context  (void);
153
154
155
156 static GType                _ibus_type_im_context = 0;
157 static GtkIMContextClass    *parent_class = NULL;
158
159 static IBusBus              *_bus = NULL;
160
161 void
162 ibus_im_context_register_type (GTypeModule *type_module)
163 {
164     IDEBUG ("%s", __FUNCTION__);
165
166     static const GTypeInfo ibus_im_context_info = {
167         sizeof (IBusIMContextClass),
168         (GBaseInitFunc)      NULL,
169         (GBaseFinalizeFunc)  NULL,
170         (GClassInitFunc)     ibus_im_context_class_init,
171         (GClassFinalizeFunc) ibus_im_context_class_fini,
172         NULL,            /* class data */
173         sizeof (IBusIMContext),
174         0,
175         (GInstanceInitFunc)    ibus_im_context_init,
176     };
177
178     if (!_ibus_type_im_context) {
179         if (type_module) {
180             _ibus_type_im_context =
181                 g_type_module_register_type (type_module,
182                     GTK_TYPE_IM_CONTEXT,
183                     "IBusIMContext",
184                     &ibus_im_context_info,
185                     (GTypeFlags)0);
186         }
187         else {
188             _ibus_type_im_context =
189                 g_type_register_static (GTK_TYPE_IM_CONTEXT,
190                     "IBusIMContext",
191                     &ibus_im_context_info,
192                     (GTypeFlags)0);
193         }
194     }
195 }
196
197 GType
198 ibus_im_context_get_type (void)
199 {
200     IDEBUG ("%s", __FUNCTION__);
201
202     if (_ibus_type_im_context == 0) {
203         ibus_im_context_register_type (NULL);
204     }
205
206     g_assert (_ibus_type_im_context != 0);
207     return _ibus_type_im_context;
208 }
209
210 IBusIMContext *
211 ibus_im_context_new (void)
212 {
213     IDEBUG ("%s", __FUNCTION__);
214
215     GObject *obj = g_object_new (IBUS_TYPE_IM_CONTEXT, NULL);
216     return IBUS_IM_CONTEXT (obj);
217 }
218
219 static gboolean
220 _focus_in_cb (GtkWidget     *widget,
221               GdkEventFocus *event,
222               gpointer       user_data)
223 {
224     if (_focus_im_context == NULL && _fake_context != NULL) {
225         ibus_input_context_focus_in (_fake_context);
226     }
227     return FALSE;
228 }
229
230 static gboolean
231 _focus_out_cb (GtkWidget     *widget,
232                GdkEventFocus *event,
233                gpointer       user_data)
234 {
235     if (_focus_im_context == NULL && _fake_context != NULL) {
236         ibus_input_context_focus_out (_fake_context);
237     }
238     return FALSE;
239 }
240
241 static void
242 _process_key_event_done (GObject      *object,
243                          GAsyncResult *res,
244                          gpointer      user_data)
245 {
246     IBusInputContext *context = (IBusInputContext *)object;
247     GdkEventKey *event = (GdkEventKey *) user_data;
248
249     GError *error = NULL;
250     gboolean retval = ibus_input_context_process_key_event_async_finish (
251             context,
252             res,
253             &error);
254
255     if (error != NULL) {
256         g_warning ("Process Key Event failed: %s.", error->message);
257         g_error_free (error);
258     }
259
260     if (retval == FALSE) {
261         event->state |= IBUS_IGNORED_MASK;
262         gdk_event_put ((GdkEvent *)event);
263     }
264     gdk_event_free ((GdkEvent *)event);
265 }
266
267
268 /* emit "retrieve-surrounding" glib signal of GtkIMContext, if
269  * context->caps has IBUS_CAP_SURROUNDING_TEXT and the current IBus
270  * engine needs surrounding-text.
271  *
272  * if "force" is TRUE, emit the signal regardless of whether the
273  * engine needs surrounding-text.
274  */
275 static void
276 _request_surrounding_text (IBusIMContext *context, gboolean force)
277 {
278     if (context && context->enable &&
279         (context->caps & IBUS_CAP_SURROUNDING_TEXT) != 0 &&
280         (force ||
281          ibus_input_context_needs_surrounding_text (context->ibuscontext))) {
282         gboolean return_value;
283         IDEBUG ("requesting surrounding text");
284         g_signal_emit (context, _signal_retrieve_surrounding_id, 0,
285                        &return_value);
286     }
287 }
288
289
290 static gint
291 _key_snooper_cb (GtkWidget   *widget,
292                  GdkEventKey *event,
293                  gpointer     user_data)
294 {
295     IDEBUG ("%s", __FUNCTION__);
296     gboolean retval = FALSE;
297
298     IBusIMContext *ibusimcontext = (IBusIMContext *) _focus_im_context;
299     IBusInputContext *ibuscontext = NULL;
300
301     if (ibusimcontext != NULL &&
302         ibusimcontext->has_focus == TRUE) {
303         /* has IC with focus and use_key_snooper is true */
304         if (_use_key_snooper)
305             ibuscontext = ibusimcontext->ibuscontext;
306     }
307     else {
308         /* If no IC has focus, and fake IC has been created, then pass key events to fake IC. */
309         ibuscontext = _fake_context;
310     }
311
312     if (ibuscontext == NULL)
313         return FALSE;
314
315     if (G_UNLIKELY (event->state & IBUS_HANDLED_MASK))
316         return TRUE;
317
318     if (G_UNLIKELY (event->state & IBUS_IGNORED_MASK))
319         return FALSE;
320
321     do {
322         if (_fake_context != ibuscontext)
323             break;
324
325         /* window has input focus is not changed */
326         if (_input_window == event->window)
327             break;
328
329         if (_input_window != NULL) {
330             g_object_remove_weak_pointer ((GObject *) _input_window,
331                                           (gpointer *) &_input_window);
332         }
333         if (event->window != NULL) {
334             g_object_add_weak_pointer ((GObject *) event->window,
335                                        (gpointer *) &_input_window);
336         }
337         _input_window = event->window;
338
339         /* Trace widget has input focus, and listen focus events of it.
340          * It is workaround for Alt+Shift+Tab shortcut key issue(crosbug.com/8855).
341          * gtk_get_event_widget returns the widget that is associated with the
342          * GdkWindow of the GdkEvent.
343          * */
344         GtkWidget *widget = gtk_get_event_widget ((GdkEvent *)event);
345         /* g_assert (_input_widget != widget). */
346         if (_input_widget == widget)
347             break;
348
349         if (_input_widget != NULL) {
350             g_signal_handlers_disconnect_by_func (_input_widget,
351                                                   (GCallback) _focus_in_cb,
352                                                   NULL);
353             g_signal_handlers_disconnect_by_func (_input_widget,
354                                                   (GCallback) _focus_out_cb,
355                                                   NULL);
356             g_object_remove_weak_pointer ((GObject *) _input_widget,
357                                           (gpointer *) &_input_widget);
358         }
359
360         if (widget != NULL) {
361             g_signal_connect (widget,
362                               "focus-in-event",
363                               (GCallback) _focus_in_cb,
364                               NULL);
365             g_signal_connect (widget,
366                               "focus-out-event",
367                               (GCallback) _focus_out_cb,
368                               NULL);
369             g_object_add_weak_pointer ((GObject *) widget,
370                                        (gpointer *) &_input_widget);
371         }
372         _input_widget = widget;
373
374     } while (0);
375
376     if (ibusimcontext != NULL) {
377         _request_surrounding_text (ibusimcontext, FALSE);
378         ibusimcontext->time = event->time;
379     }
380
381     guint state = event->state;
382     if (event->type == GDK_KEY_RELEASE) {
383         state |= IBUS_RELEASE_MASK;
384     }
385
386     if (_use_sync_mode) {
387         retval = ibus_input_context_process_key_event (
388                                         ibuscontext,
389                                         event->keyval,
390                                         event->hardware_keycode - 8,
391                                         state);
392     }
393     else {
394         ibus_input_context_process_key_event_async (
395                                         ibuscontext,
396                                         event->keyval,
397                                         event->hardware_keycode - 8,
398                                         state,
399                                         -1,
400                                         NULL,
401                                         _process_key_event_done,
402                                         gdk_event_copy ((GdkEvent *) event));
403         retval = TRUE;
404
405     }
406
407     if (retval) {
408         event->state |= IBUS_HANDLED_MASK;
409     }
410     else {
411         event->state |= IBUS_IGNORED_MASK;
412     }
413
414     return retval;
415 }
416
417 static gboolean
418 _get_boolean_env(const gchar *name,
419                  gboolean     defval)
420 {
421     const gchar *value = g_getenv (name);
422
423     if (value == NULL)
424       return defval;
425
426     if (g_strcmp0 (value, "") == 0 ||
427         g_strcmp0 (value, "0") == 0 ||
428         g_strcmp0 (value, "false") == 0 ||
429         g_strcmp0 (value, "False") == 0 ||
430         g_strcmp0 (value, "FALSE") == 0)
431       return FALSE;
432
433     return TRUE;
434 }
435
436 static void
437 ibus_im_context_class_init (IBusIMContextClass *class)
438 {
439     IDEBUG ("%s", __FUNCTION__);
440
441     GtkIMContextClass *im_context_class = GTK_IM_CONTEXT_CLASS (class);
442     GObjectClass *gobject_class = G_OBJECT_CLASS (class);
443
444     parent_class = (GtkIMContextClass *) g_type_class_peek_parent (class);
445
446     im_context_class->reset = ibus_im_context_reset;
447     im_context_class->focus_in = ibus_im_context_focus_in;
448     im_context_class->focus_out = ibus_im_context_focus_out;
449     im_context_class->filter_keypress = ibus_im_context_filter_keypress;
450     im_context_class->get_preedit_string = ibus_im_context_get_preedit_string;
451     im_context_class->set_client_window = ibus_im_context_set_client_window;
452     im_context_class->set_cursor_location = ibus_im_context_set_cursor_location;
453     im_context_class->set_use_preedit = ibus_im_context_set_use_preedit;
454     im_context_class->set_surrounding = ibus_im_context_set_surrounding;
455     gobject_class->finalize = ibus_im_context_finalize;
456
457     _signal_commit_id =
458         g_signal_lookup ("commit", G_TYPE_FROM_CLASS (class));
459     g_assert (_signal_commit_id != 0);
460
461     _signal_preedit_changed_id =
462         g_signal_lookup ("preedit-changed", G_TYPE_FROM_CLASS (class));
463     g_assert (_signal_preedit_changed_id != 0);
464
465     _signal_preedit_start_id =
466         g_signal_lookup ("preedit-start", G_TYPE_FROM_CLASS (class));
467     g_assert (_signal_preedit_start_id != 0);
468
469     _signal_preedit_end_id =
470         g_signal_lookup ("preedit-end", G_TYPE_FROM_CLASS (class));
471     g_assert (_signal_preedit_end_id != 0);
472
473     _signal_delete_surrounding_id =
474         g_signal_lookup ("delete-surrounding", G_TYPE_FROM_CLASS (class));
475     g_assert (_signal_delete_surrounding_id != 0);
476
477     _signal_retrieve_surrounding_id =
478         g_signal_lookup ("retrieve-surrounding", G_TYPE_FROM_CLASS (class));
479     g_assert (_signal_retrieve_surrounding_id != 0);
480
481     _use_key_snooper = !_get_boolean_env ("IBUS_DISABLE_SNOOPER",
482                                           !(ENABLE_SNOOPER));
483     _use_sync_mode = _get_boolean_env ("IBUS_ENABLE_SYNC_MODE", FALSE);
484
485     /* env IBUS_DISABLE_SNOOPER does not exist */
486     if (_use_key_snooper) {
487         /* disable snooper if app is in _no_snooper_apps */
488         const gchar * prgname = g_get_prgname ();
489         if (g_getenv ("IBUS_NO_SNOOPER_APPS")) {
490             _no_snooper_apps = g_getenv ("IBUS_NO_SNOOPER_APPS");
491         }
492         gchar **p;
493         gchar ** apps = g_strsplit (_no_snooper_apps, ",", 0);
494         for (p = apps; *p != NULL; p++) {
495             if (g_regex_match_simple (*p, prgname, 0, 0)) {
496                 _use_key_snooper = FALSE;
497                 break;
498             }
499         }
500         g_strfreev (apps);
501     }
502
503     /* init bus object */
504     if (_bus == NULL) {
505         ibus_set_display (gdk_display_get_name (gdk_display_get_default ()));
506         _bus = ibus_bus_new ();
507
508         /* init the global fake context */
509         if (ibus_bus_is_connected (_bus)) {
510             _create_fake_input_context ();
511         }
512
513         g_signal_connect (_bus, "connected", G_CALLBACK (_bus_connected_cb), NULL);
514     }
515
516
517     /* always install snooper */
518     if (_key_snooper_id == 0)
519         _key_snooper_id = gtk_key_snooper_install (_key_snooper_cb, NULL);
520 }
521
522 static void
523 ibus_im_context_class_fini (IBusIMContextClass *class)
524 {
525     if (_key_snooper_id != 0) {
526         IDEBUG ("snooper is terminated.");
527         gtk_key_snooper_remove (_key_snooper_id);
528         _key_snooper_id = 0;
529     }
530 }
531
532 /* Copied from gtk+2.0-2.20.1/modules/input/imcedilla.c to fix crosbug.com/11421.
533  * Overwrite the original Gtk+'s compose table in gtk+-2.x.y/gtk/gtkimcontextsimple.c. */
534
535 /* The difference between this and the default input method is the handling
536  * of C+acute - this method produces C WITH CEDILLA rather than C WITH ACUTE.
537  * For languages that use CCedilla and not acute, this is the preferred mapping,
538  * and is particularly important for pt_BR, where the us-intl keyboard is
539  * used extensively.
540  */
541 static guint16 cedilla_compose_seqs[] = {
542 #ifdef DEPRECATED_GDK_KEYSYMS
543   GDK_dead_acute,       GDK_C,  0,      0,      0,      0x00C7, /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */
544   GDK_dead_acute,       GDK_c,  0,      0,      0,      0x00E7, /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */
545   GDK_Multi_key,        GDK_apostrophe, GDK_C,  0,      0,      0x00C7, /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */
546   GDK_Multi_key,        GDK_apostrophe, GDK_c,  0,      0,      0x00E7, /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */
547   GDK_Multi_key,        GDK_C,  GDK_apostrophe, 0,      0,      0x00C7, /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */
548   GDK_Multi_key,        GDK_c,  GDK_apostrophe, 0,      0,      0x00E7, /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */
549 #else
550   GDK_KEY_dead_acute,   GDK_KEY_C,      0,      0,      0,      0x00C7, /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */
551   GDK_KEY_dead_acute,   GDK_KEY_c,      0,      0,      0,      0x00E7, /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */
552   GDK_KEY_Multi_key,    GDK_KEY_apostrophe,     GDK_KEY_C,  0,      0,      0x00C7, /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */
553   GDK_KEY_Multi_key,    GDK_KEY_apostrophe,     GDK_KEY_c,  0,      0,      0x00E7, /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */
554   GDK_KEY_Multi_key,    GDK_KEY_C,  GDK_KEY_apostrophe, 0,      0,      0x00C7, /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */
555   GDK_KEY_Multi_key,    GDK_KEY_c,  GDK_KEY_apostrophe, 0,      0,      0x00E7, /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */
556 #endif
557 };
558
559 static void
560 ibus_im_context_init (GObject *obj)
561 {
562     IDEBUG ("%s", __FUNCTION__);
563
564     IBusIMContext *ibusimcontext = IBUS_IM_CONTEXT (obj);
565
566     ibusimcontext->client_window = NULL;
567
568     // Init ibus status
569     ibusimcontext->enable = FALSE;
570
571     // Init preedit status
572     ibusimcontext->preedit_string = NULL;
573     ibusimcontext->preedit_attrs = NULL;
574     ibusimcontext->preedit_cursor_pos = 0;
575     ibusimcontext->preedit_visible = FALSE;
576
577     // Init cursor area
578     ibusimcontext->cursor_area.x = -1;
579     ibusimcontext->cursor_area.y = -1;
580     ibusimcontext->cursor_area.width = 0;
581     ibusimcontext->cursor_area.height = 0;
582
583     ibusimcontext->ibuscontext = NULL;
584     ibusimcontext->has_focus = FALSE;
585     ibusimcontext->time = GDK_CURRENT_TIME;
586 #ifdef ENABLE_SURROUNDING
587     ibusimcontext->caps = IBUS_CAP_PREEDIT_TEXT | IBUS_CAP_FOCUS | IBUS_CAP_SURROUNDING_TEXT;
588 #else
589     ibusimcontext->caps = IBUS_CAP_PREEDIT_TEXT | IBUS_CAP_FOCUS;
590 #endif
591
592
593     // Create slave im context
594     ibusimcontext->slave = gtk_im_context_simple_new ();
595     gtk_im_context_simple_add_table (GTK_IM_CONTEXT_SIMPLE (ibusimcontext->slave),
596                                      cedilla_compose_seqs,
597                                      4,
598                                      G_N_ELEMENTS (cedilla_compose_seqs) / (4 + 2));
599
600     g_signal_connect (ibusimcontext->slave,
601                       "commit",
602                       G_CALLBACK (_slave_commit_cb),
603                       ibusimcontext);
604     g_signal_connect (ibusimcontext->slave,
605                       "preedit-start",
606                       G_CALLBACK (_slave_preedit_start_cb),
607                       ibusimcontext);
608     g_signal_connect (ibusimcontext->slave,
609                       "preedit-end",
610                       G_CALLBACK (_slave_preedit_end_cb),
611                       ibusimcontext);
612     g_signal_connect (ibusimcontext->slave,
613                       "preedit-changed",
614                       G_CALLBACK (_slave_preedit_changed_cb),
615                       ibusimcontext);
616     g_signal_connect (ibusimcontext->slave,
617                       "retrieve-surrounding",
618                       G_CALLBACK (_slave_retrieve_surrounding_cb),
619                       ibusimcontext);
620     g_signal_connect (ibusimcontext->slave,
621                       "delete-surrounding",
622                       G_CALLBACK (_slave_delete_surrounding_cb),
623                       ibusimcontext);
624
625     if (ibus_bus_is_connected (_bus)) {
626         _create_input_context (ibusimcontext);
627     }
628
629     g_signal_connect (_bus, "connected", G_CALLBACK (_bus_connected_cb), obj);
630 }
631
632 static void
633 ibus_im_context_finalize (GObject *obj)
634 {
635     IDEBUG ("%s", __FUNCTION__);
636
637     IBusIMContext *ibusimcontext = IBUS_IM_CONTEXT (obj);
638
639     g_signal_handlers_disconnect_by_func (_bus, G_CALLBACK (_bus_connected_cb), obj);
640
641     if (ibusimcontext->ibuscontext) {
642         ibus_proxy_destroy ((IBusProxy *)ibusimcontext->ibuscontext);
643     }
644
645     ibus_im_context_set_client_window ((GtkIMContext *)ibusimcontext, NULL);
646
647     if (ibusimcontext->slave) {
648         g_object_unref (ibusimcontext->slave);
649         ibusimcontext->slave = NULL;
650     }
651
652     // release preedit
653     if (ibusimcontext->preedit_string) {
654         g_free (ibusimcontext->preedit_string);
655     }
656     if (ibusimcontext->preedit_attrs) {
657         pango_attr_list_unref (ibusimcontext->preedit_attrs);
658     }
659
660     G_OBJECT_CLASS(parent_class)->finalize (obj);
661 }
662
663 static gboolean
664 ibus_im_context_filter_keypress (GtkIMContext *context,
665                                  GdkEventKey  *event)
666 {
667     IDEBUG ("%s", __FUNCTION__);
668
669     IBusIMContext *ibusimcontext = IBUS_IM_CONTEXT (context);
670
671     if (G_LIKELY (ibusimcontext->ibuscontext && ibusimcontext->has_focus)) {
672         /* If context does not have focus, ibus will process key event in sync mode.
673          * It is a workaround for increase search in treeview.
674          */
675         gboolean retval = FALSE;
676
677         if (event->state & IBUS_HANDLED_MASK)
678             return TRUE;
679
680         if (event->state & IBUS_IGNORED_MASK)
681             return gtk_im_context_filter_keypress (ibusimcontext->slave, event);
682
683         /* XXX it is a workaround for some applications do not set client window. */
684         if (ibusimcontext->client_window == NULL && event->window != NULL)
685             gtk_im_context_set_client_window ((GtkIMContext *)ibusimcontext, event->window);
686
687         _request_surrounding_text (ibusimcontext, FALSE);
688
689         if (ibusimcontext != NULL) {
690             ibusimcontext->time = event->time;
691         }
692
693         guint state = event->state;
694         if (event->type == GDK_KEY_RELEASE) {
695             state |= IBUS_RELEASE_MASK;
696         }
697
698         if (_use_sync_mode) {
699             retval = ibus_input_context_process_key_event (
700                                         ibusimcontext->ibuscontext,
701                                         event->keyval,
702                                         event->hardware_keycode - 8,
703                                         state);
704         }
705         else {
706             ibus_input_context_process_key_event_async (
707                                         ibusimcontext->ibuscontext,
708                                         event->keyval,
709                                         event->hardware_keycode - 8,
710                                         state,
711                                         -1,
712                                         NULL,
713                                         _process_key_event_done,
714                                         gdk_event_copy ((GdkEvent *) event));
715             retval = TRUE;
716         }
717
718         if (retval) {
719             event->state |= IBUS_HANDLED_MASK;
720             return TRUE;
721         }
722         else {
723             event->state |= IBUS_IGNORED_MASK;
724             return gtk_im_context_filter_keypress (ibusimcontext->slave, event);
725         }
726     }
727     else {
728         return gtk_im_context_filter_keypress (ibusimcontext->slave, event);
729     }
730 }
731
732 static void
733 ibus_im_context_focus_in (GtkIMContext *context)
734 {
735     IDEBUG ("%s", __FUNCTION__);
736
737     IBusIMContext *ibusimcontext = (IBusIMContext *) context;
738
739     if (ibusimcontext->has_focus)
740         return;
741
742     if (_focus_im_context != NULL) {
743         g_assert (_focus_im_context != context);
744         gtk_im_context_focus_out (_focus_im_context);
745         g_assert (_focus_im_context == NULL);
746     }
747     else {
748         /* focus out fake context */
749         if (_fake_context != NULL) {
750             ibus_input_context_focus_out (_fake_context);
751         }
752     }
753
754     ibusimcontext->has_focus = TRUE;
755     if (ibusimcontext->ibuscontext) {
756         ibus_input_context_focus_in (ibusimcontext->ibuscontext);
757     }
758
759     gtk_im_context_focus_in (ibusimcontext->slave);
760
761     /* set_cursor_location_internal() will get origin from X server,
762      * it blocks UI. So delay it to idle callback. */
763     g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
764                      (GSourceFunc) _set_cursor_location_internal,
765                      g_object_ref (ibusimcontext),
766                      (GDestroyNotify) g_object_unref);
767
768     /* retrieve the initial surrounding-text (regardless of whether
769      * the current IBus engine needs surrounding-text) */
770     _request_surrounding_text (ibusimcontext, TRUE);
771
772     g_object_add_weak_pointer ((GObject *) context,
773                                (gpointer *) &_focus_im_context);
774     _focus_im_context = context;
775 }
776
777 static void
778 ibus_im_context_focus_out (GtkIMContext *context)
779 {
780     IDEBUG ("%s", __FUNCTION__);
781     IBusIMContext *ibusimcontext = (IBusIMContext *) context;
782
783     if (ibusimcontext->has_focus == FALSE) {
784         return;
785     }
786
787     g_assert (context == _focus_im_context);
788     g_object_remove_weak_pointer ((GObject *) context,
789                                   (gpointer *) &_focus_im_context);
790     _focus_im_context = NULL;
791
792     ibusimcontext->has_focus = FALSE;
793     if (ibusimcontext->ibuscontext) {
794         ibus_input_context_focus_out (ibusimcontext->ibuscontext);
795     }
796
797     gtk_im_context_focus_out (ibusimcontext->slave);
798
799     /* focus in the fake ic */
800     if (_fake_context != NULL) {
801         ibus_input_context_focus_in (_fake_context);
802     }
803 }
804
805 static void
806 ibus_im_context_reset (GtkIMContext *context)
807 {
808     IDEBUG ("%s", __FUNCTION__);
809
810     IBusIMContext *ibusimcontext = IBUS_IM_CONTEXT (context);
811
812     if (ibusimcontext->ibuscontext) {
813         ibus_input_context_reset (ibusimcontext->ibuscontext);
814     }
815     gtk_im_context_reset (ibusimcontext->slave);
816 }
817
818
819 static void
820 ibus_im_context_get_preedit_string (GtkIMContext   *context,
821                                     gchar         **str,
822                                     PangoAttrList **attrs,
823                                     gint           *cursor_pos)
824 {
825     IDEBUG ("%s", __FUNCTION__);
826
827     IBusIMContext *ibusimcontext = IBUS_IM_CONTEXT (context);
828
829     if (ibusimcontext->enable) {
830         if (ibusimcontext->preedit_visible) {
831             if (str) {
832                 *str = g_strdup (ibusimcontext->preedit_string ? ibusimcontext->preedit_string: "");
833             }
834
835             if (attrs) {
836                 *attrs = ibusimcontext->preedit_attrs ?
837                             pango_attr_list_ref (ibusimcontext->preedit_attrs):
838                             pango_attr_list_new ();
839             }
840
841             if (cursor_pos) {
842                 *cursor_pos = ibusimcontext->preedit_cursor_pos;
843             }
844         }
845         else {
846             if (str) {
847                 *str = g_strdup ("");
848             }
849             if (attrs) {
850                 *attrs = pango_attr_list_new ();
851             }
852             if (cursor_pos) {
853                 *cursor_pos = 0;
854             }
855         }
856     }
857     else {
858         gtk_im_context_get_preedit_string (ibusimcontext->slave, str, attrs, cursor_pos);
859     }
860     IDEBUG ("str=%s", *str);
861 }
862
863
864 static void
865 ibus_im_context_set_client_window (GtkIMContext *context, GdkWindow *client)
866 {
867     IDEBUG ("%s", __FUNCTION__);
868
869     IBusIMContext *ibusimcontext = IBUS_IM_CONTEXT (context);
870
871     if (ibusimcontext->client_window) {
872         g_object_unref (ibusimcontext->client_window);
873         ibusimcontext->client_window = NULL;
874     }
875
876     if (client != NULL)
877         ibusimcontext->client_window = g_object_ref (client);
878
879     if (ibusimcontext->slave)
880         gtk_im_context_set_client_window (ibusimcontext->slave, client);
881 }
882
883 static gboolean
884 _set_cursor_location_internal (IBusIMContext *ibusimcontext)
885 {
886     GdkRectangle area;
887
888     if(ibusimcontext->client_window == NULL ||
889        ibusimcontext->ibuscontext == NULL) {
890         return FALSE;
891     }
892
893     area = ibusimcontext->cursor_area;
894     if (area.x == -1 && area.y == -1 && area.width == 0 && area.height == 0) {
895 #if GTK_CHECK_VERSION (2, 91, 0)
896         area.x = 0;
897         area.y += gdk_window_get_height (ibusimcontext->client_window);
898 #else
899         gint w, h;
900         gdk_drawable_get_size (ibusimcontext->client_window, &w, &h);
901         area.y += h;
902         area.x = 0;
903 #endif
904     }
905
906     gdk_window_get_root_coords (ibusimcontext->client_window,
907                                 area.x, area.y,
908                                 &area.x, &area.y);
909     ibus_input_context_set_cursor_location (ibusimcontext->ibuscontext,
910                                             area.x,
911                                             area.y,
912                                             area.width,
913                                             area.height);
914     return FALSE;
915 }
916
917 static void
918 ibus_im_context_set_cursor_location (GtkIMContext *context, GdkRectangle *area)
919 {
920     IDEBUG ("%s", __FUNCTION__);
921
922     IBusIMContext *ibusimcontext = IBUS_IM_CONTEXT (context);
923
924     if (ibusimcontext->cursor_area.x == area->x &&
925         ibusimcontext->cursor_area.y == area->y &&
926         ibusimcontext->cursor_area.width == area->width &&
927         ibusimcontext->cursor_area.height == area->height) {
928         return;
929     }
930     ibusimcontext->cursor_area = *area;
931     _set_cursor_location_internal (ibusimcontext);
932     gtk_im_context_set_cursor_location (ibusimcontext->slave, area);
933 }
934
935 static void
936 ibus_im_context_set_use_preedit (GtkIMContext *context, gboolean use_preedit)
937 {
938     IDEBUG ("%s", __FUNCTION__);
939
940     IBusIMContext *ibusimcontext = IBUS_IM_CONTEXT (context);
941
942     if(ibusimcontext->ibuscontext) {
943         if (use_preedit) {
944             ibusimcontext->caps |= IBUS_CAP_PREEDIT_TEXT;
945         }
946         else {
947             ibusimcontext->caps &= ~IBUS_CAP_PREEDIT_TEXT;
948         }
949         ibus_input_context_set_capabilities (ibusimcontext->ibuscontext,
950                                              ibusimcontext->caps);
951     }
952     gtk_im_context_set_use_preedit (ibusimcontext->slave, use_preedit);
953 }
954
955 static void
956 ibus_im_context_set_surrounding (GtkIMContext  *context,
957                                  const gchar   *text,
958                                  gint           len,
959                                  gint           cursor_index)
960 {
961     g_return_if_fail (context != NULL);
962     g_return_if_fail (IBUS_IS_IM_CONTEXT (context));
963     g_return_if_fail (text != NULL);
964     g_return_if_fail (strlen (text) >= len);
965     g_return_if_fail (0 <= cursor_index && cursor_index <= len);
966
967     IBusIMContext *ibusimcontext = IBUS_IM_CONTEXT (context);
968
969     if (ibusimcontext->enable && ibusimcontext->ibuscontext) {
970         IBusText *ibustext;
971         guint cursor_pos;
972         gchar *p;
973
974         p = g_strndup (text, len);
975         cursor_pos = g_utf8_strlen (p, cursor_index);
976         ibustext = ibus_text_new_from_string (p);
977         g_free (p);
978         ibus_input_context_set_surrounding_text (ibusimcontext->ibuscontext,
979                                                  ibustext,
980                                                  cursor_pos);
981     }
982     gtk_im_context_set_surrounding (ibusimcontext->slave,
983                                     text,
984                                     len,
985                                     cursor_index);
986 }
987
988 static void
989 _bus_connected_cb (IBusBus          *bus,
990                    IBusIMContext    *ibusimcontext)
991 {
992     IDEBUG ("%s", __FUNCTION__);
993     if (ibusimcontext)
994         _create_input_context (ibusimcontext);
995     else
996         _create_fake_input_context ();
997 }
998
999 static void
1000 _ibus_context_commit_text_cb (IBusInputContext *ibuscontext,
1001                               IBusText         *text,
1002                               IBusIMContext    *ibusimcontext)
1003 {
1004     IDEBUG ("%s", __FUNCTION__);
1005
1006     g_signal_emit (ibusimcontext, _signal_commit_id, 0, text->text);
1007
1008     _request_surrounding_text (ibusimcontext, FALSE);
1009 }
1010
1011 static gboolean
1012 _key_is_modifier (guint keyval)
1013 {
1014   /* See gdkkeys-x11.c:_gdk_keymap_key_is_modifier() for how this
1015    * really should be implemented */
1016
1017     switch (keyval) {
1018 #ifdef DEPRECATED_GDK_KEYSYMS
1019     case GDK_Shift_L:
1020     case GDK_Shift_R:
1021     case GDK_Control_L:
1022     case GDK_Control_R:
1023     case GDK_Caps_Lock:
1024     case GDK_Shift_Lock:
1025     case GDK_Meta_L:
1026     case GDK_Meta_R:
1027     case GDK_Alt_L:
1028     case GDK_Alt_R:
1029     case GDK_Super_L:
1030     case GDK_Super_R:
1031     case GDK_Hyper_L:
1032     case GDK_Hyper_R:
1033     case GDK_ISO_Lock:
1034     case GDK_ISO_Level2_Latch:
1035     case GDK_ISO_Level3_Shift:
1036     case GDK_ISO_Level3_Latch:
1037     case GDK_ISO_Level3_Lock:
1038     case GDK_ISO_Level5_Shift:
1039     case GDK_ISO_Level5_Latch:
1040     case GDK_ISO_Level5_Lock:
1041     case GDK_ISO_Group_Shift:
1042     case GDK_ISO_Group_Latch:
1043     case GDK_ISO_Group_Lock:
1044         return TRUE;
1045 #else
1046     case GDK_KEY_Shift_L:
1047     case GDK_KEY_Shift_R:
1048     case GDK_KEY_Control_L:
1049     case GDK_KEY_Control_R:
1050     case GDK_KEY_Caps_Lock:
1051     case GDK_KEY_Shift_Lock:
1052     case GDK_KEY_Meta_L:
1053     case GDK_KEY_Meta_R:
1054     case GDK_KEY_Alt_L:
1055     case GDK_KEY_Alt_R:
1056     case GDK_KEY_Super_L:
1057     case GDK_KEY_Super_R:
1058     case GDK_KEY_Hyper_L:
1059     case GDK_KEY_Hyper_R:
1060     case GDK_KEY_ISO_Lock:
1061     case GDK_KEY_ISO_Level2_Latch:
1062     case GDK_KEY_ISO_Level3_Shift:
1063     case GDK_KEY_ISO_Level3_Latch:
1064     case GDK_KEY_ISO_Level3_Lock:
1065     case GDK_KEY_ISO_Level5_Shift:
1066     case GDK_KEY_ISO_Level5_Latch:
1067     case GDK_KEY_ISO_Level5_Lock:
1068     case GDK_KEY_ISO_Group_Shift:
1069     case GDK_KEY_ISO_Group_Latch:
1070     case GDK_KEY_ISO_Group_Lock:
1071         return TRUE;
1072 #endif
1073     default:
1074         return FALSE;
1075     }
1076 }
1077 /* Copy from gdk */
1078 static GdkEventKey *
1079 _create_gdk_event (IBusIMContext *ibusimcontext,
1080                    guint          keyval,
1081                    guint          keycode,
1082                    guint          state)
1083 {
1084     gunichar c = 0;
1085     gchar buf[8];
1086
1087     GdkEventKey *event = (GdkEventKey *)gdk_event_new ((state & IBUS_RELEASE_MASK) ? GDK_KEY_RELEASE : GDK_KEY_PRESS);
1088
1089     if (ibusimcontext && ibusimcontext->client_window)
1090         event->window = g_object_ref (ibusimcontext->client_window);
1091     else if (_input_window)
1092         event->window = g_object_ref (_input_window);
1093
1094     /* The time is copied the latest value from the previous
1095      * GdkKeyEvent in filter_keypress().
1096      *
1097      * We understand the best way would be to pass the all time value
1098      * to IBus functions process_key_event() and IBus DBus functions
1099      * ProcessKeyEvent() in IM clients and IM engines so that the
1100      * _create_gdk_event() could get the correct time values.
1101      * However it would causes to change many functions and the time value
1102      * would not provide the useful meanings for each IBus engines but just
1103      * pass the original value to ForwardKeyEvent().
1104      * We use the saved value at the moment.
1105      *
1106      * Another idea might be to have the time implementation in X servers
1107      * but some Xorg uses clock_gettime() and others use gettimeofday()
1108      * and the values would be different in each implementation and 
1109      * locale/remote X server. So probably that idea would not work. */
1110     if (ibusimcontext) {
1111         event->time = ibusimcontext->time;
1112     } else {
1113         event->time = GDK_CURRENT_TIME;
1114     }
1115
1116     event->send_event = FALSE;
1117     event->state = state;
1118     event->keyval = keyval;
1119     event->string = NULL;
1120     event->length = 0;
1121     event->hardware_keycode = (keycode != 0) ? keycode + 8 : 0;
1122     event->group = 0;
1123     event->is_modifier = _key_is_modifier (keyval);
1124
1125 #ifdef DEPRECATED_GDK_KEYSYMS
1126     if (keyval != GDK_VoidSymbol)
1127 #else
1128     if (keyval != GDK_KEY_VoidSymbol)
1129 #endif
1130         c = gdk_keyval_to_unicode (keyval);
1131
1132     if (c) {
1133         gsize bytes_written;
1134         gint len;
1135
1136         /* Apply the control key - Taken from Xlib
1137          */
1138         if (event->state & GDK_CONTROL_MASK) {
1139             if ((c >= '@' && c < '\177') || c == ' ') c &= 0x1F;
1140             else if (c == '2') {
1141                 event->string = g_memdup ("\0\0", 2);
1142                 event->length = 1;
1143                 buf[0] = '\0';
1144                 goto out;
1145             }
1146             else if (c >= '3' && c <= '7') c -= ('3' - '\033');
1147             else if (c == '8') c = '\177';
1148             else if (c == '/') c = '_' & 0x1F;
1149         }
1150
1151         len = g_unichar_to_utf8 (c, buf);
1152         buf[len] = '\0';
1153
1154         event->string = g_locale_from_utf8 (buf, len,
1155                                             NULL, &bytes_written,
1156                                             NULL);
1157         if (event->string)
1158             event->length = bytes_written;
1159 #ifdef DEPRECATED_GDK_KEYSYMS
1160     } else if (keyval == GDK_Escape) {
1161 #else
1162     } else if (keyval == GDK_KEY_Escape) {
1163 #endif
1164         event->length = 1;
1165         event->string = g_strdup ("\033");
1166     }
1167 #ifdef DEPRECATED_GDK_KEYSYMS
1168     else if (keyval == GDK_Return ||
1169              keyval == GDK_KP_Enter) {
1170 #else
1171     else if (keyval == GDK_KEY_Return ||
1172              keyval == GDK_KEY_KP_Enter) {
1173 #endif
1174         event->length = 1;
1175         event->string = g_strdup ("\r");
1176     }
1177
1178     if (!event->string) {
1179         event->length = 0;
1180         event->string = g_strdup ("");
1181     }
1182 out:
1183     return event;
1184 }
1185
1186 static void
1187 _ibus_context_forward_key_event_cb (IBusInputContext  *ibuscontext,
1188                                     guint              keyval,
1189                                     guint              keycode,
1190                                     guint              state,
1191                                     IBusIMContext     *ibusimcontext)
1192 {
1193     IDEBUG ("%s", __FUNCTION__);
1194     GdkEventKey *event = _create_gdk_event (ibusimcontext, keyval, keycode, state);
1195     gdk_event_put ((GdkEvent *)event);
1196     gdk_event_free ((GdkEvent *)event);
1197 }
1198
1199 static void
1200 _ibus_context_delete_surrounding_text_cb (IBusInputContext *ibuscontext,
1201                                           gint              offset_from_cursor,
1202                                           guint             nchars,
1203                                           IBusIMContext    *ibusimcontext)
1204 {
1205     gboolean return_value;
1206     g_signal_emit (ibusimcontext, _signal_delete_surrounding_id, 0, offset_from_cursor, nchars, &return_value);
1207 }
1208
1209 static void
1210 _ibus_context_update_preedit_text_cb (IBusInputContext  *ibuscontext,
1211                                       IBusText          *text,
1212                                       gint               cursor_pos,
1213                                       gboolean           visible,
1214                                       IBusIMContext     *ibusimcontext)
1215 {
1216     IDEBUG ("%s", __FUNCTION__);
1217
1218     const gchar *str;
1219     gboolean flag;
1220
1221     if (ibusimcontext->preedit_string) {
1222         g_free (ibusimcontext->preedit_string);
1223     }
1224     if (ibusimcontext->preedit_attrs) {
1225         pango_attr_list_unref (ibusimcontext->preedit_attrs);
1226         ibusimcontext->preedit_attrs = NULL;
1227     }
1228
1229     str = text->text;
1230     ibusimcontext->preedit_string = g_strdup (str);
1231     if (text->attrs) {
1232         guint i;
1233         ibusimcontext->preedit_attrs = pango_attr_list_new ();
1234         for (i = 0; ; i++) {
1235             IBusAttribute *attr = ibus_attr_list_get (text->attrs, i);
1236             if (attr == NULL) {
1237                 break;
1238             }
1239
1240             PangoAttribute *pango_attr;
1241             switch (attr->type) {
1242             case IBUS_ATTR_TYPE_UNDERLINE:
1243                 pango_attr = pango_attr_underline_new (attr->value);
1244                 break;
1245             case IBUS_ATTR_TYPE_FOREGROUND:
1246                 pango_attr = pango_attr_foreground_new (
1247                                         ((attr->value & 0xff0000) >> 8) | 0xff,
1248                                         ((attr->value & 0x00ff00)) | 0xff,
1249                                         ((attr->value & 0x0000ff) << 8) | 0xff);
1250                 break;
1251             case IBUS_ATTR_TYPE_BACKGROUND:
1252                 pango_attr = pango_attr_background_new (
1253                                         ((attr->value & 0xff0000) >> 8) | 0xff,
1254                                         ((attr->value & 0x00ff00)) | 0xff,
1255                                         ((attr->value & 0x0000ff) << 8) | 0xff);
1256                 break;
1257             default:
1258                 continue;
1259             }
1260             pango_attr->start_index = g_utf8_offset_to_pointer (str, attr->start_index) - str;
1261             pango_attr->end_index = g_utf8_offset_to_pointer (str, attr->end_index) - str;
1262             pango_attr_list_insert (ibusimcontext->preedit_attrs, pango_attr);
1263         }
1264     }
1265
1266     ibusimcontext->preedit_cursor_pos = cursor_pos;
1267
1268     flag = ibusimcontext->preedit_visible != visible;
1269     ibusimcontext->preedit_visible = visible;
1270
1271     if (ibusimcontext->preedit_visible) {
1272         if (flag) {
1273             /* invisible => visible */
1274             g_signal_emit (ibusimcontext, _signal_preedit_start_id, 0);
1275         }
1276         g_signal_emit (ibusimcontext, _signal_preedit_changed_id, 0);
1277     }
1278     else {
1279         if (flag) {
1280             /* visible => invisible */
1281             g_signal_emit (ibusimcontext, _signal_preedit_changed_id, 0);
1282             g_signal_emit (ibusimcontext, _signal_preedit_end_id, 0);
1283         }
1284         else {
1285             /* still invisible */
1286             /* do nothing */
1287         }
1288     }
1289 }
1290
1291 static void
1292 _ibus_context_show_preedit_text_cb (IBusInputContext   *ibuscontext,
1293                                     IBusIMContext      *ibusimcontext)
1294 {
1295     IDEBUG ("%s", __FUNCTION__);
1296
1297     if (ibusimcontext->preedit_visible == TRUE)
1298         return;
1299
1300     ibusimcontext->preedit_visible = TRUE;
1301     g_signal_emit (ibusimcontext, _signal_preedit_start_id, 0);
1302     g_signal_emit (ibusimcontext, _signal_preedit_changed_id, 0);
1303
1304     _request_surrounding_text (ibusimcontext, FALSE);
1305 }
1306
1307 static void
1308 _ibus_context_hide_preedit_text_cb (IBusInputContext *ibuscontext,
1309                                     IBusIMContext    *ibusimcontext)
1310 {
1311     IDEBUG ("%s", __FUNCTION__);
1312
1313     if (ibusimcontext->preedit_visible == FALSE)
1314         return;
1315
1316     ibusimcontext->preedit_visible = FALSE;
1317     g_signal_emit (ibusimcontext, _signal_preedit_changed_id, 0);
1318     g_signal_emit (ibusimcontext, _signal_preedit_end_id, 0);
1319 }
1320
1321 static void
1322 _ibus_context_enabled_cb (IBusInputContext *ibuscontext,
1323                           IBusIMContext    *ibusimcontext)
1324 {
1325     IDEBUG ("%s", __FUNCTION__);
1326
1327     ibusimcontext->enable = TRUE;
1328
1329     /* retrieve the initial surrounding-text (regardless of whether
1330      * the current IBus engine needs surrounding-text) */
1331     _request_surrounding_text (ibusimcontext, TRUE);
1332 }
1333
1334 static void
1335 _ibus_context_disabled_cb (IBusInputContext *ibuscontext,
1336                            IBusIMContext    *ibusimcontext)
1337 {
1338     IDEBUG ("%s", __FUNCTION__);
1339     ibusimcontext->enable = FALSE;
1340
1341     /* clear preedit */
1342     ibusimcontext->preedit_visible = FALSE;
1343     ibusimcontext->preedit_cursor_pos = 0;
1344     g_free (ibusimcontext->preedit_string);
1345     ibusimcontext->preedit_string = NULL;
1346
1347     g_signal_emit (ibusimcontext, _signal_preedit_changed_id, 0);
1348     g_signal_emit (ibusimcontext, _signal_preedit_end_id, 0);
1349 }
1350
1351 static void
1352 _ibus_context_destroy_cb (IBusInputContext *ibuscontext,
1353                           IBusIMContext    *ibusimcontext)
1354 {
1355     IDEBUG ("%s", __FUNCTION__);
1356     g_assert (ibusimcontext->ibuscontext == ibuscontext);
1357
1358     g_object_unref (ibusimcontext->ibuscontext);
1359     ibusimcontext->ibuscontext = NULL;
1360
1361     ibusimcontext->enable = FALSE;
1362
1363     /* clear preedit */
1364     ibusimcontext->preedit_visible = FALSE;
1365     ibusimcontext->preedit_cursor_pos = 0;
1366     g_free (ibusimcontext->preedit_string);
1367     ibusimcontext->preedit_string = NULL;
1368
1369     g_signal_emit (ibusimcontext, _signal_preedit_changed_id, 0);
1370     g_signal_emit (ibusimcontext, _signal_preedit_end_id, 0);
1371 }
1372
1373 static void
1374 _create_input_context_done (IBusBus       *bus,
1375                             GAsyncResult  *res,
1376                             IBusIMContext *ibusimcontext)
1377 {
1378     GError *error = NULL;
1379     IBusInputContext *context = ibus_bus_create_input_context_async_finish (
1380             _bus, res, &error);
1381
1382     if (ibusimcontext->cancellable != NULL) {
1383         g_object_unref (ibusimcontext->cancellable);
1384         ibusimcontext->cancellable = NULL;
1385     }
1386
1387     if (context == NULL) {
1388         g_warning ("Create input context failed: %s.", error->message);
1389         g_error_free (error);
1390     }
1391     else {
1392
1393         ibusimcontext->ibuscontext = context;
1394
1395         g_signal_connect (ibusimcontext->ibuscontext,
1396                           "commit-text",
1397                           G_CALLBACK (_ibus_context_commit_text_cb),
1398                           ibusimcontext);
1399         g_signal_connect (ibusimcontext->ibuscontext,
1400                           "forward-key-event",
1401                           G_CALLBACK (_ibus_context_forward_key_event_cb),
1402                           ibusimcontext);
1403         g_signal_connect (ibusimcontext->ibuscontext,
1404                           "delete-surrounding-text",
1405                           G_CALLBACK (_ibus_context_delete_surrounding_text_cb),
1406                           ibusimcontext);
1407         g_signal_connect (ibusimcontext->ibuscontext,
1408                           "update-preedit-text",
1409                           G_CALLBACK (_ibus_context_update_preedit_text_cb),
1410                           ibusimcontext);
1411         g_signal_connect (ibusimcontext->ibuscontext,
1412                           "show-preedit-text",
1413                           G_CALLBACK (_ibus_context_show_preedit_text_cb),
1414                           ibusimcontext);
1415         g_signal_connect (ibusimcontext->ibuscontext,
1416                           "hide-preedit-text",
1417                           G_CALLBACK (_ibus_context_hide_preedit_text_cb),
1418                           ibusimcontext);
1419         g_signal_connect (ibusimcontext->ibuscontext,
1420                           "enabled",
1421                           G_CALLBACK (_ibus_context_enabled_cb),
1422                           ibusimcontext);
1423         g_signal_connect (ibusimcontext->ibuscontext,
1424                           "disabled",
1425                           G_CALLBACK (_ibus_context_disabled_cb),
1426                           ibusimcontext);
1427         g_signal_connect (ibusimcontext->ibuscontext, "destroy",
1428                           G_CALLBACK (_ibus_context_destroy_cb),
1429                           ibusimcontext);
1430
1431         ibus_input_context_set_capabilities (ibusimcontext->ibuscontext, ibusimcontext->caps);
1432
1433         if (ibusimcontext->has_focus) {
1434             ibus_input_context_focus_in (ibusimcontext->ibuscontext);
1435             _set_cursor_location_internal (ibusimcontext);
1436         }
1437     }
1438
1439     g_object_unref (ibusimcontext);
1440 }
1441
1442 static void
1443 _create_input_context (IBusIMContext *ibusimcontext)
1444 {
1445     IDEBUG ("%s", __FUNCTION__);
1446
1447     g_assert (ibusimcontext->ibuscontext == NULL);
1448
1449     if (ibusimcontext->cancellable != NULL) {
1450         /* Cancel previous create input context request */
1451         g_cancellable_cancel (ibusimcontext->cancellable);
1452         g_object_unref (ibusimcontext->cancellable);
1453         ibusimcontext->cancellable = NULL;
1454     }
1455
1456     ibusimcontext->cancellable = g_cancellable_new ();
1457
1458     ibus_bus_create_input_context_async (_bus,
1459             "gtk-im", -1,
1460             ibusimcontext->cancellable,
1461             (GAsyncReadyCallback)_create_input_context_done,
1462             g_object_ref (ibusimcontext));
1463 }
1464
1465 /* Callback functions for slave context */
1466 static void
1467 _slave_commit_cb (GtkIMContext  *slave,
1468                   gchar         *string,
1469                   IBusIMContext *ibusimcontext)
1470 {
1471 #if 0
1472     if ((GtkIMContext *)context == CURRENT_CONTEXT && ibus_im_client_is_enabled (_client))
1473         return;
1474 #endif
1475     g_signal_emit (ibusimcontext, _signal_commit_id, 0, string);
1476 }
1477
1478 static void
1479 _slave_preedit_changed_cb (GtkIMContext  *slave,
1480                            IBusIMContext *ibusimcontext)
1481 {
1482     if (ibusimcontext->enable && ibusimcontext->ibuscontext) {
1483         return;
1484     }
1485
1486     g_signal_emit (ibusimcontext, _signal_preedit_changed_id, 0);
1487 }
1488
1489 static void
1490 _slave_preedit_start_cb (GtkIMContext  *slave,
1491                          IBusIMContext *ibusimcontext)
1492 {
1493     if (ibusimcontext->enable && ibusimcontext->ibuscontext) {
1494         return;
1495     }
1496
1497     g_signal_emit (ibusimcontext, _signal_preedit_start_id, 0);
1498 }
1499
1500 static void
1501 _slave_preedit_end_cb (GtkIMContext  *slave,
1502                        IBusIMContext *ibusimcontext)
1503 {
1504     if (ibusimcontext->enable && ibusimcontext->ibuscontext) {
1505         return;
1506     }
1507     g_signal_emit (ibusimcontext, _signal_preedit_end_id, 0);
1508 }
1509
1510 static gboolean
1511 _slave_retrieve_surrounding_cb (GtkIMContext  *slave,
1512                                 IBusIMContext *ibusimcontext)
1513 {
1514     gboolean return_value;
1515
1516     if (ibusimcontext->enable && ibusimcontext->ibuscontext) {
1517         return FALSE;
1518     }
1519     g_signal_emit (ibusimcontext, _signal_retrieve_surrounding_id, 0,
1520                    &return_value);
1521     return return_value;
1522 }
1523
1524 static gboolean
1525 _slave_delete_surrounding_cb (GtkIMContext  *slave,
1526                               gint           offset_from_cursor,
1527                               guint          nchars,
1528                               IBusIMContext *ibusimcontext)
1529 {
1530     gboolean return_value;
1531
1532     if (ibusimcontext->enable && ibusimcontext->ibuscontext) {
1533         return FALSE;
1534     }
1535     g_signal_emit (ibusimcontext, _signal_delete_surrounding_id, 0, offset_from_cursor, nchars, &return_value);
1536     return return_value;
1537 }
1538
1539 #ifdef OS_CHROMEOS
1540 static void
1541 _ibus_fake_context_destroy_cb (IBusInputContext *ibuscontext,
1542                                gpointer          user_data)
1543 {
1544     /* The fack IC may be destroyed when the connection is lost.
1545      * Should release it. */
1546     g_assert (ibuscontext == _fake_context);
1547     g_object_unref (_fake_context);
1548     _fake_context = NULL;
1549 }
1550
1551 static GCancellable     *_fake_cancellable = NULL;
1552
1553 static void
1554 _create_fake_input_context_done (IBusBus       *bus,
1555                                  GAsyncResult  *res,
1556                                  IBusIMContext *ibusimcontext)
1557 {
1558     GError *error = NULL;
1559     IBusInputContext *context = ibus_bus_create_input_context_async_finish (
1560             _bus, res, &error);
1561
1562     if (_fake_cancellable != NULL) {
1563         g_object_unref (_fake_cancellable);
1564         _fake_cancellable = NULL;
1565     }
1566
1567     if (context == NULL) {
1568         g_warning ("Create fake input context failed: %s.", error->message);
1569         g_error_free (error);
1570         return;
1571     }
1572
1573     _fake_context = context;
1574
1575     g_signal_connect (_fake_context, "forward-key-event",
1576                       G_CALLBACK (_ibus_context_forward_key_event_cb),
1577                       NULL);
1578     g_signal_connect (_fake_context, "destroy",
1579                       G_CALLBACK (_ibus_fake_context_destroy_cb),
1580                       NULL);
1581
1582     guint32 caps = IBUS_CAP_PREEDIT_TEXT | IBUS_CAP_FOCUS | IBUS_CAP_SURROUNDING_TEXT;
1583     ibus_input_context_set_capabilities (_fake_context, caps);
1584
1585     /* focus in/out the fake context */
1586     if (_focus_im_context == NULL)
1587         ibus_input_context_focus_in (_fake_context);
1588     else
1589         ibus_input_context_focus_out (_fake_context);
1590 }
1591
1592 static void
1593 _create_fake_input_context (void)
1594 {
1595     g_return_if_fail (_fake_context == NULL);
1596
1597      /* Global engine is always enabled in Chrome OS,
1598       * so create fake IC, and set focus if no other IC has focus.
1599      */
1600
1601     if (_fake_cancellable != NULL) {
1602         g_cancellable_cancel (_fake_cancellable);
1603         g_object_unref (_fake_cancellable);
1604         _fake_cancellable = NULL;
1605     }
1606
1607     _fake_cancellable = g_cancellable_new ();
1608
1609     ibus_bus_create_input_context_async (_bus,
1610             "fake-gtk-im", -1,
1611             _fake_cancellable,
1612             (GAsyncReadyCallback)_create_fake_input_context_done,
1613             NULL);
1614
1615 }
1616 #else
1617 static void
1618 _create_fake_input_context (void)
1619 {
1620     /* For Linux desktop, do not use fake IC. */
1621 }
1622 #endif