summaryrefslogtreecommitdiffstats
path: root/bus/inputcontext.c
diff options
context:
space:
mode:
Diffstat (limited to 'bus/inputcontext.c')
-rw-r--r--bus/inputcontext.c1559
1 files changed, 1559 insertions, 0 deletions
diff --git a/bus/inputcontext.c b/bus/inputcontext.c
new file mode 100644
index 0000000..a4e3359
--- /dev/null
+++ b/bus/inputcontext.c
@@ -0,0 +1,1559 @@
+/* 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 <ibusinternal.h>
+#include <ibusmarshalers.h>
+#include "ibusimpl.h"
+#include "inputcontext.h"
+#include "engineproxy.h"
+#include "factoryproxy.h"
+
+#define BUS_INPUT_CONTEXT_GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), BUS_TYPE_INPUT_CONTEXT, BusInputContextPrivate))
+
+enum {
+ PROCESS_KEY_EVENT,
+ SET_CURSOR_LOCATION,
+ FOCUS_IN,
+ FOCUS_OUT,
+ UPDATE_PREEDIT_TEXT,
+ SHOW_PREEDIT_TEXT,
+ HIDE_PREEDIT_TEXT,
+ UPDATE_AUXILIARY_TEXT,
+ SHOW_AUXILIARY_TEXT,
+ HIDE_AUXILIARY_TEXT,
+ UPDATE_LOOKUP_TABLE,
+ SHOW_LOOKUP_TABLE,
+ HIDE_LOOKUP_TABLE,
+ PAGE_UP_LOOKUP_TABLE,
+ PAGE_DOWN_LOOKUP_TABLE,
+ CURSOR_UP_LOOKUP_TABLE,
+ CURSOR_DOWN_LOOKUP_TABLE,
+ REGISTER_PROPERTIES,
+ UPDATE_PROPERTY,
+ ENABLED,
+ DISABLED,
+ ENGINE_CHANGED,
+ REQUEST_ENGINE,
+ REQUEST_NEXT_ENGINE,
+ REQUEST_PREV_ENGINE,
+ LAST_SIGNAL,
+};
+
+enum {
+ PROP_0,
+};
+
+
+/* IBusInputContextPriv */
+struct _BusInputContextPrivate {
+ BusConnection *connection;
+ BusEngineProxy *engine;
+ gchar *client;
+
+ gboolean has_focus;
+ gboolean enabled;
+
+ /* capabilities */
+ guint capabilities;
+
+ /* cursor location */
+ gint x;
+ gint y;
+ gint w;
+ gint h;
+};
+
+typedef struct _BusInputContextPrivate BusInputContextPrivate;
+
+static guint context_signals[LAST_SIGNAL] = { 0 };
+
+/* functions prototype */
+static void bus_input_context_class_init (BusInputContextClass *klass);
+static void bus_input_context_init (BusInputContext *context);
+static void bus_input_context_destroy (BusInputContext *context);
+static gboolean bus_input_context_ibus_message (BusInputContext *context,
+ BusConnection *connection,
+ IBusMessage *message);
+static gboolean bus_input_context_filter_keyboard_shortcuts
+ (BusInputContext *context,
+ guint keyval,
+ guint modifiers);
+static gboolean bus_input_context_send_signal (BusInputContext *context,
+ const gchar *signal_name,
+ GType first_arg_type,
+ ...);
+static void _engine_destroy_cb (BusEngineProxy *factory,
+ BusInputContext *context);
+
+static IBusServiceClass *parent_class = NULL;
+static guint id = 0;
+
+GType
+bus_input_context_get_type (void)
+{
+ static GType type = 0;
+
+ static const GTypeInfo type_info = {
+ sizeof (BusInputContextClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) bus_input_context_class_init,
+ NULL, /* class finalize */
+ NULL, /* class data */
+ sizeof (BusInputContext),
+ 0,
+ (GInstanceInitFunc) bus_input_context_init,
+ };
+
+ if (type == 0) {
+ type = g_type_register_static (IBUS_TYPE_SERVICE,
+ "BusInputContext",
+ &type_info,
+ (GTypeFlags) 0);
+ }
+ return type;
+}
+
+static void
+_connection_destroy_cb (BusConnection *connection,
+ BusInputContext *context)
+{
+ BUS_IS_CONNECTION (connection);
+ BUS_IS_INPUT_CONTEXT (context);
+
+ ibus_object_destroy (IBUS_OBJECT (context));
+}
+
+
+BusInputContext *
+bus_input_context_new (BusConnection *connection,
+ const gchar *client)
+{
+ g_assert (BUS_IS_CONNECTION (connection));
+ g_assert (client != NULL);
+
+ BusInputContext *context;
+ gchar *path;
+ BusInputContextPrivate *priv;
+
+ path = g_strdup_printf (IBUS_PATH_INPUT_CONTEXT, ++id);
+
+ context = (BusInputContext *) g_object_new (BUS_TYPE_INPUT_CONTEXT,
+ "path", path,
+ NULL);
+ g_free (path);
+
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+#if 0
+ ibus_service_add_to_connection (IBUS_SERVICE (context),
+ IBUS_CONNECTION (connection));
+#endif
+
+ g_object_ref (connection);
+ priv->connection = connection;
+ priv->client = g_strdup (client);
+
+ g_signal_connect (priv->connection,
+ "destroy",
+ (GCallback) _connection_destroy_cb,
+ context);
+
+ return context;
+}
+
+static void
+bus_input_context_class_init (BusInputContextClass *klass)
+{
+ IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (klass);
+
+ parent_class = (IBusServiceClass *) g_type_class_peek_parent (klass);
+
+ g_type_class_add_private (klass, sizeof (BusInputContextPrivate));
+
+ ibus_object_class->destroy = (IBusObjectDestroyFunc) bus_input_context_destroy;
+
+ IBUS_SERVICE_CLASS (klass)->ibus_message = (ServiceIBusMessageFunc) bus_input_context_ibus_message;
+
+ /* install signals */
+ context_signals[PROCESS_KEY_EVENT] =
+ g_signal_new (I_("process-key-event"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ ibus_marshal_BOOL__UINT_UINT,
+ G_TYPE_BOOLEAN,
+ 2,
+ G_TYPE_UINT,
+ G_TYPE_UINT);
+
+ context_signals[SET_CURSOR_LOCATION] =
+ g_signal_new (I_("set-cursor-location"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ ibus_marshal_VOID__INT_INT_INT_INT,
+ G_TYPE_NONE,
+ 4,
+ G_TYPE_INT,
+ G_TYPE_INT,
+ G_TYPE_INT,
+ G_TYPE_INT);
+
+ context_signals[FOCUS_IN] =
+ g_signal_new (I_("focus-in"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ ibus_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ context_signals[FOCUS_OUT] =
+ g_signal_new (I_("focus-out"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ ibus_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ context_signals[UPDATE_PREEDIT_TEXT] =
+ g_signal_new (I_("update-preedit-text"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ ibus_marshal_VOID__OBJECT_UINT_BOOLEAN,
+ G_TYPE_NONE,
+ 3,
+ IBUS_TYPE_TEXT,
+ G_TYPE_UINT,
+ G_TYPE_BOOLEAN);
+
+ context_signals[SHOW_PREEDIT_TEXT] =
+ g_signal_new (I_("show-preedit-text"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ ibus_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ context_signals[HIDE_PREEDIT_TEXT] =
+ g_signal_new (I_("hide-preedit-text"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ ibus_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ context_signals[UPDATE_AUXILIARY_TEXT] =
+ g_signal_new (I_("update-auxiliary-text"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ ibus_marshal_VOID__OBJECT_BOOLEAN,
+ G_TYPE_NONE,
+ 2,
+ IBUS_TYPE_TEXT,
+ G_TYPE_BOOLEAN);
+
+ context_signals[SHOW_AUXILIARY_TEXT] =
+ g_signal_new (I_("show-auxiliary-text"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ ibus_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ context_signals[HIDE_AUXILIARY_TEXT] =
+ g_signal_new (I_("hide-auxiliary-text"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ ibus_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ context_signals[UPDATE_LOOKUP_TABLE] =
+ g_signal_new (I_("update-lookup-table"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ ibus_marshal_VOID__OBJECT_BOOLEAN,
+ G_TYPE_NONE,
+ 2,
+ IBUS_TYPE_LOOKUP_TABLE,
+ G_TYPE_BOOLEAN);
+
+ context_signals[SHOW_LOOKUP_TABLE] =
+ g_signal_new (I_("show-lookup-table"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ ibus_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ context_signals[HIDE_LOOKUP_TABLE] =
+ g_signal_new (I_("hide-lookup-table"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ ibus_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ context_signals[PAGE_UP_LOOKUP_TABLE] =
+ g_signal_new (I_("page-up-lookup-table"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ ibus_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ context_signals[PAGE_DOWN_LOOKUP_TABLE] =
+ g_signal_new (I_("page-down-lookup-table"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ ibus_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ context_signals[CURSOR_UP_LOOKUP_TABLE] =
+ g_signal_new (I_("cursor-up-lookup-table"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ ibus_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ context_signals[CURSOR_DOWN_LOOKUP_TABLE] =
+ g_signal_new (I_("cursor-down-lookup-table"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ ibus_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ context_signals[REGISTER_PROPERTIES] =
+ g_signal_new (I_("register-properties"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ ibus_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ IBUS_TYPE_PROP_LIST);
+
+ context_signals[UPDATE_PROPERTY] =
+ g_signal_new (I_("update-property"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ ibus_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ IBUS_TYPE_PROPERTY);
+
+ context_signals[ENABLED] =
+ g_signal_new (I_("enabled"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ ibus_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ context_signals[DISABLED] =
+ g_signal_new (I_("disabled"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ ibus_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ context_signals[ENGINE_CHANGED] =
+ g_signal_new (I_("factory-changed"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ ibus_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ context_signals[REQUEST_ENGINE] =
+ g_signal_new (I_("request-engine"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ ibus_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ context_signals[REQUEST_NEXT_ENGINE] =
+ g_signal_new (I_("request-next-engine"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ ibus_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ context_signals[REQUEST_PREV_ENGINE] =
+ g_signal_new (I_("request-prev-engine"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ ibus_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
+
+static void
+bus_input_context_init (BusInputContext *context)
+{
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+ priv->connection = NULL;
+ priv->client = NULL;
+ priv->engine = NULL;
+ priv->has_focus = FALSE;
+ priv->enabled = FALSE;
+
+ priv->capabilities = 0;
+
+ priv->x = 0;
+ priv->y = 0;
+ priv->w = 0;
+ priv->h = 0;
+
+}
+
+static void
+bus_input_context_destroy (BusInputContext *context)
+{
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+ if (priv->has_focus) {
+ bus_input_context_focus_out (context);
+ priv->has_focus = FALSE;
+ }
+
+ if (priv->engine) {
+ g_signal_handlers_disconnect_by_func (priv->engine,
+ G_CALLBACK (_engine_destroy_cb),
+ context);
+ g_object_unref (priv->engine);
+ priv->engine = NULL;
+ }
+
+ if (priv->connection) {
+ g_signal_handlers_disconnect_by_func (priv->connection,
+ (GCallback) _connection_destroy_cb,
+ context);
+ g_object_unref (priv->connection);
+ priv->connection = NULL;
+ }
+
+ if (priv->client) {
+ g_free (priv->client);
+ priv->client = NULL;
+ }
+
+ IBUS_OBJECT_CLASS(parent_class)->destroy (IBUS_OBJECT (context));
+}
+
+/* introspectable interface */
+static IBusMessage *
+_ibus_introspect (BusInputContext *context,
+ IBusMessage *message,
+ BusConnection *connection)
+{
+ static const gchar *introspect =
+ "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
+ "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
+ "<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=\"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;
+}
+
+typedef struct {
+ BusInputContext *context;
+ IBusMessage *message;
+}CallData;
+
+static void
+_ic_process_key_event_reply_cb (gboolean retval,
+ CallData *call_data)
+{
+ IBusMessage *reply;
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (call_data->context);
+
+ reply = ibus_message_new_method_return (call_data->message);
+ ibus_message_append_args (reply,
+ G_TYPE_BOOLEAN, &retval,
+ G_TYPE_INVALID);
+ ibus_connection_send ((IBusConnection *)priv->connection, reply);
+
+ g_object_unref (call_data->context);
+ ibus_message_unref (call_data->message);
+ ibus_message_unref (reply);
+ g_slice_free (CallData, call_data);
+}
+
+static IBusMessage *
+_ic_process_key_event (BusInputContext *context,
+ IBusMessage *message,
+ BusConnection *connection)
+{
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+ g_assert (message != NULL);
+ g_assert (BUS_IS_CONNECTION (connection));
+
+ IBusMessage *reply = NULL;
+ guint keyval, modifiers;
+ gboolean retval;
+ IBusError *error;
+
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+
+ error = ibus_error_new ();
+ retval = ibus_message_get_args (message,
+ &error,
+ G_TYPE_UINT, &keyval,
+ G_TYPE_UINT, &modifiers,
+ G_TYPE_INVALID);
+
+ if (!retval) {
+ reply = ibus_message_new_error (message,
+ error->name,
+ error->message);
+ ibus_error_free (error);
+ return reply;
+ }
+
+ ibus_error_free (error);
+
+ retval = bus_input_context_filter_keyboard_shortcuts (context, keyval, modifiers);
+
+ if (retval) {
+ reply = ibus_message_new_method_return (message);
+ ibus_message_append_args (reply,
+ G_TYPE_BOOLEAN, &retval,
+ G_TYPE_INVALID);
+ }
+ else if (priv->enabled && priv->engine) {
+ CallData *call_data = g_slice_new (CallData);
+ call_data->context = context;
+ call_data->message = message;
+ g_object_ref (context);
+ ibus_message_ref (message);
+
+ bus_engine_proxy_process_key_event (priv->engine,
+ keyval,
+ modifiers,
+ (GFunc) _ic_process_key_event_reply_cb,
+ call_data);
+ }
+ else {
+ reply = ibus_message_new_method_return (message);
+ ibus_message_append_args (reply,
+ G_TYPE_BOOLEAN, &retval,
+ G_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static IBusMessage *
+_ic_set_cursor_location (BusInputContext *context,
+ IBusMessage *message,
+ BusConnection *connection)
+{
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+ g_assert (message != NULL);
+ g_assert (BUS_IS_CONNECTION (connection));
+
+ IBusMessage *reply;
+ guint x, y, w, h;
+ gboolean retval;
+ IBusError *error;
+
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+ retval = ibus_message_get_args (message, &error,
+ G_TYPE_INT, &x,
+ G_TYPE_INT, &y,
+ G_TYPE_INT, &w,
+ G_TYPE_INT, &h,
+ G_TYPE_INVALID);
+
+ if (!retval) {
+ reply = ibus_message_new_error (message,
+ error->name,
+ error->message);
+ ibus_error_free (error);
+ return reply;
+ }
+
+ priv->x = x;
+ priv->y = y;
+ priv->h = h;
+ priv->w = w;
+
+ if (priv->engine) {
+ bus_engine_proxy_set_cursor_location (priv->engine, x, y, w, h);
+ }
+
+ if (priv->capabilities & IBUS_CAP_FOCUS) {
+ g_signal_emit (context,
+ context_signals[SET_CURSOR_LOCATION],
+ 0,
+ x,
+ y,
+ w,
+ h);
+ }
+
+ reply = ibus_message_new_method_return (message);
+ return reply;
+}
+
+static IBusMessage *
+_ic_focus_in (BusInputContext *context,
+ IBusMessage *message,
+ BusConnection *connection)
+{
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+ g_assert (message != NULL);
+ g_assert (BUS_IS_CONNECTION (connection));
+
+ IBusMessage *reply;
+
+ bus_input_context_focus_in (context);
+
+ reply = ibus_message_new_method_return (message);
+
+ return reply;
+}
+
+static IBusMessage *
+_ic_focus_out (BusInputContext *context,
+ IBusMessage *message,
+ BusConnection *connection)
+{
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+ g_assert (message != NULL);
+ g_assert (BUS_IS_CONNECTION (connection));
+
+ IBusMessage *reply;
+
+ bus_input_context_focus_out (context);
+
+ reply = ibus_message_new_method_return (message);
+
+ return reply;
+}
+
+static IBusMessage *
+_ic_reset (BusInputContext *context,
+ IBusMessage *message,
+ BusConnection *connection)
+{
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+ g_assert (message != NULL);
+ g_assert (BUS_IS_CONNECTION (connection));
+
+ IBusMessage *reply;
+
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+
+ if (priv->engine) {
+ bus_engine_proxy_reset (priv->engine);
+ }
+
+ reply = ibus_message_new_method_return (message);
+ return reply;
+}
+
+static IBusMessage *
+_ic_set_capabilities (BusInputContext *context,
+ IBusMessage *message,
+ BusConnection *connection)
+{
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+ g_assert (message != NULL);
+ g_assert (BUS_IS_CONNECTION (connection));
+
+ IBusMessage *reply;
+ guint caps;
+ gboolean retval;
+ IBusError *error;
+
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+
+ retval = ibus_message_get_args (message,
+ &error,
+ G_TYPE_UINT, &caps,
+ G_TYPE_INVALID);
+
+ if (!retval) {
+ reply = ibus_message_new_error (message,
+ error->name,
+ error->message);
+ ibus_error_free (error);
+ return reply;
+ }
+
+ if (priv->capabilities != caps) {
+ priv->capabilities = caps;
+
+ if (priv->engine) {
+ bus_engine_proxy_set_capabilities (priv->engine, caps);
+ }
+ }
+
+ reply = ibus_message_new_method_return (message);
+ return reply;
+}
+
+static IBusMessage *
+_ic_is_enabled (BusInputContext *context,
+ IBusMessage *message,
+ BusConnection *connection)
+{
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+ g_assert (message != NULL);
+ g_assert (BUS_IS_CONNECTION (connection));
+
+ IBusMessage *reply;
+
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+ reply = ibus_message_new_method_return (message);
+ ibus_message_append_args (reply,
+ G_TYPE_BOOLEAN, &priv->enabled,
+ G_TYPE_INVALID);
+
+ return reply;
+}
+
+static IBusMessage *
+_ic_set_engine (BusInputContext *context,
+ IBusMessage *message,
+ BusConnection *connection)
+{
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+ g_assert (message != NULL);
+ g_assert (BUS_IS_CONNECTION (connection));
+
+ gboolean retval;
+ IBusMessage *reply;
+ IBusError *error;
+ gchar *engine_name;
+
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+ retval = ibus_message_get_args (message,
+ &error,
+ G_TYPE_STRING, &engine_name,
+ G_TYPE_INVALID);
+ if (!retval) {
+ reply = ibus_message_new_error (message,
+ error->name,
+ error->message);
+ ibus_error_free (error);
+ return reply;
+ }
+
+ g_signal_emit (context, context_signals[REQUEST_ENGINE], 0, engine_name);
+
+ if (priv->engine == NULL) {
+ reply = ibus_message_new_error_printf (message,
+ "org.freedesktop.IBus.NoEngine",
+ "can not find engine with name %s",
+ engine_name);
+ return reply;
+ }
+
+ bus_input_context_enable (context);
+
+ reply = ibus_message_new_method_return (message);
+ return reply;
+}
+
+static IBusMessage *
+_ic_get_engine (BusInputContext *context,
+ IBusMessage *message,
+ BusConnection *connection)
+{
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+ g_assert (message != NULL);
+ g_assert (BUS_IS_CONNECTION (connection));
+
+ IBusMessage *reply;
+ IBusEngineDesc *desc;
+
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+ if (priv->engine) {
+ desc = bus_engine_proxy_get_desc (priv->engine);
+ if (desc != NULL) {
+ reply = ibus_message_new_method_return (message);
+ ibus_message_append_args (reply,
+ IBUS_TYPE_ENGINE_DESC, &desc,
+ G_TYPE_INVALID);
+ return reply;
+ }
+ }
+
+ reply = ibus_message_new_error (message,
+ DBUS_ERROR_FAILED,
+ "InputContext does not have factory.");
+ return reply;
+}
+
+static IBusMessage *
+_ic_destroy (BusInputContext *context,
+ IBusMessage *message,
+ BusConnection *connection)
+{
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+ g_assert (message != NULL);
+ g_assert (BUS_IS_CONNECTION (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 ((IBusObject *) context);
+
+ return NULL;
+}
+
+static gboolean
+bus_input_context_ibus_message (BusInputContext *context,
+ BusConnection *connection,
+ IBusMessage *message)
+{
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+ 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) (BusInputContext *, IBusMessage *, BusConnection *);
+ } handlers[] = {
+ /* Introspectable interface */
+ { DBUS_INTERFACE_INTROSPECTABLE,
+ "Introspect", _ibus_introspect },
+ /* IBus interface */
+ { IBUS_INTERFACE_INPUT_CONTEXT, "ProcessKeyEvent", _ic_process_key_event },
+ { IBUS_INTERFACE_INPUT_CONTEXT, "SetCursorLocation", _ic_set_cursor_location },
+ { IBUS_INTERFACE_INPUT_CONTEXT, "FocusIn", _ic_focus_in },
+ { IBUS_INTERFACE_INPUT_CONTEXT, "FocusOut", _ic_focus_out },
+ { IBUS_INTERFACE_INPUT_CONTEXT, "Reset", _ic_reset },
+ { IBUS_INTERFACE_INPUT_CONTEXT, "SetCapabilities", _ic_set_capabilities },
+ { IBUS_INTERFACE_INPUT_CONTEXT, "IsEnabled", _ic_is_enabled },
+ { IBUS_INTERFACE_INPUT_CONTEXT, "SetEngine", _ic_set_engine },
+ { IBUS_INTERFACE_INPUT_CONTEXT, "GetEngine", _ic_get_engine },
+ { IBUS_INTERFACE_INPUT_CONTEXT, "Destroy", _ic_destroy },
+
+ { 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 (context, 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 (IBUS_CONNECTION (connection), reply_message);
+ ibus_message_unref (reply_message);
+ }
+
+ g_signal_stop_emission_by_name (context, "ibus-message");
+ return TRUE;
+ }
+ }
+
+ return parent_class->ibus_message ((IBusService *)context,
+ (IBusConnection *)connection,
+ message);
+}
+
+
+gboolean
+bus_input_context_is_focus (BusInputContext *context)
+{
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+ return priv->has_focus;
+}
+
+void
+bus_input_context_focus_in (BusInputContext *context)
+{
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+ if (priv->has_focus)
+ return;
+
+ priv->has_focus = TRUE;
+
+ if (priv->engine) {
+ bus_engine_proxy_focus_in (priv->engine);
+ }
+
+ if (priv->capabilities & IBUS_CAP_FOCUS) {
+ g_signal_emit (context, context_signals[FOCUS_IN], 0);
+ }
+}
+
+void
+bus_input_context_focus_out (BusInputContext *context)
+{
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+ if (!priv->has_focus)
+ return;
+
+ priv->has_focus = FALSE;
+
+ if (priv->engine) {
+ bus_engine_proxy_focus_out (priv->engine);
+ }
+
+ if (priv->capabilities & IBUS_CAP_FOCUS) {
+ g_signal_emit (context, context_signals[FOCUS_OUT], 0);
+ }
+}
+
+void
+bus_input_context_page_up (BusInputContext *context)
+{
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+ if (priv->engine) {
+ bus_engine_proxy_page_up (priv->engine);
+ }
+}
+
+void
+bus_input_context_page_down (BusInputContext *context)
+{
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+ if (priv->engine) {
+ bus_engine_proxy_page_down (priv->engine);
+ }
+}
+
+void
+bus_input_context_cursor_up (BusInputContext *context)
+{
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+ if (priv->engine) {
+ bus_engine_proxy_cursor_up (priv->engine);
+ }
+}
+
+void
+bus_input_context_cursor_down (BusInputContext *context)
+{
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+ if (priv->engine) {
+ bus_engine_proxy_cursor_down (priv->engine);
+ }
+}
+
+void
+bus_input_context_property_activate (BusInputContext *context,
+ const gchar *prop_name,
+ gint prop_state)
+{
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+ if (priv->engine) {
+ bus_engine_proxy_property_activate (priv->engine, prop_name, prop_state);
+ }
+}
+
+static void
+_engine_destroy_cb (BusEngineProxy *engine,
+ BusInputContext *context)
+{
+ g_assert (BUS_IS_ENGINE_PROXY (engine));
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+ g_assert (priv->engine == engine);
+
+ bus_input_context_set_engine (context, NULL);
+}
+
+static void
+_engine_commit_text_cb (BusEngineProxy *engine,
+ IBusText *text,
+ BusInputContext *context)
+{
+ g_assert (BUS_IS_ENGINE_PROXY (engine));
+ g_assert (text != NULL);
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+ g_assert (priv->engine == engine);
+
+ bus_input_context_send_signal (context,
+ "CommitText",
+ IBUS_TYPE_TEXT, &text,
+ G_TYPE_INVALID);
+
+}
+
+static void
+_engine_forward_key_event_cb (BusEngineProxy *engine,
+ guint keyval,
+ guint state,
+ BusInputContext *context)
+{
+ g_assert (BUS_IS_ENGINE_PROXY (engine));
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+ g_assert (priv->engine == engine);
+
+ bus_input_context_send_signal (context,
+ "ForwardKeyEvent",
+ G_TYPE_UINT, &keyval,
+ G_TYPE_UINT, &state,
+ G_TYPE_INVALID);
+
+}
+
+static void
+_engine_update_preedit_text_cb (BusEngineProxy *engine,
+ IBusText *text,
+ guint cursor_pos,
+ gboolean visible,
+ BusInputContext *context)
+{
+ g_assert (BUS_IS_ENGINE_PROXY (engine));
+ g_assert (IBUS_IS_TEXT (text));
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+ g_assert (priv->engine == engine);
+
+ if (priv->capabilities & IBUS_CAP_PREEDIT_TEXT) {
+ bus_input_context_send_signal (context,
+ "UpdatePreeditText",
+ IBUS_TYPE_TEXT, &text,
+ G_TYPE_UINT, &cursor_pos,
+ G_TYPE_BOOLEAN, &visible,
+ G_TYPE_INVALID);
+ }
+ else {
+ g_signal_emit (context,
+ context_signals[UPDATE_PREEDIT_TEXT],
+ 0,
+ text,
+ cursor_pos,
+ visible);
+ }
+}
+
+static void
+_engine_update_auxiliary_text_cb (BusEngineProxy *engine,
+ IBusText *text,
+ gboolean visible,
+ BusInputContext *context)
+{
+ g_assert (BUS_IS_ENGINE_PROXY (engine));
+ g_assert (IBUS_IS_TEXT (text));
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+ g_assert (priv->engine == engine);
+
+ if (priv->capabilities & IBUS_CAP_AUXILIARY_TEXT) {
+ bus_input_context_send_signal (context,
+ "UpdateAuxiliaryText",
+ IBUS_TYPE_TEXT, &text,
+ G_TYPE_BOOLEAN, &visible,
+ G_TYPE_INVALID);
+ }
+ else {
+ g_signal_emit (context,
+ context_signals[UPDATE_AUXILIARY_TEXT],
+ 0,
+ text,
+ visible);
+ }
+}
+
+static void
+_engine_update_lookup_table_cb (BusEngineProxy *engine,
+ IBusLookupTable *table,
+ gboolean visible,
+ BusInputContext *context)
+{
+ g_assert (BUS_IS_ENGINE_PROXY (engine));
+ g_assert (IBUS_IS_LOOKUP_TABLE (table));
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+ g_assert (priv->engine == engine);
+
+ if (priv->capabilities & IBUS_CAP_LOOKUP_TABLE) {
+ bus_input_context_send_signal (context,
+ "UpdateLookupTable",
+ IBUS_TYPE_LOOKUP_TABLE, &table,
+ G_TYPE_BOOLEAN, &visible,
+ G_TYPE_INVALID);
+ }
+ else {
+ g_signal_emit (context,
+ context_signals[UPDATE_LOOKUP_TABLE],
+ 0,
+ table,
+ visible);
+ }
+}
+
+static void
+_engine_register_properties_cb (BusEngineProxy *engine,
+ IBusPropList *prop_list,
+ BusInputContext *context)
+{
+ g_assert (BUS_IS_ENGINE_PROXY (engine));
+ g_assert (IBUS_IS_PROP_LIST (prop_list));
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+ g_assert (priv->engine == engine);
+
+ if (priv->capabilities & IBUS_CAP_PROPERTY) {
+ bus_input_context_send_signal (context,
+ "RegisterProperties",
+ IBUS_TYPE_PROP_LIST, &prop_list,
+ G_TYPE_INVALID);
+ }
+ else {
+ g_signal_emit (context,
+ context_signals[REGISTER_PROPERTIES],
+ 0,
+ prop_list);
+ }
+}
+
+static void
+_engine_update_property_cb (BusEngineProxy *engine,
+ IBusProperty *prop,
+ BusInputContext *context)
+{
+ g_assert (BUS_IS_ENGINE_PROXY (engine));
+ g_assert (IBUS_IS_PROPERTY (prop));
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+ g_assert (priv->engine == engine);
+
+ if (priv->capabilities & IBUS_CAP_PROPERTY) {
+ bus_input_context_send_signal (context,
+ "UpdateProperty",
+ IBUS_TYPE_PROPERTY, &prop,
+ G_TYPE_INVALID);
+ }
+ else {
+ g_signal_emit (context,
+ context_signals[UPDATE_PROPERTY],
+ 0,
+ prop);
+ }
+}
+
+#define DEFINE_FUNCTION(name, Name, signal_name, cap) \
+ static void \
+ _engine_##name##_cb (BusEngineProxy *engine, \
+ BusInputContext *context) \
+ { \
+ g_assert (BUS_IS_ENGINE_PROXY (engine)); \
+ g_assert (BUS_IS_INPUT_CONTEXT (context)); \
+ \
+ BusInputContextPrivate *priv; \
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context); \
+ \
+ g_assert (priv->engine == engine); \
+ \
+ if ((priv->capabilities & (cap)) == (cap)) { \
+ bus_input_context_send_signal (context, \
+ #Name, \
+ G_TYPE_INVALID); \
+ } \
+ else { \
+ g_signal_emit (context, \
+ context_signals[signal_name], \
+ 0); \
+ } \
+}
+
+DEFINE_FUNCTION (show_preedit_text, ShowPreeditText, SHOW_PREEDIT_TEXT, IBUS_CAP_PREEDIT_TEXT)
+DEFINE_FUNCTION (hide_preedit_text, HidePreeditText, HIDE_PREEDIT_TEXT, IBUS_CAP_PREEDIT_TEXT)
+DEFINE_FUNCTION (show_auxiliary_text, ShowAuxiliaryText, SHOW_AUXILIARY_TEXT, IBUS_CAP_AUXILIARY_TEXT)
+DEFINE_FUNCTION (hide_auxiliary_text, HideAuxiliaryText, HIDE_AUXILIARY_TEXT, IBUS_CAP_AUXILIARY_TEXT)
+DEFINE_FUNCTION (show_lookup_table, ShowLookupTable, SHOW_LOOKUP_TABLE, IBUS_CAP_LOOKUP_TABLE)
+DEFINE_FUNCTION (hide_lookup_table, HideLookupTable, HIDE_LOOKUP_TABLE, IBUS_CAP_LOOKUP_TABLE)
+DEFINE_FUNCTION (page_up_lookup_table, PageUpLookupTable, PAGE_UP_LOOKUP_TABLE, IBUS_CAP_LOOKUP_TABLE)
+DEFINE_FUNCTION (page_down_lookup_table, PageDownLookupTable, PAGE_DOWN_LOOKUP_TABLE, IBUS_CAP_LOOKUP_TABLE)
+DEFINE_FUNCTION (cursor_up_lookup_table, CursorUpLookupTable, CURSOR_UP_LOOKUP_TABLE, IBUS_CAP_LOOKUP_TABLE)
+DEFINE_FUNCTION (cursor_down_lookup_table, CursorDownLookupTable, CURSOR_DOWN_LOOKUP_TABLE, IBUS_CAP_LOOKUP_TABLE)
+
+#undef DEFINE_FUNCTION
+
+void
+bus_input_context_enable (BusInputContext *context)
+{
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+ if (priv->engine == NULL)
+ return;
+
+ priv->enabled = TRUE;
+
+ bus_engine_proxy_enable (priv->engine);
+ bus_input_context_send_signal (context,
+ "Enabled",
+ G_TYPE_INVALID);
+ g_signal_emit (context,
+ context_signals[ENABLED],
+ 0);
+ if (priv->has_focus) {
+ bus_engine_proxy_focus_in (priv->engine);
+ }
+}
+
+void
+bus_input_context_disable (BusInputContext *context)
+{
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+ priv->enabled = FALSE;
+
+ if (priv->engine) {
+ if (priv->has_focus) {
+ bus_engine_proxy_focus_out (priv->engine);
+ }
+ bus_engine_proxy_disable (priv->engine);
+ }
+
+ bus_input_context_send_signal (context,
+ "Disabled",
+ G_TYPE_INVALID);
+ g_signal_emit (context,
+ context_signals[DISABLED],
+ 0);
+}
+
+
+void
+bus_input_context_set_engine (BusInputContext *context,
+ BusEngineProxy *engine)
+{
+
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+ if (priv->engine != NULL) {
+ g_signal_handlers_disconnect_by_func (priv->engine, _engine_destroy_cb, context);
+ ibus_object_destroy ((IBusObject *) priv->engine);
+ g_object_unref (priv->engine);
+ priv->engine = NULL;
+ }
+
+ if (engine == NULL) {
+ bus_input_context_disable (context);
+ g_signal_emit (context,
+ context_signals[ENGINE_CHANGED],
+ 0);
+ return;
+ }
+
+ priv->engine = engine;
+ g_object_ref (priv->engine);
+
+ gint i;
+ const static struct {
+ const gchar *name;
+ GCallback callback;
+ } signals [] = {
+ { "commit-text", G_CALLBACK (_engine_commit_text_cb) },
+ { "forward-key-event", G_CALLBACK (_engine_forward_key_event_cb) },
+ { "update-preedit-text", G_CALLBACK (_engine_update_preedit_text_cb) },
+ { "show-preedit-text", G_CALLBACK (_engine_show_preedit_text_cb) },
+ { "hide-preedit-text", G_CALLBACK (_engine_hide_preedit_text_cb) },
+ { "update-auxiliary-text", G_CALLBACK (_engine_update_auxiliary_text_cb) },
+ { "show-auxiliary-text", G_CALLBACK (_engine_show_auxiliary_text_cb) },
+ { "hide-auxiliary-text", G_CALLBACK (_engine_hide_auxiliary_text_cb) },
+ { "update-lookup-table", G_CALLBACK (_engine_update_lookup_table_cb) },
+ { "show-lookup-table", G_CALLBACK (_engine_show_lookup_table_cb) },
+ { "hide-lookup-table", G_CALLBACK (_engine_hide_lookup_table_cb) },
+ { "page-up-lookup-table", G_CALLBACK (_engine_page_up_lookup_table_cb) },
+ { "page-down-lookup-table", G_CALLBACK (_engine_page_down_lookup_table_cb) },
+ { "cursor-up-lookup-table", G_CALLBACK (_engine_cursor_up_lookup_table_cb) },
+ { "cursor-down-lookup-table", G_CALLBACK (_engine_cursor_down_lookup_table_cb) },
+ { "register-properties", G_CALLBACK (_engine_register_properties_cb) },
+ { "update-property", G_CALLBACK (_engine_update_property_cb) },
+ { "destroy", G_CALLBACK (_engine_destroy_cb) },
+ { NULL, 0 }
+ };
+
+ for (i = 0; signals[i].name != NULL; i++) {
+ g_signal_connect (priv->engine,
+ signals[i].name,
+ signals[i].callback,
+ context);
+ }
+
+ g_signal_emit (context,
+ context_signals[ENGINE_CHANGED],
+ 0);
+}
+
+static gboolean
+bus_input_context_filter_keyboard_shortcuts (BusInputContext *context,
+ guint keyval,
+ guint modifiers)
+{
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+
+ BusInputContextPrivate *priv;
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+ static GQuark trigger;
+ static GQuark next_factory;
+ static GQuark prev_factory;
+
+ GQuark event;
+
+ if (trigger == 0) {
+ trigger = g_quark_from_static_string ("trigger");
+ next_factory = g_quark_from_static_string ("next-engine");
+ prev_factory = g_quark_from_static_string ("prev-engine");
+ }
+
+ event = ibus_hotkey_profile_filter_key_event (BUS_DEFAULT_HOTKEY_PROFILE,
+ keyval,
+ modifiers,
+ 0);
+
+ if (event == trigger) {
+ if (priv->engine == NULL) {
+ g_signal_emit (context, context_signals[REQUEST_ENGINE], 0, NULL);
+ }
+
+ if (priv->engine == NULL) {
+ return FALSE;
+ }
+
+ if (priv->enabled) {
+ bus_input_context_disable (context);
+ }
+ else {
+ bus_input_context_enable (context);
+ }
+
+ return TRUE;
+ }
+ else if (event == next_factory) {
+ return TRUE;
+ }
+ else if (event == prev_factory) {
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+
+static gboolean
+bus_input_context_send_signal (BusInputContext *context,
+ const gchar *signal_name,
+ GType first_arg_type,
+ ...)
+{
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+ g_assert (signal_name != NULL);
+
+ va_list args;
+ gboolean retval;
+ IBusMessage *message;
+ BusInputContextPrivate *priv;
+
+ priv = BUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+ g_assert (priv->connection != NULL);
+
+ message = ibus_message_new_signal (ibus_service_get_path ((IBusService *)context),
+ IBUS_INTERFACE_INPUT_CONTEXT,
+ signal_name);
+
+ ibus_message_set_sender (message, IBUS_SERVICE_IBUS);
+
+ va_start (args, first_arg_type);
+ ibus_message_append_args_valist (message, first_arg_type, args);
+ va_end (args);
+
+ retval = ibus_connection_send ((IBusConnection *)priv->connection, message);
+ ibus_message_unref (message);
+
+ return retval;
+}