Fix crash when turn off "use global engine" option
[platform/upstream/ibus.git] / bus / ibusimpl.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 #include <unistd.h>
24 #include <sys/types.h>
25 #include <sys/wait.h>
26 #include <signal.h>
27 #include <stdlib.h>
28 #include <locale.h>
29 #include <string.h>
30 #include <strings.h>
31 #include "types.h"
32 #include "ibusimpl.h"
33 #include "dbusimpl.h"
34 #include "server.h"
35 #include "connection.h"
36 #include "registry.h"
37 #include "factoryproxy.h"
38 #include "panelproxy.h"
39 #include "inputcontext.h"
40 #include "option.h"
41
42 struct _BusIBusImpl {
43     IBusService parent;
44     /* instance members */
45     GHashTable *factory_dict;
46
47     /* registered components */
48     GList *registered_components;
49     GList *contexts;
50
51     /* a fake input context for global engine support */
52     BusInputContext *fake_context;
53
54     /* a list of engines that are preloaded. */
55     GList *engine_list;
56     /* a list of engines that are started by a user (without the --ibus command line flag.) */
57     GList *register_engine_list;
58
59     /* if TRUE, ibus-daemon uses a keysym translated by the system (i.e. XKB) as-is.
60      * otherwise, ibus-daemon itself converts keycode into keysym. */
61     gboolean use_sys_layout;
62
63     gboolean embed_preedit_text;
64     gboolean enable_by_default;
65
66     BusRegistry     *registry;
67
68     BusInputContext *focused_context;
69     BusPanelProxy   *panel;
70     IBusConfig      *config;
71
72     /* global hotkeys such as "trigger" and "next_engine_in_menu" */
73     IBusHotkeyProfile *hotkey_profile;
74     /* a default keymap of ibus-daemon (usually "us") which is used only when use_sys_layout is FALSE. */
75     IBusKeymap      *keymap;
76
77     gboolean use_global_engine;
78     gchar *global_engine_name;
79     gchar *global_previous_engine_name;
80
81     /* engine-specific hotkeys */
82     IBusHotkeyProfile *engines_hotkey_profile;
83     GHashTable      *hotkey_to_engines_map;
84 };
85
86 struct _BusIBusImplClass {
87     IBusServiceClass parent;
88
89     /* class members */
90 };
91
92 enum {
93     LAST_SIGNAL,
94 };
95
96 enum {
97     PROP_0,
98 };
99
100 /*
101 static guint            _signals[LAST_SIGNAL] = { 0 };
102 */
103
104 /* functions prototype */
105 static void      bus_ibus_impl_destroy           (BusIBusImpl        *ibus);
106 static void      bus_ibus_impl_service_method_call
107                                                  (IBusService        *service,
108                                                   GDBusConnection    *connection,
109                                                   const gchar        *sender,
110                                                   const gchar        *object_path,
111                                                   const gchar        *interface_name,
112                                                   const gchar        *method_name,
113                                                   GVariant           *parameters,
114                                                   GDBusMethodInvocation
115                                                                      *invocation);
116 /* TODO use property to replace some getter and setter in future */
117 #if 0
118 static GVariant *ibus_ibus_impl_service_get_property
119                                               (IBusService        *service,
120                                                GDBusConnection    *connection,
121                                                const gchar        *sender,
122                                                const gchar        *object_path,
123                                                const gchar        *interface_name,
124                                                const gchar        *property_name,
125                                                GError            **error);
126 static gboolean  ibus_ibus_impl_service_set_property
127                                               (IBusService        *service,
128                                                GDBusConnection    *connection,
129                                                const gchar        *sender,
130                                                const gchar        *object_path,
131                                                const gchar        *interface_name,
132                                                const gchar        *property_name,
133                                                GVariant           *value,
134                                                GError            **error);
135 #endif
136 static void     bus_ibus_impl_set_trigger       (BusIBusImpl        *ibus,
137                                                  GVariant           *value);
138 static void     bus_ibus_impl_set_next_engine_in_menu
139                                                 (BusIBusImpl        *ibus,
140                                                  GVariant           *value);
141 static void     bus_ibus_impl_set_previous_engine
142                                                 (BusIBusImpl        *ibus,
143                                                  GVariant           *value);
144 static void     bus_ibus_impl_set_preload_engines
145                                                 (BusIBusImpl        *ibus,
146                                                  GVariant           *value);
147 static void     bus_ibus_impl_set_use_sys_layout
148                                                 (BusIBusImpl        *ibus,
149                                                  GVariant           *value);
150 static void     bus_ibus_impl_set_embed_preedit_text
151                                                 (BusIBusImpl        *ibus,
152                                                  GVariant           *value);
153 static void     bus_ibus_impl_set_enable_by_default
154                                                 (BusIBusImpl        *ibus,
155                                                  GVariant           *value);
156 static void     bus_ibus_impl_set_use_global_engine
157                                                 (BusIBusImpl        *ibus,
158                                                  GVariant           *value);
159 static void     bus_ibus_impl_registry_changed  (BusIBusImpl        *ibus);
160 static void     bus_ibus_impl_global_engine_changed
161                                                 (BusIBusImpl        *ibus);
162 static void     bus_ibus_impl_set_context_engine_from_desc
163                                                 (BusIBusImpl        *ibus,
164                                                  BusInputContext    *context,
165                                                  IBusEngineDesc     *desc);
166 static gchar   *bus_ibus_impl_load_global_engine_name_from_config
167                                                 (BusIBusImpl        *ibus);
168 static void     bus_ibus_impl_save_global_engine_name_to_config
169                                                 (BusIBusImpl        *ibus);
170
171 static gchar   *bus_ibus_impl_load_global_previous_engine_name_from_config
172                                                 (BusIBusImpl        *ibus);
173 static void     bus_ibus_impl_save_global_previous_engine_name_to_config
174                                                 (BusIBusImpl        *ibus);
175 static void     bus_ibus_impl_update_engines_hotkey_profile
176                                                 (BusIBusImpl        *ibus);
177 static BusInputContext
178                *bus_ibus_impl_create_input_context
179                                                 (BusIBusImpl        *ibus,
180                                                  BusConnection      *connection,
181                                                  const gchar        *client);
182 /* some callback functions */
183 static void     _context_engine_changed_cb      (BusInputContext    *context,
184                                                  BusIBusImpl        *ibus);
185
186 /* The interfaces available in this class, which consists of a list of methods this class implements and
187  * a list of signals this class may emit. Method calls to the interface that are not defined in this XML
188  * will be automatically rejected by the GDBus library (see src/ibusservice.c for details.) */
189 static const gchar introspection_xml[] =
190     "<node>\n"
191     "  <interface name='org.freedesktop.IBus'>\n"
192     "    <method name='GetAddress'>\n"
193     "      <arg direction='out' type='s' name='address' />\n"
194     "    </method>\n"
195     "    <method name='CreateInputContext'>\n"
196     "      <arg direction='in'  type='s' name='client_name' />\n"
197     "      <arg direction='out' type='o' name='object_path' />\n"
198     "    </method>\n"
199     "    <method name='CurrentInputContext'>\n"
200     "      <arg direction='out' type='o' name='object_path' />\n"
201     "    </method>\n"
202     "    <method name='RegisterComponent'>\n"
203     "      <arg direction='in'  type='v' name='component' />\n"
204     "    </method>\n"
205     "    <method name='ListEngines'>\n"
206     "      <arg direction='out' type='av' name='engines' />\n"
207     "    </method>\n"
208     "    <method name='ListActiveEngines'>\n"
209     "      <arg direction='out' type='av' name='engines' />\n"
210     "    </method>\n"
211     "    <method name='Exit'>\n"
212     "      <arg direction='in'  type='b' name='restart' />\n"
213     "    </method>\n"
214     "    <method name='Ping'>\n"
215     "      <arg direction='in'  type='v' name='data' />\n"
216     "      <arg direction='out' type='v' name='data' />\n"
217     "    </method>\n"
218     "    <method name='GetUseSysLayout'>\n"
219     "      <arg direction='out' type='b' name='enabled' />\n"
220     "    </method>\n"
221     "    <method name='GetUseGlobalEngine'>\n"
222     "      <arg direction='out' type='b' name='enabled' />\n"
223     "    </method>\n"
224     "    <method name='GetGlobalEngine'>\n"
225     "      <arg direction='out' type='v' name='desc' />\n"
226     "    </method>\n"
227     "    <method name='SetGlobalEngine'>\n"
228     "      <arg direction='in'  type='s' name='engine_name' />\n"
229     "    </method>\n"
230     "    <method name='IsGlobalEngineEnabled'>\n"
231     "      <arg direction='out' type='b' name='enabled' />\n"
232     "    </method>\n"
233     "    <signal name='RegistryChanged'>\n"
234     "    </signal>\n"
235     "    <signal name='GlobalEngineChanged'>\n"
236     "      <arg type='s' name='engine_name' />\n"
237     "    </signal>\n"
238     "  </interface>\n"
239     "</node>\n";
240
241
242 G_DEFINE_TYPE (BusIBusImpl, bus_ibus_impl, IBUS_TYPE_SERVICE)
243
244 static void
245 bus_ibus_impl_class_init (BusIBusImplClass *class)
246 {
247     IBUS_OBJECT_CLASS (class)->destroy = (IBusObjectDestroyFunc) bus_ibus_impl_destroy;
248
249     /* override the parent class's implementation. */
250     IBUS_SERVICE_CLASS (class)->service_method_call = bus_ibus_impl_service_method_call;
251     /* register the xml so that bus_ibus_impl_service_method_call will be called on a method call defined in the xml (e.g. 'GetAddress'.) */
252     ibus_service_class_add_interfaces (IBUS_SERVICE_CLASS (class), introspection_xml);
253 }
254
255 /**
256  * _panel_destroy_cb:
257  *
258  * A callback function which is called when (1) the connection to the panel process is terminated,
259  * or (2) ibus_proxy_destroy (ibus->panel); is called. See src/ibusproxy.c for details.
260  */
261 static void
262 _panel_destroy_cb (BusPanelProxy *panel,
263                    BusIBusImpl   *ibus)
264 {
265     g_assert (BUS_IS_PANEL_PROXY (panel));
266     g_assert (BUS_IS_IBUS_IMPL (ibus));
267
268     g_return_if_fail (ibus->panel == panel);
269
270     ibus->panel = NULL;
271     g_object_unref (panel);
272 }
273
274 static void
275 bus_ibus_impl_set_hotkey (BusIBusImpl *ibus,
276                           GQuark       hotkey,
277                           GVariant    *value)
278 {
279     g_assert (BUS_IS_IBUS_IMPL (ibus));
280
281     ibus_hotkey_profile_remove_hotkey_by_event (ibus->hotkey_profile, hotkey);
282
283     if (value == NULL) {
284         return;
285     }
286
287     GVariantIter iter;
288     g_variant_iter_init (&iter, value);
289     const gchar *str = NULL;
290     while (g_variant_iter_loop (&iter,"&s", &str)) {
291        ibus_hotkey_profile_add_hotkey_from_string (ibus->hotkey_profile,
292                                                    str,
293                                                    hotkey);
294     }
295
296 }
297
298 /**
299  * bus_ibus_impl_set_trigger:
300  *
301  * A function to be called when "trigger" config is updated. If the value is NULL, the default trigger (Ctrl+space) is set.
302  */
303 static void
304 bus_ibus_impl_set_trigger (BusIBusImpl *ibus,
305                            GVariant    *value)
306 {
307     GQuark hotkey = g_quark_from_static_string ("trigger");
308     if (value != NULL) {
309         bus_ibus_impl_set_hotkey (ibus, hotkey, value);
310     }
311 #ifndef OS_CHROMEOS
312     else {
313         /* set default trigger */
314         ibus_hotkey_profile_remove_hotkey_by_event (ibus->hotkey_profile, hotkey);
315         ibus_hotkey_profile_add_hotkey (ibus->hotkey_profile,
316                                         IBUS_space,
317                                         IBUS_CONTROL_MASK,
318                                         hotkey);
319     }
320 #endif
321 }
322
323 /**
324  * bus_ibus_impl_set_enable_unconditional:
325  *
326  * A function to be called when "enable_unconditional" config is updated.
327  */
328 static void
329 bus_ibus_impl_set_enable_unconditional (BusIBusImpl *ibus,
330                                         GVariant    *value)
331 {
332     GQuark hotkey = g_quark_from_static_string ("enable-unconditional");
333     bus_ibus_impl_set_hotkey (ibus, hotkey, value);
334 }
335
336 /**
337  * bus_ibus_impl_set_disable_unconditional:
338  *
339  * A function to be called when "disable_unconditional" config is updated.
340  */
341 static void
342 bus_ibus_impl_set_disable_unconditional (BusIBusImpl *ibus,
343                                          GVariant    *value)
344 {
345     GQuark hotkey = g_quark_from_static_string ("disable-unconditional");
346     bus_ibus_impl_set_hotkey (ibus, hotkey, value);
347 }
348
349 /**
350  * bus_ibus_impl_set_next_engine_in_menu:
351  *
352  * A function to be called when "next_engine_in_menu" config is updated.
353  */
354 static void
355 bus_ibus_impl_set_next_engine_in_menu (BusIBusImpl *ibus,
356                                        GVariant    *value)
357 {
358     GQuark hotkey = g_quark_from_static_string ("next-engine-in-menu");
359     bus_ibus_impl_set_hotkey (ibus, hotkey, value);
360 }
361
362 /**
363  * bus_ibus_impl_set_previous_engine:
364  *
365  * A function to be called when "previous_engine" config is updated.
366  */
367 static void
368 bus_ibus_impl_set_previous_engine (BusIBusImpl *ibus,
369                                    GVariant    *value)
370 {
371     GQuark hotkey = g_quark_from_static_string ("previous-engine");
372     bus_ibus_impl_set_hotkey (ibus, hotkey, value);
373 }
374
375 /**
376  * bus_ibus_impl_set_preload_engines:
377  *
378  * A function to be called when "preload_engines" config is updated.
379  */
380 static void
381 bus_ibus_impl_set_preload_engines (BusIBusImpl *ibus,
382                                    GVariant    *value)
383 {
384     GList *engine_list = NULL;
385
386     g_list_foreach (ibus->engine_list, (GFunc) g_object_unref, NULL);
387     g_list_free (ibus->engine_list);
388
389     if (value != NULL && g_variant_classify (value) == G_VARIANT_CLASS_ARRAY) {
390         GVariantIter iter;
391         g_variant_iter_init (&iter, value);
392         const gchar *engine_name = NULL;
393         while (g_variant_iter_loop (&iter, "&s", &engine_name)) {
394             IBusEngineDesc *engine = bus_registry_find_engine_by_name (ibus->registry, engine_name);
395             if (engine == NULL || g_list_find (engine_list, engine) != NULL)
396                 continue;
397             engine_list = g_list_append (engine_list, engine);
398         }
399     }
400
401     g_list_foreach (engine_list, (GFunc) g_object_ref, NULL);
402     ibus->engine_list = engine_list;
403
404     if (ibus->engine_list) {
405         BusComponent *component = bus_component_from_engine_desc ((IBusEngineDesc *) ibus->engine_list->data);
406         if (component && !bus_component_is_running (component)) {
407             bus_component_start (component, g_verbose);
408         }
409     }
410
411     bus_ibus_impl_update_engines_hotkey_profile (ibus);
412 }
413
414 /**
415  * bus_ibus_impl_set_use_sys_layout:
416  *
417  * A function to be called when "use_system_keyboard_layout" config is updated.
418  */
419 static void
420 bus_ibus_impl_set_use_sys_layout (BusIBusImpl *ibus,
421                                   GVariant    *value)
422 {
423     if (value != NULL && g_variant_classify (value) == G_VARIANT_CLASS_BOOLEAN) {
424         ibus->use_sys_layout = g_variant_get_boolean (value);
425     }
426 }
427
428 /**
429  * bus_ibus_impl_set_embed_preedit_text:
430  *
431  * A function to be called when "use_embed_preedit_text" config is updated.
432  */
433 static void
434 bus_ibus_impl_set_embed_preedit_text (BusIBusImpl *ibus,
435                                       GVariant    *value)
436 {
437     if (value != NULL && g_variant_classify (value) == G_VARIANT_CLASS_BOOLEAN) {
438         ibus->embed_preedit_text = g_variant_get_boolean (value);
439     }
440 }
441
442 /**
443  * bus_ibus_impl_set_enable_by_default:
444  *
445  * A function to be called when "enable_by_default" config is updated.
446  */
447 static void
448 bus_ibus_impl_set_enable_by_default (BusIBusImpl *ibus,
449                                      GVariant    *value)
450 {
451     if (value != NULL && g_variant_classify (value) == G_VARIANT_CLASS_BOOLEAN) {
452         ibus->enable_by_default = g_variant_get_boolean (value);
453     }
454 }
455
456 /**
457  * bus_ibus_impl_set_use_global_engine:
458  *
459  * A function to be called when "use_global_engine" config is updated.
460  */
461 static void
462 bus_ibus_impl_set_use_global_engine (BusIBusImpl *ibus,
463                                      GVariant    *value)
464 {
465     if (value == NULL || g_variant_classify (value) != G_VARIANT_CLASS_BOOLEAN)
466         return;
467
468     gboolean new_value = g_variant_get_boolean (value);
469     if (ibus->use_global_engine == new_value)
470         return;
471
472     if (new_value) {
473         /* turn on use_global_engine option */
474         ibus->use_global_engine = TRUE;
475         if (ibus->panel && ibus->focused_context == NULL) {
476             bus_panel_proxy_focus_in (ibus->panel, ibus->fake_context);
477         }
478     }
479     else {
480         /* turn off use_global_engine option */
481         ibus->use_global_engine = FALSE;
482
483         /* if fake context has the focus, we should focus out it */
484         if (ibus->panel && ibus->focused_context == NULL) {
485             bus_panel_proxy_focus_out (ibus->panel, ibus->fake_context);
486         }
487         /* remove engine in fake context */
488         bus_input_context_set_engine (ibus->fake_context, NULL);
489     }
490 }
491
492 #ifndef OS_CHROMEOS
493 static gint
494 _engine_desc_cmp (IBusEngineDesc *desc1,
495                   IBusEngineDesc *desc2)
496 {
497     return - ((gint) ibus_engine_desc_get_rank (desc1)) +
498               ((gint) ibus_engine_desc_get_rank (desc2));
499 }
500 #endif
501
502 /**
503  * bus_ibus_impl_set_default_preload_engines:
504  *
505  * If the "preload_engines" config variable is not set yet, set the default value which is determined based on a current locale.
506  */
507 static void
508 bus_ibus_impl_set_default_preload_engines (BusIBusImpl *ibus)
509 {
510 #ifndef OS_CHROMEOS
511     g_assert (BUS_IS_IBUS_IMPL (ibus));
512
513     static gboolean done = FALSE;
514
515     if (done || ibus->config == NULL) {
516         return;
517     }
518
519     GVariant *variant = ibus_config_get_value (ibus->config, "general", "preload_engines");
520     if (variant != NULL) {
521         done = TRUE;
522         g_variant_unref (variant);
523         return;
524     }
525
526     done = TRUE;
527
528     /* The setlocale call first checks LC_ALL. If it's not available, checks
529      * LC_CTYPE. If it's also not available, checks LANG. */
530     gchar *lang = g_strdup (setlocale (LC_CTYPE, NULL));
531     if (lang == NULL) {
532         return;
533     }
534
535     gchar *p = index (lang, '.');
536     if (p) {
537         *p = '\0';
538     }
539
540     GList *engines = bus_registry_get_engines_by_language (ibus->registry, lang);
541     if (engines == NULL) {
542         p = index (lang, '_');
543         if (p) {
544             *p = '\0';
545             engines = bus_registry_get_engines_by_language (ibus->registry, lang);
546         }
547     }
548     g_free (lang);
549
550     /* sort engines by rank */
551     engines = g_list_sort (engines, (GCompareFunc) _engine_desc_cmp);
552
553     GVariantBuilder builder;
554     g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
555     GList *list;
556     for (list = engines; list != NULL; list = list->next) {
557         IBusEngineDesc *desc = (IBusEngineDesc *) list->data;
558         /* ignore engines with rank <= 0 */
559         if (ibus_engine_desc_get_rank (desc) > 0)
560             g_variant_builder_add (&builder, "s", ibus_engine_desc_get_name (desc));
561     }
562
563     GVariant *value = g_variant_builder_end (&builder);
564     if (value != NULL) {
565         if (g_variant_n_children (value) > 0) {
566             ibus_config_set_value (ibus->config,
567                                    "general", "preload_engines", value);
568         } else {
569             /* We don't update preload_engines with an empty string for safety.
570              * Just unref the floating value. */
571             g_variant_unref (value);
572         }
573     }
574     g_list_free (engines);
575 #endif
576 }
577
578 /* The list of config entries that are related to ibus-daemon. */
579 const static struct {
580     gchar *section;
581     gchar *key;
582     void (*func) (BusIBusImpl *, GVariant *);
583 } bus_ibus_impl_config_items [] = {
584     { "general/hotkey", "trigger",               bus_ibus_impl_set_trigger },
585     { "general/hotkey", "enable_unconditional",  bus_ibus_impl_set_enable_unconditional },
586     { "general/hotkey", "disable_unconditional", bus_ibus_impl_set_disable_unconditional },
587     { "general/hotkey", "next_engine_in_menu",   bus_ibus_impl_set_next_engine_in_menu },
588     { "general/hotkey", "previous_engine",       bus_ibus_impl_set_previous_engine },
589     { "general", "preload_engines",              bus_ibus_impl_set_preload_engines },
590     { "general", "use_system_keyboard_layout",   bus_ibus_impl_set_use_sys_layout },
591     { "general", "use_global_engine",            bus_ibus_impl_set_use_global_engine },
592     { "general", "embed_preedit_text",           bus_ibus_impl_set_embed_preedit_text },
593     { "general", "enable_by_default",            bus_ibus_impl_set_enable_by_default },
594 };
595
596 /**
597  * bus_ibus_impl_reload_config
598  *
599  * Read config entries (e.g. preload_engines) from the config daemon.
600  */
601 static void
602 bus_ibus_impl_reload_config (BusIBusImpl *ibus)
603 {
604     g_assert (BUS_IS_IBUS_IMPL (ibus));
605
606     gint i;
607     for (i = 0; i < G_N_ELEMENTS (bus_ibus_impl_config_items); i++) {
608         GVariant *variant = NULL;
609         if (ibus->config != NULL)
610             variant = ibus_config_get_value (ibus->config,
611                             bus_ibus_impl_config_items[i].section,
612                             bus_ibus_impl_config_items[i].key);
613         bus_ibus_impl_config_items[i].func (ibus, variant); /* variant could be NULL if the deamon is not ready yet. */
614         if (variant) g_variant_unref (variant);
615     }
616 }
617
618 /**
619  * _config_value_changed_cb:
620  *
621  * A callback function to be called when the "ValueChanged" D-Bus signal is sent from the config daemon.
622  */
623 static void
624 _config_value_changed_cb (IBusConfig  *config,
625                           gchar       *section,
626                           gchar       *key,
627                           GVariant    *value,
628                           BusIBusImpl *ibus)
629 {
630     g_assert (IBUS_IS_CONFIG (config));
631     g_assert (section);
632     g_assert (key);
633     g_assert (value);
634     g_assert (BUS_IS_IBUS_IMPL (ibus));
635
636     gint i;
637     for (i = 0; i < G_N_ELEMENTS (bus_ibus_impl_config_items); i++) {
638         if (g_strcmp0 (bus_ibus_impl_config_items[i].section, section) == 0 &&
639             g_strcmp0 (bus_ibus_impl_config_items[i].key, key) == 0) {
640             bus_ibus_impl_config_items[i].func (ibus, value);
641             break;
642         }
643     }
644 }
645
646 /**
647  * _config_destroy_cb:
648  *
649  * A callback function which is called when (1) the connection to the config process is terminated,
650  * or (2) ibus_proxy_destroy (ibus->config); is called. See src/ibusproxy.c for details.
651  */
652 static void
653 _config_destroy_cb (IBusConfig  *config,
654                     BusIBusImpl *ibus)
655 {
656     g_assert (IBUS_IS_CONFIG (config));
657     g_assert (BUS_IS_IBUS_IMPL (ibus));
658
659     g_assert (ibus->config == config);
660
661     g_object_unref (ibus->config);
662     ibus->config = NULL;
663 }
664
665 static void
666 _registry_changed_cb (BusRegistry *registry,
667                       BusIBusImpl *ibus)
668 {
669     bus_ibus_impl_registry_changed (ibus);
670 }
671
672 /*
673  * _dbus_name_owner_changed_cb:
674  *
675  * A callback function to be called when the name-owner-changed signal is sent to the dbus object.
676  * This usually means a client (e.g. a panel/config/engine process or an application) is connected/disconnected to/from the bus.
677  */
678 static void
679 _dbus_name_owner_changed_cb (BusDBusImpl *dbus,
680                              const gchar *name,
681                              const gchar *old_name,
682                              const gchar *new_name,
683                              BusIBusImpl *ibus)
684 {
685     g_assert (BUS_IS_DBUS_IMPL (dbus));
686     g_assert (name != NULL);
687     g_assert (old_name != NULL);
688     g_assert (new_name != NULL);
689     g_assert (BUS_IS_IBUS_IMPL (ibus));
690
691     if (g_strcmp0 (name, IBUS_SERVICE_PANEL) == 0) {
692         if (g_strcmp0 (new_name, "") != 0) {
693             /* a Panel process is started. */
694             BusConnection *connection;
695
696             if (ibus->panel != NULL) {
697                 ibus_proxy_destroy ((IBusProxy *) ibus->panel);
698                 /* panel should be NULL after destroy. See _panel_destroy_cb for details. */
699                 g_assert (ibus->panel == NULL);
700             }
701
702             connection = bus_dbus_impl_get_connection_by_name (BUS_DEFAULT_DBUS, new_name);
703             g_return_if_fail (connection != NULL);
704
705             ibus->panel = bus_panel_proxy_new (connection);
706
707             g_signal_connect (ibus->panel,
708                               "destroy",
709                               G_CALLBACK (_panel_destroy_cb),
710                               ibus);
711
712             if (ibus->focused_context != NULL) {
713                 bus_panel_proxy_focus_in (ibus->panel, ibus->focused_context);
714             }
715             else if (ibus->use_global_engine) {
716                 bus_panel_proxy_focus_in (ibus->panel, ibus->fake_context);
717             }
718         }
719     }
720     else if (g_strcmp0 (name, IBUS_SERVICE_CONFIG) == 0) {
721         if (g_strcmp0 (new_name, "") != 0) {
722             /* a config process is started. */
723             BusConnection *connection;
724
725             if (ibus->config != NULL) {
726                 ibus_proxy_destroy ((IBusProxy *) ibus->config);
727                 /* config should be NULL after destroy. See _config_destroy_cb for details. */
728                 g_assert (ibus->config == NULL);
729             }
730
731             /* get a connection between ibus-daemon and the config daemon. */
732             connection = bus_dbus_impl_get_connection_by_name (BUS_DEFAULT_DBUS, new_name);
733             g_return_if_fail (connection != NULL);
734
735             ibus->config = g_initable_new (IBUS_TYPE_CONFIG,
736                                            NULL,
737                                            NULL,
738                                            /* The following properties are necessary to initialize GDBusProxy object
739                                             * which is a parent of the config object. */
740                                            "g-connection",      bus_connection_get_dbus_connection (connection),
741                                            "g-flags",           G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START | G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
742                                            "g-interface-name",  IBUS_INTERFACE_CONFIG,
743                                            "g-object-path",     IBUS_PATH_CONFIG,
744                                            "g-default-timeout", g_gdbus_timeout,
745                                            NULL);
746
747             g_signal_connect (ibus->config,
748                               "value-changed",
749                               G_CALLBACK (_config_value_changed_cb),
750                               ibus);
751
752             g_signal_connect (ibus->config,
753                               "destroy",
754                               G_CALLBACK (_config_destroy_cb),
755                               ibus);
756
757             bus_ibus_impl_set_default_preload_engines (ibus);
758             bus_ibus_impl_reload_config (ibus);
759         }
760     }
761
762     bus_registry_name_owner_changed (ibus->registry, name, old_name, new_name);
763 }
764
765 /**
766  * bus_ibus_impl_init:
767  *
768  * The constructor of BusIBusImpl. Initialize all member variables of a BusIBusImpl object.
769  */
770 static void
771 bus_ibus_impl_init (BusIBusImpl *ibus)
772 {
773     ibus->factory_dict = g_hash_table_new_full (
774                             g_str_hash,
775                             g_str_equal,
776                             NULL,
777                             (GDestroyNotify) g_object_unref);
778
779     ibus->fake_context = bus_input_context_new (NULL, "fake");
780     g_object_ref_sink (ibus->fake_context);
781     bus_dbus_impl_register_object (BUS_DEFAULT_DBUS,
782                                    (IBusService *) ibus->fake_context);
783     bus_input_context_set_capabilities (ibus->fake_context,
784                                         IBUS_CAP_PREEDIT_TEXT |
785                                         IBUS_CAP_FOCUS |
786                                         IBUS_CAP_SURROUNDING_TEXT);
787     g_signal_connect (ibus->fake_context,
788                       "engine-changed",
789                       G_CALLBACK (_context_engine_changed_cb),
790                       ibus);
791     bus_input_context_focus_in (ibus->fake_context);
792
793     ibus->engine_list = NULL;
794     ibus->register_engine_list = NULL;
795     ibus->contexts = NULL;
796     ibus->focused_context = NULL;
797     ibus->panel = NULL;
798     ibus->config = NULL;
799
800     ibus->registry = bus_registry_new ();
801
802     g_signal_connect (ibus->registry,
803                       "changed",
804                       G_CALLBACK (_registry_changed_cb),
805                       ibus);
806 #ifdef G_THREADS_ENABLED
807     extern gint g_monitor_timeout;
808     if (g_monitor_timeout != 0) {
809         /* Start the monitor of registry changes. */
810         bus_registry_start_monitor_changes (ibus->registry);
811     }
812 #endif
813
814     ibus->hotkey_profile = ibus_hotkey_profile_new ();
815     ibus->keymap = ibus_keymap_get ("us");
816
817     ibus->use_sys_layout = FALSE;
818     ibus->embed_preedit_text = TRUE;
819     ibus->enable_by_default = FALSE;
820     ibus->use_global_engine = FALSE;
821     ibus->global_engine_name = NULL;
822     ibus->global_previous_engine_name = NULL;
823
824     ibus->engines_hotkey_profile = NULL;
825     ibus->hotkey_to_engines_map = NULL;
826
827     bus_ibus_impl_reload_config (ibus);
828
829     g_signal_connect (BUS_DEFAULT_DBUS,
830                       "name-owner-changed",
831                       G_CALLBACK (_dbus_name_owner_changed_cb),
832                       ibus);
833 }
834
835 /**
836  * bus_ibus_impl_destroy:
837  *
838  * The destructor of BusIBusImpl.
839  */
840 static void
841 bus_ibus_impl_destroy (BusIBusImpl *ibus)
842 {
843     pid_t pid;
844     glong timeout;
845     gint status;
846     gboolean flag;
847
848     bus_registry_stop_all_components (ibus->registry);
849
850     pid = 0;
851     timeout = 0;
852     flag = FALSE;
853     while (1) {
854         while ((pid = waitpid (0, &status, WNOHANG)) > 0);
855
856         if (pid == -1) { /* all children finished */
857             break;
858         }
859         if (pid == 0) { /* no child status changed */
860             g_usleep (1000);
861             timeout += 1000;
862             if (timeout >= G_USEC_PER_SEC) {
863                 if (flag == FALSE) {
864                     gpointer old;
865                     old = signal (SIGTERM, SIG_IGN);
866                     /* send TERM signal to the whole process group (i.e. engines, panel, and config daemon.) */
867                     kill (-getpid (), SIGTERM);
868                     signal (SIGTERM, old);
869                     flag = TRUE;
870                 }
871                 else {
872                     g_warning ("Not every child processes exited!");
873                     break;
874                 }
875             }
876         }
877     }
878
879     g_list_foreach (ibus->engine_list, (GFunc) g_object_unref, NULL);
880     g_list_free (ibus->engine_list);
881     ibus->engine_list = NULL;
882
883     g_list_foreach (ibus->register_engine_list, (GFunc) g_object_unref, NULL);
884     g_list_free (ibus->register_engine_list);
885     ibus->register_engine_list = NULL;
886
887     if (ibus->factory_dict != NULL) {
888         g_hash_table_destroy (ibus->factory_dict);
889         ibus->factory_dict = NULL;
890     }
891
892     if (ibus->hotkey_profile != NULL) {
893         g_object_unref (ibus->hotkey_profile);
894         ibus->hotkey_profile = NULL;
895     }
896
897     if (ibus->keymap != NULL) {
898         g_object_unref (ibus->keymap);
899         ibus->keymap = NULL;
900     }
901
902     g_free (ibus->global_engine_name);
903     ibus->global_engine_name = NULL;
904
905     g_free (ibus->global_previous_engine_name);
906     ibus->global_previous_engine_name = NULL;
907
908     if (ibus->engines_hotkey_profile != NULL) {
909         g_object_unref (ibus->engines_hotkey_profile);
910         ibus->engines_hotkey_profile = NULL;
911     }
912
913     if (ibus->hotkey_to_engines_map) {
914         g_hash_table_unref (ibus->hotkey_to_engines_map);
915         ibus->hotkey_to_engines_map = NULL;
916     }
917
918     if (ibus->fake_context) {
919         g_object_unref (ibus->fake_context);
920         ibus->fake_context = NULL;
921     }
922
923     bus_server_quit ();
924     IBUS_OBJECT_CLASS (bus_ibus_impl_parent_class)->destroy (IBUS_OBJECT (ibus));
925 }
926
927 /**
928  * _ibus_get_address:
929  *
930  * Implement the "GetAddress" method call of the org.freedesktop.IBus interface.
931  */
932 static void
933 _ibus_get_address (BusIBusImpl           *ibus,
934                    GVariant              *parameters,
935                    GDBusMethodInvocation *invocation)
936 {
937     g_dbus_method_invocation_return_value (invocation,
938                                            g_variant_new ("(s)", bus_server_get_address ()));
939 }
940
941 static IBusEngineDesc *
942 _find_engine_desc_by_name (BusIBusImpl *ibus,
943                            const gchar *engine_name)
944 {
945     IBusEngineDesc *desc = NULL;
946     GList *p;
947
948     /* find engine in registered engine list */
949     for (p = ibus->register_engine_list; p != NULL; p = p->next) {
950         desc = (IBusEngineDesc *) p->data;
951         if (g_strcmp0 (ibus_engine_desc_get_name (desc), engine_name) == 0)
952             return desc;
953     }
954
955     /* find engine in preload engine list */
956     for (p = ibus->engine_list; p != NULL; p = p->next) {
957         desc = (IBusEngineDesc *) p->data;
958         if (g_strcmp0 (ibus_engine_desc_get_name (desc), engine_name) == 0)
959             return desc;
960     }
961
962     return NULL;
963 }
964
965 /**
966  * _context_request_engine_cb:
967  *
968  * A callback function to be called when the "request-engine" signal is sent to the context.
969  */
970 static void
971 _context_request_engine_cb (BusInputContext *context,
972                             const gchar     *engine_name,
973                             BusIBusImpl     *ibus)
974 {
975     IBusEngineDesc *desc = NULL;
976
977     /* context should has focus before request an engine */
978     g_return_if_fail (bus_input_context_has_focus (context) ||
979                       context == ibus->focused_context);
980
981     if (engine_name != NULL && engine_name[0] != '\0') {
982         /* request engine by name */
983         desc = _find_engine_desc_by_name (ibus, engine_name);
984         g_return_if_fail (desc != NULL);
985     }
986     else {
987         /* Use global engine if possible. */
988         if (ibus->use_global_engine) {
989             gchar *name = g_strdup (ibus->global_engine_name);
990             if (name == NULL) {
991                 name = bus_ibus_impl_load_global_engine_name_from_config (ibus);
992             }
993             if (name) {
994                 desc = _find_engine_desc_by_name (ibus, name);
995                 g_free (name);
996             }
997         }
998         /* request default engine */
999         if (!desc) {
1000             if (ibus->register_engine_list) {
1001                 desc = (IBusEngineDesc *) ibus->register_engine_list->data;
1002             }
1003             else if (ibus->engine_list) {
1004                 desc = (IBusEngineDesc *) ibus->engine_list->data;
1005             }
1006         }
1007         if (!desc) {
1008             /* no engine is available. the user hasn't ran ibus-setup yet and
1009              * the bus_ibus_impl_set_default_preload_engines() function could
1010              * not find any default engines. another possiblity is that the
1011              * user hasn't installed an engine yet? just give up. */
1012             g_warning ("No engine is available. Run ibus-setup first.");
1013             return;
1014         }
1015     }
1016
1017     bus_ibus_impl_set_context_engine_from_desc (ibus, context, desc);
1018 }
1019
1020 /**
1021  * bus_ibus_impl_context_request_next_engine_in_menu:
1022  *
1023  * Process the "next_engine_in_menu" hotkey.
1024  */
1025 static void
1026 bus_ibus_impl_context_request_next_engine_in_menu (BusIBusImpl     *ibus,
1027                                                    BusInputContext *context)
1028 {
1029     BusEngineProxy *engine;
1030     IBusEngineDesc *desc;
1031     IBusEngineDesc *next_desc = NULL;
1032     GList *p;
1033
1034     engine = bus_input_context_get_engine (context);
1035     if (engine == NULL) {
1036         _context_request_engine_cb (context, NULL, ibus);
1037         return;
1038     }
1039
1040     desc = bus_engine_proxy_get_desc (engine);
1041
1042     p = g_list_find (ibus->register_engine_list, desc);
1043     if (p != NULL) {
1044         p = p->next;
1045     }
1046     if (p == NULL) {
1047         p = g_list_find (ibus->engine_list, desc);
1048         if (p != NULL) {
1049             p = p->next;
1050         }
1051     }
1052
1053     if (p != NULL) {
1054         next_desc = (IBusEngineDesc*) p->data;
1055     }
1056     else {
1057         if (ibus->register_engine_list) {
1058             next_desc = (IBusEngineDesc *) ibus->register_engine_list->data;
1059         }
1060         else if (ibus->engine_list) {
1061             next_desc = (IBusEngineDesc *) ibus->engine_list->data;
1062         }
1063     }
1064
1065     bus_ibus_impl_set_context_engine_from_desc (ibus, context, next_desc);
1066 }
1067
1068 /**
1069  * bus_ibus_impl_context_request_previous_engine:
1070  *
1071  * Process the "previous_engine" hotkey.
1072  */
1073 static void
1074 bus_ibus_impl_context_request_previous_engine (BusIBusImpl     *ibus,
1075                                                BusInputContext *context)
1076 {
1077     gchar *engine_name = NULL;
1078     if (!ibus->use_global_engine) {
1079         engine_name = (gchar *) g_object_get_data (G_OBJECT (context), "previous-engine-name");
1080     }
1081     else {
1082         if (!ibus->global_previous_engine_name) {
1083             ibus->global_previous_engine_name = bus_ibus_impl_load_global_previous_engine_name_from_config (ibus);
1084         }
1085         engine_name = ibus->global_previous_engine_name;
1086     }
1087
1088     /*
1089      * If the previous engine name is not found, switch to the next engine
1090      * in the menu. This behavior is better than doing nothing.
1091      */
1092     if (!engine_name) {
1093         bus_ibus_impl_context_request_next_engine_in_menu (ibus, context);
1094         return;
1095     }
1096     _context_request_engine_cb (context, engine_name, ibus);
1097 }
1098
1099 static void
1100 bus_ibus_impl_set_context_engine_from_desc (BusIBusImpl     *ibus,
1101                                             BusInputContext *context,
1102                                             IBusEngineDesc  *desc)
1103 {
1104     bus_input_context_set_engine_by_desc (context,
1105                                           desc,
1106                                           g_gdbus_timeout, /* timeout in msec. */
1107                                           NULL, /* we do not cancel the call. */
1108                                           NULL, /* use the default callback function. */
1109                                           NULL);
1110 }
1111
1112 /**
1113  * bus_ibus_impl_set_focused_context:
1114  *
1115  * Set the current focused context.
1116  */
1117 static void
1118 bus_ibus_impl_set_focused_context (BusIBusImpl     *ibus,
1119                                    BusInputContext *context)
1120 {
1121     g_assert (BUS_IS_IBUS_IMPL (ibus));
1122     g_assert (context == NULL || BUS_IS_INPUT_CONTEXT (context));
1123     g_assert (context == NULL || bus_input_context_get_capabilities (context) & IBUS_CAP_FOCUS);
1124
1125     /* Do noting if it is not focused context. */
1126     if (ibus->focused_context == context) {
1127         return;
1128     }
1129
1130     BusEngineProxy *engine = NULL;
1131
1132     if (ibus->focused_context) {
1133         if (ibus->use_global_engine) {
1134             /* dettach engine from the focused context */
1135             engine = bus_input_context_get_engine (ibus->focused_context);
1136             if (engine) {
1137                 g_object_ref (engine);
1138                 bus_input_context_set_engine (ibus->focused_context, NULL);
1139             }
1140         }
1141
1142         if (ibus->panel != NULL)
1143             bus_panel_proxy_focus_out (ibus->panel, ibus->focused_context);
1144
1145         g_object_unref (ibus->focused_context);
1146         ibus->focused_context = NULL;
1147     }
1148
1149     if (context == NULL && ibus->use_global_engine) {
1150         context = ibus->fake_context;
1151     }
1152
1153     if (context) {
1154         ibus->focused_context = (BusInputContext *) g_object_ref (context);
1155         /* attach engine to the focused context */
1156         if (engine != NULL) {
1157             bus_input_context_set_engine (context, engine);
1158             if (bus_engine_proxy_is_enabled (engine))
1159                 bus_input_context_enable (context);
1160             g_object_unref (engine);
1161         }
1162
1163         if (ibus->panel != NULL)
1164             bus_panel_proxy_focus_in (ibus->panel, context);
1165     }
1166 }
1167
1168
1169 /**
1170  * _context_engine_changed_cb:
1171  *
1172  * A callback function to be called when the "engine-changed" signal is sent to the context.
1173  * Update global engine as well if necessary.
1174  */
1175 static void
1176 _context_engine_changed_cb (BusInputContext *context,
1177                             BusIBusImpl     *ibus)
1178 {
1179     if (!ibus->use_global_engine)
1180         return;
1181
1182     if ((context == ibus->focused_context) ||
1183         (ibus->focused_context == NULL && context == ibus->fake_context)) {
1184         BusEngineProxy *engine = bus_input_context_get_engine (context);
1185         if (engine != NULL) {
1186             /* only set global engine if engine is not NULL */
1187             const gchar *name = ibus_engine_desc_get_name (bus_engine_proxy_get_desc (engine));
1188             if (g_strcmp0 (name, ibus->global_engine_name) == 0)
1189                 return;
1190             g_free (ibus->global_previous_engine_name);
1191             ibus->global_previous_engine_name = ibus->global_engine_name;
1192             ibus->global_engine_name = g_strdup (name);
1193             /* save changes */
1194             bus_ibus_impl_save_global_engine_name_to_config (ibus);
1195             bus_ibus_impl_save_global_previous_engine_name_to_config (ibus);
1196             bus_ibus_impl_global_engine_changed (ibus);
1197         }
1198     }
1199 }
1200
1201 /**
1202  * _context_focus_in_cb:
1203  *
1204  * A callback function to be called when the "focus-in" signal is sent to the context.
1205  * If necessary, enables the global engine on the context and update ibus->focused_context.
1206  */
1207 static void
1208 _context_focus_in_cb (BusInputContext *context,
1209                       BusIBusImpl     *ibus)
1210 {
1211     g_assert (BUS_IS_IBUS_IMPL (ibus));
1212     g_assert (BUS_IS_INPUT_CONTEXT (context));
1213
1214     /* Do nothing if context does not support focus.
1215      * The global engine shoule be detached from the focused context. */
1216     if ((bus_input_context_get_capabilities (context) & IBUS_CAP_FOCUS) == 0) {
1217         return;
1218     }
1219
1220     bus_ibus_impl_set_focused_context (ibus, context);
1221 }
1222
1223 /**
1224  * _context_focus_out_cb:
1225  *
1226  * A callback function to be called when the "focus-out" signal is sent to the context.
1227  */
1228 static void
1229 _context_focus_out_cb (BusInputContext    *context,
1230                        BusIBusImpl        *ibus)
1231 {
1232     g_assert (BUS_IS_IBUS_IMPL (ibus));
1233     g_assert (BUS_IS_INPUT_CONTEXT (context));
1234
1235     /* Do noting if context does not support focus.
1236      * Actually, the context should emit focus signals, if it does not support focus */
1237     if ((bus_input_context_get_capabilities (context) & IBUS_CAP_FOCUS) == 0) {
1238         return;
1239     }
1240
1241     /* Do noting if it is not focused context. */
1242     if (ibus->focused_context != context) {
1243         return;
1244     }
1245
1246
1247     if (ibus->use_global_engine == FALSE) {
1248         /* Do not change the focused context, if use_global_engine option is enabled.
1249          * If focused context swith to NULL, users can not swith engine in panel anymore.
1250          **/
1251         bus_ibus_impl_set_focused_context (ibus, NULL);
1252     }
1253 }
1254
1255 /**
1256  * _context_destroy_cb:
1257  *
1258  * A callback function to be called when the "destroy" signal is sent to the context.
1259  */
1260 static void
1261 _context_destroy_cb (BusInputContext    *context,
1262                      BusIBusImpl        *ibus)
1263 {
1264     g_assert (BUS_IS_IBUS_IMPL (ibus));
1265     g_assert (BUS_IS_INPUT_CONTEXT (context));
1266
1267     if (context == ibus->focused_context) {
1268         bus_ibus_impl_set_focused_context (ibus, NULL);
1269     }
1270
1271     ibus->contexts = g_list_remove (ibus->contexts, context);
1272     g_object_unref (context);
1273 }
1274
1275 /**
1276  * _context_enabled_cb:
1277  *
1278  * A callback function to be called when the "enabled" signal is sent to the context.
1279  */
1280 static void
1281 _context_enabled_cb (BusInputContext    *context,
1282                      BusIBusImpl        *ibus)
1283 {
1284     /* FIXME implement this. */
1285 }
1286
1287 /**
1288  * _context_disabled_cb:
1289  *
1290  * A callback function to be called when the "disabled" signal is sent to the context.
1291  */
1292 static void
1293 _context_disabled_cb (BusInputContext    *context,
1294                       BusIBusImpl        *ibus)
1295 {
1296     /* FIXME implement this. */
1297 }
1298
1299 /**
1300  * bus_ibus_impl_create_input_context:
1301  * @client: A name of a client. e.g. "gtk-im"
1302  * @returns: A BusInputContext object.
1303  *
1304  * Create a new BusInputContext object for the client.
1305  */
1306 static BusInputContext *
1307 bus_ibus_impl_create_input_context (BusIBusImpl   *ibus,
1308                                     BusConnection *connection,
1309                                     const gchar   *client)
1310 {
1311     BusInputContext *context = bus_input_context_new (connection, client);
1312     g_object_ref_sink (context);
1313     ibus->contexts = g_list_append (ibus->contexts, context);
1314
1315     /* Installs glib signal handlers so that the ibus object could be notified when e.g. an IBus.InputContext D-Bus method is called. */
1316     static const struct {
1317         gchar *name;
1318         GCallback callback;
1319     } signals [] = {
1320         { "request-engine", G_CALLBACK (_context_request_engine_cb) },
1321         { "engine-changed", G_CALLBACK (_context_engine_changed_cb) },
1322         { "focus-in",       G_CALLBACK (_context_focus_in_cb) },
1323         { "focus-out",      G_CALLBACK (_context_focus_out_cb) },
1324         { "destroy",        G_CALLBACK (_context_destroy_cb) },
1325         { "enabled",        G_CALLBACK (_context_enabled_cb) },
1326         { "disabled",       G_CALLBACK (_context_disabled_cb) },
1327     };
1328
1329     gint i;
1330     for (i = 0; i < G_N_ELEMENTS (signals); i++) {
1331         g_signal_connect (context,
1332                           signals[i].name,
1333                           signals[i].callback,
1334                           ibus);
1335     }
1336
1337     if (ibus->enable_by_default) {
1338         bus_input_context_enable (context);
1339     }
1340
1341     /* register the context object so that the object could handle IBus.InputContext method calls. */
1342     bus_dbus_impl_register_object (BUS_DEFAULT_DBUS,
1343                                    (IBusService *) context);
1344     g_object_ref (context);
1345     return context;
1346 }
1347
1348 /**
1349  * _ibus_create_input_context:
1350  *
1351  * Implement the "CreateInputContext" method call of the org.freedesktop.IBus interface.
1352  */
1353 static void
1354 _ibus_create_input_context (BusIBusImpl           *ibus,
1355                             GVariant              *parameters,
1356                             GDBusMethodInvocation *invocation)
1357 {
1358     const gchar *client_name = NULL;  // e.g. "gtk-im"
1359     g_variant_get (parameters, "(&s)", &client_name);
1360
1361     BusConnection *connection =
1362             bus_connection_lookup (g_dbus_method_invocation_get_connection (invocation));
1363     BusInputContext *context =
1364             bus_ibus_impl_create_input_context (ibus,
1365                                                 connection,
1366                                                 client_name);
1367     if (context) {
1368         const gchar *path = ibus_service_get_object_path ((IBusService *) context);
1369         /* the format-string 'o' is for a D-Bus object path. */
1370         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", path));
1371         g_object_unref (context);
1372     }
1373     else {
1374         g_dbus_method_invocation_return_error (invocation,
1375                                                G_DBUS_ERROR,
1376                                                G_DBUS_ERROR_FAILED,
1377                                                "Create input context failed!");
1378     }
1379 }
1380
1381 /**
1382  * _ibus_current_input_context:
1383  *
1384  * Implement the "CurrentInputContext" method call of the org.freedesktop.IBus interface.
1385  */
1386 static void
1387 _ibus_current_input_context (BusIBusImpl           *ibus,
1388                              GVariant              *parameters,
1389                              GDBusMethodInvocation *invocation)
1390 {
1391     if (!ibus->focused_context)
1392     {
1393         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
1394                         "No focused input context");
1395     }
1396     else {
1397         const gchar *path = ibus_service_get_object_path ((IBusService *) ibus->focused_context);
1398         /* the format-string 'o' is for a D-Bus object path. */
1399         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", path));
1400     }
1401 }
1402
1403 static void
1404 _component_destroy_cb (BusComponent *component,
1405                        BusIBusImpl  *ibus)
1406 {
1407     g_assert (BUS_IS_IBUS_IMPL (ibus));
1408     g_assert (BUS_IS_COMPONENT (component));
1409
1410     ibus->registered_components = g_list_remove (ibus->registered_components, component);
1411
1412     /* remove engines from engine_list */
1413     GList *engines = bus_component_get_engines (component);
1414     GList *p;
1415     for (p = engines; p != NULL; p = p->next) {
1416         if (g_list_find (ibus->register_engine_list, p->data)) {
1417             ibus->register_engine_list = g_list_remove (ibus->register_engine_list, p->data);
1418             g_object_unref (p->data);
1419         }
1420     }
1421     g_list_free (engines);
1422
1423     g_object_unref (component);
1424
1425     bus_ibus_impl_update_engines_hotkey_profile (ibus);
1426 }
1427
1428 /**
1429  * _ibus_register_component:
1430  *
1431  * Implement the "RegisterComponent" method call of the org.freedesktop.IBus interface.
1432  */
1433 static void
1434 _ibus_register_component (BusIBusImpl           *ibus,
1435                           GVariant              *parameters,
1436                           GDBusMethodInvocation *invocation)
1437 {
1438     GVariant *variant = g_variant_get_child_value (parameters, 0);
1439     IBusComponent *component = (IBusComponent *) ibus_serializable_deserialize (variant);
1440
1441     if (!IBUS_IS_COMPONENT (component)) {
1442         if (component)
1443             g_object_unref (component);
1444         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
1445                         "The first argument should be an IBusComponent.");
1446         return;
1447     }
1448
1449     BusConnection *connection = bus_connection_lookup (g_dbus_method_invocation_get_connection (invocation));
1450     BusFactoryProxy *factory = bus_factory_proxy_new (connection);
1451
1452     if (factory == NULL) {
1453         g_object_unref (component);
1454         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
1455                         "Create factory failed.");
1456         return;
1457     }
1458
1459     g_object_ref_sink (component);
1460
1461     BusComponent *buscomp = bus_component_new (component, factory);
1462     bus_component_set_destroy_with_factory (buscomp, TRUE);
1463     g_object_unref (component);
1464     g_object_unref (factory);
1465
1466     ibus->registered_components = g_list_append (ibus->registered_components,
1467                                                 g_object_ref_sink (buscomp));
1468     GList *engines = bus_component_get_engines (buscomp);
1469     g_list_foreach (engines, (GFunc) g_object_ref, NULL);
1470     ibus->register_engine_list = g_list_concat (ibus->register_engine_list,
1471                                                engines);
1472
1473     g_signal_connect (buscomp, "destroy", G_CALLBACK (_component_destroy_cb), ibus);
1474
1475     bus_ibus_impl_update_engines_hotkey_profile (ibus);
1476
1477     g_dbus_method_invocation_return_value (invocation, NULL);
1478 }
1479
1480 /**
1481  * _ibus_list_engines:
1482  *
1483  * Implement the "ListEngines" method call of the org.freedesktop.IBus interface.
1484  */
1485 static void
1486 _ibus_list_engines (BusIBusImpl           *ibus,
1487                     GVariant              *parameters,
1488                     GDBusMethodInvocation *invocation)
1489 {
1490     GVariantBuilder builder;
1491     g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
1492
1493     GList *engines = bus_registry_get_engines (ibus->registry);
1494     GList *p;
1495     for (p = engines; p != NULL; p = p->next) {
1496         g_variant_builder_add (&builder, "v", ibus_serializable_serialize ((IBusSerializable *) p->data));
1497     }
1498     g_list_free (engines);
1499     g_dbus_method_invocation_return_value (invocation, g_variant_new ("(av)", &builder));
1500 }
1501
1502 /**
1503  * _ibus_list_active_engines:
1504  *
1505  * Implement the "ListActiveEngines" method call of the org.freedesktop.IBus interface.
1506  */
1507 static void
1508 _ibus_list_active_engines (BusIBusImpl           *ibus,
1509                            GVariant              *parameters,
1510                            GDBusMethodInvocation *invocation)
1511 {
1512     GVariantBuilder builder;
1513     g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
1514
1515     GList *p;
1516     for (p = ibus->engine_list; p != NULL; p = p->next) {
1517         g_variant_builder_add (&builder, "v", ibus_serializable_serialize ((IBusSerializable *) p->data));
1518     }
1519     for (p = ibus->register_engine_list; p != NULL; p = p->next) {
1520         g_variant_builder_add (&builder, "v", ibus_serializable_serialize ((IBusSerializable *) p->data));
1521     }
1522     g_dbus_method_invocation_return_value (invocation, g_variant_new ("(av)", &builder));
1523 }
1524
1525 /**
1526  * _ibus_exit:
1527  *
1528  * Implement the "Exit" method call of the org.freedesktop.IBus interface.
1529  */
1530 static void
1531 _ibus_exit (BusIBusImpl           *ibus,
1532             GVariant              *parameters,
1533             GDBusMethodInvocation *invocation)
1534 {
1535     gboolean restart = FALSE;
1536     g_variant_get (parameters, "(b)", &restart);
1537
1538     g_dbus_method_invocation_return_value (invocation, NULL);
1539
1540     /* Make sure the reply has been sent out before exit */
1541     g_dbus_connection_flush_sync (g_dbus_method_invocation_get_connection (invocation),
1542                                   NULL,
1543                                   NULL);
1544     bus_server_quit ();
1545
1546     if (!restart) {
1547         exit (0);
1548     }
1549     else {
1550         extern gchar **g_argv;
1551         gchar *exe;
1552         gint fd;
1553
1554         exe = g_strdup_printf ("/proc/%d/exe", getpid ());
1555         exe = g_file_read_link (exe, NULL);
1556
1557         if (exe == NULL)
1558             exe = BINDIR "/ibus-daemon";
1559
1560         /* close all fds except stdin, stdout, stderr */
1561         for (fd = 3; fd <= sysconf (_SC_OPEN_MAX); fd ++) {
1562             close (fd);
1563         }
1564
1565         execv (exe, g_argv);
1566
1567         /* If the server binary is replaced while the server is running,
1568          * "readlink /proc/[pid]/exe" might return a path with " (deleted)"
1569          * suffix. */
1570         const gchar suffix[] = " (deleted)";
1571         if (g_str_has_suffix (exe, suffix)) {
1572             exe [strlen (exe) - sizeof (suffix) + 1] = '\0';
1573             execv (exe, g_argv);
1574         }
1575         g_warning ("execv %s failed!", g_argv[0]);
1576         exit (-1);
1577     }
1578
1579     /* should not reach here */
1580     g_assert_not_reached ();
1581 }
1582
1583 /**
1584  * _ibus_ping:
1585  *
1586  * Implement the "Ping" method call of the org.freedesktop.IBus interface.
1587  */
1588 static void
1589 _ibus_ping (BusIBusImpl           *ibus,
1590             GVariant              *parameters,
1591             GDBusMethodInvocation *invocation)
1592 {
1593     g_dbus_method_invocation_return_value (invocation, parameters);
1594 }
1595
1596 /**
1597  * _ibus_get_use_sys_layout:
1598  *
1599  * Implement the "GetUseSysLayout" method call of the org.freedesktop.IBus interface.
1600  */
1601 static void
1602 _ibus_get_use_sys_layout (BusIBusImpl           *ibus,
1603                           GVariant              *parameters,
1604                           GDBusMethodInvocation *invocation)
1605 {
1606     g_dbus_method_invocation_return_value (invocation,
1607                     g_variant_new ("(b)", ibus->use_sys_layout));
1608 }
1609
1610 /**
1611  * _ibus_get_use_global_engine:
1612  *
1613  * Implement the "GetUseGlobalEngine" method call of the org.freedesktop.IBus interface.
1614  */
1615 static void
1616 _ibus_get_use_global_engine (BusIBusImpl           *ibus,
1617                              GVariant              *parameters,
1618                              GDBusMethodInvocation *invocation)
1619 {
1620     g_dbus_method_invocation_return_value (invocation,
1621                     g_variant_new ("(b)", ibus->use_global_engine));
1622 }
1623
1624 /**
1625  * _ibus_get_global_engine:
1626  *
1627  * Implement the "GetGlobalEngine" method call of the org.freedesktop.IBus interface.
1628  */
1629 static void
1630 _ibus_get_global_engine (BusIBusImpl           *ibus,
1631                          GVariant              *parameters,
1632                          GDBusMethodInvocation *invocation)
1633 {
1634     IBusEngineDesc *desc = NULL;
1635
1636     do {
1637         if (!ibus->use_global_engine)
1638             break;
1639         BusInputContext *context = ibus->focused_context;
1640         if (context == NULL)
1641             context = ibus->fake_context;
1642
1643         desc = bus_input_context_get_engine_desc (context);
1644
1645         if (desc == NULL)
1646             break;
1647
1648         GVariant *variant = ibus_serializable_serialize ((IBusSerializable *) desc);
1649         g_dbus_method_invocation_return_value (invocation,
1650                                                g_variant_new ("(v)", variant));
1651         return;
1652     } while (0);
1653
1654     g_dbus_method_invocation_return_error (invocation,
1655                     G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
1656                     "No global engine.");
1657 }
1658
1659 struct _SetGlobalEngineData {
1660     BusIBusImpl *ibus;
1661     GDBusMethodInvocation *invocation;
1662 };
1663 typedef struct _SetGlobalEngineData SetGlobalEngineData;
1664
1665 static void
1666 _ibus_set_global_engine_ready_cb (BusInputContext       *context,
1667                                   GAsyncResult          *res,
1668                                   SetGlobalEngineData   *data)
1669 {
1670     BusIBusImpl *ibus = data->ibus;
1671
1672     GError *error = NULL;
1673     if (!bus_input_context_set_engine_by_desc_finish (context, res, &error)) {
1674         g_error_free (error);
1675         g_dbus_method_invocation_return_error (data->invocation,
1676                                                G_DBUS_ERROR,
1677                                                G_DBUS_ERROR_FAILED,
1678                                                "Set global engine failed.");
1679
1680     }
1681     else {
1682         g_dbus_method_invocation_return_value (data->invocation, NULL);
1683
1684         if (ibus->use_global_engine && (context != ibus->focused_context)) {
1685             /* context and ibus->focused_context don't match. This means that
1686              * the focus is moved before _ibus_set_global_engine() asynchronous
1687              * call finishes. In this case, the engine for the context currently
1688              * being focused hasn't been updated. Update the engine here so that
1689              * subsequent _ibus_get_global_engine() call could return a
1690              * consistent engine name. */
1691             BusEngineProxy *engine = bus_input_context_get_engine (context);
1692             if (engine && ibus->focused_context != NULL) {
1693                 g_object_ref (engine);
1694                 bus_input_context_set_engine (context, NULL);
1695                 bus_input_context_set_engine (ibus->focused_context, engine);
1696                 g_object_unref (engine);
1697             }
1698         }
1699     }
1700
1701     g_object_unref (ibus);
1702     g_slice_free (SetGlobalEngineData, data);
1703 }
1704
1705 /**
1706  * _ibus_set_global_engine:
1707  *
1708  * Implement the "SetGlobalEngine" method call of the org.freedesktop.IBus interface.
1709  */
1710 static void
1711 _ibus_set_global_engine (BusIBusImpl           *ibus,
1712                          GVariant              *parameters,
1713                          GDBusMethodInvocation *invocation)
1714 {
1715     if (!ibus->use_global_engine) {
1716         g_dbus_method_invocation_return_error (invocation,
1717                         G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
1718                         "Global engine feature is disabled.");
1719         return;
1720     }
1721
1722     BusInputContext *context = ibus->focused_context;
1723     if (context == NULL)
1724         context = ibus->fake_context;
1725
1726     const gchar *new_engine_name = NULL;
1727     g_variant_get (parameters, "(&s)", &new_engine_name);
1728     const gchar *old_engine_name = NULL;
1729
1730     BusEngineProxy *engine = bus_input_context_get_engine (context);
1731     if (engine) {
1732         old_engine_name =
1733                 ibus_engine_desc_get_name (bus_engine_proxy_get_desc (engine));
1734     }
1735
1736     if (g_strcmp0 (new_engine_name, old_engine_name) == 0) {
1737         /* If the user requested the same global engine, then we just enable the
1738          * original one. */
1739         bus_input_context_enable (context);
1740         g_dbus_method_invocation_return_value (invocation, NULL);
1741         return;
1742     }
1743
1744     IBusEngineDesc *desc = _find_engine_desc_by_name (ibus, new_engine_name);
1745     if (desc == NULL) {
1746         g_dbus_method_invocation_return_error (invocation,
1747                                                G_DBUS_ERROR,
1748                                                G_DBUS_ERROR_FAILED,
1749                                                "Can not find engine %s.",
1750                                                new_engine_name);
1751         return;
1752     }
1753
1754     SetGlobalEngineData *data = g_slice_new0 (SetGlobalEngineData);
1755     data->ibus = g_object_ref (ibus);
1756     data->invocation = invocation;
1757     bus_input_context_set_engine_by_desc (context,
1758                                           desc,
1759                                           g_gdbus_timeout, /* timeout in msec. */
1760                                           NULL, /* we do not cancel the call. */
1761                                           (GAsyncReadyCallback) _ibus_set_global_engine_ready_cb,
1762                                           data);
1763 }
1764
1765 /**
1766  * _ibus_is_global_engine_enabled:
1767  *
1768  * Implement the "IsGlobalEngineEnabled" method call of the org.freedesktop.IBus interface.
1769  */
1770 static void
1771 _ibus_is_global_engine_enabled (BusIBusImpl           *ibus,
1772                                 GVariant              *parameters,
1773                                 GDBusMethodInvocation *invocation)
1774 {
1775     gboolean enabled = FALSE;
1776
1777     do {
1778         if (!ibus->use_global_engine)
1779             break;
1780
1781         BusInputContext *context = ibus->focused_context;
1782         if (context == NULL)
1783             context = ibus->fake_context;
1784         if (context == NULL)
1785             break;
1786
1787         enabled = bus_input_context_is_enabled (context);
1788     } while (0);
1789
1790     g_dbus_method_invocation_return_value (invocation,
1791                     g_variant_new ("(b)", enabled));
1792 }
1793
1794 /**
1795  * bus_ibus_impl_service_method_call:
1796  *
1797  * Handle a D-Bus method call whose destination and interface name are both "org.freedesktop.IBus"
1798  */
1799 static void
1800 bus_ibus_impl_service_method_call (IBusService           *service,
1801                                    GDBusConnection       *connection,
1802                                    const gchar           *sender,
1803                                    const gchar           *object_path,
1804                                    const gchar           *interface_name,
1805                                    const gchar           *method_name,
1806                                    GVariant              *parameters,
1807                                    GDBusMethodInvocation *invocation)
1808 {
1809     if (g_strcmp0 (interface_name, "org.freedesktop.IBus") != 0) {
1810         IBUS_SERVICE_CLASS (bus_ibus_impl_parent_class)->service_method_call (
1811                         service, connection, sender, object_path, interface_name, method_name,
1812                         parameters, invocation);
1813         return;
1814     }
1815
1816     /* all methods in the xml definition above should be listed here. */
1817     static const struct {
1818         const gchar *method_name;
1819         void (* method_callback) (BusIBusImpl *, GVariant *, GDBusMethodInvocation *);
1820     } methods [] =  {
1821         /* IBus interface */
1822         { "GetAddress",            _ibus_get_address },
1823         { "CreateInputContext",    _ibus_create_input_context },
1824         { "CurrentInputContext",   _ibus_current_input_context },
1825         { "RegisterComponent",     _ibus_register_component },
1826         { "ListEngines",           _ibus_list_engines },
1827         { "ListActiveEngines",     _ibus_list_active_engines },
1828         { "Exit",                  _ibus_exit },
1829         { "Ping",                  _ibus_ping },
1830         { "GetUseSysLayout",       _ibus_get_use_sys_layout },
1831         { "GetUseGlobalEngine",    _ibus_get_use_global_engine },
1832         { "GetGlobalEngine",       _ibus_get_global_engine },
1833         { "SetGlobalEngine",       _ibus_set_global_engine },
1834         { "IsGlobalEngineEnabled", _ibus_is_global_engine_enabled },
1835     };
1836
1837     gint i;
1838     for (i = 0; i < G_N_ELEMENTS (methods); i++) {
1839         if (g_strcmp0 (methods[i].method_name, method_name) == 0) {
1840             methods[i].method_callback ((BusIBusImpl *) service, parameters, invocation);
1841             return;
1842         }
1843     }
1844
1845     /* notreached - unknown method calls that are not in the introspection_xml should be handled by the GDBus library. */
1846     g_return_if_reached ();
1847 }
1848
1849 BusIBusImpl *
1850 bus_ibus_impl_get_default (void)
1851 {
1852     static BusIBusImpl *ibus = NULL;
1853
1854     if (ibus == NULL) {
1855         ibus = (BusIBusImpl *) g_object_new (BUS_TYPE_IBUS_IMPL,
1856                                              "object-path", IBUS_PATH_IBUS,
1857                                              NULL);
1858     }
1859     return ibus;
1860 }
1861
1862 BusFactoryProxy *
1863 bus_ibus_impl_lookup_factory (BusIBusImpl *ibus,
1864                               const gchar *path)
1865 {
1866     g_assert (BUS_IS_IBUS_IMPL (ibus));
1867
1868     BusFactoryProxy *factory;
1869
1870     factory = (BusFactoryProxy *) g_hash_table_lookup (ibus->factory_dict, path);
1871
1872     return factory;
1873 }
1874
1875 IBusHotkeyProfile *
1876 bus_ibus_impl_get_hotkey_profile (BusIBusImpl *ibus)
1877 {
1878     g_assert (BUS_IS_IBUS_IMPL (ibus));
1879
1880     return ibus->hotkey_profile;
1881 }
1882
1883 IBusKeymap *
1884 bus_ibus_impl_get_keymap (BusIBusImpl *ibus)
1885 {
1886
1887     g_assert (BUS_IS_IBUS_IMPL (ibus));
1888
1889     return ibus->keymap;
1890 }
1891
1892 BusRegistry *
1893 bus_ibus_impl_get_registry (BusIBusImpl *ibus)
1894 {
1895
1896     g_assert (BUS_IS_IBUS_IMPL (ibus));
1897
1898     return ibus->registry;
1899 }
1900
1901 /**
1902  * bus_ibus_impl_emit_signal:
1903  *
1904  * Send a D-Bus signal to buses (connections) that are listening to the signal.
1905  */
1906 static void
1907 bus_ibus_impl_emit_signal (BusIBusImpl *ibus,
1908                            const gchar *signal_name,
1909                            GVariant    *parameters)
1910 {
1911     static guint32 serial = 0;
1912     GDBusMessage *message = g_dbus_message_new_signal ("/org/freedesktop/IBus",
1913                                                        "org.freedesktop.IBus",
1914                                                        signal_name);
1915     /* set a non-zero serial to make libdbus happy */
1916     g_dbus_message_set_serial (message, ++serial);
1917     g_dbus_message_set_sender (message, "org.freedesktop.IBus");
1918     if (parameters)
1919         g_dbus_message_set_body (message, parameters);
1920     bus_dbus_impl_dispatch_message_by_rule (BUS_DEFAULT_DBUS, message, NULL);
1921     g_object_unref (message);
1922 }
1923
1924 static void
1925 bus_ibus_impl_registry_changed (BusIBusImpl *ibus)
1926 {
1927     bus_ibus_impl_emit_signal (ibus, "RegistryChanged", NULL);
1928 }
1929
1930 static void
1931 bus_ibus_impl_global_engine_changed (BusIBusImpl *ibus)
1932 {
1933     const gchar *name = ibus->global_engine_name ? ibus->global_engine_name : "";
1934     bus_ibus_impl_emit_signal (ibus, "GlobalEngineChanged",
1935                                g_variant_new ("(s)", name));
1936 }
1937
1938 gboolean
1939 bus_ibus_impl_filter_keyboard_shortcuts (BusIBusImpl     *ibus,
1940                                          BusInputContext *context,
1941                                          guint           keyval,
1942                                          guint           modifiers,
1943                                          guint           prev_keyval,
1944                                          guint           prev_modifiers)
1945 {
1946     static GQuark trigger = 0;
1947     static GQuark enable_unconditional = 0;
1948     static GQuark disable_unconditional = 0;
1949     static GQuark next = 0;
1950     static GQuark previous = 0;
1951
1952     GQuark event;
1953     GList *engine_list;
1954
1955     if (trigger == 0) {
1956         trigger = g_quark_from_static_string ("trigger");
1957         enable_unconditional = g_quark_from_static_string ("enable-unconditional");
1958         disable_unconditional = g_quark_from_static_string ("disable-unconditional");
1959         next = g_quark_from_static_string ("next-engine-in-menu");
1960         previous = g_quark_from_static_string ("previous-engine");
1961     }
1962
1963     /* Try global hotkeys first. */
1964     event = ibus_hotkey_profile_filter_key_event (ibus->hotkey_profile,
1965                                                   keyval,
1966                                                   modifiers,
1967                                                   prev_keyval,
1968                                                   prev_modifiers,
1969                                                   0);
1970
1971     if (event == trigger) {
1972         gboolean enabled = bus_input_context_is_enabled (context);
1973         if (enabled) {
1974             bus_input_context_disable (context);
1975         }
1976         else {
1977             bus_input_context_enable (context);
1978         }
1979         return (enabled != bus_input_context_is_enabled (context));
1980     }
1981     if (event == enable_unconditional) {
1982         gboolean enabled = bus_input_context_is_enabled (context);
1983         if (!enabled) {
1984             bus_input_context_enable (context);
1985         }
1986         return bus_input_context_is_enabled (context);
1987     }
1988     if (event == disable_unconditional) {
1989         gboolean enabled = bus_input_context_is_enabled (context);
1990         if (enabled) {
1991             bus_input_context_disable (context);
1992         }
1993         return !bus_input_context_is_enabled (context);
1994     }
1995     if (event == next) {
1996         if (bus_input_context_is_enabled (context)) {
1997             bus_ibus_impl_context_request_next_engine_in_menu (ibus, context);
1998         }
1999         else {
2000             bus_input_context_enable (context);
2001         }
2002         return TRUE;
2003     }
2004     if (event == previous) {
2005         if (bus_input_context_is_enabled (context)) {
2006             bus_ibus_impl_context_request_previous_engine (ibus, context);
2007         }
2008         else {
2009             bus_input_context_enable (context);
2010         }
2011         return TRUE;
2012     }
2013
2014     if (!ibus->engines_hotkey_profile || !ibus->hotkey_to_engines_map) {
2015         return FALSE;
2016     }
2017
2018     /* Then try engines hotkeys. */
2019     event = ibus_hotkey_profile_filter_key_event (ibus->engines_hotkey_profile,
2020                                                   keyval,
2021                                                   modifiers,
2022                                                   prev_keyval,
2023                                                   prev_modifiers,
2024                                                   0);
2025     if (event == 0) {
2026         return FALSE;
2027     }
2028
2029     engine_list = g_hash_table_lookup (ibus->hotkey_to_engines_map,
2030                                        GUINT_TO_POINTER (event));
2031     if (engine_list) {
2032         BusEngineProxy *current_engine = bus_input_context_get_engine (context);
2033         IBusEngineDesc *current_engine_desc =
2034             (current_engine ? bus_engine_proxy_get_desc (current_engine) : NULL);
2035         IBusEngineDesc *new_engine_desc = (IBusEngineDesc *) engine_list->data;
2036
2037         g_assert (new_engine_desc);
2038
2039         /* Find out what engine we should switch to. If the current engine has
2040          * the same hotkey, then we should switch to the next engine with the
2041          * same hotkey in the list. Otherwise, we just switch to the first
2042          * engine in the list. */
2043         GList *p = engine_list;
2044         for (; p->next != NULL; p = p->next) {
2045             if (current_engine_desc == (IBusEngineDesc *) p->data) {
2046                 new_engine_desc = (IBusEngineDesc *) p->next->data;
2047                 break;
2048             }
2049         }
2050
2051         if (current_engine_desc != new_engine_desc) {
2052             bus_ibus_impl_set_context_engine_from_desc (ibus, context, new_engine_desc);
2053         }
2054
2055         return TRUE;
2056     }
2057
2058     return FALSE;
2059 }
2060
2061 /**
2062  * bus_ibus_impl_load_global_engine_name_from_config:
2063  *
2064  * Retrieve the "global_engine" config from the config daemon. Return NULL if the daemon is not ready.
2065  */
2066 static gchar*
2067 bus_ibus_impl_load_global_engine_name_from_config (BusIBusImpl *ibus)
2068 {
2069     g_assert (BUS_IS_IBUS_IMPL (ibus));
2070     if (ibus->config == NULL) {
2071         /* the config component is not started yet. */
2072         return NULL;
2073     }
2074     g_assert (IBUS_IS_CONFIG (ibus->config));
2075
2076     GVariant *variant = ibus_config_get_value (ibus->config, "general", "global_engine");
2077     gchar *engine_name = NULL;
2078     if (variant != NULL) {
2079         g_variant_get (variant, "s", &engine_name);
2080         g_variant_unref (variant);
2081     }
2082     return engine_name;
2083 }
2084
2085 /**
2086  * bus_ibus_impl_save_global_engine_name_to_config:
2087  *
2088  * Save the "global_engine" config value on the config daemon. No-op if the daemon is not ready.
2089  */
2090 static void
2091 bus_ibus_impl_save_global_engine_name_to_config (BusIBusImpl *ibus)
2092 {
2093     g_assert (BUS_IS_IBUS_IMPL (ibus));
2094
2095     if (ibus->config &&
2096         ibus->use_global_engine &&
2097         ibus->global_engine_name) {
2098         ibus_config_set_value (ibus->config,
2099                         "general", "global_engine",
2100                         g_variant_new ("s", ibus->global_engine_name));
2101     }
2102 }
2103
2104 /**
2105  * bus_ibus_impl_load_global_previous_engine_name_from_config:
2106  *
2107  * Retrieve the "global_previous_engine" config from the config daemon. Return NULL if the daemon is not ready.
2108  */
2109 static gchar*
2110 bus_ibus_impl_load_global_previous_engine_name_from_config (BusIBusImpl *ibus)
2111 {
2112     g_assert (BUS_IS_IBUS_IMPL (ibus));
2113     if (ibus->config == NULL) {
2114         /* the config component is not started yet. */
2115         return NULL;
2116     }
2117     g_assert (IBUS_IS_CONFIG (ibus->config));
2118
2119     GVariant *value = ibus_config_get_value (ibus->config, "general", "global_previous_engine");
2120     if (value == NULL)
2121         return NULL;
2122     gchar *engine_name = NULL;
2123     g_variant_get (value, "(s)", &engine_name);
2124     g_variant_unref (value);
2125     return engine_name;
2126 }
2127
2128 /**
2129  * bus_ibus_impl_save_global_previous_engine_name_to_config:
2130  *
2131  * Save the "global_previous_engine" config value on the config daemon. No-op if the daemon is not ready.
2132  */
2133 static void
2134 bus_ibus_impl_save_global_previous_engine_name_to_config (BusIBusImpl *ibus)
2135 {
2136     g_assert (BUS_IS_IBUS_IMPL (ibus));
2137
2138     if (ibus->config &&
2139         ibus->use_global_engine &&
2140         ibus->global_previous_engine_name) {
2141         ibus_config_set_value (ibus->config,
2142                         "general", "global_previous_engine",
2143                         g_variant_new ("s", ibus->global_previous_engine_name));
2144     }
2145 }
2146
2147 /**
2148  * _add_engine_hotkey:
2149  *
2150  * Check the engine-specific hot key of the engine, and update ibus->engines_hotkey_profile.
2151  */
2152 static void
2153 _add_engine_hotkey (IBusEngineDesc *engine, BusIBusImpl *ibus)
2154 {
2155     const gchar *hotkeys;
2156     gchar **hotkey_list;
2157     gchar **p;
2158     gchar *hotkey;
2159     GList *engine_list;
2160
2161     GQuark event;
2162     guint keyval;
2163     guint modifiers;
2164
2165     if (!engine) {
2166         return;
2167     }
2168
2169     hotkeys = ibus_engine_desc_get_hotkeys (engine);
2170
2171     if (!hotkeys || !*hotkeys) {
2172         return;
2173     }
2174
2175     hotkey_list = g_strsplit_set (hotkeys, ";,", 0);
2176
2177     for (p = hotkey_list; p && *p; ++p) {
2178         hotkey = g_strstrip (*p);
2179         if (!*hotkey || !ibus_key_event_from_string (hotkey, &keyval, &modifiers)) {
2180             continue;
2181         }
2182
2183         /* If the hotkey already exists, we won't need to add it again. */
2184         event = ibus_hotkey_profile_lookup_hotkey (ibus->engines_hotkey_profile,
2185                                                    keyval, modifiers);
2186         if (event == 0) {
2187             event = g_quark_from_string (hotkey);
2188             ibus_hotkey_profile_add_hotkey (ibus->engines_hotkey_profile,
2189                                             keyval, modifiers, event);
2190         }
2191
2192         engine_list = g_hash_table_lookup (ibus->hotkey_to_engines_map,
2193                                            GUINT_TO_POINTER (event));
2194
2195         /* As we will rebuild the engines hotkey map whenever an engine was
2196          * added or removed, we don't need to hold a reference of the engine
2197          * here. */
2198         engine_list = g_list_append (engine_list, engine);
2199
2200         /* We need to steal the value before adding it back, otherwise it will
2201          * be destroyed. */
2202         g_hash_table_steal (ibus->hotkey_to_engines_map, GUINT_TO_POINTER (event));
2203
2204         g_hash_table_insert (ibus->hotkey_to_engines_map,
2205                              GUINT_TO_POINTER (event), engine_list);
2206     }
2207
2208     g_strfreev (hotkey_list);
2209 }
2210
2211 /**
2212  * bus_ibus_impl_update_engines_hotkey_profile:
2213  *
2214  * Check engine-specific hot keys of all active engines, and update ibus->engines_hotkey_profile.
2215  */
2216 static void
2217 bus_ibus_impl_update_engines_hotkey_profile (BusIBusImpl *ibus)
2218 {
2219     if (ibus->engines_hotkey_profile) {
2220         g_object_unref (ibus->engines_hotkey_profile);
2221     }
2222
2223     if (ibus->hotkey_to_engines_map) {
2224         g_hash_table_unref (ibus->hotkey_to_engines_map);
2225     }
2226
2227     ibus->engines_hotkey_profile = ibus_hotkey_profile_new ();
2228     ibus->hotkey_to_engines_map =
2229         g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_list_free);
2230
2231     g_list_foreach (ibus->register_engine_list, (GFunc) _add_engine_hotkey, ibus);
2232     g_list_foreach (ibus->engine_list, (GFunc) _add_engine_hotkey, ibus);
2233 }
2234
2235 gboolean
2236 bus_ibus_impl_is_use_sys_layout (BusIBusImpl *ibus)
2237 {
2238     g_assert (BUS_IS_IBUS_IMPL (ibus));
2239
2240     return ibus->use_sys_layout;
2241 }
2242
2243 gboolean
2244 bus_ibus_impl_is_embed_preedit_text (BusIBusImpl *ibus)
2245 {
2246     g_assert (BUS_IS_IBUS_IMPL (ibus));
2247
2248     return ibus->embed_preedit_text;
2249 }
2250
2251 BusInputContext *
2252 bus_ibus_impl_get_focused_input_context (BusIBusImpl *ibus)
2253 {
2254     g_assert (BUS_IS_IBUS_IMPL (ibus));
2255
2256     return ibus->focused_context;
2257 }