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.
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.
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.
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.
24 #include <sys/types.h>
33 #include "connection.h"
35 #include "factoryproxy.h"
36 #include "panelproxy.h"
37 #include "inputcontext.h"
42 /* instance members */
43 GHashTable *factory_dict;
45 /* registered components */
46 GList *registered_components;
49 /* a fake input context for global engine support */
50 BusInputContext *fake_context;
52 /* a list of engines that are preloaded. */
54 /* a list of engines that are started by a user (without the --ibus command line flag.) */
55 GList *register_engine_list;
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;
61 gboolean embed_preedit_text;
62 gboolean enable_by_default;
64 BusRegistry *registry;
66 BusInputContext *focused_context;
69 /* a default keymap of ibus-daemon (usually "us") which is used only when use_sys_layout is FALSE. */
72 gboolean use_global_engine;
73 gchar *global_engine_name;
74 gchar *global_previous_engine_name;
76 /* engine-specific hotkeys */
77 IBusHotkeyProfile *engines_hotkey_profile;
78 GHashTable *hotkey_to_engines_map;
81 struct _BusIBusImplClass {
82 IBusServiceClass parent;
96 static guint _signals[LAST_SIGNAL] = { 0 };
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,
105 const gchar *object_path,
106 const gchar *interface_name,
107 const gchar *method_name,
108 GVariant *parameters,
109 GDBusMethodInvocation
111 /* TODO use property to replace some getter and setter in future */
113 static GVariant *ibus_ibus_impl_service_get_property
114 (IBusService *service,
115 GDBusConnection *connection,
117 const gchar *object_path,
118 const gchar *interface_name,
119 const gchar *property_name,
121 static gboolean ibus_ibus_impl_service_set_property
122 (IBusService *service,
123 GDBusConnection *connection,
125 const gchar *object_path,
126 const gchar *interface_name,
127 const gchar *property_name,
131 static void bus_ibus_impl_registry_changed (BusIBusImpl *ibus);
132 static void bus_ibus_impl_global_engine_changed
134 static void bus_ibus_impl_set_context_engine_from_desc
136 BusInputContext *context,
137 IBusEngineDesc *desc);
138 static void bus_ibus_impl_update_engines_hotkey_profile
140 static BusInputContext
141 *bus_ibus_impl_create_input_context
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
150 BusInputContext *context);
151 /* some callback functions */
152 static void _context_engine_changed_cb (BusInputContext *context,
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[] =
160 " <interface name='org.freedesktop.IBus'>\n"
161 " <method name='GetAddress'>\n"
162 " <arg direction='out' type='s' name='address' />\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"
168 " <method name='CurrentInputContext'>\n"
169 " <arg direction='out' type='o' name='object_path' />\n"
171 " <method name='RegisterComponent'>\n"
172 " <arg direction='in' type='v' name='component' />\n"
174 " <method name='ListEngines'>\n"
175 " <arg direction='out' type='av' name='engines' />\n"
177 " <method name='GetEnginesByNames'>\n"
178 " <arg direction='in' type='as' name='names' />\n"
179 " <arg direction='out' type='av' name='engines' />\n"
181 " <method name='ListActiveEngines'>\n"
182 " <arg direction='out' type='av' name='engines' />\n"
184 " <method name='Exit'>\n"
185 " <arg direction='in' type='b' name='restart' />\n"
187 " <method name='Ping'>\n"
188 " <arg direction='in' type='v' name='data' />\n"
189 " <arg direction='out' type='v' name='data' />\n"
191 " <method name='GetUseSysLayout'>\n"
192 " <arg direction='out' type='b' name='enabled' />\n"
194 " <method name='GetUseGlobalEngine'>\n"
195 " <arg direction='out' type='b' name='enabled' />\n"
197 " <method name='GetGlobalEngine'>\n"
198 " <arg direction='out' type='v' name='desc' />\n"
200 " <method name='SetGlobalEngine'>\n"
201 " <arg direction='in' type='s' name='engine_name' />\n"
203 " <method name='IsGlobalEngineEnabled'>\n"
204 " <arg direction='out' type='b' name='enabled' />\n"
206 " <signal name='RegistryChanged'>\n"
208 " <signal name='GlobalEngineChanged'>\n"
209 " <arg type='s' name='engine_name' />\n"
215 G_DEFINE_TYPE (BusIBusImpl, bus_ibus_impl, IBUS_TYPE_SERVICE)
218 bus_ibus_impl_class_init (BusIBusImplClass *class)
220 IBUS_OBJECT_CLASS (class)->destroy = (IBusObjectDestroyFunc) bus_ibus_impl_destroy;
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);
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.
235 _panel_destroy_cb (BusPanelProxy *panel,
238 g_assert (BUS_IS_PANEL_PROXY (panel));
239 g_assert (BUS_IS_IBUS_IMPL (ibus));
241 g_return_if_fail (ibus->panel == panel);
244 g_object_unref (panel);
248 _registry_changed_cb (BusRegistry *registry,
251 bus_ibus_impl_registry_changed (ibus);
255 * _dbus_name_owner_changed_cb:
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.
261 _dbus_name_owner_changed_cb (BusDBusImpl *dbus,
262 BusConnection *orig_connection,
264 const gchar *old_name,
265 const gchar *new_name,
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));
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;
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);
285 connection = bus_dbus_impl_get_connection_by_name (BUS_DEFAULT_DBUS, new_name);
286 g_return_if_fail (connection != NULL);
288 ibus->panel = bus_panel_proxy_new (connection);
290 g_signal_connect (ibus->panel,
292 G_CALLBACK (_panel_destroy_cb),
295 if (ibus->focused_context != NULL) {
296 bus_panel_proxy_focus_in (ibus->panel, ibus->focused_context);
298 else if (ibus->use_global_engine) {
299 bus_panel_proxy_focus_in (ibus->panel, ibus->fake_context);
304 bus_registry_name_owner_changed (ibus->registry, name, old_name, new_name);
308 * bus_ibus_impl_init:
310 * The constructor of BusIBusImpl. Initialize all member variables of a BusIBusImpl object.
313 bus_ibus_impl_init (BusIBusImpl *ibus)
315 ibus->factory_dict = g_hash_table_new_full (
319 (GDestroyNotify) g_object_unref);
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 |
328 IBUS_CAP_SURROUNDING_TEXT);
329 g_signal_connect (ibus->fake_context,
331 G_CALLBACK (_context_engine_changed_cb),
333 bus_input_context_focus_in (ibus->fake_context);
335 ibus->engine_list = NULL;
336 ibus->register_engine_list = NULL;
337 ibus->contexts = NULL;
338 ibus->focused_context = NULL;
340 ibus->registry = bus_registry_new ();
342 g_signal_connect (ibus->registry,
344 G_CALLBACK (_registry_changed_cb),
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);
354 ibus->keymap = ibus_keymap_get ("us");
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;
363 ibus->engines_hotkey_profile = NULL;
364 ibus->hotkey_to_engines_map = NULL;
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);
370 g_signal_connect (BUS_DEFAULT_DBUS,
371 "name-owner-changed",
372 G_CALLBACK (_dbus_name_owner_changed_cb),
377 * bus_ibus_impl_destroy:
379 * The destructor of BusIBusImpl.
382 bus_ibus_impl_destroy (BusIBusImpl *ibus)
389 bus_registry_stop_all_components (ibus->registry);
395 while ((pid = waitpid (0, &status, WNOHANG)) > 0);
397 if (pid == -1) { /* all children finished */
400 if (pid == 0) { /* no child status changed */
403 if (timeout >= G_USEC_PER_SEC) {
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);
413 g_warning ("Not every child processes exited!");
420 g_list_free_full (ibus->engine_list, g_object_unref);
421 ibus->engine_list = NULL;
423 g_list_free_full (ibus->register_engine_list, g_object_unref);
424 ibus->register_engine_list = NULL;
426 if (ibus->factory_dict != NULL) {
427 g_hash_table_destroy (ibus->factory_dict);
428 ibus->factory_dict = NULL;
431 if (ibus->keymap != NULL) {
432 g_object_unref (ibus->keymap);
436 g_free (ibus->global_engine_name);
437 ibus->global_engine_name = NULL;
439 g_free (ibus->global_previous_engine_name);
440 ibus->global_previous_engine_name = NULL;
442 if (ibus->engines_hotkey_profile != NULL) {
443 g_object_unref (ibus->engines_hotkey_profile);
444 ibus->engines_hotkey_profile = NULL;
447 if (ibus->hotkey_to_engines_map) {
448 g_hash_table_unref (ibus->hotkey_to_engines_map);
449 ibus->hotkey_to_engines_map = NULL;
452 if (ibus->fake_context) {
453 g_object_unref (ibus->fake_context);
454 ibus->fake_context = NULL;
457 IBUS_OBJECT_CLASS (bus_ibus_impl_parent_class)->destroy (IBUS_OBJECT (ibus));
463 * Implement the "GetAddress" method call of the org.freedesktop.IBus interface.
466 _ibus_get_address (BusIBusImpl *ibus,
467 GVariant *parameters,
468 GDBusMethodInvocation *invocation)
470 g_dbus_method_invocation_return_value (invocation,
471 g_variant_new ("(s)", bus_server_get_address ()));
474 static IBusEngineDesc *
475 _find_engine_desc_by_name (BusIBusImpl *ibus,
476 const gchar *engine_name)
478 IBusEngineDesc *desc = NULL;
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)
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)
498 * _context_request_engine_cb:
500 * A callback function to be called when the "request-engine" signal is sent to the context.
502 static IBusEngineDesc *
503 _context_request_engine_cb (BusInputContext *context,
504 const gchar *engine_name,
507 return bus_ibus_impl_get_engine_desc (ibus, engine_name);
511 * bus_ibus_impl_get_engine_desc:
513 * Get the IBusEngineDesc by engine_name. If the engine_name is NULL, return
514 * a default engine desc.
516 static IBusEngineDesc *
517 bus_ibus_impl_get_engine_desc (BusIBusImpl *ibus,
518 const gchar *engine_name)
520 g_return_val_if_fail (engine_name != NULL, NULL);
521 g_return_val_if_fail (engine_name[0] != '\0', NULL);
523 return bus_registry_find_engine_by_name (ibus->registry, engine_name);
527 bus_ibus_impl_set_context_engine_from_desc (BusIBusImpl *ibus,
528 BusInputContext *context,
529 IBusEngineDesc *desc)
531 bus_input_context_set_engine_by_desc (context,
533 g_gdbus_timeout, /* timeout in msec. */
534 NULL, /* we do not cancel the call. */
535 NULL, /* use the default callback function. */
540 * bus_ibus_impl_set_focused_context:
542 * Set the current focused context.
545 bus_ibus_impl_set_focused_context (BusIBusImpl *ibus,
546 BusInputContext *context)
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);
552 /* Do noting if it is not focused context. */
553 if (ibus->focused_context == context) {
557 BusEngineProxy *engine = NULL;
558 gboolean is_enabled = FALSE;
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);
565 // is_enabled = bus_input_context_is_enabled (ibus->focused_context);
567 g_object_ref (engine);
568 bus_input_context_set_engine (ibus->focused_context, NULL);
572 if (ibus->panel != NULL)
573 bus_panel_proxy_focus_out (ibus->panel, ibus->focused_context);
575 g_object_unref (ibus->focused_context);
576 ibus->focused_context = NULL;
579 if (context == NULL && ibus->use_global_engine) {
580 context = ibus->fake_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);
589 bus_input_context_enable (context);
591 g_object_unref (engine);
594 if (ibus->panel != NULL)
595 bus_panel_proxy_focus_in (ibus->panel, context);
600 bus_ibus_impl_set_global_engine (BusIBusImpl *ibus,
601 BusEngineProxy *engine)
603 if (!ibus->use_global_engine)
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);
614 bus_ibus_impl_set_global_engine_by_name (BusIBusImpl *ibus,
617 if (!ibus->use_global_engine)
620 BusInputContext *context =
621 ibus->focused_context != NULL ? ibus->focused_context : ibus->fake_context;
623 if (context == NULL) {
627 if (g_strcmp0 (name, ibus->global_engine_name) == 0) {
628 /* If the user requested the same global engine, then we just enable the
630 bus_input_context_enable (context);
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.
638 IBusEngineDesc *desc = NULL;
639 desc = bus_ibus_impl_get_engine_desc (ibus, name);
641 bus_ibus_impl_set_context_engine_from_desc (ibus,
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.
651 bus_ibus_impl_check_global_engine (BusIBusImpl *ibus)
653 GList *engine_list = NULL;
656 if (!ibus->use_global_engine)
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)) {
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);
673 /* Just switch to the fist engine in the list. */
674 engine_list = ibus->register_engine_list;
676 engine_list = ibus->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));
685 /* No engine available? Just disable global engine. */
686 bus_ibus_impl_set_global_engine (ibus, NULL);
690 * _context_engine_changed_cb:
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.
696 _context_engine_changed_cb (BusInputContext *context,
699 if (!ibus->use_global_engine)
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)
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);
719 * _context_focus_in_cb:
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.
725 _context_focus_in_cb (BusInputContext *context,
728 g_assert (BUS_IS_IBUS_IMPL (ibus));
729 g_assert (BUS_IS_INPUT_CONTEXT (context));
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) {
737 bus_ibus_impl_set_focused_context (ibus, context);
741 * _context_focus_out_cb:
743 * A callback function to be called when the "focus-out" signal is sent to the context.
746 _context_focus_out_cb (BusInputContext *context,
749 g_assert (BUS_IS_IBUS_IMPL (ibus));
750 g_assert (BUS_IS_INPUT_CONTEXT (context));
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) {
758 /* Do noting if it is not focused context. */
759 if (ibus->focused_context != context) {
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.
768 bus_ibus_impl_set_focused_context (ibus, NULL);
773 * _context_destroy_cb:
775 * A callback function to be called when the "destroy" signal is sent to the context.
778 _context_destroy_cb (BusInputContext *context,
781 g_assert (BUS_IS_IBUS_IMPL (ibus));
782 g_assert (BUS_IS_INPUT_CONTEXT (context));
784 if (context == ibus->focused_context) {
785 bus_ibus_impl_set_focused_context (ibus, NULL);
788 ibus->contexts = g_list_remove (ibus->contexts, context);
789 g_object_unref (context);
793 * bus_ibus_impl_create_input_context:
794 * @client: A name of a client. e.g. "gtk-im"
795 * @returns: A BusInputContext object.
797 * Create a new BusInputContext object for the client.
799 static BusInputContext *
800 bus_ibus_impl_create_input_context (BusIBusImpl *ibus,
801 BusConnection *connection,
804 BusInputContext *context = bus_input_context_new (connection, client);
805 g_object_ref_sink (context);
806 ibus->contexts = g_list_append (ibus->contexts, context);
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 {
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) },
821 for (i = 0; i < G_N_ELEMENTS (signals); i++) {
822 g_signal_connect (context,
828 if (ibus->enable_by_default) {
829 bus_input_context_enable (context);
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);
840 * _ibus_create_input_context:
842 * Implement the "CreateInputContext" method call of the org.freedesktop.IBus interface.
845 _ibus_create_input_context (BusIBusImpl *ibus,
846 GVariant *parameters,
847 GDBusMethodInvocation *invocation)
849 const gchar *client_name = NULL; // e.g. "gtk-im"
850 g_variant_get (parameters, "(&s)", &client_name);
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,
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);
865 g_dbus_method_invocation_return_error (invocation,
868 "Create input context failed!");
873 * _ibus_current_input_context:
875 * Implement the "CurrentInputContext" method call of the org.freedesktop.IBus interface.
878 _ibus_current_input_context (BusIBusImpl *ibus,
879 GVariant *parameters,
880 GDBusMethodInvocation *invocation)
882 if (!ibus->focused_context)
884 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
885 "No focused input context");
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));
895 _component_destroy_cb (BusComponent *component,
898 g_assert (BUS_IS_IBUS_IMPL (ibus));
899 g_assert (BUS_IS_COMPONENT (component));
901 ibus->registered_components = g_list_remove (ibus->registered_components, component);
903 /* remove engines from engine_list */
904 GList *engines = bus_component_get_engines (component);
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);
912 g_list_free (engines);
914 g_object_unref (component);
916 bus_ibus_impl_check_global_engine (ibus);
917 bus_ibus_impl_update_engines_hotkey_profile (ibus);
921 * _ibus_register_component:
923 * Implement the "RegisterComponent" method call of the org.freedesktop.IBus interface.
926 _ibus_register_component (BusIBusImpl *ibus,
927 GVariant *parameters,
928 GDBusMethodInvocation *invocation)
930 GVariant *variant = g_variant_get_child_value (parameters, 0);
931 IBusComponent *component = (IBusComponent *) ibus_serializable_deserialize (variant);
933 if (!IBUS_IS_COMPONENT (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.");
941 BusConnection *connection = bus_connection_lookup (g_dbus_method_invocation_get_connection (invocation));
942 BusFactoryProxy *factory = bus_factory_proxy_new (connection);
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.");
951 g_object_ref_sink (component);
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);
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,
965 g_signal_connect (buscomp, "destroy", G_CALLBACK (_component_destroy_cb), ibus);
967 bus_ibus_impl_update_engines_hotkey_profile (ibus);
969 g_dbus_method_invocation_return_value (invocation, NULL);
973 * _ibus_list_engines:
975 * Implement the "ListEngines" method call of the org.freedesktop.IBus interface.
978 _ibus_list_engines (BusIBusImpl *ibus,
979 GVariant *parameters,
980 GDBusMethodInvocation *invocation)
982 GVariantBuilder builder;
983 g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
985 GList *engines = bus_registry_get_engines (ibus->registry);
987 for (p = engines; p != NULL; p = p->next) {
988 g_variant_builder_add (&builder, "v", ibus_serializable_serialize ((IBusSerializable *) p->data));
990 g_list_free (engines);
991 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(av)", &builder));
995 * _ibus_get_engines_by_names:
997 * Implement the "GetEnginesByNames" method call of the org.freedesktop.IBus interface.
1000 _ibus_get_engines_by_names (BusIBusImpl *ibus,
1001 GVariant *parameters,
1002 GDBusMethodInvocation *invocation)
1004 const gchar **names = NULL;
1005 g_variant_get (parameters, "(^a&s)", &names);
1007 g_assert (names != NULL);
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++]);
1017 g_variant_builder_add (
1020 ibus_serializable_serialize ((IBusSerializable *)desc));
1022 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(av)", &builder));
1026 * _ibus_list_active_engines:
1028 * Implement the "ListActiveEngines" method call of the org.freedesktop.IBus interface.
1031 _ibus_list_active_engines (BusIBusImpl *ibus,
1032 GVariant *parameters,
1033 GDBusMethodInvocation *invocation)
1035 GVariantBuilder builder;
1036 g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
1039 for (p = ibus->engine_list; p != NULL; p = p->next) {
1040 g_variant_builder_add (&builder, "v", ibus_serializable_serialize ((IBusSerializable *) p->data));
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));
1045 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(av)", &builder));
1051 * Implement the "Exit" method call of the org.freedesktop.IBus interface.
1054 _ibus_exit (BusIBusImpl *ibus,
1055 GVariant *parameters,
1056 GDBusMethodInvocation *invocation)
1058 gboolean restart = FALSE;
1059 g_variant_get (parameters, "(b)", &restart);
1061 g_dbus_method_invocation_return_value (invocation, NULL);
1063 /* Make sure the reply has been sent out before exit */
1064 g_dbus_connection_flush_sync (g_dbus_method_invocation_get_connection (invocation),
1068 bus_server_quit (restart);
1074 * Implement the "Ping" method call of the org.freedesktop.IBus interface.
1077 _ibus_ping (BusIBusImpl *ibus,
1078 GVariant *parameters,
1079 GDBusMethodInvocation *invocation)
1081 g_dbus_method_invocation_return_value (invocation, parameters);
1085 * _ibus_get_use_sys_layout:
1087 * Implement the "GetUseSysLayout" method call of the org.freedesktop.IBus interface.
1090 _ibus_get_use_sys_layout (BusIBusImpl *ibus,
1091 GVariant *parameters,
1092 GDBusMethodInvocation *invocation)
1094 g_dbus_method_invocation_return_value (invocation,
1095 g_variant_new ("(b)", ibus->use_sys_layout));
1099 * _ibus_get_use_global_engine:
1101 * Implement the "GetUseGlobalEngine" method call of the org.freedesktop.IBus interface.
1104 _ibus_get_use_global_engine (BusIBusImpl *ibus,
1105 GVariant *parameters,
1106 GDBusMethodInvocation *invocation)
1108 g_dbus_method_invocation_return_value (invocation,
1109 g_variant_new ("(b)", ibus->use_global_engine));
1113 * _ibus_get_global_engine:
1115 * Implement the "GetGlobalEngine" method call of the org.freedesktop.IBus interface.
1118 _ibus_get_global_engine (BusIBusImpl *ibus,
1119 GVariant *parameters,
1120 GDBusMethodInvocation *invocation)
1122 IBusEngineDesc *desc = NULL;
1125 if (!ibus->use_global_engine)
1127 BusInputContext *context = ibus->focused_context;
1128 if (context == NULL)
1129 context = ibus->fake_context;
1131 desc = bus_input_context_get_engine_desc (context);
1136 GVariant *variant = ibus_serializable_serialize ((IBusSerializable *) desc);
1137 g_dbus_method_invocation_return_value (invocation,
1138 g_variant_new ("(v)", variant));
1142 g_dbus_method_invocation_return_error (invocation,
1143 G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
1144 "No global engine.");
1147 struct _SetGlobalEngineData {
1149 GDBusMethodInvocation *invocation;
1151 typedef struct _SetGlobalEngineData SetGlobalEngineData;
1154 _ibus_set_global_engine_ready_cb (BusInputContext *context,
1156 SetGlobalEngineData *data)
1158 BusIBusImpl *ibus = data->ibus;
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,
1165 G_DBUS_ERROR_FAILED,
1166 "Set global engine failed.");
1170 g_dbus_method_invocation_return_value (data->invocation, NULL);
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);
1189 g_object_unref (ibus);
1190 g_slice_free (SetGlobalEngineData, data);
1194 * _ibus_set_global_engine:
1196 * Implement the "SetGlobalEngine" method call of the org.freedesktop.IBus interface.
1199 _ibus_set_global_engine (BusIBusImpl *ibus,
1200 GVariant *parameters,
1201 GDBusMethodInvocation *invocation)
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.");
1210 BusInputContext *context = ibus->focused_context;
1211 if (context == NULL)
1212 context = ibus->fake_context;
1214 const gchar *engine_name = NULL;
1215 g_variant_get (parameters, "(&s)", &engine_name);
1217 IBusEngineDesc *desc = bus_ibus_impl_get_engine_desc(ibus, engine_name);
1219 g_dbus_method_invocation_return_error (invocation,
1221 G_DBUS_ERROR_FAILED,
1222 "Can not find engine %s.",
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,
1232 g_gdbus_timeout, /* timeout in msec. */
1233 NULL, /* we do not cancel the call. */
1234 (GAsyncReadyCallback) _ibus_set_global_engine_ready_cb,
1239 * _ibus_is_global_engine_enabled:
1241 * Implement the "IsGlobalEngineEnabled" method call of the org.freedesktop.IBus interface.
1244 _ibus_is_global_engine_enabled (BusIBusImpl *ibus,
1245 GVariant *parameters,
1246 GDBusMethodInvocation *invocation)
1248 gboolean enabled = FALSE;
1251 if (!ibus->use_global_engine)
1254 BusInputContext *context = ibus->focused_context;
1255 if (context == NULL)
1256 context = ibus->fake_context;
1257 if (context == NULL)
1263 g_dbus_method_invocation_return_value (invocation,
1264 g_variant_new ("(b)", enabled));
1268 * bus_ibus_impl_service_method_call:
1270 * Handle a D-Bus method call whose destination and interface name are both "org.freedesktop.IBus"
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)
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);
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 *);
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 },
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);
1319 /* notreached - unknown method calls that are not in the introspection_xml should be handled by the GDBus library. */
1320 g_return_if_reached ();
1324 bus_ibus_impl_get_default (void)
1326 static BusIBusImpl *ibus = NULL;
1329 ibus = (BusIBusImpl *) g_object_new (BUS_TYPE_IBUS_IMPL,
1330 "object-path", IBUS_PATH_IBUS,
1337 bus_ibus_impl_lookup_factory (BusIBusImpl *ibus,
1340 g_assert (BUS_IS_IBUS_IMPL (ibus));
1342 BusFactoryProxy *factory;
1344 factory = (BusFactoryProxy *) g_hash_table_lookup (ibus->factory_dict, path);
1350 bus_ibus_impl_get_keymap (BusIBusImpl *ibus)
1353 g_assert (BUS_IS_IBUS_IMPL (ibus));
1355 return ibus->keymap;
1359 bus_ibus_impl_get_registry (BusIBusImpl *ibus)
1362 g_assert (BUS_IS_IBUS_IMPL (ibus));
1364 return ibus->registry;
1368 * bus_ibus_impl_emit_signal:
1370 * Send a D-Bus signal to buses (connections) that are listening to the signal.
1373 bus_ibus_impl_emit_signal (BusIBusImpl *ibus,
1374 const gchar *signal_name,
1375 GVariant *parameters)
1377 GDBusMessage *message = g_dbus_message_new_signal ("/org/freedesktop/IBus",
1378 "org.freedesktop.IBus",
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");
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);
1390 bus_ibus_impl_registry_changed (BusIBusImpl *ibus)
1392 bus_ibus_impl_emit_signal (ibus, "RegistryChanged", NULL);
1396 bus_ibus_impl_global_engine_changed (BusIBusImpl *ibus)
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));
1404 bus_ibus_impl_filter_keyboard_shortcuts (BusIBusImpl *ibus,
1405 BusInputContext *context,
1409 guint prev_modifiers)
1415 * _add_engine_hotkey:
1417 * Check the engine-specific hot key of the engine, and update ibus->engines_hotkey_profile.
1420 _add_engine_hotkey (IBusEngineDesc *engine, BusIBusImpl *ibus)
1422 const gchar *hotkeys;
1423 gchar **hotkey_list;
1436 hotkeys = ibus_engine_desc_get_hotkeys (engine);
1438 if (!hotkeys || !*hotkeys) {
1442 hotkey_list = g_strsplit_set (hotkeys, ";,", 0);
1444 for (p = hotkey_list; p && *p; ++p) {
1445 hotkey = g_strstrip (*p);
1446 if (!*hotkey || !ibus_key_event_from_string (hotkey, &keyval, &modifiers)) {
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,
1454 event = g_quark_from_string (hotkey);
1455 ibus_hotkey_profile_add_hotkey (ibus->engines_hotkey_profile,
1456 keyval, modifiers, event);
1459 engine_list = g_hash_table_lookup (ibus->hotkey_to_engines_map,
1460 GUINT_TO_POINTER (event));
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
1465 engine_list = g_list_append (engine_list, engine);
1467 /* We need to steal the value before adding it back, otherwise it will
1469 g_hash_table_steal (ibus->hotkey_to_engines_map, GUINT_TO_POINTER (event));
1471 g_hash_table_insert (ibus->hotkey_to_engines_map,
1472 GUINT_TO_POINTER (event), engine_list);
1475 g_strfreev (hotkey_list);
1479 * bus_ibus_impl_update_engines_hotkey_profile:
1481 * Check engine-specific hot keys of all active engines, and update ibus->engines_hotkey_profile.
1484 bus_ibus_impl_update_engines_hotkey_profile (BusIBusImpl *ibus)
1486 if (ibus->engines_hotkey_profile) {
1487 g_object_unref (ibus->engines_hotkey_profile);
1490 if (ibus->hotkey_to_engines_map) {
1491 g_hash_table_unref (ibus->hotkey_to_engines_map);
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);
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);
1503 bus_ibus_impl_is_use_sys_layout (BusIBusImpl *ibus)
1505 g_assert (BUS_IS_IBUS_IMPL (ibus));
1507 return ibus->use_sys_layout;
1511 bus_ibus_impl_is_embed_preedit_text (BusIBusImpl *ibus)
1513 g_assert (BUS_IS_IBUS_IMPL (ibus));
1515 return ibus->embed_preedit_text;
1519 bus_ibus_impl_get_focused_input_context (BusIBusImpl *ibus)
1521 g_assert (BUS_IS_IBUS_IMPL (ibus));
1523 return ibus->focused_context;