summaryrefslogtreecommitdiffstats
path: root/bus/ibusimpl.c
diff options
context:
space:
mode:
Diffstat (limited to 'bus/ibusimpl.c')
-rw-r--r--bus/ibusimpl.c935
1 files changed, 935 insertions, 0 deletions
diff --git a/bus/ibusimpl.c b/bus/ibusimpl.c
new file mode 100644
index 0000000..31799d6
--- /dev/null
+++ b/bus/ibusimpl.c
@@ -0,0 +1,935 @@
+/* vim:set et sts=4: */
+/* ibus - The Input Bus
+ * Copyright (C) 2008-2009 Huang Peng <shawn.p.huang@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "ibusimpl.h"
+#include "dbusimpl.h"
+#include "server.h"
+#include "connection.h"
+#include "registry.h"
+#include "factoryproxy.h"
+#include "panelproxy.h"
+#include "inputcontext.h"
+
+
+enum {
+ LAST_SIGNAL,
+};
+
+enum {
+ PROP_0,
+};
+
+// static guint _signals[LAST_SIGNAL] = { 0 };
+
+/* functions prototype */
+static void bus_ibus_impl_class_init (BusIBusImplClass *klass);
+static void bus_ibus_impl_init (BusIBusImpl *ibus);
+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 _factory_destroy_cb (BusFactoryProxy *factory,
+ BusIBusImpl *ibus);
+
+static IBusServiceClass *parent_class = NULL;
+
+GType
+bus_ibus_impl_get_type (void)
+{
+ static GType type = 0;
+
+ static const GTypeInfo type_info = {
+ sizeof (BusIBusImplClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) bus_ibus_impl_class_init,
+ NULL, /* class finalize */
+ NULL, /* class data */
+ sizeof (BusIBusImpl),
+ 0,
+ (GInstanceInitFunc) bus_ibus_impl_init,
+ };
+
+ if (type == 0) {
+ type = g_type_register_static (IBUS_TYPE_SERVICE,
+ "BusIBusImpl",
+ &type_info,
+ (GTypeFlags) 0);
+ }
+ return type;
+}
+
+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);
+
+ parent_class = (IBusServiceClass *) g_type_class_peek_parent (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_trigger (BusIBusImpl *ibus,
+ GValue *value)
+{
+ g_assert (BUS_IS_IBUS_IMPL (ibus));
+
+ GValueArray *array;
+ gint i;
+
+ ibus_hotkey_profile_remove_hotkey_by_event (ibus->hotkey_profile,
+ g_quark_from_static_string ("trigger"));
+
+ if (value == NULL) {
+ ibus_hotkey_profile_add_hotkey (ibus->hotkey_profile,
+ IBUS_space,
+ IBUS_CONTROL_MASK,
+ g_quark_from_static_string ("trigger"));
+ 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),
+ g_quark_from_static_string ("trigger"));
+ }
+}
+
+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;
+}
+
+static void
+bus_ibus_impl_reload_config (BusIBusImpl *ibus)
+{
+ 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", "preload_engines", bus_ibus_impl_set_preload_engines },
+ { NULL, NULL, NULL },
+ };
+
+ for (i = 0; entries[i].section != NULL; 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", "preload_engines", bus_ibus_impl_set_preload_engines },
+ { NULL, NULL, NULL },
+ };
+
+ for (i = 0; entries[i].section != NULL; i++) {
+ if (g_strcmp0 (entries[i].section, section) == 0 &&
+ g_strcmp0 (entries[i].key, key) == 0) {
+ entries[i].func (ibus, value);
+ break;
+ }
+ }
+}
+
+static void
+_config_destroy_cb (IBusConfig *config,
+ BusIBusImpl *ibus)
+{
+ g_assert (IBUS_IS_CONFIG (config));
+ g_assert (BUS_IS_IBUS_IMPL (ibus));
+
+ g_assert (ibus->config == config);
+
+ ibus->config = NULL;
+ g_object_unref (config);
+}
+
+static void
+_dbus_name_owner_changed_cb (BusDBusImpl *dbus,
+ 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 (old_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) {
+ BusConnection *connection;
+
+ if (ibus->panel != NULL) {
+ ibus_object_destroy (IBUS_OBJECT (ibus->panel));
+ ibus->panel = NULL;
+ }
+
+ connection = bus_dbus_impl_get_connection_by_name (BUS_DEFAULT_DBUS, new_name);
+ g_return_if_fail (connection != NULL);
+
+ ibus->panel = bus_panel_proxy_new (connection);
+
+ g_signal_connect (ibus->panel,
+ "destroy",
+ G_CALLBACK (_panel_destroy_cb),
+ ibus);
+
+ if (ibus->focused_context != NULL) {
+ bus_panel_proxy_focus_in (ibus->panel, 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));
+ ibus->config = NULL;
+ }
+
+ 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_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_ibus_impl_reload_config (ibus);
+ }
+ }
+
+ factory = bus_registry_name_owner_changed (ibus->registry, name, old_name, new_name);
+
+ if (factory) {
+ bus_ibus_impl_add_factory (ibus, factory);
+ g_object_unref (factory);
+ }
+}
+
+static void
+bus_ibus_impl_init (BusIBusImpl *ibus)
+{
+ ibus->factory_dict = g_hash_table_new_full (
+ g_str_hash,
+ g_str_equal,
+ NULL,
+ (GDestroyNotify) g_object_unref);
+
+ ibus->registry = bus_registry_new ();
+ ibus->engine_list = NULL;
+ ibus->register_engine_list = NULL;
+ ibus->contexts = NULL;
+ ibus->focused_context = NULL;
+ ibus->panel = NULL;
+ ibus->config = NULL;
+
+ ibus->hotkey_profile = ibus_hotkey_profile_new ();
+
+ bus_ibus_impl_reload_config (ibus);
+
+ g_signal_connect (BUS_DEFAULT_DBUS,
+ "name-owner-changed",
+ G_CALLBACK (_dbus_name_owner_changed_cb),
+ ibus);
+}
+
+static void
+bus_ibus_impl_destroy (BusIBusImpl *ibus)
+{
+ 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);
+ ibus->register_engine_list = NULL;
+
+ if (ibus->factory_dict != NULL) {
+ g_hash_table_destroy (ibus->factory_dict);
+ ibus->factory_dict = NULL;
+ }
+
+ if (ibus->hotkey_profile != NULL) {
+ g_object_unref (ibus->hotkey_profile);
+ ibus->hotkey_profile = NULL;
+ }
+
+ bus_server_quit (BUS_DEFAULT_SERVER);
+
+ IBUS_OBJECT_CLASS(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.DBus\">\n"
+ " <method name=\"RequestName\">\n"
+ " <arg direction=\"in\" type=\"s\"/>\n"
+ " <arg direction=\"in\" type=\"u\"/>\n"
+ " <arg direction=\"out\" type=\"u\"/>\n"
+ " </method>\n"
+ " <signal name=\"NameOwnerChanged\">\n"
+ " <arg type=\"s\"/>\n"
+ " <arg type=\"s\"/>\n"
+ " <arg type=\"s\"/>\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;
+
+ address = ibus_server_get_address (IBUS_SERVER (BUS_DEFAULT_SERVER));
+
+ reply = ibus_message_new_method_return (message);
+ ibus_message_append_args (message,
+ G_TYPE_STRING, &address,
+ G_TYPE_INVALID);
+
+ return reply;
+}
+
+static void
+_context_request_engine_cb (BusInputContext *context,
+ gchar *engine_name,
+ BusIBusImpl *ibus)
+{
+ IBusEngineDesc *engine_desc = NULL;
+ IBusComponent *comp;
+ BusFactoryProxy *factory;
+ BusEngineProxy *engine;
+
+ 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 */
+ GList *p;
+ gboolean found = FALSE;
+
+ /* 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) {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found) {
+ /* 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) {
+ found = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ engine_desc = NULL;
+ }
+ }
+
+ if (engine_desc == NULL)
+ return;
+
+ factory = bus_factory_proxy_get_from_engine (engine_desc);
+
+ 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);
+
+ gint time = 0;
+ while (time < G_USEC_PER_SEC * 3) {
+ if (g_main_context_pending (NULL)) {
+ g_main_context_iteration (NULL, FALSE);
+ }
+ else {
+ g_usleep (50 * 1000);
+ time += 50 * 1000;
+ }
+ factory = bus_factory_proxy_get_from_engine (engine_desc);
+ if (factory != NULL) {
+ break;
+ }
+ }
+ }
+ factory = bus_factory_proxy_get_from_engine (engine_desc);
+ }
+
+ if (factory == NULL)
+ return;
+
+ engine = bus_factory_proxy_create_engine (factory, engine_desc);
+
+ if (engine == NULL)
+ return;
+
+ bus_input_context_set_engine (context, engine);
+}
+
+static void
+_context_request_next_engine_cb (BusInputContext *context,
+ BusIBusImpl *ibus)
+{
+
+}
+
+static void
+_context_request_prev_engine_cb (BusInputContext *context,
+ BusIBusImpl *ibus)
+{
+
+}
+
+static void
+_context_focus_out_cb (BusInputContext *context,
+ BusIBusImpl *ibus)
+{
+ g_assert (BUS_IS_IBUS_IMPL (ibus));
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+
+ if (ibus->focused_context != context)
+ return;
+
+ if (ibus->panel != NULL) {
+ bus_panel_proxy_focus_out (ibus->panel, context);
+ }
+
+ if (context) {
+ g_object_unref (context);
+ ibus->focused_context = NULL;
+ }
+}
+
+static void
+_context_focus_in_cb (BusInputContext *context,
+ BusIBusImpl *ibus)
+{
+ g_assert (BUS_IS_IBUS_IMPL (ibus));
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+
+ if (ibus->focused_context) {
+ /* focus out context */
+ bus_input_context_focus_out (ibus->focused_context);
+ g_assert (ibus->focused_context == NULL);
+ }
+
+ g_object_ref (context);
+ ibus->focused_context = context;
+
+ if (ibus->panel != NULL) {
+ bus_panel_proxy_focus_in (ibus->panel, ibus->focused_context);
+ }
+
+}
+
+static void
+_context_destroy_cb (BusInputContext *context,
+ BusIBusImpl *ibus)
+{
+ g_assert (BUS_IS_IBUS_IMPL (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);
+ }
+
+ ibus->contexts = g_list_remove (ibus->contexts, context);
+ g_object_unref (context);
+}
+
+static IBusMessage *
+_ibus_create_input_context (BusIBusImpl *ibus,
+ IBusMessage *message,
+ BusConnection *connection)
+{
+ 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);
+ ibus->contexts = g_list_append (ibus->contexts, context);
+
+ 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) },
+ { "focus-in", G_CALLBACK (_context_focus_in_cb) },
+ { "focus-out", G_CALLBACK (_context_focus_out_cb) },
+ { "destroy", G_CALLBACK (_context_destroy_cb) },
+ { NULL, NULL }
+ };
+
+ for (i = 0; signals[i].name != NULL; i++) {
+ g_signal_connect (context,
+ signals[i].name,
+ signals[i].callback,
+ 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_dbus_impl_register_object (BUS_DEFAULT_DBUS,
+ (IBusService *)context);
+ return reply;
+}
+
+static void
+_factory_destroy_cb (BusFactoryProxy *factory,
+ BusIBusImpl *ibus)
+{
+ g_assert (BUS_IS_IBUS_IMPL (ibus));
+ g_assert (BUS_IS_FACTORY_PROXY (factory));
+
+ IBusComponent *component;
+ GList *engines, *p;
+
+ ibus->factory_list = g_list_remove (ibus->factory_list, factory);
+
+ component = bus_factory_proxy_get_component (factory);
+
+ 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);
+ }
+
+ g_object_unref (factory);
+}
+
+static void
+bus_ibus_impl_add_factory (BusIBusImpl *ibus,
+ BusFactoryProxy *factory)
+{
+ g_assert (BUS_IS_IBUS_IMPL (ibus));
+ g_assert (BUS_IS_FACTORY_PROXY (factory));
+
+ g_object_ref (factory);
+ ibus->factory_list = g_list_append (ibus->factory_list, factory);
+
+ g_signal_connect (factory, "destroy", G_CALLBACK (_factory_destroy_cb), ibus);
+}
+
+
+static IBusMessage *
+_ibus_register_component (BusIBusImpl *ibus,
+ IBusMessage *message,
+ BusConnection *connection)
+{
+ IBusMessage *reply;
+ IBusError *error;
+ gboolean retval;
+ GList *engines;
+ IBusComponent *component;
+ BusFactoryProxy *factory;
+
+ retval = ibus_message_get_args (message, &error,
+ IBUS_TYPE_COMPONENT, &component,
+ G_TYPE_INVALID);
+
+ 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;
+ }
+
+ factory = bus_factory_proxy_new (component, connection);
+
+ if (factory == NULL) {
+ reply = ibus_message_new_error (message,
+ DBUS_ERROR_FAILED,
+ "Can not create factory");
+ return reply;
+ }
+
+ bus_ibus_impl_add_factory (ibus, factory);
+ g_object_unref (factory);
+
+ engines = ibus_component_get_engines (component);
+
+ 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);
+
+ reply = ibus_message_new_method_return (message);
+ return reply;
+}
+
+static IBusMessage *
+_ibus_list_engines (BusIBusImpl *ibus,
+ IBusMessage *message,
+ BusConnection *connection)
+{
+ IBusMessage *reply;
+ IBusMessageIter iter, sub_iter;
+ GList *engines, *p;
+
+ reply = ibus_message_new_method_return (message);
+
+ ibus_message_iter_init_append (reply, &iter);
+ ibus_message_iter_open_container (&iter, IBUS_TYPE_ARRAY, "v", &sub_iter);
+
+ 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));
+ }
+ g_list_free (engines);
+ ibus_message_iter_close_container (&iter, &sub_iter);
+
+ return reply;
+}
+
+static IBusMessage *
+_ibus_list_active_engines (BusIBusImpl *ibus,
+ IBusMessage *message,
+ BusConnection *connection)
+{
+ IBusMessage *reply;
+ IBusMessageIter iter, sub_iter;
+ GList *p;
+
+ reply = ibus_message_new_method_return (message);
+
+ ibus_message_iter_init_append (reply, &iter);
+ ibus_message_iter_open_container (&iter, IBUS_TYPE_ARRAY, "v", &sub_iter);
+
+ for (p = ibus->engine_list; p != NULL; p = p->next) {
+ ibus_message_iter_append (&sub_iter, IBUS_TYPE_ENGINE_DESC, &(p->data));
+ }
+
+ for (p = ibus->register_engine_list; p != NULL; p = p->next) {
+ ibus_message_iter_append (&sub_iter, IBUS_TYPE_ENGINE_DESC, &(p->data));
+ }
+ ibus_message_iter_close_container (&iter, &sub_iter);
+
+ return reply;
+}
+
+static IBusMessage *
+_ibus_kill (BusIBusImpl *ibus,
+ IBusMessage *message,
+ BusConnection *connection)
+{
+ IBusMessage *reply;
+
+ reply = ibus_message_new_method_return (message);
+ ibus_connection_send ((IBusConnection *) connection, reply);
+ ibus_connection_flush ((IBusConnection *) connection);
+ ibus_message_unref (reply);
+
+ ibus_object_destroy (IBUS_OBJECT (ibus));
+ return NULL;
+}
+
+static gboolean
+bus_ibus_impl_ibus_message (BusIBusImpl *ibus,
+ BusConnection *connection,
+ IBusMessage *message)
+{
+ g_assert (BUS_IS_IBUS_IMPL (ibus));
+ g_assert (BUS_IS_CONNECTION (connection));
+ g_assert (message != NULL);
+
+ gint i;
+ IBusMessage *reply_message = NULL;
+
+ 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, "RegisterComponent", _ibus_register_component },
+ { IBUS_INTERFACE_IBUS, "ListEngines", _ibus_list_engines },
+ { IBUS_INTERFACE_IBUS, "ListActiveEngines", _ibus_list_active_engines },
+ { IBUS_INTERFACE_IBUS, "Kill", _ibus_kill },
+ { NULL, NULL, NULL }
+ };
+
+ ibus_message_set_sender (message, bus_connection_get_unique_name (connection));
+ ibus_message_set_destination (message, DBUS_SERVICE_DBUS);
+
+ for (i = 0; handlers[i].interface != NULL; i++) {
+ if (ibus_message_is_method_call (message,
+ handlers[i].interface,
+ handlers[i].name)) {
+
+ reply_message = handlers[i].handler (ibus, message, connection);
+ if (reply_message) {
+
+ 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);
+
+ ibus_connection_send ((IBusConnection *) connection, reply_message);
+ ibus_message_unref (reply_message);
+ }
+
+ g_signal_stop_emission_by_name (ibus, "ibus-message");
+ return TRUE;
+ }
+ }
+
+ return parent_class->ibus_message ((IBusService *) ibus,
+ (IBusConnection *) connection,
+ message);
+}
+
+BusFactoryProxy *
+bus_ibus_impl_lookup_factory (BusIBusImpl *ibus,
+ const gchar *path)
+{
+ g_assert (BUS_IS_IBUS_IMPL (ibus));
+
+ BusFactoryProxy *factory;
+
+ factory = (BusFactoryProxy *) g_hash_table_lookup (ibus->factory_dict, path);
+
+ return factory;
+}
+
+IBusHotkeyProfile *
+bus_ibus_impl_get_hotkey_profile (BusIBusImpl *ibus)
+{
+ g_assert (BUS_IS_IBUS_IMPL (ibus));
+
+ return ibus->hotkey_profile;
+}
+
+BusRegistry *
+bus_ibus_impl_get_registry (BusIBusImpl *ibus)
+{
+
+ g_assert (BUS_IS_IBUS_IMPL (ibus));
+
+ return ibus->registry;
+}
+