+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
/* vim:set et sts=4: */
/* ibus - The Input Bus
- * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
- * Copyright (C) 2008-2010 Red Hat, Inc.
+ * Copyright (C) 2008-2013 Peng Huang <shawn.p.huang@gmail.com>
+ * Copyright (C) 2008-2013 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* Boston, MA 02111-1307, USA.
*/
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <signal.h>
-#include <stdlib.h>
+#include "ibusimpl.h"
+
#include <locale.h>
+#include <signal.h>
#include <strings.h>
-#include "ibusimpl.h"
-#include "dbusimpl.h"
-#include "server.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
#include "connection.h"
-#include "registry.h"
+#include "dbusimpl.h"
#include "factoryproxy.h"
-#include "panelproxy.h"
+#include "global.h"
#include "inputcontext.h"
-#include "option.h"
-
-enum {
- LAST_SIGNAL,
-};
-
-enum {
- PROP_0,
-};
-
-// static guint _signals[LAST_SIGNAL] = { 0 };
-
-/* functions prototype */
-static void bus_ibus_impl_destroy (BusIBusImpl *ibus);
-static gboolean bus_ibus_impl_ibus_message (BusIBusImpl *ibus,
- BusConnection *connection,
- IBusMessage *message);
-static void bus_ibus_impl_add_factory (BusIBusImpl *ibus,
- BusFactoryProxy *factory);
-static void bus_ibus_impl_set_trigger (BusIBusImpl *ibus,
- GValue *value);
-static void bus_ibus_impl_set_preload_engines
- (BusIBusImpl *ibus,
- GValue *value);
-static void bus_ibus_impl_set_use_sys_layout
- (BusIBusImpl *ibus,
- GValue *value);
-static void bus_ibus_impl_set_embed_preedit_text
- (BusIBusImpl *ibus,
- GValue *value);
-
-static void bus_ibus_impl_set_use_global_engine
- (BusIBusImpl *ibus,
- GValue *value);
-static void bus_ibus_impl_set_global_engine (BusIBusImpl *ibus,
- BusEngineProxy *engine);
-
-static void bus_ibus_impl_registry_changed (BusIBusImpl *ibus);
-static void _factory_destroy_cb (BusFactoryProxy *factory,
- BusIBusImpl *ibus);
-
-G_DEFINE_TYPE(BusIBusImpl, bus_ibus_impl, IBUS_TYPE_SERVICE)
-
-BusIBusImpl *
-bus_ibus_impl_get_default (void)
-{
- static BusIBusImpl *ibus = NULL;
-
- if (ibus == NULL) {
- ibus = (BusIBusImpl *) g_object_new (BUS_TYPE_IBUS_IMPL,
- "path", IBUS_PATH_IBUS,
- NULL);
- bus_dbus_impl_register_object (BUS_DEFAULT_DBUS,
- (IBusService *)ibus);
- }
- return ibus;
-}
-
-static void
-bus_ibus_impl_class_init (BusIBusImplClass *klass)
-{
- IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (klass);
-
- ibus_object_class->destroy = (IBusObjectDestroyFunc) bus_ibus_impl_destroy;
-
- IBUS_SERVICE_CLASS (klass)->ibus_message = (ServiceIBusMessageFunc) bus_ibus_impl_ibus_message;
-
-}
-
-static void
-_panel_destroy_cb (BusPanelProxy *panel,
- BusIBusImpl *ibus)
-{
- g_assert (BUS_IS_PANEL_PROXY (panel));
- g_assert (BUS_IS_IBUS_IMPL (ibus));
-
- g_return_if_fail (ibus->panel == panel);
-
- ibus->panel = NULL;
- g_object_unref (panel);
-}
-
-static void
-bus_ibus_impl_set_hotkey (BusIBusImpl *ibus,
- GQuark hotkey,
- GValue *value)
-{
- g_assert (BUS_IS_IBUS_IMPL (ibus));
-
- GValueArray *array;
- gint i;
-
- ibus_hotkey_profile_remove_hotkey_by_event (ibus->hotkey_profile, hotkey);
-
- if (value == NULL) {
- return;
- }
-
- g_return_if_fail (G_VALUE_TYPE (value) == G_TYPE_VALUE_ARRAY);
- array = g_value_get_boxed (value);
-
- for (i = 0; i < array->n_values; i++) {
- GValue *str;
-
- str = g_value_array_get_nth (array, i);
- g_return_if_fail (G_VALUE_TYPE (str) == G_TYPE_STRING);
-
- ibus_hotkey_profile_add_hotkey_from_string (ibus->hotkey_profile,
- g_value_get_string (str),
- hotkey);
- }
-
-}
-
-static void
-bus_ibus_impl_set_trigger (BusIBusImpl *ibus,
- GValue *value)
-{
- GQuark hotkey = g_quark_from_static_string ("trigger");
- bus_ibus_impl_set_hotkey (ibus, hotkey, value);
- if (value == NULL) {
- ibus_hotkey_profile_add_hotkey (ibus->hotkey_profile,
- IBUS_space,
- IBUS_CONTROL_MASK,
- hotkey);
- }
-}
-
-static void
-bus_ibus_impl_set_next_engine (BusIBusImpl *ibus,
- GValue *value)
-{
- GQuark hotkey = g_quark_from_static_string ("next-engine");
- bus_ibus_impl_set_hotkey (ibus, hotkey, value);
-}
-
-static void
-bus_ibus_impl_set_prev_engine (BusIBusImpl *ibus,
- GValue *value)
-{
- GQuark hotkey = g_quark_from_static_string ("prev-engine");
- bus_ibus_impl_set_hotkey (ibus, hotkey, value);
-}
-
-static void
-bus_ibus_impl_set_preload_engines (BusIBusImpl *ibus,
- GValue *value)
-{
- GList *engine_list = NULL;
-
- g_list_foreach (ibus->engine_list, (GFunc) g_object_unref, NULL);
- g_list_free (ibus->engine_list);
-
- if (value != NULL && G_VALUE_TYPE (value) == G_TYPE_VALUE_ARRAY) {
- GValueArray *array;
- gint i;
-
- array = (GValueArray *) g_value_get_boxed (value);
- for (i = 0; array && i < array->n_values; i++) {
- const gchar *engine_name;
- IBusEngineDesc *engine;
-
- if (G_VALUE_TYPE (&array->values[i]) != G_TYPE_STRING)
- continue;
-
- engine_name = g_value_get_string (&array->values[i]);
-
- engine = bus_registry_find_engine_by_name (ibus->registry, engine_name);
-
- if (engine == NULL || g_list_find (engine_list, engine) != NULL)
- continue;
-
- engine_list = g_list_append (engine_list, engine);
- }
- }
-
- g_list_foreach (engine_list, (GFunc) g_object_ref, NULL);
- ibus->engine_list = engine_list;
-
- if (ibus->engine_list) {
- IBusComponent *component;
-
- component = ibus_component_get_from_engine ((IBusEngineDesc *) ibus->engine_list->data);
- if (component && !ibus_component_is_running (component)) {
- ibus_component_start (component, g_verbose);
- }
- }
-}
+#include "panelproxy.h"
+#include "server.h"
+#include "types.h"
-static void
-bus_ibus_impl_set_use_sys_layout (BusIBusImpl *ibus,
- GValue *value)
-{
- if (value != NULL && G_VALUE_TYPE (value) == G_TYPE_BOOLEAN) {
- ibus->use_sys_layout = g_value_get_boolean (value);
- }
-}
+struct _BusIBusImpl {
+ IBusService parent;
+ /* instance members */
+ GHashTable *factory_dict;
-static void
-bus_ibus_impl_set_embed_preedit_text (BusIBusImpl *ibus,
- GValue *value){
- if (value != NULL && G_VALUE_TYPE (value) == G_TYPE_BOOLEAN) {
- ibus->embed_preedit_text = g_value_get_boolean (value);
- }
+ /* registered components */
+ GList *registered_components;
+ GList *contexts;
-}
+ /* a fake input context for global engine support */
+ BusInputContext *fake_context;
+
+ /* a list of engines that are started by a user (without the --ibus
+ * command line flag.) */
+ GList *register_engine_list;
-static void
-bus_ibus_impl_set_use_global_engine (BusIBusImpl *ibus,
- GValue *value)
-{
- gboolean new_value;
+ /* if TRUE, ibus-daemon uses a keysym translated by the system
+ * (i.e. XKB) as-is. otherwise, ibus-daemon itself converts keycode
+ * into keysym. */
+ gboolean use_sys_layout;
- if (value == NULL || G_VALUE_TYPE (value) != G_TYPE_BOOLEAN) {
- return;
- }
+ gboolean embed_preedit_text;
- new_value = g_value_get_boolean (value);
- if (ibus->use_global_engine == new_value) {
- return;
- }
+ IBusRegistry *registry;
- if (new_value == TRUE) {
- BusEngineProxy *engine;
- /* turn on use_global_engine option */
- ibus->use_global_engine = TRUE;
- engine = ibus->focused_context != NULL ?
- bus_input_context_get_engine (ibus->focused_context) : NULL;
- if (engine) {
- bus_ibus_impl_set_global_engine (ibus, engine);
- }
- }
- else {
- /* turn off use_global_engine option */
- bus_ibus_impl_set_global_engine (ibus, NULL);
- ibus->use_global_engine = FALSE;
- }
-}
+ /* a list of BusComponent objects that are created from component XML
+ * files (or from the cache of them). */
+ GList *components;
-static gint
-_engine_desc_cmp (IBusEngineDesc *desc1,
- IBusEngineDesc *desc2)
-{
- return - ((gint) desc1->rank) + ((gint) desc2->rank);
-}
+ /* a mapping from an engine name (e.g. 'pinyin') to the corresponding
+ * IBusEngineDesc object. */
+ GHashTable *engine_table;
-static void
-bus_ibus_impl_set_default_preload_engines (BusIBusImpl *ibus)
-{
- g_assert (BUS_IS_IBUS_IMPL (ibus));
+ BusInputContext *focused_context;
+ BusPanelProxy *panel;
- static gboolean done = FALSE;
- GValue value = { 0 };
- GList *engines, *list;
- gchar *lang, *p;
- GValueArray *array;
+ /* a default keymap of ibus-daemon (usually "us") which is used only
+ * when use_sys_layout is FALSE. */
+ IBusKeymap *keymap;
- if (done || ibus->config == NULL) {
- return;
- }
+ gboolean use_global_engine;
+ gchar *global_engine_name;
+ gchar *global_previous_engine_name;
+};
- if (ibus_config_get_value (ibus->config, "general", "preload_engines", &value)) {
- done = TRUE;
- g_value_unset (&value);
- return;
- }
+struct _BusIBusImplClass {
+ IBusServiceClass parent;
- done = TRUE;
- lang = g_strdup (setlocale (LC_ALL, NULL));
- p = index (lang, '.');
- if (p) {
- *p = '\0';
- }
+ /* class members */
+};
- engines = bus_registry_get_engines_by_language (ibus->registry, lang);
- if (engines == NULL) {
- p = index (lang, '_');
- if (p) {
- *p = '\0';
- engines = bus_registry_get_engines_by_language (ibus->registry, lang);
- }
- }
- g_free (lang);
+enum {
+ LAST_SIGNAL,
+};
- /* sort engines by rank */
- engines = g_list_sort (engines, (GCompareFunc) _engine_desc_cmp);
+enum {
+ PROP_0,
+};
- g_value_init (&value, G_TYPE_VALUE_ARRAY);
- array = g_value_array_new (5);
- for (list = engines; list != NULL; list = list->next) {
- IBusEngineDesc *desc;
- GValue name = { 0 };
- desc = (IBusEngineDesc *)list->data;
+/*
+static guint _signals[LAST_SIGNAL] = { 0 };
+*/
- /* ignore engines with rank <== 0 */
- if (desc->rank <= 0)
- break;
- g_value_init (&name, G_TYPE_STRING);
- g_value_set_string (&name, desc->name);
- g_value_array_append (array, &name);
- }
- g_value_take_boxed (&value, array);
- ibus_config_set_value (ibus->config, "general", "preload_engines", &value);
- g_value_unset (&value);
- g_list_free (engines);
-}
+/* functions prototype */
+static void bus_ibus_impl_destroy (BusIBusImpl *ibus);
+static void bus_ibus_impl_service_method_call
+ (IBusService *service,
+ GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation
+ *invocation);
+static GVariant *
+ bus_ibus_impl_service_get_property
+ (IBusService *service,
+ GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *property_name,
+ GError **error);
+static gboolean
+ bus_ibus_impl_service_set_property
+ (IBusService *service,
+ GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *property_name,
+ GVariant *value,
+ GError **error);
+static void bus_ibus_impl_registry_init
+ (BusIBusImpl *ibus);
+static void bus_ibus_impl_registry_changed
+ (BusIBusImpl *ibus);
+static void bus_ibus_impl_registry_destroy
+ (BusIBusImpl *ibus);
+static void bus_ibus_impl_component_name_owner_changed
+ (BusIBusImpl *ibus,
+ const gchar *name,
+ const gchar *old_name,
+ const gchar *new_name);
+static void bus_ibus_impl_global_engine_changed
+ (BusIBusImpl *ibus);
+static void bus_ibus_impl_set_context_engine_from_desc
+ (BusIBusImpl *ibus,
+ BusInputContext *context,
+ IBusEngineDesc *desc);
+static BusInputContext
+ *bus_ibus_impl_create_input_context
+ (BusIBusImpl *ibus,
+ BusConnection *connection,
+ const gchar *client);
+static IBusEngineDesc
+ *bus_ibus_impl_get_engine_desc
+ (BusIBusImpl *ibus,
+ const gchar *engine_name);
+static void bus_ibus_impl_set_focused_context
+ (BusIBusImpl *ibus,
+ BusInputContext *context);
+/* some callback functions */
+static void _context_engine_changed_cb
+ (BusInputContext *context,
+ BusIBusImpl *ibus);
+
+/* The interfaces available in this class, which consists of a list of
+ * methods this class implements and a list of signals this class may emit.
+ * Method calls to the interface that are not defined in this XML will
+ * be automatically rejected by the GDBus library (see src/ibusservice.c
+ * for details.)
+ * Implement org.freedesktop.DBus.Properties
+ * http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties */
+static const gchar introspection_xml[] =
+ "<node>\n"
+ " <interface name='org.freedesktop.IBus'>\n"
+ " <property name='Address' type='s' access='read' />\n"
+ " <property name='CurrentInputContext' type='o' access='read' />\n"
+ " <property name='Engines' type='av' access='read' />\n"
+ " <property name='GlobalEngine' type='v' access='read' />\n"
+ " <property name='PreloadEngines' type='as' access='write'>\n"
+ " <annotation\n"
+ " name='org.freedesktop.DBus.Property.EmitsChangedSignal'\n"
+ " value='true' />\n"
+ " </property>\n"
+ " <property name='EmbedPreeditText' type='b' access='readwrite'>\n"
+ " <annotation\n"
+ " name='org.freedesktop.DBus.Property.EmitsChangedSignal'\n"
+ " value='true' />\n"
+ " </property>\n"
+ " <method name='CreateInputContext'>\n"
+ " <arg direction='in' type='s' name='client_name' />\n"
+ " <arg direction='out' type='o' name='object_path' />\n"
+ " </method>\n"
+ " <method name='RegisterComponent'>\n"
+ " <arg direction='in' type='v' name='component' />\n"
+ " </method>\n"
+ " <method name='GetEnginesByNames'>\n"
+ " <arg direction='in' type='as' name='names' />\n"
+ " <arg direction='out' type='av' name='engines' />\n"
+ " </method>\n"
+ " <method name='Exit'>\n"
+ " <arg direction='in' type='b' name='restart' />\n"
+ " </method>\n"
+ " <method name='Ping'>\n"
+ " <arg direction='in' type='v' name='data' />\n"
+ " <arg direction='out' type='v' name='data' />\n"
+ " </method>\n"
+ " <method name='SetGlobalEngine'>\n"
+ " <arg direction='in' type='s' name='engine_name' />\n"
+ " </method>\n"
+ " <signal name='RegistryChanged'>\n"
+ " </signal>\n"
+ " <signal name='GlobalEngineChanged'>\n"
+ " <arg type='s' name='engine_name' />\n"
+ " </signal>\n"
+ " <property name='ActiveEngines' type='av' access='read' />\n"
+ " <method name='GetAddress'>\n"
+ " <arg direction='out' type='s' name='address' />\n"
+ " <annotation name='org.freedesktop.DBus.Deprecated' value='true'/>\n"
+ " </method>\n"
+ " <method name='CurrentInputContext'>\n"
+ " <arg direction='out' type='o' name='object_path' />\n"
+ " <annotation name='org.freedesktop.DBus.Deprecated' value='true'/>\n"
+ " </method>\n"
+ " <method name='ListEngines'>\n"
+ " <arg direction='out' type='av' name='engines' />\n"
+ " <annotation name='org.freedesktop.DBus.Deprecated' value='true'/>\n"
+ " </method>\n"
+ " <method name='ListActiveEngines'>\n"
+ " <arg direction='out' type='av' name='engines' />\n"
+ " <annotation name='org.freedesktop.DBus.Deprecated' value='true'/>\n"
+ " </method>\n"
+ " <method name='GetUseSysLayout'>\n"
+ " <arg direction='out' type='b' name='enabled' />\n"
+ " <annotation name='org.freedesktop.DBus.Deprecated' value='true'/>\n"
+ " </method>\n"
+ " <method name='GetUseGlobalEngine'>\n"
+ " <arg direction='out' type='b' name='enabled' />\n"
+ " </method>\n"
+ " <method name='IsGlobalEngineEnabled'>\n"
+ " <arg direction='out' type='b' name='enabled' />\n"
+ " <annotation name='org.freedesktop.DBus.Deprecated' value='true'/>\n"
+ " </method>\n"
+ " <method name='GetGlobalEngine'>\n"
+ " <arg direction='out' type='v' name='desc' />\n"
+ " <annotation name='org.freedesktop.DBus.Deprecated' value='true'/>\n"
+ " </method>\n"
+ " </interface>\n"
+ "</node>\n";
+
+
+G_DEFINE_TYPE (BusIBusImpl, bus_ibus_impl, IBUS_TYPE_SERVICE)
static void
-bus_ibus_impl_reload_config (BusIBusImpl *ibus)
+bus_ibus_impl_class_init (BusIBusImplClass *class)
{
- g_assert (BUS_IS_IBUS_IMPL (ibus));
-
- gint i;
- GValue value = { 0 };
-
- const static struct {
- gchar *section;
- gchar *key;
- void ( *func) (BusIBusImpl *, GValue *);
- } entries [] = {
- { "general/hotkey", "trigger", bus_ibus_impl_set_trigger },
- { "general/hotkey", "next_engine", bus_ibus_impl_set_next_engine },
- { "general/hotkey", "prev_engine", bus_ibus_impl_set_prev_engine },
- { "general", "preload_engines", bus_ibus_impl_set_preload_engines },
- { "general", "use_system_keyboard_layout", bus_ibus_impl_set_use_sys_layout },
- { "general", "use_global_engine", bus_ibus_impl_set_use_global_engine },
- { "general", "embed_preedit_text", bus_ibus_impl_set_embed_preedit_text },
- };
-
- for (i = 0; i < G_N_ELEMENTS (entries); i++) {
- if (ibus->config != NULL &&
- ibus_config_get_value (ibus->config,
- entries[i].section,
- entries[i].key,
- &value)) {
- entries[i].func (ibus, &value);
- g_value_unset (&value);
- }
- else {
- entries[i].func (ibus, NULL);
- }
- }
-}
-
-static void
-_config_value_changed_cb (IBusConfig *config,
- gchar *section,
- gchar *key,
- GValue *value,
- BusIBusImpl *ibus)
-{
- g_assert (IBUS_IS_CONFIG (config));
- g_assert (section);
- g_assert (key);
- g_assert (value);
- g_assert (BUS_IS_IBUS_IMPL (ibus));
-
- gint i;
-
- const static struct {
- gchar *section;
- gchar *key;
- void ( *func) (BusIBusImpl *, GValue *);
- } entries [] = {
- { "general/hotkey", "trigger", bus_ibus_impl_set_trigger },
- { "general/hotkey", "next_engine", bus_ibus_impl_set_next_engine },
- { "general/hotkey", "prev_engine", bus_ibus_impl_set_prev_engine },
- { "general", "preload_engines", bus_ibus_impl_set_preload_engines },
- { "general", "use_system_keyboard_layout", bus_ibus_impl_set_use_sys_layout },
- { "general", "use_global_engine", bus_ibus_impl_set_use_global_engine },
- { "general", "embed_preedit_text", bus_ibus_impl_set_embed_preedit_text },
- };
-
- for (i = 0; i < G_N_ELEMENTS (entries); i++) {
- if (g_strcmp0 (entries[i].section, section) == 0 &&
- g_strcmp0 (entries[i].key, key) == 0) {
- entries[i].func (ibus, value);
- break;
- }
- }
+ IBUS_OBJECT_CLASS (class)->destroy =
+ (IBusObjectDestroyFunc) bus_ibus_impl_destroy;
+
+ /* override the parent class's implementation. */
+ IBUS_SERVICE_CLASS (class)->service_method_call =
+ bus_ibus_impl_service_method_call;
+ IBUS_SERVICE_CLASS (class)->service_get_property =
+ bus_ibus_impl_service_get_property;
+ IBUS_SERVICE_CLASS (class)->service_set_property =
+ bus_ibus_impl_service_set_property;
+ /* 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'.) */
+ ibus_service_class_add_interfaces (IBUS_SERVICE_CLASS (class),
+ introspection_xml);
}
+/**
+ * _panel_destroy_cb:
+ *
+ * A callback function which is called when (1) the connection to the panel process is terminated,
+ * or (2) ibus_proxy_destroy (ibus->panel); is called. See src/ibusproxy.c for details.
+ */
static void
-_config_destroy_cb (IBusConfig *config,
- BusIBusImpl *ibus)
+_panel_destroy_cb (BusPanelProxy *panel,
+ BusIBusImpl *ibus)
{
- g_assert (IBUS_IS_CONFIG (config));
+ g_assert (BUS_IS_PANEL_PROXY (panel));
g_assert (BUS_IS_IBUS_IMPL (ibus));
- g_assert (ibus->config == config);
+ g_return_if_fail (ibus->panel == panel);
- g_object_unref (ibus->config);
- ibus->config = NULL;
+ ibus->panel = NULL;
+ g_object_unref (panel);
}
static void
-_registry_changed_cb (BusRegistry *registry,
- BusIBusImpl *ibus)
+_registry_changed_cb (IBusRegistry *registry,
+ BusIBusImpl *ibus)
{
bus_ibus_impl_registry_changed (ibus);
}
+/*
+ * _dbus_name_owner_changed_cb:
+ *
+ * A callback function to be called when the name-owner-changed signal is sent to the dbus object.
+ * This usually means a client (e.g. a panel/config/engine process or an application) is connected/disconnected to/from the bus.
+ */
static void
-_dbus_name_owner_changed_cb (BusDBusImpl *dbus,
- const gchar *name,
- const gchar *old_name,
- const gchar *new_name,
- BusIBusImpl *ibus)
+_dbus_name_owner_changed_cb (BusDBusImpl *dbus,
+ BusConnection *orig_connection,
+ const gchar *name,
+ const gchar *old_name,
+ const gchar *new_name,
+ BusIBusImpl *ibus)
{
g_assert (BUS_IS_DBUS_IMPL (dbus));
g_assert (name != NULL);
g_assert (new_name != NULL);
g_assert (BUS_IS_IBUS_IMPL (ibus));
- BusFactoryProxy *factory;
-
if (g_strcmp0 (name, IBUS_SERVICE_PANEL) == 0) {
if (g_strcmp0 (new_name, "") != 0) {
+ /* a Panel process is started. */
BusConnection *connection;
+ BusInputContext *context = NULL;
if (ibus->panel != NULL) {
- ibus_object_destroy (IBUS_OBJECT (ibus->panel));
- /* panel should be NULL after destroy */
+ ibus_proxy_destroy ((IBusProxy *) ibus->panel);
+ /* panel should be NULL after destroy. See _panel_destroy_cb for details. */
g_assert (ibus->panel == NULL);
}
g_return_if_fail (connection != NULL);
ibus->panel = bus_panel_proxy_new (connection);
- g_object_ref_sink (ibus->panel);
g_signal_connect (ibus->panel,
"destroy",
ibus);
if (ibus->focused_context != NULL) {
- bus_panel_proxy_focus_in (ibus->panel, ibus->focused_context);
+ context = ibus->focused_context;
}
- }
- }
- else if (g_strcmp0 (name, IBUS_SERVICE_CONFIG) == 0) {
- if (g_strcmp0 (new_name, "") != 0) {
- BusConnection *connection;
-
- if (ibus->config != NULL) {
- ibus_object_destroy (IBUS_OBJECT (ibus->config));
- /* config should be NULL */
- g_assert (ibus->config == NULL);
+ else if (ibus->use_global_engine) {
+ context = ibus->fake_context;
}
- connection = bus_dbus_impl_get_connection_by_name (BUS_DEFAULT_DBUS, new_name);
- g_return_if_fail (connection != NULL);
-
- ibus->config = g_object_new (IBUS_TYPE_CONFIG,
- "name", NULL,
- "path", IBUS_PATH_CONFIG,
- "connection", connection,
- NULL);
- g_object_ref_sink (ibus->config);
+ if (context != NULL) {
+ BusEngineProxy *engine;
- g_signal_connect (ibus->config,
- "value-changed",
- G_CALLBACK (_config_value_changed_cb),
- ibus);
-
- g_signal_connect (ibus->config,
- "destroy",
- G_CALLBACK (_config_destroy_cb),
- ibus);
+ bus_panel_proxy_focus_in (ibus->panel, context);
- bus_ibus_impl_set_default_preload_engines (ibus);
- bus_ibus_impl_reload_config (ibus);
+ engine = bus_input_context_get_engine (context);
+ if (engine != NULL) {
+ IBusPropList *prop_list =
+ bus_engine_proxy_get_properties (engine);
+ bus_panel_proxy_register_properties (ibus->panel,
+ prop_list);
+ }
+ }
}
}
- factory = bus_registry_name_owner_changed (ibus->registry, name, old_name, new_name);
-
- if (factory) {
- bus_ibus_impl_add_factory (ibus, factory);
- }
+ bus_ibus_impl_component_name_owner_changed (ibus, name, old_name, new_name);
}
+/**
+ * bus_ibus_impl_init:
+ *
+ * The constructor of BusIBusImpl. Initialize all member variables of a BusIBusImpl object.
+ */
static void
bus_ibus_impl_init (BusIBusImpl *ibus)
{
NULL,
(GDestroyNotify) g_object_unref);
- ibus->engine_list = NULL;
+ ibus->fake_context = bus_input_context_new (NULL, "fake");
+ g_object_ref_sink (ibus->fake_context);
+ bus_dbus_impl_register_object (BUS_DEFAULT_DBUS,
+ (IBusService *) ibus->fake_context);
+ bus_input_context_set_capabilities (ibus->fake_context,
+ IBUS_CAP_PREEDIT_TEXT |
+ IBUS_CAP_FOCUS |
+ IBUS_CAP_SURROUNDING_TEXT);
+ g_signal_connect (ibus->fake_context,
+ "engine-changed",
+ G_CALLBACK (_context_engine_changed_cb),
+ ibus);
+ bus_input_context_focus_in (ibus->fake_context);
+
ibus->register_engine_list = NULL;
ibus->contexts = NULL;
ibus->focused_context = NULL;
ibus->panel = NULL;
- ibus->config = NULL;
-
- ibus->registry = bus_registry_new ();
-
- g_signal_connect (ibus->registry,
- "changed",
- G_CALLBACK (_registry_changed_cb),
- ibus);
-#ifdef G_THREADS_ENABLED
- extern gint g_monitor_timeout;
- if (g_monitor_timeout != 0) {
- bus_registry_start_monitor_changes (ibus->registry);
- }
-#endif
- ibus->hotkey_profile = ibus_hotkey_profile_new ();
ibus->keymap = ibus_keymap_get ("us");
- ibus->use_sys_layout = FALSE;
+ ibus->use_sys_layout = TRUE;
ibus->embed_preedit_text = TRUE;
- ibus->use_global_engine = FALSE;
- ibus->global_engine = NULL;
+ ibus->use_global_engine = TRUE;
+ ibus->global_engine_name = NULL;
+ ibus->global_previous_engine_name = NULL;
- bus_ibus_impl_reload_config (ibus);
+ /* focus the fake_context, if use_global_engine is enabled. */
+ if (ibus->use_global_engine)
+ bus_ibus_impl_set_focused_context (ibus, ibus->fake_context);
g_signal_connect (BUS_DEFAULT_DBUS,
"name-owner-changed",
G_CALLBACK (_dbus_name_owner_changed_cb),
ibus);
+
+ bus_ibus_impl_registry_init (ibus);
}
+/**
+ * bus_ibus_impl_destroy:
+ *
+ * The destructor of BusIBusImpl.
+ */
static void
bus_ibus_impl_destroy (BusIBusImpl *ibus)
{
gint status;
gboolean flag;
- bus_registry_stop_all_components (ibus->registry);
+ g_list_foreach (ibus->components, (GFunc) bus_component_stop, NULL);
pid = 0;
timeout = 0;
if (flag == FALSE) {
gpointer old;
old = signal (SIGTERM, SIG_IGN);
+ /* send TERM signal to the whole process group (i.e. engines, panel, and config daemon.) */
kill (-getpid (), SIGTERM);
signal (SIGTERM, old);
flag = TRUE;
}
}
}
- };
-
- g_list_foreach (ibus->engine_list, (GFunc) g_object_unref, NULL);
- g_list_free (ibus->engine_list);
- ibus->engine_list = NULL;
+ }
- g_list_foreach (ibus->register_engine_list, (GFunc) g_object_unref, NULL);
- g_list_free (ibus->register_engine_list);
+ g_list_free_full (ibus->register_engine_list, g_object_unref);
ibus->register_engine_list = NULL;
if (ibus->factory_dict != NULL) {
ibus->factory_dict = NULL;
}
- if (ibus->hotkey_profile != NULL) {
- g_object_unref (ibus->hotkey_profile);
- ibus->hotkey_profile = NULL;
- }
-
if (ibus->keymap != NULL) {
g_object_unref (ibus->keymap);
ibus->keymap = NULL;
}
- if (ibus->global_engine) {
- g_object_unref (ibus->global_engine);
- ibus->global_engine = NULL;
- }
-
- bus_server_quit (BUS_DEFAULT_SERVER);
- ibus_object_destroy ((IBusObject *) BUS_DEFAULT_SERVER);
- IBUS_OBJECT_CLASS(bus_ibus_impl_parent_class)->destroy (IBUS_OBJECT (ibus));
-}
-
-/* introspectable interface */
-static IBusMessage *
-_ibus_introspect (BusIBusImpl *ibus,
- IBusMessage *message,
- BusConnection *connection)
-{
- static const gchar *introspect =
- DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
- "<node>\n"
- " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
- " <method name=\"Introspect\">\n"
- " <arg name=\"data\" direction=\"out\" type=\"s\"/>\n"
- " </method>\n"
- " </interface>\n"
- " <interface name=\"org.freedesktop.IBus\">\n"
- " <method name=\"GetAddress\">\n"
- " <arg name=\"address\" direction=\"out\" type=\"s\"/>\n"
- " </method>\n"
- " <method name=\"CreateInputContext\">\n"
- " <arg name=\"name\" direction=\"in\" type=\"s\"/>\n"
- " <arg name=\"context\" direction=\"out\" type=\"o\"/>\n"
- " </method>\n"
- " <method name=\"CurrentInputContext\">\n"
- " <arg name=\"name\" direction=\"out\" type=\"s\"/>\n"
- " </method>\n"
- " <method name=\"RegisterComponent\">\n"
- " <arg name=\"components\" direction=\"in\" type=\"v\"/>\n"
- " </method>\n"
- " <method name=\"ListEngines\">\n"
- " <arg name=\"engines\" direction=\"out\" type=\"av\"/>\n"
- " </method>\n"
- " <method name=\"ListActiveEngines\">\n"
- " <arg name=\"engines\" direction=\"out\" type=\"av\"/>\n"
- " </method>\n"
- " <method name=\"Exit\">\n"
- " <arg name=\"restart\" direction=\"in\" type=\"b\"/>\n"
- " </method>\n"
- " <method name=\"Ping\">\n"
- " <arg name=\"data\" direction=\"in\" type=\"v\"/>\n"
- " <arg name=\"data\" direction=\"out\" type=\"v\"/>\n"
- " </method>\n"
- " <signal name=\"RegistryChanged\">\n"
- " </signal>\n"
- " </interface>\n"
- "</node>\n";
-
- IBusMessage *reply_message;
- reply_message = ibus_message_new_method_return (message);
- ibus_message_append_args (reply_message,
- G_TYPE_STRING, &introspect,
- G_TYPE_INVALID);
-
- return reply_message;
-}
-
-
-
-static IBusMessage *
-_ibus_get_address (BusIBusImpl *ibus,
- IBusMessage *message,
- BusConnection *connection)
-{
- const gchar *address;
- IBusMessage *reply;
+ g_free (ibus->global_engine_name);
+ ibus->global_engine_name = NULL;
- address = ibus_server_get_address (IBUS_SERVER (BUS_DEFAULT_SERVER));
+ g_free (ibus->global_previous_engine_name);
+ ibus->global_previous_engine_name = NULL;
+
+ if (ibus->fake_context) {
+ g_object_unref (ibus->fake_context);
+ ibus->fake_context = NULL;
+ }
- reply = ibus_message_new_method_return (message);
- ibus_message_append_args (reply,
- G_TYPE_STRING, &address,
- G_TYPE_INVALID);
+ bus_ibus_impl_registry_destroy (ibus);
- return reply;
+ IBUS_OBJECT_CLASS (bus_ibus_impl_parent_class)->destroy (IBUS_OBJECT (ibus));
}
-static BusEngineProxy *
-bus_ibus_impl_create_engine (IBusEngineDesc *engine_desc)
+/**
+ * _ibus_get_address:
+ *
+ * Implement the "Address" method call of the org.freedesktop.IBus interface.
+ */
+static GVariant *
+_ibus_get_address (BusIBusImpl *ibus,
+ GDBusConnection *connection,
+ GError **error)
{
- IBusComponent *comp;
- BusFactoryProxy *factory;
- BusEngineProxy *engine;
- GTimeVal t1, t2;
+ if (error) {
+ *error = NULL;
+ }
- factory = bus_factory_proxy_get_from_engine (engine_desc);
+ return g_variant_new_string (bus_server_get_address ());
+}
- if (factory == NULL) {
- /* try to execute the engine */
- comp = ibus_component_get_from_engine (engine_desc);
- g_assert (comp);
-
- if (!ibus_component_is_running (comp)) {
- ibus_component_start (comp, g_verbose);
- g_get_current_time (&t1);
- while (1) {
- if (g_main_context_pending (NULL)) {
- g_main_context_iteration (NULL, FALSE);
- factory = bus_factory_proxy_get_from_engine (engine_desc);
- if (factory != NULL) {
- break;
- }
- }
- g_get_current_time (&t2);
- if (t2.tv_sec - t1.tv_sec >= 5)
- break;
- }
- }
- else {
- factory = bus_factory_proxy_get_from_engine (engine_desc);
- }
- }
+static void
+_ibus_get_address_depre (BusIBusImpl *ibus,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation)
+{
+ GDBusConnection *connection =
+ g_dbus_method_invocation_get_connection (invocation);
+ GError *error = NULL;
+ GVariant *variant = NULL;
- if (factory == NULL) {
- return NULL;
- }
+ g_warning ("org.freedesktop.IBus.GetAddress() is deprecated!");
- g_object_ref (factory);
- engine = bus_factory_proxy_create_engine (factory, engine_desc);
- g_object_unref (factory);
+ variant = _ibus_get_address (ibus, connection, &error);
+
+ g_dbus_method_invocation_return_value (invocation,
+ g_variant_new ("(s)", g_variant_get_string (variant, NULL)));
- return engine;
+ g_variant_unref (variant);
}
static IBusEngineDesc *
-_find_engine_desc_by_name(BusIBusImpl *ibus,
- gchar *engine_name)
+_find_engine_desc_by_name (BusIBusImpl *ibus,
+ const gchar *engine_name)
{
- IBusEngineDesc *engine_desc = NULL;
+ IBusEngineDesc *desc = NULL;
GList *p;
/* find engine in registered engine list */
for (p = ibus->register_engine_list; p != NULL; p = p->next) {
- engine_desc = (IBusEngineDesc *)p->data;
- if (g_strcmp0 (engine_desc->name, engine_name) == 0)
- return engine_desc;
- }
-
- /* find engine in preload engine list */
- for (p = ibus->engine_list; p != NULL; p = p->next) {
- engine_desc = (IBusEngineDesc *)p->data;
- if (g_strcmp0 (engine_desc->name, engine_name) == 0)
- return engine_desc;
+ desc = (IBusEngineDesc *) p->data;
+ if (g_strcmp0 (ibus_engine_desc_get_name (desc), engine_name) == 0)
+ return desc;
}
return NULL;
}
-static void
+/**
+ * _context_request_engine_cb:
+ *
+ * A callback function to be called when the "request-engine" signal is sent to the context.
+ */
+static IBusEngineDesc *
_context_request_engine_cb (BusInputContext *context,
- gchar *engine_name,
+ const gchar *engine_name,
BusIBusImpl *ibus)
{
- IBusEngineDesc *engine_desc = NULL;
- BusEngineProxy *engine;
+ if (engine_name == NULL || engine_name[0] == '\0')
+ engine_name = DEFAULT_ENGINE;
- /* context should has focus before request an engine */
- g_return_if_fail (bus_input_context_has_focus (context));
+ return bus_ibus_impl_get_engine_desc (ibus, engine_name);
+}
- if (engine_name == NULL || engine_name[0] == '\0') {
- /* request default engine */
- if (ibus->register_engine_list) {
- engine_desc = (IBusEngineDesc *)ibus->register_engine_list->data;
- }
- else if (ibus->engine_list) {
- engine_desc = (IBusEngineDesc *)ibus->engine_list->data;
- }
- }
- else {
- /* request engine by name */
- engine_desc = _find_engine_desc_by_name (ibus, engine_name);
- }
+/**
+ * bus_ibus_impl_get_engine_desc:
+ *
+ * Get the IBusEngineDesc by engine_name. If the engine_name is NULL, return
+ * a default engine desc.
+ */
+static IBusEngineDesc *
+bus_ibus_impl_get_engine_desc (BusIBusImpl *ibus,
+ const gchar *engine_name)
+{
+ g_return_val_if_fail (engine_name != NULL, NULL);
+ g_return_val_if_fail (engine_name[0] != '\0', NULL);
- if (engine_desc != NULL) {
- engine = bus_ibus_impl_create_engine (engine_desc);
- if (engine != NULL) {
- bus_input_context_set_engine (context, engine);
- }
+ IBusEngineDesc *desc = _find_engine_desc_by_name (ibus, engine_name);
+ if (desc == NULL) {
+ desc = (IBusEngineDesc *) g_hash_table_lookup (ibus->engine_table,
+ engine_name);
}
+ return desc;
}
static void
-_context_request_next_engine_cb (BusInputContext *context,
- BusIBusImpl *ibus)
+bus_ibus_impl_set_context_engine_from_desc (BusIBusImpl *ibus,
+ BusInputContext *context,
+ IBusEngineDesc *desc)
{
- BusEngineProxy *engine;
- IBusEngineDesc *desc;
- IBusEngineDesc *next_desc = NULL;
- GList *p;
+ bus_input_context_set_engine_by_desc (context,
+ desc,
+ g_gdbus_timeout, /* timeout in msec. */
+ NULL, /* we do not cancel the call. */
+ NULL, /* use the default callback function. */
+ NULL);
+}
- engine = bus_input_context_get_engine (context);
- if (engine == NULL) {
- _context_request_engine_cb (context, NULL, ibus);
+/**
+ * bus_ibus_impl_set_focused_context:
+ *
+ * Set the current focused context.
+ */
+static void
+bus_ibus_impl_set_focused_context (BusIBusImpl *ibus,
+ BusInputContext *context)
+{
+ g_assert (BUS_IS_IBUS_IMPL (ibus));
+ g_assert (context == NULL || BUS_IS_INPUT_CONTEXT (context));
+ g_assert (context == NULL || bus_input_context_get_capabilities (context) & IBUS_CAP_FOCUS);
+
+ /* Do noting if it is focused context. */
+ if (ibus->focused_context == context) {
return;
}
- desc = bus_engine_proxy_get_desc (engine);
+ BusEngineProxy *engine = NULL;
- p = g_list_find (ibus->register_engine_list, desc);
- if (p != NULL) {
- p = p->next;
- }
- if (p == NULL) {
- p = g_list_find (ibus->engine_list, desc);
- if (p != NULL) {
- p = p->next;
+ if (ibus->focused_context) {
+ if (ibus->use_global_engine) {
+ /* dettach engine from the focused context */
+ engine = bus_input_context_get_engine (ibus->focused_context);
+ if (engine) {
+ g_object_ref (engine);
+ bus_input_context_set_engine (ibus->focused_context, NULL);
+ }
}
- }
- if (p != NULL) {
- next_desc = (IBusEngineDesc*) p->data;
+ if (ibus->panel != NULL)
+ bus_panel_proxy_focus_out (ibus->panel, ibus->focused_context);
+
+ g_object_unref (ibus->focused_context);
+ ibus->focused_context = NULL;
}
- else {
- if (ibus->register_engine_list) {
- next_desc = (IBusEngineDesc *)ibus->register_engine_list->data;
- }
- else if (ibus->engine_list) {
- next_desc = (IBusEngineDesc *)ibus->engine_list->data;
- }
+
+ if (context == NULL && ibus->use_global_engine) {
+ context = ibus->fake_context;
}
- if (next_desc != NULL) {
- engine = bus_ibus_impl_create_engine (next_desc);
+ if (context) {
+ ibus->focused_context = (BusInputContext *) g_object_ref (context);
+ /* attach engine to the focused context */
if (engine != NULL) {
bus_input_context_set_engine (context, engine);
+ bus_input_context_enable (context);
}
+
+ if (ibus->panel != NULL)
+ bus_panel_proxy_focus_in (ibus->panel, context);
}
+
+ if (engine != NULL)
+ g_object_unref (engine);
}
static void
-_context_request_prev_engine_cb (BusInputContext *context,
- BusIBusImpl *ibus)
+bus_ibus_impl_set_global_engine (BusIBusImpl *ibus,
+ BusEngineProxy *engine)
{
+ if (!ibus->use_global_engine)
+ return;
+ if (ibus->focused_context) {
+ bus_input_context_set_engine (ibus->focused_context, engine);
+ } else if (ibus->fake_context) {
+ bus_input_context_set_engine (ibus->fake_context, engine);
+ }
}
static void
-_global_engine_destroy_cb (BusEngineProxy *engine,
- BusIBusImpl *ibus)
+bus_ibus_impl_set_global_engine_by_name (BusIBusImpl *ibus,
+ const gchar *name)
{
- if (ibus->global_engine != engine) {
+ if (!ibus->use_global_engine)
+ return;
+
+ BusInputContext *context =
+ ibus->focused_context != NULL ? ibus->focused_context : ibus->fake_context;
+
+ if (context == NULL) {
+ return;
+ }
+
+ if (g_strcmp0 (name, ibus->global_engine_name) == 0) {
+ /* If the user requested the same global engine, then we just enable the
+ * original one. */
+ bus_input_context_enable (context);
return;
}
- g_signal_handlers_disconnect_by_func (ibus->global_engine,
- G_CALLBACK (_global_engine_destroy_cb), ibus);
- g_object_unref (ibus->global_engine);
- ibus->global_engine = NULL;
+ /* If there is a focused input context, then we just change the engine of
+ * the focused context, which will then change the global engine
+ * automatically. Otherwise, we need to change the global engine directly.
+ */
+ IBusEngineDesc *desc = NULL;
+ desc = bus_ibus_impl_get_engine_desc (ibus, name);
+ if (desc != NULL) {
+ bus_ibus_impl_set_context_engine_from_desc (ibus,
+ context,
+ desc);
+ }
}
+/* When preload_engines and register_engiens are changed, this function
+ * will check the global engine. If necessay, it will change the global engine.
+ */
static void
-bus_ibus_impl_set_global_engine (BusIBusImpl *ibus,
- BusEngineProxy *engine)
+bus_ibus_impl_check_global_engine (BusIBusImpl *ibus)
{
- g_assert (ibus->use_global_engine == TRUE);
+ GList *engine_list = NULL;
+
+ /* do nothing */
+ if (!ibus->use_global_engine)
+ return;
- if (ibus->global_engine == engine) {
+ /* The current global engine is not removed, so do nothing. */
+ if (ibus->global_engine_name != NULL &&
+ _find_engine_desc_by_name (ibus, ibus->global_engine_name)) {
return;
}
- if (ibus->global_engine) {
- ibus_object_destroy ((IBusObject *)ibus->global_engine);
- /* global_engine should be NULL */
- g_assert (ibus->global_engine == NULL);
+ /* If the previous engine is available, then just switch to it. */
+ if (ibus->global_previous_engine_name != NULL &&
+ _find_engine_desc_by_name (ibus, ibus->global_previous_engine_name)) {
+ bus_ibus_impl_set_global_engine_by_name (
+ ibus, ibus->global_previous_engine_name);
+ return;
}
- if (engine != NULL && !IBUS_OBJECT_DESTROYED (engine)) {
- g_object_ref (engine);
- ibus->global_engine = engine;
- g_signal_connect (ibus->global_engine, "destroy",
- G_CALLBACK (_global_engine_destroy_cb), ibus);
+ /* Just switch to the fist engine in the list. */
+ engine_list = ibus->register_engine_list;
+
+ if (engine_list) {
+ IBusEngineDesc *engine_desc = (IBusEngineDesc *)engine_list->data;
+ bus_ibus_impl_set_global_engine_by_name (ibus,
+ ibus_engine_desc_get_name (engine_desc));
+ return;
}
+
+ /* No engine available? Just disable global engine. */
+ bus_ibus_impl_set_global_engine (ibus, NULL);
}
+/**
+ * _context_engine_changed_cb:
+ *
+ * A callback function to be called when the "engine-changed" signal is sent to the context.
+ * Update global engine as well if necessary.
+ */
static void
_context_engine_changed_cb (BusInputContext *context,
BusIBusImpl *ibus)
{
- BusEngineProxy *engine;
-
- if (context != ibus->focused_context ||
- ibus->use_global_engine != TRUE) {
+ if (!ibus->use_global_engine)
return;
- }
- engine = bus_input_context_get_engine (context);
- if (engine != NULL) {
- /* only set global engine if engine is not NULL */
- bus_ibus_impl_set_global_engine (ibus, engine);
+ if ((context == ibus->focused_context) ||
+ (ibus->focused_context == NULL && context == ibus->fake_context)) {
+ BusEngineProxy *engine = bus_input_context_get_engine (context);
+ if (engine != NULL) {
+ /* only set global engine if engine is not NULL */
+ const gchar *name = ibus_engine_desc_get_name (bus_engine_proxy_get_desc (engine));
+ if (g_strcmp0 (name, ibus->global_engine_name) == 0)
+ return;
+ g_free (ibus->global_previous_engine_name);
+ ibus->global_previous_engine_name = ibus->global_engine_name;
+ ibus->global_engine_name = g_strdup (name);
+ bus_ibus_impl_global_engine_changed (ibus);
+ }
}
}
+/**
+ * _context_focus_in_cb:
+ *
+ * A callback function to be called when the "focus-in" signal is sent to the context.
+ * If necessary, enables the global engine on the context and update ibus->focused_context.
+ */
static void
-_context_focus_out_cb (BusInputContext *context,
- BusIBusImpl *ibus)
+_context_focus_in_cb (BusInputContext *context,
+ BusIBusImpl *ibus)
{
g_assert (BUS_IS_IBUS_IMPL (ibus));
g_assert (BUS_IS_INPUT_CONTEXT (context));
- /* Do noting if context does not support focus.
- * Actually, the context should emit focus signals, if it does not support focus */
+ /* Do nothing if context does not support focus.
+ * The global engine shoule be detached from the focused context. */
if ((bus_input_context_get_capabilities (context) & IBUS_CAP_FOCUS) == 0) {
return;
}
- /* Do noting if it is not focused context. */
- if (ibus->focused_context != context) {
- return;
- }
-
- ibus->focused_context = NULL;
-
- if (ibus->panel != NULL) {
- bus_panel_proxy_focus_out (ibus->panel, context);
- }
-
- /* If the use_global_engine option is enabled,
- * the global engine shoule be detached from the focused context. */
- if (ibus->use_global_engine) {
- bus_input_context_set_engine (context, NULL);
- }
-
- g_object_unref (context);
+ bus_ibus_impl_set_focused_context (ibus, context);
}
+/**
+ * _context_focus_out_cb:
+ *
+ * A callback function to be called when the "focus-out" signal is sent to the context.
+ */
static void
-_context_focus_in_cb (BusInputContext *context,
- BusIBusImpl *ibus)
+_context_focus_out_cb (BusInputContext *context,
+ BusIBusImpl *ibus)
{
g_assert (BUS_IS_IBUS_IMPL (ibus));
g_assert (BUS_IS_INPUT_CONTEXT (context));
- /* Do nothing if context does not support focus.
- * The global engine shoule be detached from the focused context. */
+ /* Do noting if context does not support focus.
+ * Actually, the context should emit focus signals, if it does not support focus */
if ((bus_input_context_get_capabilities (context) & IBUS_CAP_FOCUS) == 0) {
return;
}
- /* Do nothing if it is focused context already. */
- if (ibus->focused_context == context) {
+ /* Do noting if it is not focused context. */
+ if (ibus->focused_context != context) {
return;
}
- if (ibus->focused_context) {
- /* focus out context */
- bus_input_context_focus_out (ibus->focused_context);
- g_assert (ibus->focused_context == NULL);
- }
-
- /* If the use_global_engine option is enabled, then we need:
- * - Switch the context to use the global engine or save the context's
- * existing engine as global engine.
- * - Set the context's enabled state according to the saved state.
- * Note: we get this signal only if the context supports IBUS_CAP_FOCUS. */
- if (ibus->use_global_engine) {
- bus_input_context_set_engine (context, ibus->global_engine);
- if (ibus->global_engine &&
- bus_engine_proxy_is_enabled (ibus->global_engine)) {
- bus_input_context_enable (context);
- }
- }
-
- if (ibus->panel != NULL) {
- bus_panel_proxy_focus_in (ibus->panel, context);
- }
-
- g_object_ref (context);
- ibus->focused_context = context;
+ bus_ibus_impl_set_focused_context (ibus, NULL);
}
+/**
+ * _context_destroy_cb:
+ *
+ * A callback function to be called when the "destroy" signal is sent to the context.
+ */
static void
_context_destroy_cb (BusInputContext *context,
BusIBusImpl *ibus)
g_assert (BUS_IS_INPUT_CONTEXT (context));
if (context == ibus->focused_context) {
- /* focus out context */
- bus_input_context_focus_out (ibus->focused_context);
- g_assert (ibus->focused_context == NULL);
+ bus_ibus_impl_set_focused_context (ibus, NULL);
}
ibus->contexts = g_list_remove (ibus->contexts, context);
g_object_unref (context);
}
-#if 0
-static void
-_context_enabled_cb (BusInputContext *context,
- BusIBusImpl *ibus)
-{
-}
-
-static void
-_context_disabled_cb (BusInputContext *context,
- BusIBusImpl *ibus)
-{
-}
-#endif
-
-static IBusMessage *
-_ibus_create_input_context (BusIBusImpl *ibus,
- IBusMessage *message,
- BusConnection *connection)
+/**
+ * bus_ibus_impl_create_input_context:
+ * @client: A name of a client. e.g. "gtk-im"
+ * @returns: A BusInputContext object.
+ *
+ * Create a new BusInputContext object for the client.
+ */
+static BusInputContext *
+bus_ibus_impl_create_input_context (BusIBusImpl *ibus,
+ BusConnection *connection,
+ const gchar *client)
{
- g_assert (BUS_IS_IBUS_IMPL (ibus));
- g_assert (message != NULL);
- g_assert (BUS_IS_CONNECTION (connection));
-
- gint i;
- gchar *client;
- IBusError *error;
- IBusMessage *reply;
- BusInputContext *context;
- const gchar *path;
-
- if (!ibus_message_get_args (message,
- &error,
- G_TYPE_STRING, &client,
- G_TYPE_INVALID)) {
- reply = ibus_message_new_error (message,
- DBUS_ERROR_INVALID_ARGS,
- "Argument 1 of CreateInputContext should be an string");
- ibus_error_free (error);
- return reply;
- }
-
- context = bus_input_context_new (connection, client);
+ BusInputContext *context = bus_input_context_new (connection, client);
g_object_ref_sink (context);
ibus->contexts = g_list_append (ibus->contexts, context);
+ /* Installs glib signal handlers so that the ibus object could be notified when e.g. an IBus.InputContext D-Bus method is called. */
static const struct {
gchar *name;
GCallback callback;
} signals [] = {
- { "request-engine", G_CALLBACK (_context_request_engine_cb) },
- { "request-next-engine", G_CALLBACK (_context_request_next_engine_cb) },
- { "request-prev-engine", G_CALLBACK (_context_request_prev_engine_cb) },
+ { "request-engine", G_CALLBACK (_context_request_engine_cb) },
{ "engine-changed", G_CALLBACK (_context_engine_changed_cb) },
{ "focus-in", G_CALLBACK (_context_focus_in_cb) },
{ "focus-out", G_CALLBACK (_context_focus_out_cb) },
{ "destroy", G_CALLBACK (_context_destroy_cb) },
- #if 0
- { "enabled", G_CALLBACK (_context_enabled_cb) },
- { "disabled", G_CALLBACK (_context_disabled_cb) },
- #endif
};
+ gint i;
for (i = 0; i < G_N_ELEMENTS (signals); i++) {
g_signal_connect (context,
signals[i].name,
ibus);
}
- path = ibus_service_get_path ((IBusService *) context);
- reply = ibus_message_new_method_return (message);
- ibus_message_append_args (reply,
- IBUS_TYPE_OBJECT_PATH, &path,
- G_TYPE_INVALID);
+ bus_input_context_enable (context);
+ /* register the context object so that the object could handle IBus.InputContext method calls. */
bus_dbus_impl_register_object (BUS_DEFAULT_DBUS,
- (IBusService *)context);
- return reply;
+ (IBusService *) context);
+ g_object_ref (context);
+ return context;
}
-static IBusMessage *
-_ibus_current_input_context (BusIBusImpl *ibus,
- IBusMessage *message,
- BusConnection *connection)
+/**
+ * _ibus_create_input_context:
+ *
+ * Implement the "CreateInputContext" method call of the org.freedesktop.IBus interface.
+ */
+static void
+_ibus_create_input_context (BusIBusImpl *ibus,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation)
{
- g_assert (BUS_IS_IBUS_IMPL (ibus));
- g_assert (message != NULL);
- g_assert (BUS_IS_CONNECTION (connection));
+ const gchar *client_name = NULL; // e.g. "gtk-im"
+ g_variant_get (parameters, "(&s)", &client_name);
+
+ BusConnection *connection =
+ bus_connection_lookup (g_dbus_method_invocation_get_connection (invocation));
+ BusInputContext *context =
+ bus_ibus_impl_create_input_context (ibus,
+ connection,
+ client_name);
+ if (context) {
+ const gchar *path = ibus_service_get_object_path ((IBusService *) context);
+ /* the format-string 'o' is for a D-Bus object path. */
+ g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", path));
+ g_object_unref (context);
+ }
+ else {
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "Create input context failed!");
+ }
+}
- IBusMessage *reply;
- const gchar *path;
+/**
+ * _ibus_get_current_input_context:
+ *
+ * Implement the "CurrentInputContext" method call of the
+ * org.freedesktop.IBus interface.
+ */
+static GVariant *
+_ibus_get_current_input_context (BusIBusImpl *ibus,
+ GDBusConnection *connection,
+ GError **error)
+{
+ if (error) {
+ *error = NULL;
+ }
if (!ibus->focused_context)
{
- reply = ibus_message_new_error (message,
- DBUS_ERROR_FAILED,
- "No input context focused");
- return reply;
+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+ "No focused input context");
+ return NULL;
}
+ else {
+ const gchar *path = ibus_service_get_object_path (
+ (IBusService *) ibus->focused_context);
+ /* the format-string 'o' is for a D-Bus object path. */
+ return g_variant_new_object_path (path);
+ }
+}
- reply = ibus_message_new_method_return (message);
- path = ibus_service_get_path((IBusService *)ibus->focused_context);
- ibus_message_append_args (reply,
- G_TYPE_STRING, &path,
- G_TYPE_INVALID);
-
- return reply;
+static void
+_ibus_current_input_context_depre (BusIBusImpl *ibus,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation)
+{
+ GDBusConnection *connection =
+ g_dbus_method_invocation_get_connection (invocation);
+ GVariant *variant = NULL;
+ GError *error = NULL;
+
+ g_warning ("org.freedesktop.IBus.CurrentInputContext() is deprecated!");
+
+ variant = _ibus_get_current_input_context (ibus, connection, &error);
+
+ if (variant == NULL) {
+ g_dbus_method_invocation_return_error (
+ invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+ error->message);
+ g_error_free (error);
+ } else {
+ const gchar *path = g_variant_get_string (variant, NULL);
+ g_dbus_method_invocation_return_value (invocation,
+ g_variant_new ("(o)", path));
+ g_variant_unref (variant);
+ }
}
static void
-_factory_destroy_cb (BusFactoryProxy *factory,
- BusIBusImpl *ibus)
+_component_destroy_cb (BusComponent *component,
+ BusIBusImpl *ibus)
{
g_assert (BUS_IS_IBUS_IMPL (ibus));
- g_assert (BUS_IS_FACTORY_PROXY (factory));
+ g_assert (BUS_IS_COMPONENT (component));
- IBusComponent *component;
- GList *engines, *p;
+ ibus->registered_components = g_list_remove (ibus->registered_components, component);
- ibus->factory_list = g_list_remove (ibus->factory_list, factory);
+ /* remove engines from engine_list */
+ GList *engines = bus_component_get_engines (component);
+ GList *p;
+ for (p = engines; p != NULL; p = p->next) {
+ if (g_list_find (ibus->register_engine_list, p->data)) {
+ ibus->register_engine_list = g_list_remove (ibus->register_engine_list, p->data);
+ g_object_unref (p->data);
+ }
+ }
+ g_list_free (engines);
- component = bus_factory_proxy_get_component (factory);
+ g_object_unref (component);
- if (component != NULL) {
- p = engines = ibus_component_get_engines (component);
- for (; p != NULL; p = p->next) {
- if (g_list_find (ibus->register_engine_list, p->data)) {
- ibus->register_engine_list = g_list_remove (ibus->register_engine_list, p->data);
- g_object_unref (p->data);
- }
- }
- g_list_free (engines);
+ bus_ibus_impl_check_global_engine (ibus);
+}
+
+/**
+ * _ibus_register_component:
+ *
+ * Implement the "RegisterComponent" method call of the
+ * org.freedesktop.IBus interface.
+ */
+static void
+_ibus_register_component (BusIBusImpl *ibus,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation)
+{
+ GVariant *variant = g_variant_get_child_value (parameters, 0);
+ IBusComponent *component =
+ (IBusComponent *) ibus_serializable_deserialize (variant);
+
+ if (!IBUS_IS_COMPONENT (component)) {
+ if (component)
+ g_object_unref (component);
+ g_dbus_method_invocation_return_error (
+ invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+ "The first argument should be an IBusComponent.");
+ return;
}
+ BusConnection *connection = bus_connection_lookup (
+ g_dbus_method_invocation_get_connection (invocation));
+ BusFactoryProxy *factory = bus_factory_proxy_new (connection);
+
+ if (factory == NULL) {
+ g_object_unref (component);
+ g_dbus_method_invocation_return_error (
+ invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+ "Create factory failed.");
+ return;
+ }
+
+ g_object_ref_sink (component);
+
+ BusComponent *buscomp = bus_component_new (component, factory);
+ bus_component_set_destroy_with_factory (buscomp, TRUE);
+ g_object_unref (component);
g_object_unref (factory);
+
+ ibus->registered_components = g_list_append (ibus->registered_components,
+ g_object_ref_sink (buscomp));
+ GList *engines = bus_component_get_engines (buscomp);
+ g_list_foreach (engines, (GFunc) g_object_ref, NULL);
+ ibus->register_engine_list = g_list_concat (ibus->register_engine_list,
+ engines);
+
+ g_signal_connect (buscomp,
+ "destroy",
+ G_CALLBACK (_component_destroy_cb),
+ ibus);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
}
-static void
-bus_ibus_impl_add_factory (BusIBusImpl *ibus,
- BusFactoryProxy *factory)
+/**
+ * _ibus_get_engines:
+ *
+ * Implement the "Engines" method call of the org.freedesktop.IBus interface.
+ */
+static GVariant *
+_ibus_get_engines (BusIBusImpl *ibus,
+ GDBusConnection *connection,
+ GError **error)
{
- g_assert (BUS_IS_IBUS_IMPL (ibus));
- g_assert (BUS_IS_FACTORY_PROXY (factory));
+ GVariantBuilder builder;
+ GList *engines = NULL;
+ GList *p;
+
+ if (error) {
+ *error = NULL;
+ }
- g_object_ref_sink (factory);
- ibus->factory_list = g_list_append (ibus->factory_list, factory);
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
- g_signal_connect (factory, "destroy", G_CALLBACK (_factory_destroy_cb), ibus);
+ engines = g_hash_table_get_values (ibus->engine_table);
+
+ for (p = engines; p != NULL; p = p->next) {
+ g_variant_builder_add (
+ &builder, "v",
+ ibus_serializable_serialize ((IBusSerializable *) p->data));
+ }
+
+ g_list_free (engines);
+
+ return g_variant_builder_end (&builder);
}
+static void
+_ibus_list_engines_depre (BusIBusImpl *ibus,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation)
+{
+ GDBusConnection *connection =
+ g_dbus_method_invocation_get_connection (invocation);
+ GError *error = NULL;
+ GVariant *variant = NULL;
+
+ g_warning ("org.freedesktop.IBus.ListEngines() is deprecated!");
-static IBusMessage *
-_ibus_register_component (BusIBusImpl *ibus,
- IBusMessage *message,
- BusConnection *connection)
+ variant = _ibus_get_engines (ibus, connection, &error);
+
+ g_dbus_method_invocation_return_value (invocation,
+ g_variant_new ("(@av)", variant));
+}
+
+/**
+ * _ibus_get_engines_by_names:
+ *
+ * Implement the "GetEnginesByNames" method call of the org.freedesktop.IBus interface.
+ */
+static void
+_ibus_get_engines_by_names (BusIBusImpl *ibus,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation)
{
- IBusMessage *reply;
- IBusError *error;
- gboolean retval;
- GList *engines;
- IBusComponent *component;
- BusFactoryProxy *factory;
+ const gchar **names = NULL;
+ g_variant_get (parameters, "(^a&s)", &names);
+
+ g_assert (names != NULL);
+
+ gint i = 0;
+ GVariantBuilder builder;
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
+ while (names[i] != NULL) {
+ IBusEngineDesc *desc = (IBusEngineDesc *) g_hash_table_lookup (
+ ibus->engine_table, names[i++]);
+ if (desc == NULL)
+ continue;
+ g_variant_builder_add (
+ &builder,
+ "v",
+ ibus_serializable_serialize ((IBusSerializable *)desc));
+ }
+ g_dbus_method_invocation_return_value (invocation, g_variant_new ("(av)", &builder));
+}
- retval = ibus_message_get_args (message, &error,
- IBUS_TYPE_COMPONENT, &component,
- G_TYPE_INVALID);
+/**
+ * _ibus_get_active_engines:
+ *
+ * Implement the "ActiveEngines" method call of the
+ * org.freedesktop.IBus interface.
+ */
+static GVariant *
+_ibus_get_active_engines (BusIBusImpl *ibus,
+ GDBusConnection *connection,
+ GError **error)
+{
+ GVariantBuilder builder;
+ GList *p;
- if (!retval) {
- reply = ibus_message_new_error_printf (message,
- DBUS_ERROR_INVALID_ARGS,
- "1st Argument must be IBusComponent: %s",
- error->message);
- ibus_error_free (error);
- return reply;
+ if (error) {
+ *error = NULL;
}
- g_object_ref_sink (component);
- factory = bus_factory_proxy_new (component, connection);
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
- if (factory == NULL) {
- reply = ibus_message_new_error (message,
- DBUS_ERROR_FAILED,
- "Can not create factory");
- return reply;
+ for (p = ibus->register_engine_list; p != NULL; p = p->next) {
+ g_variant_builder_add (
+ &builder, "v",
+ ibus_serializable_serialize ((IBusSerializable *) p->data));
}
- bus_ibus_impl_add_factory (ibus, factory);
+ return g_variant_builder_end (&builder);
+}
- engines = ibus_component_get_engines (component);
+static void
+_ibus_list_active_engines_depre (BusIBusImpl *ibus,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation)
+{
+ GDBusConnection *connection =
+ g_dbus_method_invocation_get_connection (invocation);
+ GError *error = NULL;
+ GVariant *variant = NULL;
- g_list_foreach (engines, (GFunc) g_object_ref, NULL);
- ibus->register_engine_list = g_list_concat (ibus->register_engine_list, engines);
- g_object_unref (component);
+ g_warning ("org.freedesktop.IBus.ListActiveEngines() is deprecated!");
+
+ variant = _ibus_get_active_engines (ibus, connection, &error);
- reply = ibus_message_new_method_return (message);
- return reply;
+ g_dbus_method_invocation_return_value (invocation,
+ g_variant_new ("(@av)", variant));
}
-static IBusMessage *
-_ibus_list_engines (BusIBusImpl *ibus,
- IBusMessage *message,
- BusConnection *connection)
+/**
+ * _ibus_exit:
+ *
+ * Implement the "Exit" method call of the org.freedesktop.IBus interface.
+ */
+static void
+_ibus_exit (BusIBusImpl *ibus,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation)
{
- IBusMessage *reply;
- IBusMessageIter iter, sub_iter;
- GList *engines, *p;
+ gboolean restart = FALSE;
+ g_variant_get (parameters, "(b)", &restart);
- reply = ibus_message_new_method_return (message);
+ g_dbus_method_invocation_return_value (invocation, NULL);
- ibus_message_iter_init_append (reply, &iter);
- ibus_message_iter_open_container (&iter, IBUS_TYPE_ARRAY, "v", &sub_iter);
+ /* Make sure the reply has been sent out before exit */
+ g_dbus_connection_flush_sync (
+ g_dbus_method_invocation_get_connection (invocation),
+ NULL,
+ NULL);
- engines = bus_registry_get_engines (ibus->registry);
- for (p = engines; p != NULL; p = p->next) {
- ibus_message_iter_append (&sub_iter, IBUS_TYPE_ENGINE_DESC, &(p->data));
+ bus_server_quit (restart);
+}
+
+/**
+ * _ibus_ping:
+ *
+ * Implement the "Ping" method call of the org.freedesktop.IBus interface.
+ */
+static void
+_ibus_ping (BusIBusImpl *ibus,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation)
+{
+ g_dbus_method_invocation_return_value (invocation, parameters);
+}
+
+/**
+ * _ibus_get_use_sys_layout:
+ *
+ * Implement the "UseSysLayout" method call of the
+ * org.freedesktop.IBus interface.
+ */
+static GVariant *
+_ibus_get_use_sys_layout (BusIBusImpl *ibus,
+ GDBusConnection *connection,
+ GError **error)
+{
+ if (error) {
+ *error = NULL;
}
- g_list_free (engines);
- ibus_message_iter_close_container (&iter, &sub_iter);
- return reply;
+ return g_variant_new_boolean (ibus->use_sys_layout);
}
-static IBusMessage *
-_ibus_list_active_engines (BusIBusImpl *ibus,
- IBusMessage *message,
- BusConnection *connection)
+static void
+_ibus_get_use_sys_layout_depre (BusIBusImpl *ibus,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation)
{
- IBusMessage *reply;
- IBusMessageIter iter, sub_iter;
- GList *p;
+ GDBusConnection *connection =
+ g_dbus_method_invocation_get_connection (invocation);
+ GError *error = NULL;
+ GVariant *variant = NULL;
- reply = ibus_message_new_method_return (message);
+ g_warning ("org.freedesktop.IBus.GetUseSysLayout() is deprecated!");
- ibus_message_iter_init_append (reply, &iter);
- ibus_message_iter_open_container (&iter, IBUS_TYPE_ARRAY, "v", &sub_iter);
+ variant = _ibus_get_use_sys_layout (ibus, connection, &error);
- for (p = ibus->engine_list; p != NULL; p = p->next) {
- ibus_message_iter_append (&sub_iter, IBUS_TYPE_ENGINE_DESC, &(p->data));
- }
+ g_dbus_method_invocation_return_value (invocation,
+ g_variant_new ("(b)", g_variant_get_boolean (variant)));
- for (p = ibus->register_engine_list; p != NULL; p = p->next) {
- ibus_message_iter_append (&sub_iter, IBUS_TYPE_ENGINE_DESC, &(p->data));
+ g_variant_unref (variant);
+}
+
+/**
+ * _ibus_get_use_global_engine:
+ *
+ * Implement the "UseGlobalEngine" method call of the
+ * org.freedesktop.IBus interface.
+ */
+static GVariant *
+_ibus_get_use_global_engine (BusIBusImpl *ibus,
+ GDBusConnection *connection,
+ GError **error)
+{
+ if (error) {
+ *error = NULL;
}
- ibus_message_iter_close_container (&iter, &sub_iter);
- return reply;
+ return g_variant_new_boolean (ibus->use_global_engine);
}
+static void
+_ibus_get_use_global_engine_depre (BusIBusImpl *ibus,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation)
+{
+ GDBusConnection *connection =
+ g_dbus_method_invocation_get_connection (invocation);
+ GError *error = NULL;
+ GVariant *variant = NULL;
-static IBusMessage *
-_ibus_exit (BusIBusImpl *ibus,
- IBusMessage *message,
- BusConnection *connection)
+ g_warning ("org.freedesktop.IBus.GetUseGlobalEngine() is deprecated!");
+
+ variant = _ibus_get_use_global_engine (ibus, connection, &error);
+
+ g_dbus_method_invocation_return_value (invocation,
+ g_variant_new ("(b)", g_variant_get_boolean (variant)));
+
+ g_variant_unref (variant);
+}
+
+/**
+ * _ibus_get_global_engine:
+ *
+ * Implement the "GlobalEngine" method call of the
+ * org.freedesktop.IBus interface.
+ */
+static GVariant *
+_ibus_get_global_engine (BusIBusImpl *ibus,
+ GDBusConnection *connection,
+ GError **error)
{
- IBusMessage *reply;
- IBusError *error;
- gboolean restart;
+ IBusEngineDesc *desc = NULL;
- if (!ibus_message_get_args (message,
- &error,
- G_TYPE_BOOLEAN, &restart,
- G_TYPE_INVALID)) {
- reply = ibus_message_new_error (message,
- DBUS_ERROR_INVALID_ARGS,
- "Argument 1 of Exit should be an boolean");
- ibus_error_free (error);
- return reply;
+ if (error) {
+ *error = NULL;
}
- reply = ibus_message_new_method_return (message);
- ibus_connection_send ((IBusConnection *) connection, reply);
- ibus_connection_flush ((IBusConnection *) connection);
- ibus_message_unref (reply);
+ do {
+ if (!ibus->use_global_engine)
+ break;
+ BusInputContext *context = ibus->focused_context;
+ if (context == NULL)
+ context = ibus->fake_context;
+
+ desc = bus_input_context_get_engine_desc (context);
+
+ if (desc == NULL)
+ break;
- ibus_object_destroy ((IBusObject *) BUS_DEFAULT_SERVER);
+ GVariant *variant = ibus_serializable_serialize (
+ (IBusSerializable *) desc);
+ // Set type "v" for introspection_xml.
+ return g_variant_new_variant (variant);
+ } while (0);
+
+ g_set_error (error,
+ G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+ "No global engine.");
+ return NULL;
+}
- if (!restart) {
- exit (0);
+static void
+_ibus_get_global_engine_depre (BusIBusImpl *ibus,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation)
+{
+ GDBusConnection *connection =
+ g_dbus_method_invocation_get_connection (invocation);
+ GError *error = NULL;
+ GVariant *variant = NULL;
+
+ g_warning ("org.freedesktop.IBus.GetGlobalEngine() is deprecated!");
+
+ variant = _ibus_get_global_engine (ibus, connection, &error);
+
+ if (variant == NULL) {
+ g_dbus_method_invocation_return_error (
+ invocation,
+ G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+ error->message);
+ g_error_free (error);
+ } else {
+ GVariant *retval = g_variant_get_variant (variant);
+ g_dbus_method_invocation_return_value (invocation,
+ g_variant_new ("(v)", retval));
+ g_variant_unref (variant);
+ }
+}
+
+struct _SetGlobalEngineData {
+ BusIBusImpl *ibus;
+ GDBusMethodInvocation *invocation;
+};
+typedef struct _SetGlobalEngineData SetGlobalEngineData;
+
+static void
+_ibus_set_global_engine_ready_cb (BusInputContext *context,
+ GAsyncResult *res,
+ SetGlobalEngineData *data)
+{
+ BusIBusImpl *ibus = data->ibus;
+
+ GError *error = NULL;
+ if (!bus_input_context_set_engine_by_desc_finish (context, res, &error)) {
+ g_error_free (error);
+ g_dbus_method_invocation_return_error (data->invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "Set global engine failed.");
}
else {
- extern gchar **g_argv;
- gchar *exe;
- gint fd;
+ g_dbus_method_invocation_return_value (data->invocation, NULL);
+
+ if (ibus->use_global_engine && (context != ibus->focused_context)) {
+ /* context and ibus->focused_context don't match. This means that
+ * the focus is moved before _ibus_set_global_engine() asynchronous
+ * call finishes. In this case, the engine for the context currently
+ * being focused hasn't been updated. Update the engine here so that
+ * subsequent _ibus_get_global_engine() call could return a
+ * consistent engine name. */
+ BusEngineProxy *engine = bus_input_context_get_engine (context);
+ if (engine && ibus->focused_context != NULL) {
+ g_object_ref (engine);
+ bus_input_context_set_engine (context, NULL);
+ bus_input_context_set_engine (ibus->focused_context, engine);
+ g_object_unref (engine);
+ }
+ }
+ }
+
+ g_object_unref (ibus);
+ g_slice_free (SetGlobalEngineData, data);
+}
+
+/**
+ * _ibus_set_global_engine:
+ *
+ * Implement the "SetGlobalEngine" method call of the
+ * org.freedesktop.IBus interface.
+ */
+static void
+_ibus_set_global_engine (BusIBusImpl *ibus,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation)
+{
+ if (!ibus->use_global_engine) {
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+ "Global engine feature is disabled.");
+ return;
+ }
+
+ BusInputContext *context = ibus->focused_context;
+ if (context == NULL)
+ context = ibus->fake_context;
+
+ const gchar *engine_name = NULL;
+ g_variant_get (parameters, "(&s)", &engine_name);
+
+ IBusEngineDesc *desc = bus_ibus_impl_get_engine_desc(ibus, engine_name);
+ if (desc == NULL) {
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "Can not find engine %s.",
+ engine_name);
+ return;
+ }
+
+ SetGlobalEngineData *data = g_slice_new0 (SetGlobalEngineData);
+ data->ibus = g_object_ref (ibus);
+ data->invocation = invocation;
+ bus_input_context_set_engine_by_desc (context,
+ desc,
+ g_gdbus_timeout, /* timeout in msec. */
+ NULL, /* we do not cancel the call. */
+ (GAsyncReadyCallback) _ibus_set_global_engine_ready_cb,
+ data);
+}
+
+/**
+ * _ibus_get_global_engine_enabled:
+ *
+ * Implement the "GlobalEngineEnabled" method call of the
+ * org.freedesktop.IBus interface.
+ */
+static GVariant *
+_ibus_get_global_engine_enabled (BusIBusImpl *ibus,
+ GDBusConnection *connection,
+ GError **error)
+{
+ gboolean enabled = FALSE;
+
+ if (error) {
+ *error = NULL;
+ }
- exe = g_strdup_printf ("/proc/%d/exe", getpid ());
- exe = g_file_read_link (exe, NULL);
+ do {
+ if (!ibus->use_global_engine)
+ break;
+
+ BusInputContext *context = ibus->focused_context;
+ if (context == NULL)
+ context = ibus->fake_context;
+ if (context == NULL)
+ break;
+
+ enabled = TRUE;
+ } while (0);
- if (exe == NULL)
- exe = BINDIR"/ibus-daemon";
+ return g_variant_new_boolean (enabled);
+}
+
+static void
+_ibus_is_global_engine_enabled_depre (BusIBusImpl *ibus,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation)
+{
+ GDBusConnection *connection =
+ g_dbus_method_invocation_get_connection (invocation);
+ GError *error = NULL;
+ GVariant *variant = NULL;
- /* close all fds except stdin, stdout, stderr */
- for (fd = 3; fd <= sysconf (_SC_OPEN_MAX); fd ++) {
- close (fd);
+ g_warning ("org.freedesktop.IBus.IsGlobalEngineEnabled() is deprecated!");
+
+ variant = _ibus_get_global_engine_enabled (ibus, connection, &error);
+
+ g_dbus_method_invocation_return_value (invocation,
+ g_variant_new ("(b)", g_variant_get_boolean (variant)));
+
+ g_variant_unref (variant);
+}
+
+/**
+ * _ibus_set_preload_engines:
+ *
+ * Implement the "PreloadEngines" method call of the
+ * org.freedesktop.IBus interface.
+ */
+static gboolean
+_ibus_set_preload_engines (BusIBusImpl *ibus,
+ GDBusConnection *connection,
+ GVariant *value,
+ GError **error)
+{
+ int i, j;
+ const gchar **names = NULL;
+ IBusEngineDesc *desc = NULL;
+ BusComponent *component = NULL;
+ BusFactoryProxy *factory = NULL;
+ GPtrArray *array = g_ptr_array_new ();
+
+ if (error) {
+ *error = NULL;
+ }
+
+ g_variant_get (value, "^a&s", &names);
+
+ for (i = 0; names[i] != NULL; i++) {
+ gboolean has_component = FALSE;
+
+ desc = bus_ibus_impl_get_engine_desc(ibus, names[i]);
+
+ if (desc == NULL) {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "Can not find engine %s.",
+ names[i]);
+ g_ptr_array_free (array, FALSE);
+ return FALSE;
}
- execv (exe, g_argv);
+ component = bus_component_from_engine_desc (desc);
+ factory = bus_component_get_factory (component);
+
+ if (factory != NULL) {
+ continue;
+ }
- /* If the server binary is replaced while the server is running,
- * "readlink /proc/[pid]/exe" might return a path with " (deleted)"
- * suffix. */
- const gchar suffix[] = " (deleted)";
- if (g_str_has_suffix (exe, suffix)) {
- exe [strlen (exe) - strlen (suffix)] = '\0';
- execv (exe, g_argv);
+ for (j = 0; j < array->len; j++) {
+ if (component == (BusComponent *) g_ptr_array_index (array, j)) {
+ has_component = TRUE;
+ break;
+ }
+ }
+
+ if (!has_component) {
+ g_ptr_array_add (array, component);
}
- g_warning ("execv %s failed!", g_argv[0]);
- exit (-1);
}
- /* should not reach here */
- g_assert_not_reached ();
+ for (j = 0; j < array->len; j++) {
+ bus_component_start ((BusComponent *) g_ptr_array_index (array, j),
+ g_verbose);
+ }
- return NULL;
+ g_ptr_array_free (array, FALSE);
+
+ return TRUE;
}
-static IBusMessage *
-_ibus_ping (BusIBusImpl *ibus,
- IBusMessage *message,
- BusConnection *connection)
+/**
+ * _ibus_get_embed_preedit_text:
+ *
+ * Implement the "EmbedPreeditText" method call of
+ * the org.freedesktop.IBus interface.
+ */
+static GVariant *
+_ibus_get_embed_preedit_text (BusIBusImpl *ibus,
+ GDBusConnection *connection,
+ GError **error)
{
- IBusMessage *reply;
- IBusMessageIter src, dst;
+ if (error) {
+ *error = NULL;
+ }
- reply = ibus_message_new_method_return (message);
+ return g_variant_new_boolean (ibus->embed_preedit_text);
+}
- ibus_message_iter_init (message, &src);
- ibus_message_iter_init_append (reply, &dst);
+/**
+ * _ibus_set_embed_preedit_text:
+ *
+ * Implement the "EmbedPreeditText" method call of
+ * the org.freedesktop.IBus interface.
+ */
+static gboolean
+_ibus_set_embed_preedit_text (BusIBusImpl *ibus,
+ GDBusConnection *connection,
+ GVariant *value,
+ GError **error)
+{
+ if (error) {
+ *error = NULL;
+ }
- ibus_message_iter_copy_data (&dst, &src);
+ ibus->embed_preedit_text = g_variant_get_boolean (value);
- return reply;
+ return TRUE;
}
-static gboolean
-bus_ibus_impl_ibus_message (BusIBusImpl *ibus,
- BusConnection *connection,
- IBusMessage *message)
+/**
+ * bus_ibus_impl_service_method_call:
+ *
+ * Handle a D-Bus method call whose destination and interface name are
+ * both "org.freedesktop.IBus"
+ */
+static void
+bus_ibus_impl_service_method_call (IBusService *service,
+ GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation)
{
- g_assert (BUS_IS_IBUS_IMPL (ibus));
- g_assert (BUS_IS_CONNECTION (connection));
- g_assert (message != NULL);
+ if (g_strcmp0 (interface_name, IBUS_INTERFACE_IBUS) != 0) {
+ IBUS_SERVICE_CLASS (bus_ibus_impl_parent_class)->service_method_call (
+ service, connection, sender, object_path,
+ interface_name, method_name,
+ parameters, invocation);
+ return;
+ }
+
+ /* all methods in the xml definition above should be listed here. */
+ static const struct {
+ const gchar *method_name;
+ void (* method_callback) (BusIBusImpl *,
+ GVariant *,
+ GDBusMethodInvocation *);
+ } methods [] = {
+ /* IBus interface */
+ { "CreateInputContext", _ibus_create_input_context },
+ { "RegisterComponent", _ibus_register_component },
+ { "GetEnginesByNames", _ibus_get_engines_by_names },
+ { "Exit", _ibus_exit },
+ { "Ping", _ibus_ping },
+ { "SetGlobalEngine", _ibus_set_global_engine },
+ /* Start of deprecated methods */
+ { "GetAddress", _ibus_get_address_depre },
+ { "CurrentInputContext", _ibus_current_input_context_depre },
+ { "ListEngines", _ibus_list_engines_depre },
+ { "ListActiveEngines", _ibus_list_active_engines_depre },
+ { "GetUseSysLayout", _ibus_get_use_sys_layout_depre },
+ { "GetUseGlobalEngine", _ibus_get_use_global_engine_depre },
+ { "GetGlobalEngine", _ibus_get_global_engine_depre },
+ { "IsGlobalEngineEnabled", _ibus_is_global_engine_enabled_depre },
+ /* End of deprecated methods */
+ };
gint i;
- IBusMessage *reply_message = NULL;
+ for (i = 0; i < G_N_ELEMENTS (methods); i++) {
+ if (g_strcmp0 (methods[i].method_name, method_name) == 0) {
+ methods[i].method_callback ((BusIBusImpl *) service,
+ parameters,
+ invocation);
+ return;
+ }
+ }
+
+ g_warning ("service_method_call received an unknown method: %s",
+ method_name ? method_name : "(null)");
+}
+
+/**
+ * bus_ibus_impl_service_get_property:
+ *
+ * Handle org.freedesktop.DBus.Properties.Get
+ */
+static GVariant *
+bus_ibus_impl_service_get_property (IBusService *service,
+ GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *property_name,
+ GError **error)
+{
+ gint i;
static const struct {
- const gchar *interface;
- const gchar *name;
- IBusMessage *(* handler) (BusIBusImpl *, IBusMessage *, BusConnection *);
- } handlers[] = {
- /* Introspectable interface */
- { DBUS_INTERFACE_INTROSPECTABLE,
- "Introspect", _ibus_introspect },
- /* IBus interface */
- { IBUS_INTERFACE_IBUS, "GetAddress", _ibus_get_address },
- { IBUS_INTERFACE_IBUS, "CreateInputContext", _ibus_create_input_context },
- { IBUS_INTERFACE_IBUS, "CurrentInputContext", _ibus_current_input_context },
- { IBUS_INTERFACE_IBUS, "RegisterComponent", _ibus_register_component },
- { IBUS_INTERFACE_IBUS, "ListEngines", _ibus_list_engines },
- { IBUS_INTERFACE_IBUS, "ListActiveEngines", _ibus_list_active_engines },
- { IBUS_INTERFACE_IBUS, "Exit", _ibus_exit },
- { IBUS_INTERFACE_IBUS, "Ping", _ibus_ping },
+ const gchar *method_name;
+ GVariant * (* method_callback) (BusIBusImpl *,
+ GDBusConnection *,
+ GError **);
+ } methods [] = {
+ { "Address", _ibus_get_address },
+ { "CurrentInputContext", _ibus_get_current_input_context },
+ { "Engines", _ibus_get_engines },
+ { "ActiveEngines", _ibus_get_active_engines },
+ { "GlobalEngine", _ibus_get_global_engine },
+ { "EmbedPreeditText", _ibus_get_embed_preedit_text },
};
- ibus_message_set_sender (message, bus_connection_get_unique_name (connection));
- ibus_message_set_destination (message, DBUS_SERVICE_DBUS);
+ if (g_strcmp0 (interface_name, IBUS_INTERFACE_IBUS) != 0) {
+ return IBUS_SERVICE_CLASS (
+ bus_ibus_impl_parent_class)->service_get_property (
+ service, connection, sender, object_path,
+ interface_name, property_name,
+ error);
+ }
- if (ibus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_CALL) {
- for (i = 0; i < G_N_ELEMENTS (handlers); i++) {
- if (ibus_message_is_method_call (message,
- handlers[i].interface,
- handlers[i].name)) {
+ for (i = 0; i < G_N_ELEMENTS (methods); i++) {
+ if (g_strcmp0 (methods[i].method_name, property_name) == 0) {
+ return methods[i].method_callback ((BusIBusImpl *) service,
+ connection,
+ error);
+ }
+ }
- reply_message = handlers[i].handler (ibus, message, connection);
- if (reply_message) {
+ g_warning ("service_get_property received an unknown property: %s",
+ property_name ? property_name : "(null)");
+ return NULL;
+}
- ibus_message_set_sender (reply_message, DBUS_SERVICE_DBUS);
- ibus_message_set_destination (reply_message, bus_connection_get_unique_name (connection));
- ibus_message_set_no_reply (reply_message, TRUE);
+static void
+_emit_properties_changed (BusIBusImpl *service,
+ GDBusConnection *connection,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *property_name,
+ GVariant *value,
+ gboolean is_changed)
+{
+ GVariantBuilder *builder;
+ GVariantBuilder *invalidated_builder;
+ GError *error = NULL;
+
+ builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
+ invalidated_builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
+
+ if (is_changed) {
+ g_variant_builder_add (builder, "{sv}", property_name, value);
+ } else {
+ g_variant_builder_add (invalidated_builder, "s", property_name);
+ }
+
+ g_dbus_connection_emit_signal (connection,
+ NULL,
+ object_path,
+ "org.freedesktop.DBus.Properties",
+ "PropertiesChanged",
+ g_variant_new ("(sa{sv}as)",
+ interface_name,
+ builder,
+ invalidated_builder),
+ &error);
+
+ if (error) {
+ g_warning ("Failed to emit property %s in %s.%s: %s",
+ property_name,
+ "org.freedesktop.DBus.Properties",
+ "PropertiesChanged",
+ error->message);
+ g_error_free (error);
+ }
+}
- ibus_connection_send ((IBusConnection *) connection, reply_message);
- ibus_message_unref (reply_message);
- }
+/**
+ * bus_ibus_impl_service_set_property:
+ *
+ * Handle org.freedesktop.DBus.Properties.Set
+ */
+static gboolean
+bus_ibus_impl_service_set_property (IBusService *service,
+ GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *property_name,
+ GVariant *value,
+ GError **error)
+{
+ gint i;
- g_signal_stop_emission_by_name (ibus, "ibus-message");
- return TRUE;
- }
+ static const struct {
+ const gchar *method_name;
+ gboolean (* method_callback) (BusIBusImpl *,
+ GDBusConnection *,
+ GVariant *,
+ GError **);
+ } methods [] = {
+ { "PreloadEngines", _ibus_set_preload_engines },
+ { "EmbedPreeditText", _ibus_set_embed_preedit_text },
+ };
+
+ if (g_strcmp0 (interface_name, IBUS_INTERFACE_IBUS) != 0) {
+ return IBUS_SERVICE_CLASS (
+ bus_ibus_impl_parent_class)->service_set_property (
+ service, connection, sender, object_path,
+ interface_name, property_name,
+ value, error);
+ }
+
+ for (i = 0; i < G_N_ELEMENTS (methods); i++) {
+ if (g_strcmp0 (methods[i].method_name, property_name) == 0) {
+ gboolean retval = methods[i].method_callback (
+ (BusIBusImpl *) service,
+ connection,
+ value,
+ error);
+
+ _emit_properties_changed ((BusIBusImpl *) service,
+ connection,
+ object_path,
+ interface_name,
+ property_name,
+ value,
+ retval);
+
+ return retval;
}
}
- return IBUS_SERVICE_CLASS(bus_ibus_impl_parent_class)->ibus_message (
- (IBusService *) ibus,
- (IBusConnection *) connection,
- message);
+ g_warning ("service_set_property received an unknown property: %s",
+ property_name ? property_name : "(null)");
+ return FALSE;
+}
+
+BusIBusImpl *
+bus_ibus_impl_get_default (void)
+{
+ static BusIBusImpl *ibus = NULL;
+
+ if (ibus == NULL) {
+ ibus = (BusIBusImpl *) g_object_new (BUS_TYPE_IBUS_IMPL,
+ "object-path", IBUS_PATH_IBUS,
+ NULL);
+ }
+ return ibus;
}
BusFactoryProxy *
return factory;
}
-IBusHotkeyProfile *
-bus_ibus_impl_get_hotkey_profile (BusIBusImpl *ibus)
+IBusKeymap *
+bus_ibus_impl_get_keymap (BusIBusImpl *ibus)
{
+
g_assert (BUS_IS_IBUS_IMPL (ibus));
- return ibus->hotkey_profile;
+ return ibus->keymap;
}
-IBusKeymap *
-bus_ibus_impl_get_keymap (BusIBusImpl *ibus)
+/**
+ * bus_ibus_impl_registry_init:
+ *
+ * Initialize IBusRegistry.
+ */
+static void
+bus_ibus_impl_registry_init (BusIBusImpl *ibus)
{
+ GList *p;
+ GList *components;
+ IBusRegistry *registry = ibus_registry_new ();
+
+ ibus->registry = NULL;
+ ibus->components = NULL;
+ ibus->engine_table = g_hash_table_new (g_str_hash, g_str_equal);
+
+ if (g_strcmp0 (g_cache, "none") == 0) {
+ /* Only load registry, but not read and write cache. */
+ ibus_registry_load (registry);
+ }
+ else if (g_strcmp0 (g_cache, "refresh") == 0) {
+ /* Load registry and overwrite the cache. */
+ ibus_registry_load (registry);
+ ibus_registry_save_cache (registry, TRUE);
+ }
+ else if (g_strcmp0 (g_cache, "auto") == 0) {
+ /* Load registry from cache. If the cache does not exist or
+ * it is outdated, then generate it.
+ */
+ if (ibus_registry_load_cache (registry, FALSE) == FALSE ||
+ ibus_registry_check_modification (registry)) {
+
+ ibus_object_destroy (IBUS_OBJECT (registry));
+ registry = ibus_registry_new ();
+
+ if (ibus_registry_load_cache (registry, TRUE) == FALSE ||
+ ibus_registry_check_modification (registry)) {
+
+ ibus_object_destroy (IBUS_OBJECT (registry));
+ registry = ibus_registry_new ();
+ ibus_registry_load (registry);
+ ibus_registry_save_cache (registry, TRUE);
+ }
+ }
+ }
+
+ ibus->registry = registry;
+ components = ibus_registry_get_components (registry);
+
+ for (p = components; p != NULL; p = p->next) {
+ IBusComponent *component = (IBusComponent *) p->data;
+ BusComponent *buscomp = bus_component_new (component,
+ NULL /* factory */);
+ GList *engines = NULL;
+ GList *p1;
+
+ g_object_ref_sink (buscomp);
+ ibus->components = g_list_append (ibus->components, buscomp);
+
+ engines = bus_component_get_engines (buscomp);
+ for (p1 = engines; p1 != NULL; p1 = p1->next) {
+ IBusEngineDesc *desc = (IBusEngineDesc *) p1->data;
+ const gchar *name = ibus_engine_desc_get_name (desc);
+ if (g_hash_table_lookup (ibus->engine_table, name) == NULL) {
+ g_hash_table_insert (ibus->engine_table,
+ (gpointer) name,
+ desc);
+ } else {
+ g_message ("Engine %s is already registered by other component",
+ name);
+ }
+ }
+ g_list_free (engines);
+ }
+
+ g_list_free (components);
+
+ g_signal_connect (ibus->registry,
+ "changed",
+ G_CALLBACK (_registry_changed_cb),
+ ibus);
+ ibus_registry_start_monitor_changes (ibus->registry);
+}
+
+static void
+bus_ibus_impl_registry_destroy (BusIBusImpl *ibus)
+{
+ g_list_free_full (ibus->components, g_object_unref);
+ ibus->components = NULL;
+
+ g_hash_table_destroy (ibus->engine_table);
+ ibus->engine_table = NULL;
+
+ ibus_object_destroy (IBUS_OBJECT (ibus->registry));
+ ibus->registry = NULL;
+}
+
+static gint
+_component_is_name_cb (BusComponent *component,
+ const gchar *name)
+{
+ g_assert (BUS_IS_COMPONENT (component));
+ g_assert (name);
+
+ return g_strcmp0 (bus_component_get_name (component), name);
+}
+
+static void
+bus_ibus_impl_component_name_owner_changed (BusIBusImpl *ibus,
+ const gchar *name,
+ const gchar *old_name,
+ const gchar *new_name)
+{
+ BusComponent *component;
+ BusFactoryProxy *factory;
g_assert (BUS_IS_IBUS_IMPL (ibus));
+ g_assert (name);
+ g_assert (old_name);
+ g_assert (new_name);
- return ibus->keymap;
+ component = bus_ibus_impl_lookup_component_by_name (ibus, name);
+
+ if (component == NULL) {
+ /* name is a unique name, or a well-known name we don't know. */
+ return;
+ }
+
+ if (g_strcmp0 (old_name, "") != 0) {
+ /* the component is stopped. */
+ factory = bus_component_get_factory (component);
+
+ if (factory != NULL) {
+ ibus_proxy_destroy ((IBusProxy *) factory);
+ }
+ }
+
+ if (g_strcmp0 (new_name, "") != 0) {
+ /* the component is started. */
+ BusConnection *connection =
+ bus_dbus_impl_get_connection_by_name (BUS_DEFAULT_DBUS,
+ new_name);
+ if (connection == NULL)
+ return;
+
+ factory = bus_factory_proxy_new (connection);
+ if (factory == NULL)
+ return;
+ bus_component_set_factory (component, factory);
+ g_object_unref (factory);
+ }
}
-BusRegistry *
-bus_ibus_impl_get_registry (BusIBusImpl *ibus)
+BusComponent *
+bus_ibus_impl_lookup_component_by_name (BusIBusImpl *ibus,
+ const gchar *name)
{
+ GList *p;
g_assert (BUS_IS_IBUS_IMPL (ibus));
+ g_assert (name);
+
+ p = g_list_find_custom (ibus->components,
+ name,
+ (GCompareFunc) _component_is_name_cb);
+ if (p) {
+ return (BusComponent *) p->data;
+ }
+ else {
+ return NULL;
+ }
+}
- return ibus->registry;
+/**
+ * bus_ibus_impl_emit_signal:
+ *
+ * Send a D-Bus signal to buses (connections) that are listening to the signal.
+ */
+static void
+bus_ibus_impl_emit_signal (BusIBusImpl *ibus,
+ const gchar *signal_name,
+ GVariant *parameters)
+{
+ GDBusMessage *message = g_dbus_message_new_signal ("/org/freedesktop/IBus",
+ "org.freedesktop.IBus",
+ signal_name);
+ /* set a non-zero serial to make libdbus happy */
+ g_dbus_message_set_serial (message, 1);
+ g_dbus_message_set_sender (message, "org.freedesktop.IBus");
+ if (parameters)
+ g_dbus_message_set_body (message, parameters);
+ bus_dbus_impl_dispatch_message_by_rule (BUS_DEFAULT_DBUS, message, NULL);
+ g_object_unref (message);
}
static void
bus_ibus_impl_registry_changed (BusIBusImpl *ibus)
{
+ bus_ibus_impl_emit_signal (ibus, "RegistryChanged", NULL);
+}
+
+static void
+bus_ibus_impl_global_engine_changed (BusIBusImpl *ibus)
+{
+ const gchar *name = ibus->global_engine_name ? ibus->global_engine_name : "";
+ bus_ibus_impl_emit_signal (ibus, "GlobalEngineChanged",
+ g_variant_new ("(s)", name));
+}
+
+gboolean
+bus_ibus_impl_is_use_sys_layout (BusIBusImpl *ibus)
+{
g_assert (BUS_IS_IBUS_IMPL (ibus));
- IBusMessage *message;
+ return ibus->use_sys_layout;
+}
- message = ibus_message_new_signal (IBUS_PATH_IBUS,
- IBUS_INTERFACE_IBUS,
- "RegistryChanged");
- ibus_message_append_args (message,
- G_TYPE_INVALID);
- ibus_message_set_sender (message, IBUS_SERVICE_IBUS);
+gboolean
+bus_ibus_impl_is_embed_preedit_text (BusIBusImpl *ibus)
+{
+ g_assert (BUS_IS_IBUS_IMPL (ibus));
- bus_dbus_impl_dispatch_message_by_rule (BUS_DEFAULT_DBUS, message, NULL);
+ return ibus->embed_preedit_text;
+}
- ibus_message_unref (message);
+BusInputContext *
+bus_ibus_impl_get_focused_input_context (BusIBusImpl *ibus)
+{
+ g_assert (BUS_IS_IBUS_IMPL (ibus));
+ return ibus->focused_context;
}