Add xkb layouts switch support and add three demo xkb layouts.
[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 <locale.h>
28 #include <strings.h>
29 #include "types.h"
30 #include "ibusimpl.h"
31 #include "dbusimpl.h"
32 #include "server.h"
33 #include "connection.h"
34 #include "registry.h"
35 #include "factoryproxy.h"
36 #include "panelproxy.h"
37 #include "inputcontext.h"
38 #include "option.h"
39
40 struct _BusIBusImpl {
41     IBusService parent;
42     /* instance members */
43     GHashTable *factory_dict;
44
45     /* registered components */
46     GList *registered_components;
47     GList *contexts;
48
49     /* a fake input context for global engine support */
50     BusInputContext *fake_context;
51     
52     /* a list of engines that are preloaded. */
53     GList *engine_list;
54     /* a list of engines that are started by a user (without the --ibus command line flag.) */
55     GList *register_engine_list;
56
57     /* if TRUE, ibus-daemon uses a keysym translated by the system (i.e. XKB) as-is.
58      * otherwise, ibus-daemon itself converts keycode into keysym. */
59     gboolean use_sys_layout;
60
61     gboolean embed_preedit_text;
62     gboolean enable_by_default;
63
64     BusRegistry     *registry;
65
66     BusInputContext *focused_context;
67     BusPanelProxy   *panel;
68
69     /* a default keymap of ibus-daemon (usually "us") which is used only when use_sys_layout is FALSE. */
70     IBusKeymap      *keymap;
71
72     gboolean use_global_engine;
73     gchar *global_engine_name;
74     gchar *global_previous_engine_name;
75
76     /* engine-specific hotkeys */
77     IBusHotkeyProfile *engines_hotkey_profile;
78     GHashTable      *hotkey_to_engines_map;
79 };
80
81 struct _BusIBusImplClass {
82     IBusServiceClass parent;
83
84     /* class members */
85 };
86
87 enum {
88     LAST_SIGNAL,
89 };
90
91 enum {
92     PROP_0,
93 };
94
95 /*
96 static guint            _signals[LAST_SIGNAL] = { 0 };
97 */
98
99 /* functions prototype */
100 static void      bus_ibus_impl_destroy           (BusIBusImpl        *ibus);
101 static void      bus_ibus_impl_service_method_call
102                                                  (IBusService        *service,
103                                                   GDBusConnection    *connection,
104                                                   const gchar        *sender,
105                                                   const gchar        *object_path,
106                                                   const gchar        *interface_name,
107                                                   const gchar        *method_name,
108                                                   GVariant           *parameters,
109                                                   GDBusMethodInvocation
110                                                                      *invocation);
111 /* TODO use property to replace some getter and setter in future */
112 #if 0
113 static GVariant *ibus_ibus_impl_service_get_property
114                                               (IBusService        *service,
115                                                GDBusConnection    *connection,
116                                                const gchar        *sender,
117                                                const gchar        *object_path,
118                                                const gchar        *interface_name,
119                                                const gchar        *property_name,
120                                                GError            **error);
121 static gboolean  ibus_ibus_impl_service_set_property
122                                               (IBusService        *service,
123                                                GDBusConnection    *connection,
124                                                const gchar        *sender,
125                                                const gchar        *object_path,
126                                                const gchar        *interface_name,
127                                                const gchar        *property_name,
128                                                GVariant           *value,
129                                                GError            **error);
130 #endif
131 static void     bus_ibus_impl_registry_changed  (BusIBusImpl        *ibus);
132 static void     bus_ibus_impl_global_engine_changed
133                                                 (BusIBusImpl        *ibus);
134 static void     bus_ibus_impl_set_context_engine_from_desc
135                                                 (BusIBusImpl        *ibus,
136                                                  BusInputContext    *context,
137                                                  IBusEngineDesc     *desc);
138 static void     bus_ibus_impl_update_engines_hotkey_profile
139                                                 (BusIBusImpl        *ibus);
140 static BusInputContext
141                *bus_ibus_impl_create_input_context
142                                                 (BusIBusImpl        *ibus,
143                                                  BusConnection      *connection,
144                                                  const gchar        *client);
145 static IBusEngineDesc
146                *bus_ibus_impl_get_engine_desc   (BusIBusImpl        *ibus,
147                                                  const gchar        *engine_name);
148 static void     bus_ibus_impl_set_focused_context
149                                                 (BusIBusImpl        *ibus,
150                                                  BusInputContext    *context);
151 /* some callback functions */
152 static void     _context_engine_changed_cb      (BusInputContext    *context,
153                                                  BusIBusImpl        *ibus);
154
155 /* The interfaces available in this class, which consists of a list of methods this class implements and
156  * a list of signals this class may emit. Method calls to the interface that are not defined in this XML
157  * will be automatically rejected by the GDBus library (see src/ibusservice.c for details.) */
158 static const gchar introspection_xml[] =
159     "<node>\n"
160     "  <interface name='org.freedesktop.IBus'>\n"
161     "    <method name='GetAddress'>\n"
162     "      <arg direction='out' type='s' name='address' />\n"
163     "    </method>\n"
164     "    <method name='CreateInputContext'>\n"
165     "      <arg direction='in'  type='s' name='client_name' />\n"
166     "      <arg direction='out' type='o' name='object_path' />\n"
167     "    </method>\n"
168     "    <method name='CurrentInputContext'>\n"
169     "      <arg direction='out' type='o' name='object_path' />\n"
170     "    </method>\n"
171     "    <method name='RegisterComponent'>\n"
172     "      <arg direction='in'  type='v' name='component' />\n"
173     "    </method>\n"
174     "    <method name='ListEngines'>\n"
175     "      <arg direction='out' type='av' name='engines' />\n"
176     "    </method>\n"
177     "    <method name='GetEnginesByNames'>\n"
178     "      <arg direction='in' type='as' name='names' />\n"
179     "      <arg direction='out' type='av' name='engines' />\n"
180     "    </method>\n"
181     "    <method name='ListActiveEngines'>\n"
182     "      <arg direction='out' type='av' name='engines' />\n"
183     "    </method>\n"
184     "    <method name='Exit'>\n"
185     "      <arg direction='in'  type='b' name='restart' />\n"
186     "    </method>\n"
187     "    <method name='Ping'>\n"
188     "      <arg direction='in'  type='v' name='data' />\n"
189     "      <arg direction='out' type='v' name='data' />\n"
190     "    </method>\n"
191     "    <method name='GetUseSysLayout'>\n"
192     "      <arg direction='out' type='b' name='enabled' />\n"
193     "    </method>\n"
194     "    <method name='GetUseGlobalEngine'>\n"
195     "      <arg direction='out' type='b' name='enabled' />\n"
196     "    </method>\n"
197     "    <method name='GetGlobalEngine'>\n"
198     "      <arg direction='out' type='v' name='desc' />\n"
199     "    </method>\n"
200     "    <method name='SetGlobalEngine'>\n"
201     "      <arg direction='in'  type='s' name='engine_name' />\n"
202     "    </method>\n"
203     "    <method name='IsGlobalEngineEnabled'>\n"
204     "      <arg direction='out' type='b' name='enabled' />\n"
205     "    </method>\n"
206     "    <signal name='RegistryChanged'>\n"
207     "    </signal>\n"
208     "    <signal name='GlobalEngineChanged'>\n"
209     "      <arg type='s' name='engine_name' />\n"
210     "    </signal>\n"
211     "  </interface>\n"
212     "</node>\n";
213
214
215 G_DEFINE_TYPE (BusIBusImpl, bus_ibus_impl, IBUS_TYPE_SERVICE)
216
217 static void
218 bus_ibus_impl_class_init (BusIBusImplClass *class)
219 {
220     IBUS_OBJECT_CLASS (class)->destroy = (IBusObjectDestroyFunc) bus_ibus_impl_destroy;
221
222     /* override the parent class's implementation. */
223     IBUS_SERVICE_CLASS (class)->service_method_call = bus_ibus_impl_service_method_call;
224     /* 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'.) */
225     ibus_service_class_add_interfaces (IBUS_SERVICE_CLASS (class), introspection_xml);
226 }
227
228 /**
229  * _panel_destroy_cb:
230  *
231  * A callback function which is called when (1) the connection to the panel process is terminated,
232  * or (2) ibus_proxy_destroy (ibus->panel); is called. See src/ibusproxy.c for details.
233  */
234 static void
235 _panel_destroy_cb (BusPanelProxy *panel,
236                    BusIBusImpl   *ibus)
237 {
238     g_assert (BUS_IS_PANEL_PROXY (panel));
239     g_assert (BUS_IS_IBUS_IMPL (ibus));
240
241     g_return_if_fail (ibus->panel == panel);
242
243     ibus->panel = NULL;
244     g_object_unref (panel);
245 }
246
247 static void
248 _registry_changed_cb (BusRegistry *registry,
249                       BusIBusImpl *ibus)
250 {
251     bus_ibus_impl_registry_changed (ibus);
252 }
253
254 /*
255  * _dbus_name_owner_changed_cb:
256  *
257  * A callback function to be called when the name-owner-changed signal is sent to the dbus object.
258  * This usually means a client (e.g. a panel/config/engine process or an application) is connected/disconnected to/from the bus.
259  */
260 static void
261 _dbus_name_owner_changed_cb (BusDBusImpl   *dbus,
262                              BusConnection *orig_connection,
263                              const gchar   *name,
264                              const gchar   *old_name,
265                              const gchar   *new_name,
266                              BusIBusImpl   *ibus)
267 {
268     g_assert (BUS_IS_DBUS_IMPL (dbus));
269     g_assert (name != NULL);
270     g_assert (old_name != NULL);
271     g_assert (new_name != NULL);
272     g_assert (BUS_IS_IBUS_IMPL (ibus));
273
274     if (g_strcmp0 (name, IBUS_SERVICE_PANEL) == 0) {
275         if (g_strcmp0 (new_name, "") != 0) {
276             /* a Panel process is started. */
277             BusConnection *connection;
278
279             if (ibus->panel != NULL) {
280                 ibus_proxy_destroy ((IBusProxy *) ibus->panel);
281                 /* panel should be NULL after destroy. See _panel_destroy_cb for details. */
282                 g_assert (ibus->panel == NULL);
283             }
284
285             connection = bus_dbus_impl_get_connection_by_name (BUS_DEFAULT_DBUS, new_name);
286             g_return_if_fail (connection != NULL);
287
288             ibus->panel = bus_panel_proxy_new (connection);
289
290             g_signal_connect (ibus->panel,
291                               "destroy",
292                               G_CALLBACK (_panel_destroy_cb),
293                               ibus);
294
295             if (ibus->focused_context != NULL) {
296                 bus_panel_proxy_focus_in (ibus->panel, ibus->focused_context);
297             }
298             else if (ibus->use_global_engine) {
299                 bus_panel_proxy_focus_in (ibus->panel, ibus->fake_context);
300             }
301         }
302     }
303
304     bus_registry_name_owner_changed (ibus->registry, name, old_name, new_name);
305 }
306
307 /**
308  * bus_ibus_impl_init:
309  *
310  * The constructor of BusIBusImpl. Initialize all member variables of a BusIBusImpl object.
311  */
312 static void
313 bus_ibus_impl_init (BusIBusImpl *ibus)
314 {
315     ibus->factory_dict = g_hash_table_new_full (
316                             g_str_hash,
317                             g_str_equal,
318                             NULL,
319                             (GDestroyNotify) g_object_unref);
320
321     ibus->fake_context = bus_input_context_new (NULL, "fake");
322     g_object_ref_sink (ibus->fake_context);
323     bus_dbus_impl_register_object (BUS_DEFAULT_DBUS,
324                                    (IBusService *) ibus->fake_context);
325     bus_input_context_set_capabilities (ibus->fake_context,
326                                         IBUS_CAP_PREEDIT_TEXT |
327                                         IBUS_CAP_FOCUS |
328                                         IBUS_CAP_SURROUNDING_TEXT);
329     g_signal_connect (ibus->fake_context,
330                       "engine-changed",
331                       G_CALLBACK (_context_engine_changed_cb),
332                       ibus);
333     bus_input_context_focus_in (ibus->fake_context);
334
335     ibus->engine_list = NULL;
336     ibus->register_engine_list = NULL;
337     ibus->contexts = NULL;
338     ibus->focused_context = NULL;
339     ibus->panel = NULL;
340     ibus->registry = bus_registry_new ();
341
342     g_signal_connect (ibus->registry,
343                       "changed",
344                       G_CALLBACK (_registry_changed_cb),
345                       ibus);
346 #ifdef G_THREADS_ENABLED
347     extern gint g_monitor_timeout;
348     if (g_monitor_timeout != 0) {
349         /* Start the monitor of registry changes. */
350         bus_registry_start_monitor_changes (ibus->registry);
351     }
352 #endif
353
354     ibus->keymap = ibus_keymap_get ("us");
355
356     ibus->use_sys_layout = TRUE;
357     ibus->embed_preedit_text = TRUE;
358     ibus->enable_by_default = TRUE;
359     ibus->use_global_engine = TRUE;
360     ibus->global_engine_name = NULL;
361     ibus->global_previous_engine_name = NULL;
362
363     ibus->engines_hotkey_profile = NULL;
364     ibus->hotkey_to_engines_map = NULL;
365
366     /* focus the fake_context, if use_global_engine is enabled. */
367     if (ibus->use_global_engine)
368         bus_ibus_impl_set_focused_context (ibus, ibus->fake_context);
369
370     g_signal_connect (BUS_DEFAULT_DBUS,
371                       "name-owner-changed",
372                       G_CALLBACK (_dbus_name_owner_changed_cb),
373                       ibus);
374 }
375
376 /**
377  * bus_ibus_impl_destroy:
378  *
379  * The destructor of BusIBusImpl.
380  */
381 static void
382 bus_ibus_impl_destroy (BusIBusImpl *ibus)
383 {
384     pid_t pid;
385     glong timeout;
386     gint status;
387     gboolean flag;
388
389     bus_registry_stop_all_components (ibus->registry);
390
391     pid = 0;
392     timeout = 0;
393     flag = FALSE;
394     while (1) {
395         while ((pid = waitpid (0, &status, WNOHANG)) > 0);
396
397         if (pid == -1) { /* all children finished */
398             break;
399         }
400         if (pid == 0) { /* no child status changed */
401             g_usleep (1000);
402             timeout += 1000;
403             if (timeout >= G_USEC_PER_SEC) {
404                 if (flag == FALSE) {
405                     gpointer old;
406                     old = signal (SIGTERM, SIG_IGN);
407                     /* send TERM signal to the whole process group (i.e. engines, panel, and config daemon.) */
408                     kill (-getpid (), SIGTERM);
409                     signal (SIGTERM, old);
410                     flag = TRUE;
411                 }
412                 else {
413                     g_warning ("Not every child processes exited!");
414                     break;
415                 }
416             }
417         }
418     }
419
420     g_list_free_full (ibus->engine_list, g_object_unref);
421     ibus->engine_list = NULL;
422
423     g_list_free_full (ibus->register_engine_list, g_object_unref);
424     ibus->register_engine_list = NULL;
425
426     if (ibus->factory_dict != NULL) {
427         g_hash_table_destroy (ibus->factory_dict);
428         ibus->factory_dict = NULL;
429     }
430
431     if (ibus->keymap != NULL) {
432         g_object_unref (ibus->keymap);
433         ibus->keymap = NULL;
434     }
435
436     g_free (ibus->global_engine_name);
437     ibus->global_engine_name = NULL;
438
439     g_free (ibus->global_previous_engine_name);
440     ibus->global_previous_engine_name = NULL;
441
442     if (ibus->engines_hotkey_profile != NULL) {
443         g_object_unref (ibus->engines_hotkey_profile);
444         ibus->engines_hotkey_profile = NULL;
445     }
446
447     if (ibus->hotkey_to_engines_map) {
448         g_hash_table_unref (ibus->hotkey_to_engines_map);
449         ibus->hotkey_to_engines_map = NULL;
450     }
451
452     if (ibus->fake_context) {
453         g_object_unref (ibus->fake_context);
454         ibus->fake_context = NULL;
455     }
456
457     IBUS_OBJECT_CLASS (bus_ibus_impl_parent_class)->destroy (IBUS_OBJECT (ibus));
458 }
459
460 /**
461  * _ibus_get_address:
462  *
463  * Implement the "GetAddress" method call of the org.freedesktop.IBus interface.
464  */
465 static void
466 _ibus_get_address (BusIBusImpl           *ibus,
467                    GVariant              *parameters,
468                    GDBusMethodInvocation *invocation)
469 {
470     g_dbus_method_invocation_return_value (invocation,
471                                            g_variant_new ("(s)", bus_server_get_address ()));
472 }
473
474 static IBusEngineDesc *
475 _find_engine_desc_by_name (BusIBusImpl *ibus,
476                            const gchar *engine_name)
477 {
478     IBusEngineDesc *desc = NULL;
479     GList *p;
480
481     /* find engine in registered engine list */
482     for (p = ibus->register_engine_list; p != NULL; p = p->next) {
483         desc = (IBusEngineDesc *) p->data;
484         if (g_strcmp0 (ibus_engine_desc_get_name (desc), engine_name) == 0)
485             return desc;
486     }
487
488     /* find engine in preload engine list */
489     for (p = ibus->engine_list; p != NULL; p = p->next) {
490         desc = (IBusEngineDesc *) p->data;
491         if (g_strcmp0 (ibus_engine_desc_get_name (desc), engine_name) == 0)
492             return desc;
493     }
494     return NULL;
495 }
496
497 /**
498  * _context_request_engine_cb:
499  *
500  * A callback function to be called when the "request-engine" signal is sent to the context.
501  */
502 static IBusEngineDesc *
503 _context_request_engine_cb (BusInputContext *context,
504                             const gchar     *engine_name,
505                             BusIBusImpl     *ibus)
506 {
507     return bus_ibus_impl_get_engine_desc (ibus, engine_name);
508 }
509
510 /**
511  * bus_ibus_impl_get_engine_desc:
512  *
513  * Get the IBusEngineDesc by engine_name. If the engine_name is NULL, return
514  * a default engine desc.
515  */
516 static IBusEngineDesc *
517 bus_ibus_impl_get_engine_desc (BusIBusImpl *ibus,
518                                const gchar *engine_name)
519 {
520     g_return_val_if_fail (engine_name != NULL, NULL);
521     g_return_val_if_fail (engine_name[0] != '\0', NULL);
522
523     return bus_registry_find_engine_by_name (ibus->registry, engine_name);
524 }
525
526 static void
527 bus_ibus_impl_set_context_engine_from_desc (BusIBusImpl     *ibus,
528                                             BusInputContext *context,
529                                             IBusEngineDesc  *desc)
530 {
531     bus_input_context_set_engine_by_desc (context,
532                                           desc,
533                                           g_gdbus_timeout, /* timeout in msec. */
534                                           NULL, /* we do not cancel the call. */
535                                           NULL, /* use the default callback function. */
536                                           NULL);
537 }
538
539 /**
540  * bus_ibus_impl_set_focused_context:
541  *
542  * Set the current focused context.
543  */
544 static void
545 bus_ibus_impl_set_focused_context (BusIBusImpl     *ibus,
546                                    BusInputContext *context)
547 {
548     g_assert (BUS_IS_IBUS_IMPL (ibus));
549     g_assert (context == NULL || BUS_IS_INPUT_CONTEXT (context));
550     g_assert (context == NULL || bus_input_context_get_capabilities (context) & IBUS_CAP_FOCUS);
551
552     /* Do noting if it is not focused context. */
553     if (ibus->focused_context == context) {
554         return;
555     }
556
557     BusEngineProxy *engine = NULL;
558     gboolean is_enabled = FALSE;
559
560     if (ibus->focused_context) {
561         if (ibus->use_global_engine) {
562             /* dettach engine from the focused context */
563             engine = bus_input_context_get_engine (ibus->focused_context);
564             if (engine) {
565                 // is_enabled = bus_input_context_is_enabled (ibus->focused_context);
566                 is_enabled = TRUE;
567                 g_object_ref (engine);
568                 bus_input_context_set_engine (ibus->focused_context, NULL);
569             }
570         }
571
572         if (ibus->panel != NULL)
573             bus_panel_proxy_focus_out (ibus->panel, ibus->focused_context);
574
575         g_object_unref (ibus->focused_context);
576         ibus->focused_context = NULL;
577     }
578
579     if (context == NULL && ibus->use_global_engine) {
580         context = ibus->fake_context;
581     }
582
583     if (context) {
584         ibus->focused_context = (BusInputContext *) g_object_ref (context);
585         /* attach engine to the focused context */
586         if (engine != NULL) {
587             bus_input_context_set_engine (context, engine);
588             if (is_enabled) {
589                 bus_input_context_enable (context);
590             }
591             g_object_unref (engine);
592         }
593
594         if (ibus->panel != NULL)
595             bus_panel_proxy_focus_in (ibus->panel, context);
596     }
597 }
598
599 static void
600 bus_ibus_impl_set_global_engine (BusIBusImpl    *ibus,
601                                  BusEngineProxy *engine)
602 {
603     if (!ibus->use_global_engine)
604         return;
605
606     if (ibus->focused_context) {
607         bus_input_context_set_engine (ibus->focused_context, engine);
608     } else if (ibus->fake_context) {
609         bus_input_context_set_engine (ibus->fake_context, engine);
610     }
611 }
612
613 static void
614 bus_ibus_impl_set_global_engine_by_name (BusIBusImpl *ibus,
615                                          const gchar *name)
616 {
617     if (!ibus->use_global_engine)
618         return;
619
620     BusInputContext *context =
621             ibus->focused_context != NULL ? ibus->focused_context : ibus->fake_context;
622
623     if (context == NULL) {
624         return;
625     }
626
627     if (g_strcmp0 (name, ibus->global_engine_name) == 0) {
628         /* If the user requested the same global engine, then we just enable the
629          * original one. */
630         bus_input_context_enable (context);
631         return;
632     }
633
634     /* If there is a focused input context, then we just change the engine of
635      * the focused context, which will then change the global engine
636      * automatically. Otherwise, we need to change the global engine directly.
637      */
638     IBusEngineDesc *desc = NULL;
639     desc = bus_ibus_impl_get_engine_desc (ibus, name);
640     if (desc != NULL) {
641         bus_ibus_impl_set_context_engine_from_desc (ibus,
642                                                     context,
643                                                     desc);
644     }
645 }
646
647 /* When preload_engines and register_engiens are changed, this function
648  * will check the global engine. If necessay, it will change the global engine.
649  */
650 static void
651 bus_ibus_impl_check_global_engine (BusIBusImpl *ibus)
652 {
653     GList *engine_list = NULL;
654
655     /* do nothing */
656     if (!ibus->use_global_engine)
657         return;
658
659     /* The current global engine is not removed, so do nothing. */
660     if (ibus->global_engine_name != NULL &&
661         _find_engine_desc_by_name (ibus, ibus->global_engine_name)) {
662         return;
663     }
664
665     /* If the previous engine is available, then just switch to it. */
666     if (ibus->global_previous_engine_name != NULL &&
667         _find_engine_desc_by_name (ibus, ibus->global_previous_engine_name)) {
668         bus_ibus_impl_set_global_engine_by_name (
669             ibus, ibus->global_previous_engine_name);
670         return;
671     }
672
673     /* Just switch to the fist engine in the list. */
674     engine_list = ibus->register_engine_list;
675     if (!engine_list)
676         engine_list = ibus->engine_list;
677
678     if (engine_list) {
679         IBusEngineDesc *engine_desc = (IBusEngineDesc *)engine_list->data;
680         bus_ibus_impl_set_global_engine_by_name (ibus,
681                         ibus_engine_desc_get_name (engine_desc));
682         return;
683     }
684
685     /* No engine available? Just disable global engine. */
686     bus_ibus_impl_set_global_engine (ibus, NULL);
687 }
688
689 /**
690  * _context_engine_changed_cb:
691  *
692  * A callback function to be called when the "engine-changed" signal is sent to the context.
693  * Update global engine as well if necessary.
694  */
695 static void
696 _context_engine_changed_cb (BusInputContext *context,
697                             BusIBusImpl     *ibus)
698 {
699     if (!ibus->use_global_engine)
700         return;
701
702     if ((context == ibus->focused_context) ||
703         (ibus->focused_context == NULL && context == ibus->fake_context)) {
704         BusEngineProxy *engine = bus_input_context_get_engine (context);
705         if (engine != NULL) {
706             /* only set global engine if engine is not NULL */
707             const gchar *name = ibus_engine_desc_get_name (bus_engine_proxy_get_desc (engine));
708             if (g_strcmp0 (name, ibus->global_engine_name) == 0)
709                 return;
710             g_free (ibus->global_previous_engine_name);
711             ibus->global_previous_engine_name = ibus->global_engine_name;
712             ibus->global_engine_name = g_strdup (name);
713             bus_ibus_impl_global_engine_changed (ibus);
714         }
715     }
716 }
717
718 /**
719  * _context_focus_in_cb:
720  *
721  * A callback function to be called when the "focus-in" signal is sent to the context.
722  * If necessary, enables the global engine on the context and update ibus->focused_context.
723  */
724 static void
725 _context_focus_in_cb (BusInputContext *context,
726                       BusIBusImpl     *ibus)
727 {
728     g_assert (BUS_IS_IBUS_IMPL (ibus));
729     g_assert (BUS_IS_INPUT_CONTEXT (context));
730
731     /* Do nothing if context does not support focus.
732      * The global engine shoule be detached from the focused context. */
733     if ((bus_input_context_get_capabilities (context) & IBUS_CAP_FOCUS) == 0) {
734         return;
735     }
736
737     bus_ibus_impl_set_focused_context (ibus, context);
738 }
739
740 /**
741  * _context_focus_out_cb:
742  *
743  * A callback function to be called when the "focus-out" signal is sent to the context.
744  */
745 static void
746 _context_focus_out_cb (BusInputContext    *context,
747                        BusIBusImpl        *ibus)
748 {
749     g_assert (BUS_IS_IBUS_IMPL (ibus));
750     g_assert (BUS_IS_INPUT_CONTEXT (context));
751
752     /* Do noting if context does not support focus.
753      * Actually, the context should emit focus signals, if it does not support focus */
754     if ((bus_input_context_get_capabilities (context) & IBUS_CAP_FOCUS) == 0) {
755         return;
756     }
757
758     /* Do noting if it is not focused context. */
759     if (ibus->focused_context != context) {
760         return;
761     }
762
763
764     if (ibus->use_global_engine == FALSE) {
765         /* Do not change the focused context, if use_global_engine option is enabled.
766          * If focused context swith to NULL, users can not swith engine in panel anymore.
767          **/
768         bus_ibus_impl_set_focused_context (ibus, NULL);
769     }
770 }
771
772 /**
773  * _context_destroy_cb:
774  *
775  * A callback function to be called when the "destroy" signal is sent to the context.
776  */
777 static void
778 _context_destroy_cb (BusInputContext    *context,
779                      BusIBusImpl        *ibus)
780 {
781     g_assert (BUS_IS_IBUS_IMPL (ibus));
782     g_assert (BUS_IS_INPUT_CONTEXT (context));
783
784     if (context == ibus->focused_context) {
785         bus_ibus_impl_set_focused_context (ibus, NULL);
786     }
787
788     ibus->contexts = g_list_remove (ibus->contexts, context);
789     g_object_unref (context);
790 }
791
792 /**
793  * bus_ibus_impl_create_input_context:
794  * @client: A name of a client. e.g. "gtk-im"
795  * @returns: A BusInputContext object.
796  *
797  * Create a new BusInputContext object for the client.
798  */
799 static BusInputContext *
800 bus_ibus_impl_create_input_context (BusIBusImpl   *ibus,
801                                     BusConnection *connection,
802                                     const gchar   *client)
803 {
804     BusInputContext *context = bus_input_context_new (connection, client);
805     g_object_ref_sink (context);
806     ibus->contexts = g_list_append (ibus->contexts, context);
807
808     /* Installs glib signal handlers so that the ibus object could be notified when e.g. an IBus.InputContext D-Bus method is called. */
809     static const struct {
810         gchar *name;
811         GCallback callback;
812     } signals [] = {
813         { "request-engine", G_CALLBACK (_context_request_engine_cb) },
814         { "engine-changed", G_CALLBACK (_context_engine_changed_cb) },
815         { "focus-in",       G_CALLBACK (_context_focus_in_cb) },
816         { "focus-out",      G_CALLBACK (_context_focus_out_cb) },
817         { "destroy",        G_CALLBACK (_context_destroy_cb) },
818     };
819
820     gint i;
821     for (i = 0; i < G_N_ELEMENTS (signals); i++) {
822         g_signal_connect (context,
823                           signals[i].name,
824                           signals[i].callback,
825                           ibus);
826     }
827
828     if (ibus->enable_by_default) {
829         bus_input_context_enable (context);
830     }
831
832     /* register the context object so that the object could handle IBus.InputContext method calls. */
833     bus_dbus_impl_register_object (BUS_DEFAULT_DBUS,
834                                    (IBusService *) context);
835     g_object_ref (context);
836     return context;
837 }
838
839 /**
840  * _ibus_create_input_context:
841  *
842  * Implement the "CreateInputContext" method call of the org.freedesktop.IBus interface.
843  */
844 static void
845 _ibus_create_input_context (BusIBusImpl           *ibus,
846                             GVariant              *parameters,
847                             GDBusMethodInvocation *invocation)
848 {
849     const gchar *client_name = NULL;  // e.g. "gtk-im"
850     g_variant_get (parameters, "(&s)", &client_name);
851
852     BusConnection *connection =
853             bus_connection_lookup (g_dbus_method_invocation_get_connection (invocation));
854     BusInputContext *context =
855             bus_ibus_impl_create_input_context (ibus,
856                                                 connection,
857                                                 client_name);
858     if (context) {
859         const gchar *path = ibus_service_get_object_path ((IBusService *) context);
860         /* the format-string 'o' is for a D-Bus object path. */
861         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", path));
862         g_object_unref (context);
863     }
864     else {
865         g_dbus_method_invocation_return_error (invocation,
866                                                G_DBUS_ERROR,
867                                                G_DBUS_ERROR_FAILED,
868                                                "Create input context failed!");
869     }
870 }
871
872 /**
873  * _ibus_current_input_context:
874  *
875  * Implement the "CurrentInputContext" method call of the org.freedesktop.IBus interface.
876  */
877 static void
878 _ibus_current_input_context (BusIBusImpl           *ibus,
879                              GVariant              *parameters,
880                              GDBusMethodInvocation *invocation)
881 {
882     if (!ibus->focused_context)
883     {
884         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
885                         "No focused input context");
886     }
887     else {
888         const gchar *path = ibus_service_get_object_path ((IBusService *) ibus->focused_context);
889         /* the format-string 'o' is for a D-Bus object path. */
890         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", path));
891     }
892 }
893
894 static void
895 _component_destroy_cb (BusComponent *component,
896                        BusIBusImpl  *ibus)
897 {
898     g_assert (BUS_IS_IBUS_IMPL (ibus));
899     g_assert (BUS_IS_COMPONENT (component));
900
901     ibus->registered_components = g_list_remove (ibus->registered_components, component);
902
903     /* remove engines from engine_list */
904     GList *engines = bus_component_get_engines (component);
905     GList *p;
906     for (p = engines; p != NULL; p = p->next) {
907         if (g_list_find (ibus->register_engine_list, p->data)) {
908             ibus->register_engine_list = g_list_remove (ibus->register_engine_list, p->data);
909             g_object_unref (p->data);
910         }
911     }
912     g_list_free (engines);
913
914     g_object_unref (component);
915
916     bus_ibus_impl_check_global_engine (ibus);
917     bus_ibus_impl_update_engines_hotkey_profile (ibus);
918 }
919
920 /**
921  * _ibus_register_component:
922  *
923  * Implement the "RegisterComponent" method call of the org.freedesktop.IBus interface.
924  */
925 static void
926 _ibus_register_component (BusIBusImpl           *ibus,
927                           GVariant              *parameters,
928                           GDBusMethodInvocation *invocation)
929 {
930     GVariant *variant = g_variant_get_child_value (parameters, 0);
931     IBusComponent *component = (IBusComponent *) ibus_serializable_deserialize (variant);
932
933     if (!IBUS_IS_COMPONENT (component)) {
934         if (component)
935             g_object_unref (component);
936         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
937                         "The first argument should be an IBusComponent.");
938         return;
939     }
940
941     BusConnection *connection = bus_connection_lookup (g_dbus_method_invocation_get_connection (invocation));
942     BusFactoryProxy *factory = bus_factory_proxy_new (connection);
943
944     if (factory == NULL) {
945         g_object_unref (component);
946         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
947                         "Create factory failed.");
948         return;
949     }
950
951     g_object_ref_sink (component);
952
953     BusComponent *buscomp = bus_component_new (component, factory);
954     bus_component_set_destroy_with_factory (buscomp, TRUE);
955     g_object_unref (component);
956     g_object_unref (factory);
957
958     ibus->registered_components = g_list_append (ibus->registered_components,
959                                                 g_object_ref_sink (buscomp));
960     GList *engines = bus_component_get_engines (buscomp);
961     g_list_foreach (engines, (GFunc) g_object_ref, NULL);
962     ibus->register_engine_list = g_list_concat (ibus->register_engine_list,
963                                                engines);
964
965     g_signal_connect (buscomp, "destroy", G_CALLBACK (_component_destroy_cb), ibus);
966
967     bus_ibus_impl_update_engines_hotkey_profile (ibus);
968
969     g_dbus_method_invocation_return_value (invocation, NULL);
970 }
971
972 /**
973  * _ibus_list_engines:
974  *
975  * Implement the "ListEngines" method call of the org.freedesktop.IBus interface.
976  */
977 static void
978 _ibus_list_engines (BusIBusImpl           *ibus,
979                     GVariant              *parameters,
980                     GDBusMethodInvocation *invocation)
981 {
982     GVariantBuilder builder;
983     g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
984
985     GList *engines = bus_registry_get_engines (ibus->registry);
986     GList *p;
987     for (p = engines; p != NULL; p = p->next) {
988         g_variant_builder_add (&builder, "v", ibus_serializable_serialize ((IBusSerializable *) p->data));
989     }
990     g_list_free (engines);
991     g_dbus_method_invocation_return_value (invocation, g_variant_new ("(av)", &builder));
992 }
993
994 /**
995  * _ibus_get_engines_by_names:
996  *
997  * Implement the "GetEnginesByNames" method call of the org.freedesktop.IBus interface.
998  */
999 static void
1000 _ibus_get_engines_by_names (BusIBusImpl           *ibus,
1001                             GVariant              *parameters,
1002                             GDBusMethodInvocation *invocation)
1003 {
1004     const gchar **names = NULL;
1005     g_variant_get (parameters, "(^a&s)", &names);
1006
1007     g_assert (names != NULL);
1008
1009     gint i = 0;
1010     GVariantBuilder builder;
1011     g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
1012     while (names[i] != NULL) {
1013         IBusEngineDesc *desc = bus_registry_find_engine_by_name (
1014                 ibus->registry, names[i++]);
1015         if (desc == NULL)
1016             continue;
1017         g_variant_builder_add (
1018                 &builder,
1019                 "v",
1020                 ibus_serializable_serialize ((IBusSerializable *)desc));
1021     }
1022     g_dbus_method_invocation_return_value (invocation, g_variant_new ("(av)", &builder));
1023 }
1024
1025 /**
1026  * _ibus_list_active_engines:
1027  *
1028  * Implement the "ListActiveEngines" method call of the org.freedesktop.IBus interface.
1029  */
1030 static void
1031 _ibus_list_active_engines (BusIBusImpl           *ibus,
1032                            GVariant              *parameters,
1033                            GDBusMethodInvocation *invocation)
1034 {
1035     GVariantBuilder builder;
1036     g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
1037
1038     GList *p;
1039     for (p = ibus->engine_list; p != NULL; p = p->next) {
1040         g_variant_builder_add (&builder, "v", ibus_serializable_serialize ((IBusSerializable *) p->data));
1041     }
1042     for (p = ibus->register_engine_list; p != NULL; p = p->next) {
1043         g_variant_builder_add (&builder, "v", ibus_serializable_serialize ((IBusSerializable *) p->data));
1044     }
1045     g_dbus_method_invocation_return_value (invocation, g_variant_new ("(av)", &builder));
1046 }
1047
1048 /**
1049  * _ibus_exit:
1050  *
1051  * Implement the "Exit" method call of the org.freedesktop.IBus interface.
1052  */
1053 static void
1054 _ibus_exit (BusIBusImpl           *ibus,
1055             GVariant              *parameters,
1056             GDBusMethodInvocation *invocation)
1057 {
1058     gboolean restart = FALSE;
1059     g_variant_get (parameters, "(b)", &restart);
1060
1061     g_dbus_method_invocation_return_value (invocation, NULL);
1062
1063     /* Make sure the reply has been sent out before exit */
1064     g_dbus_connection_flush_sync (g_dbus_method_invocation_get_connection (invocation),
1065                                   NULL,
1066                                   NULL);
1067
1068     bus_server_quit (restart);
1069 }
1070
1071 /**
1072  * _ibus_ping:
1073  *
1074  * Implement the "Ping" method call of the org.freedesktop.IBus interface.
1075  */
1076 static void
1077 _ibus_ping (BusIBusImpl           *ibus,
1078             GVariant              *parameters,
1079             GDBusMethodInvocation *invocation)
1080 {
1081     g_dbus_method_invocation_return_value (invocation, parameters);
1082 }
1083
1084 /**
1085  * _ibus_get_use_sys_layout:
1086  *
1087  * Implement the "GetUseSysLayout" method call of the org.freedesktop.IBus interface.
1088  */
1089 static void
1090 _ibus_get_use_sys_layout (BusIBusImpl           *ibus,
1091                           GVariant              *parameters,
1092                           GDBusMethodInvocation *invocation)
1093 {
1094     g_dbus_method_invocation_return_value (invocation,
1095                     g_variant_new ("(b)", ibus->use_sys_layout));
1096 }
1097
1098 /**
1099  * _ibus_get_use_global_engine:
1100  *
1101  * Implement the "GetUseGlobalEngine" method call of the org.freedesktop.IBus interface.
1102  */
1103 static void
1104 _ibus_get_use_global_engine (BusIBusImpl           *ibus,
1105                              GVariant              *parameters,
1106                              GDBusMethodInvocation *invocation)
1107 {
1108     g_dbus_method_invocation_return_value (invocation,
1109                     g_variant_new ("(b)", ibus->use_global_engine));
1110 }
1111
1112 /**
1113  * _ibus_get_global_engine:
1114  *
1115  * Implement the "GetGlobalEngine" method call of the org.freedesktop.IBus interface.
1116  */
1117 static void
1118 _ibus_get_global_engine (BusIBusImpl           *ibus,
1119                          GVariant              *parameters,
1120                          GDBusMethodInvocation *invocation)
1121 {
1122     IBusEngineDesc *desc = NULL;
1123
1124     do {
1125         if (!ibus->use_global_engine)
1126             break;
1127         BusInputContext *context = ibus->focused_context;
1128         if (context == NULL)
1129             context = ibus->fake_context;
1130
1131         desc = bus_input_context_get_engine_desc (context);
1132
1133         if (desc == NULL)
1134             break;
1135
1136         GVariant *variant = ibus_serializable_serialize ((IBusSerializable *) desc);
1137         g_dbus_method_invocation_return_value (invocation,
1138                                                g_variant_new ("(v)", variant));
1139         return;
1140     } while (0);
1141
1142     g_dbus_method_invocation_return_error (invocation,
1143                     G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
1144                     "No global engine.");
1145 }
1146
1147 struct _SetGlobalEngineData {
1148     BusIBusImpl *ibus;
1149     GDBusMethodInvocation *invocation;
1150 };
1151 typedef struct _SetGlobalEngineData SetGlobalEngineData;
1152
1153 static void
1154 _ibus_set_global_engine_ready_cb (BusInputContext       *context,
1155                                   GAsyncResult          *res,
1156                                   SetGlobalEngineData   *data)
1157 {
1158     BusIBusImpl *ibus = data->ibus;
1159
1160     GError *error = NULL;
1161     if (!bus_input_context_set_engine_by_desc_finish (context, res, &error)) {
1162         g_error_free (error);
1163         g_dbus_method_invocation_return_error (data->invocation,
1164                                                G_DBUS_ERROR,
1165                                                G_DBUS_ERROR_FAILED,
1166                                                "Set global engine failed.");
1167
1168     }
1169     else {
1170         g_dbus_method_invocation_return_value (data->invocation, NULL);
1171
1172         if (ibus->use_global_engine && (context != ibus->focused_context)) {
1173             /* context and ibus->focused_context don't match. This means that
1174              * the focus is moved before _ibus_set_global_engine() asynchronous
1175              * call finishes. In this case, the engine for the context currently
1176              * being focused hasn't been updated. Update the engine here so that
1177              * subsequent _ibus_get_global_engine() call could return a
1178              * consistent engine name. */
1179             BusEngineProxy *engine = bus_input_context_get_engine (context);
1180             if (engine && ibus->focused_context != NULL) {
1181                 g_object_ref (engine);
1182                 bus_input_context_set_engine (context, NULL);
1183                 bus_input_context_set_engine (ibus->focused_context, engine);
1184                 g_object_unref (engine);
1185             }
1186         }
1187     }
1188
1189     g_object_unref (ibus);
1190     g_slice_free (SetGlobalEngineData, data);
1191 }
1192
1193 /**
1194  * _ibus_set_global_engine:
1195  *
1196  * Implement the "SetGlobalEngine" method call of the org.freedesktop.IBus interface.
1197  */
1198 static void
1199 _ibus_set_global_engine (BusIBusImpl           *ibus,
1200                          GVariant              *parameters,
1201                          GDBusMethodInvocation *invocation)
1202 {
1203     if (!ibus->use_global_engine) {
1204         g_dbus_method_invocation_return_error (invocation,
1205                         G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
1206                         "Global engine feature is disabled.");
1207         return;
1208     }
1209
1210     BusInputContext *context = ibus->focused_context;
1211     if (context == NULL)
1212         context = ibus->fake_context;
1213
1214     const gchar *engine_name = NULL;
1215     g_variant_get (parameters, "(&s)", &engine_name);
1216
1217     IBusEngineDesc *desc = bus_ibus_impl_get_engine_desc(ibus, engine_name);
1218     if (desc == NULL) {
1219         g_dbus_method_invocation_return_error (invocation,
1220                                                G_DBUS_ERROR,
1221                                                G_DBUS_ERROR_FAILED,
1222                                                "Can not find engine %s.",
1223                                                engine_name);
1224         return;
1225     }
1226
1227     SetGlobalEngineData *data = g_slice_new0 (SetGlobalEngineData);
1228     data->ibus = g_object_ref (ibus);
1229     data->invocation = invocation;
1230     bus_input_context_set_engine_by_desc (context,
1231                                           desc,
1232                                           g_gdbus_timeout, /* timeout in msec. */
1233                                           NULL, /* we do not cancel the call. */
1234                                           (GAsyncReadyCallback) _ibus_set_global_engine_ready_cb,
1235                                           data);
1236 }
1237
1238 /**
1239  * _ibus_is_global_engine_enabled:
1240  *
1241  * Implement the "IsGlobalEngineEnabled" method call of the org.freedesktop.IBus interface.
1242  */
1243 static void
1244 _ibus_is_global_engine_enabled (BusIBusImpl           *ibus,
1245                                 GVariant              *parameters,
1246                                 GDBusMethodInvocation *invocation)
1247 {
1248     gboolean enabled = FALSE;
1249
1250     do {
1251         if (!ibus->use_global_engine)
1252             break;
1253
1254         BusInputContext *context = ibus->focused_context;
1255         if (context == NULL)
1256             context = ibus->fake_context;
1257         if (context == NULL)
1258             break;
1259
1260         enabled = TRUE;
1261     } while (0);
1262
1263     g_dbus_method_invocation_return_value (invocation,
1264                     g_variant_new ("(b)", enabled));
1265 }
1266
1267 /**
1268  * bus_ibus_impl_service_method_call:
1269  *
1270  * Handle a D-Bus method call whose destination and interface name are both "org.freedesktop.IBus"
1271  */
1272 static void
1273 bus_ibus_impl_service_method_call (IBusService           *service,
1274                                    GDBusConnection       *connection,
1275                                    const gchar           *sender,
1276                                    const gchar           *object_path,
1277                                    const gchar           *interface_name,
1278                                    const gchar           *method_name,
1279                                    GVariant              *parameters,
1280                                    GDBusMethodInvocation *invocation)
1281 {
1282     if (g_strcmp0 (interface_name, "org.freedesktop.IBus") != 0) {
1283         IBUS_SERVICE_CLASS (bus_ibus_impl_parent_class)->service_method_call (
1284                         service, connection, sender, object_path, interface_name, method_name,
1285                         parameters, invocation);
1286         return;
1287     }
1288
1289     /* all methods in the xml definition above should be listed here. */
1290     static const struct {
1291         const gchar *method_name;
1292         void (* method_callback) (BusIBusImpl *, GVariant *, GDBusMethodInvocation *);
1293     } methods [] =  {
1294         /* IBus interface */
1295         { "GetAddress",            _ibus_get_address },
1296         { "CreateInputContext",    _ibus_create_input_context },
1297         { "CurrentInputContext",   _ibus_current_input_context },
1298         { "RegisterComponent",     _ibus_register_component },
1299         { "ListEngines",           _ibus_list_engines },
1300         { "GetEnginesByNames",     _ibus_get_engines_by_names },
1301         { "ListActiveEngines",     _ibus_list_active_engines },
1302         { "Exit",                  _ibus_exit },
1303         { "Ping",                  _ibus_ping },
1304         { "GetUseSysLayout",       _ibus_get_use_sys_layout },
1305         { "GetUseGlobalEngine",    _ibus_get_use_global_engine },
1306         { "GetGlobalEngine",       _ibus_get_global_engine },
1307         { "SetGlobalEngine",       _ibus_set_global_engine },
1308         { "IsGlobalEngineEnabled", _ibus_is_global_engine_enabled },
1309     };
1310
1311     gint i;
1312     for (i = 0; i < G_N_ELEMENTS (methods); i++) {
1313         if (g_strcmp0 (methods[i].method_name, method_name) == 0) {
1314             methods[i].method_callback ((BusIBusImpl *) service, parameters, invocation);
1315             return;
1316         }
1317     }
1318
1319     /* notreached - unknown method calls that are not in the introspection_xml should be handled by the GDBus library. */
1320     g_return_if_reached ();
1321 }
1322
1323 BusIBusImpl *
1324 bus_ibus_impl_get_default (void)
1325 {
1326     static BusIBusImpl *ibus = NULL;
1327
1328     if (ibus == NULL) {
1329         ibus = (BusIBusImpl *) g_object_new (BUS_TYPE_IBUS_IMPL,
1330                                              "object-path", IBUS_PATH_IBUS,
1331                                              NULL);
1332     }
1333     return ibus;
1334 }
1335
1336 BusFactoryProxy *
1337 bus_ibus_impl_lookup_factory (BusIBusImpl *ibus,
1338                               const gchar *path)
1339 {
1340     g_assert (BUS_IS_IBUS_IMPL (ibus));
1341
1342     BusFactoryProxy *factory;
1343
1344     factory = (BusFactoryProxy *) g_hash_table_lookup (ibus->factory_dict, path);
1345
1346     return factory;
1347 }
1348
1349 IBusKeymap *
1350 bus_ibus_impl_get_keymap (BusIBusImpl *ibus)
1351 {
1352
1353     g_assert (BUS_IS_IBUS_IMPL (ibus));
1354
1355     return ibus->keymap;
1356 }
1357
1358 BusRegistry *
1359 bus_ibus_impl_get_registry (BusIBusImpl *ibus)
1360 {
1361
1362     g_assert (BUS_IS_IBUS_IMPL (ibus));
1363
1364     return ibus->registry;
1365 }
1366
1367 /**
1368  * bus_ibus_impl_emit_signal:
1369  *
1370  * Send a D-Bus signal to buses (connections) that are listening to the signal.
1371  */
1372 static void
1373 bus_ibus_impl_emit_signal (BusIBusImpl *ibus,
1374                            const gchar *signal_name,
1375                            GVariant    *parameters)
1376 {
1377     GDBusMessage *message = g_dbus_message_new_signal ("/org/freedesktop/IBus",
1378                                                        "org.freedesktop.IBus",
1379                                                        signal_name);
1380     /* set a non-zero serial to make libdbus happy */
1381     g_dbus_message_set_serial (message, 1);
1382     g_dbus_message_set_sender (message, "org.freedesktop.IBus");
1383     if (parameters)
1384         g_dbus_message_set_body (message, parameters);
1385     bus_dbus_impl_dispatch_message_by_rule (BUS_DEFAULT_DBUS, message, NULL);
1386     g_object_unref (message);
1387 }
1388
1389 static void
1390 bus_ibus_impl_registry_changed (BusIBusImpl *ibus)
1391 {
1392     bus_ibus_impl_emit_signal (ibus, "RegistryChanged", NULL);
1393 }
1394
1395 static void
1396 bus_ibus_impl_global_engine_changed (BusIBusImpl *ibus)
1397 {
1398     const gchar *name = ibus->global_engine_name ? ibus->global_engine_name : "";
1399     bus_ibus_impl_emit_signal (ibus, "GlobalEngineChanged",
1400                                g_variant_new ("(s)", name));
1401 }
1402
1403 gboolean
1404 bus_ibus_impl_filter_keyboard_shortcuts (BusIBusImpl     *ibus,
1405                                          BusInputContext *context,
1406                                          guint           keyval,
1407                                          guint           modifiers,
1408                                          guint           prev_keyval,
1409                                          guint           prev_modifiers)
1410 {
1411     return FALSE;
1412 }
1413
1414 /**
1415  * _add_engine_hotkey:
1416  *
1417  * Check the engine-specific hot key of the engine, and update ibus->engines_hotkey_profile.
1418  */
1419 static void
1420 _add_engine_hotkey (IBusEngineDesc *engine, BusIBusImpl *ibus)
1421 {
1422     const gchar *hotkeys;
1423     gchar **hotkey_list;
1424     gchar **p;
1425     gchar *hotkey;
1426     GList *engine_list;
1427
1428     GQuark event;
1429     guint keyval;
1430     guint modifiers;
1431
1432     if (!engine) {
1433         return;
1434     }
1435
1436     hotkeys = ibus_engine_desc_get_hotkeys (engine);
1437
1438     if (!hotkeys || !*hotkeys) {
1439         return;
1440     }
1441
1442     hotkey_list = g_strsplit_set (hotkeys, ";,", 0);
1443
1444     for (p = hotkey_list; p && *p; ++p) {
1445         hotkey = g_strstrip (*p);
1446         if (!*hotkey || !ibus_key_event_from_string (hotkey, &keyval, &modifiers)) {
1447             continue;
1448         }
1449
1450         /* If the hotkey already exists, we won't need to add it again. */
1451         event = ibus_hotkey_profile_lookup_hotkey (ibus->engines_hotkey_profile,
1452                                                    keyval, modifiers);
1453         if (event == 0) {
1454             event = g_quark_from_string (hotkey);
1455             ibus_hotkey_profile_add_hotkey (ibus->engines_hotkey_profile,
1456                                             keyval, modifiers, event);
1457         }
1458
1459         engine_list = g_hash_table_lookup (ibus->hotkey_to_engines_map,
1460                                            GUINT_TO_POINTER (event));
1461
1462         /* As we will rebuild the engines hotkey map whenever an engine was
1463          * added or removed, we don't need to hold a reference of the engine
1464          * here. */
1465         engine_list = g_list_append (engine_list, engine);
1466
1467         /* We need to steal the value before adding it back, otherwise it will
1468          * be destroyed. */
1469         g_hash_table_steal (ibus->hotkey_to_engines_map, GUINT_TO_POINTER (event));
1470
1471         g_hash_table_insert (ibus->hotkey_to_engines_map,
1472                              GUINT_TO_POINTER (event), engine_list);
1473     }
1474
1475     g_strfreev (hotkey_list);
1476 }
1477
1478 /**
1479  * bus_ibus_impl_update_engines_hotkey_profile:
1480  *
1481  * Check engine-specific hot keys of all active engines, and update ibus->engines_hotkey_profile.
1482  */
1483 static void
1484 bus_ibus_impl_update_engines_hotkey_profile (BusIBusImpl *ibus)
1485 {
1486     if (ibus->engines_hotkey_profile) {
1487         g_object_unref (ibus->engines_hotkey_profile);
1488     }
1489
1490     if (ibus->hotkey_to_engines_map) {
1491         g_hash_table_unref (ibus->hotkey_to_engines_map);
1492     }
1493
1494     ibus->engines_hotkey_profile = ibus_hotkey_profile_new ();
1495     ibus->hotkey_to_engines_map =
1496         g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_list_free);
1497
1498     g_list_foreach (ibus->register_engine_list, (GFunc) _add_engine_hotkey, ibus);
1499     g_list_foreach (ibus->engine_list, (GFunc) _add_engine_hotkey, ibus);
1500 }
1501
1502 gboolean
1503 bus_ibus_impl_is_use_sys_layout (BusIBusImpl *ibus)
1504 {
1505     g_assert (BUS_IS_IBUS_IMPL (ibus));
1506
1507     return ibus->use_sys_layout;
1508 }
1509
1510 gboolean
1511 bus_ibus_impl_is_embed_preedit_text (BusIBusImpl *ibus)
1512 {
1513     g_assert (BUS_IS_IBUS_IMPL (ibus));
1514
1515     return ibus->embed_preedit_text;
1516 }
1517
1518 BusInputContext *
1519 bus_ibus_impl_get_focused_input_context (BusIBusImpl *ibus)
1520 {
1521     g_assert (BUS_IS_IBUS_IMPL (ibus));
1522
1523     return ibus->focused_context;
1524 }