summaryrefslogtreecommitdiffstats
path: root/src/ibusbus.c
diff options
context:
space:
mode:
authorHuang Peng <shawn.p.huang@gmail.com>2009-02-05 10:39:56 +0800
committerHuang Peng <shawn.p.huang@gmail.com>2009-02-05 10:39:56 +0800
commitaedad1ea0a7fef604aa27f4b58433fd8f2ece29e (patch)
treeffcb531d8474bde18b90341bcd4eb639edd74525 /src/ibusbus.c
parent41ad46305a88637dd99f00a2d2a3f455505d357b (diff)
downloadibus-aedad1ea0a7fef604aa27f4b58433fd8f2ece29e.tar.gz
ibus-aedad1ea0a7fef604aa27f4b58433fd8f2ece29e.tar.xz
ibus-aedad1ea0a7fef604aa27f4b58433fd8f2ece29e.zip
re-implement ibus in c language.
Diffstat (limited to 'src/ibusbus.c')
-rw-r--r--src/ibusbus.c773
1 files changed, 773 insertions, 0 deletions
diff --git a/src/ibusbus.c b/src/ibusbus.c
new file mode 100644
index 0000000..be72770
--- /dev/null
+++ b/src/ibusbus.c
@@ -0,0 +1,773 @@
+/* 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 <gio/gio.h>
+#include "ibusbus.h"
+#include "ibusinternal.h"
+#include "ibusshare.h"
+#include "ibusconnection.h"
+
+#define IBUS_BUS_GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_BUS, IBusBusPrivate))
+
+enum {
+ CONNECTED,
+ DISCONNECTED,
+ NAME_OWNER_CHANGED,
+ LAST_SIGNAL,
+};
+
+
+/* IBusBusPriv */
+struct _IBusBusPrivate {
+ GFileMonitor *monitor;
+ IBusConnection *connection;
+ gboolean watch_dbus_signal;
+};
+typedef struct _IBusBusPrivate IBusBusPrivate;
+
+static guint bus_signals[LAST_SIGNAL] = { 0 };
+
+/* functions prototype */
+static void ibus_bus_class_init (IBusBusClass *klass);
+static void ibus_bus_init (IBusBus *bus);
+static void ibus_bus_destroy (IBusObject *object);
+static void ibus_bus_watch_dbus_signal
+ (IBusBus *bus);
+static void ibus_bus_unwatch_dbus_signal
+ (IBusBus *bus);
+static IBusObjectClass *parent_class = NULL;
+
+GType
+ibus_bus_get_type (void)
+{
+ static GType type = 0;
+
+ static const GTypeInfo type_info = {
+ sizeof (IBusBusClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) ibus_bus_class_init,
+ NULL, /* class finalize */
+ NULL, /* class data */
+ sizeof (IBusBus),
+ 0,
+ (GInstanceInitFunc) ibus_bus_init,
+ };
+
+ if (type == 0) {
+ type = g_type_register_static (IBUS_TYPE_OBJECT,
+ "IBusBus",
+ &type_info,
+ (GTypeFlags)0);
+ }
+
+ return type;
+}
+
+IBusBus *
+ibus_bus_new (void)
+{
+ IBusBus *bus = IBUS_BUS (g_object_new (IBUS_TYPE_BUS, NULL));
+
+ return bus;
+}
+
+static void
+ibus_bus_class_init (IBusBusClass *klass)
+{
+ IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (klass);
+
+ parent_class = (IBusObjectClass *) g_type_class_peek_parent (klass);
+
+ g_type_class_add_private (klass, sizeof (IBusBusPrivate));
+
+ ibus_object_class->destroy = ibus_bus_destroy;
+
+ // install signals
+ bus_signals[CONNECTED] =
+ g_signal_new (I_("connected"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ ibus_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ bus_signals[DISCONNECTED] =
+ g_signal_new (I_("disconnected"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ ibus_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+#if 0
+ bus_signals[NAME_OWNER_CHANGED] =
+ g_signal_new (I_("name-owner-changed"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ ibus_marshal_VOID__STRING_STRING_STRING,
+ G_TYPE_NONE,
+ 3,
+ G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE,
+ G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE,
+ G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE
+ );
+#endif
+}
+
+#if 0
+static gboolean
+_connection_dbus_signal_cb (IBusConnection *connection,
+ DBusMessage *message,
+ IBusBus *bus)
+{
+ g_assert (IBUS_IS_BUS (bus));
+ g_assert (message != NULL);
+ g_assert (IBUS_IS_CONNECTION (connection));
+
+ IBusBusPrivate *priv;
+ priv = IBUS_BUS_GET_PRIVATE (bus);
+
+ if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
+ DBusError error;
+ const gchar *name;
+ const gchar *old_name;
+ const gchar *new_name;
+ gboolean retval;
+
+ dbus_error_init (&error);
+ retval = dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_STRING, &old_name,
+ DBUS_TYPE_STRING, &new_name,
+ DBUS_TYPE_INVALID);
+ if (!retval) {
+ g_warning ("%s: %s", error.name, error.message);
+ dbus_error_free (&error);
+ }
+ else {
+ g_signal_emit (bus,
+ bus_signals[NAME_OWNER_CHANGED],
+ 0,
+ name,
+ old_name,
+ new_name);
+ }
+ }
+
+ return FALSE;
+}
+#endif
+
+static void
+_connection_destroy_cb (IBusConnection *connection,
+ IBusBus *bus)
+{
+ g_assert (IBUS_IS_BUS (bus));
+ g_assert (IBUS_IS_CONNECTION (connection));
+
+ IBusBusPrivate *priv;
+ priv = IBUS_BUS_GET_PRIVATE (bus);
+
+ g_assert (priv->connection == connection);
+ g_object_unref (priv->connection);
+ priv->connection = NULL;
+
+ g_signal_emit (bus, bus_signals[DISCONNECTED], 0);
+}
+
+static void
+ibus_bus_connect (IBusBus *bus)
+{
+ IBusBusPrivate *priv;
+ priv = IBUS_BUS_GET_PRIVATE (bus);
+
+ g_assert (priv->connection == NULL);
+
+ priv->connection = ibus_connection_open (ibus_get_address ());
+
+ if (priv->connection) {
+ ibus_bus_hello (bus);
+#if 0
+ g_signal_connect (priv->connection,
+ "dbus-signal",
+ (GCallback) _connection_dbus_signal_cb,
+ bus);
+#endif
+ g_signal_connect (priv->connection,
+ "destroy",
+ (GCallback) _connection_destroy_cb,
+ bus);
+ g_signal_emit (bus, bus_signals[CONNECTED], 0);
+
+ if (priv->watch_dbus_signal) {
+ ibus_bus_watch_dbus_signal (bus);
+ }
+ }
+}
+
+static void
+_changed_cb (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ IBusBus *bus)
+{
+ static GFile *socket_file = NULL;
+
+ if (socket_file == NULL) {
+ socket_file = g_file_new_for_path (ibus_get_socket_path ());
+ }
+
+ if (event_type == G_FILE_MONITOR_EVENT_CREATED) {
+ if (g_file_equal (file, socket_file)) {
+ ibus_bus_connect (bus);
+ }
+ }
+}
+
+static void
+ibus_bus_init (IBusBus *bus)
+{
+ gchar *path;
+ GFile *file;
+ IBusBusPrivate *priv;
+ priv = IBUS_BUS_GET_PRIVATE (bus);
+
+ priv->connection = NULL;
+ priv->watch_dbus_signal = FALSE;
+
+ ibus_bus_connect (bus);
+
+ path = g_strdup_printf ("/tmp/ibus-%s/", ibus_get_user_name ());
+ file = g_file_new_for_path (path);
+ priv->monitor = g_file_monitor_directory (file, 0, NULL, NULL);
+
+ g_signal_connect (priv->monitor, "changed", (GCallback) _changed_cb, bus);
+
+ g_object_unref (file);
+ g_free (path);
+}
+
+static void
+ibus_bus_destroy (IBusObject *object)
+{
+ IBusBus *bus;
+ IBusBusPrivate *priv;
+
+ bus = IBUS_BUS (object);
+ priv = IBUS_BUS_GET_PRIVATE (bus);
+
+ if (priv->monitor) {
+ g_object_unref (priv->monitor);
+ priv->monitor = NULL;
+ }
+
+ if (priv->connection) {
+ ibus_object_destroy (IBUS_OBJECT (priv->connection));
+ priv->connection = NULL;
+ }
+
+ IBUS_OBJECT_CLASS (parent_class)->destroy (object);
+}
+
+gboolean
+ibus_bus_is_connected (IBusBus *bus)
+{
+ g_assert (IBUS_IS_BUS (bus));
+
+ IBusBusPrivate *priv;
+ priv = IBUS_BUS_GET_PRIVATE (bus);
+
+ if (priv->connection) {
+ return ibus_connection_is_connected (priv->connection);
+ }
+
+ return FALSE;
+}
+
+
+IBusInputContext *
+ibus_bus_create_input_context (IBusBus *bus,
+ const gchar *client_name)
+{
+ g_assert (IBUS_IS_BUS (bus));
+ g_assert (client_name != NULL);
+ g_assert (ibus_bus_is_connected (bus));
+
+ gchar *path;
+ DBusMessage *call = NULL;
+ DBusMessage *reply = NULL;
+ IBusError *error;
+ IBusInputContext *context = NULL;
+ IBusBusPrivate *priv;
+ priv = IBUS_BUS_GET_PRIVATE (bus);
+
+ call = ibus_message_new_method_call (IBUS_SERVICE_IBUS,
+ IBUS_PATH_IBUS,
+ IBUS_INTERFACE_IBUS,
+ "CreateInputContext");
+ ibus_message_append_args (call,
+ G_TYPE_STRING, &client_name,
+ G_TYPE_INVALID);
+
+ reply = ibus_connection_send_with_reply_and_block (priv->connection,
+ call,
+ -1,
+ &error);
+ ibus_message_unref (call);
+
+ if (reply == NULL) {
+ g_warning ("%s: %s", error->name, error->message);
+ ibus_error_free (error);
+ return NULL;
+ }
+
+ if ((error = ibus_error_new_from_message (reply)) != NULL) {
+ g_warning ("%s: %s", error->name, error->message);
+ ibus_message_unref (reply);
+ ibus_error_free (error);
+ return NULL;
+ }
+
+ if (!ibus_message_get_args (reply,
+ &error,
+ IBUS_TYPE_OBJECT_PATH, &path,
+ G_TYPE_INVALID)) {
+ g_warning ("%s: %s", error->name, error->message);
+ ibus_message_unref (reply);
+ ibus_error_free (error);
+
+ return NULL;
+ }
+
+ context = ibus_input_context_new (path, priv->connection);
+ ibus_message_unref (reply);
+
+ return context;
+}
+
+static void
+ibus_bus_watch_dbus_signal (IBusBus *bus)
+{
+ g_assert (IBUS_IS_BUS (bus));
+
+ const gchar *rule;
+
+ rule = "type='signal'," \
+ "path='" DBUS_PATH_DBUS "'," \
+ "interface='" DBUS_INTERFACE_DBUS "'";
+
+ ibus_bus_add_match (bus, rule);
+
+}
+
+static void
+ibus_bus_unwatch_dbus_signal (IBusBus *bus)
+{
+ g_assert (IBUS_IS_BUS (bus));
+ g_assert (ibus_bus_is_connected (bus));
+
+ const gchar *rule;
+
+ rule = "type='signal'," \
+ "path='" DBUS_PATH_DBUS "'," \
+ "interface='" DBUS_INTERFACE_DBUS "'";
+
+ ibus_bus_remove_match (bus, rule);
+}
+
+void
+ibus_bus_set_watch_dbus_signal (IBusBus *bus,
+ gboolean watch)
+{
+ g_assert (IBUS_IS_BUS (bus));
+
+ IBusBusPrivate *priv;
+ priv = IBUS_BUS_GET_PRIVATE (bus);
+
+ if (priv->watch_dbus_signal == watch)
+ return;
+
+ priv->watch_dbus_signal = watch;
+
+ if (ibus_bus_is_connected (bus)) {
+ if (watch) {
+ ibus_bus_watch_dbus_signal (bus);
+ }
+ else {
+ ibus_bus_unwatch_dbus_signal (bus);
+ }
+ }
+}
+
+
+static gboolean
+ibus_bus_call (IBusBus *bus,
+ const gchar *name,
+ const gchar *path,
+ const gchar *interface,
+ const gchar *member,
+ GType first_arg_type,
+ ...)
+{
+ g_assert (IBUS_IS_BUS (bus));
+ g_assert (ibus_bus_is_connected (bus));
+ g_assert (name != NULL);
+ g_assert (path != NULL);
+ g_assert (interface != NULL);
+ g_assert (member);
+
+ IBusMessage *message, *reply;
+ IBusError *error;
+ va_list args;
+ GType type;
+ gboolean retval;
+ IBusBusPrivate *priv;
+
+ priv = IBUS_BUS_GET_PRIVATE (bus);
+
+ message = ibus_message_new_method_call (name, path, interface, member);
+
+ va_start (args, first_arg_type);
+ ibus_message_append_args_valist (message, first_arg_type, args);
+ va_end (args);
+
+ reply = ibus_connection_send_with_reply_and_block (
+ priv->connection,
+ message,
+ -1,
+ &error);
+ ibus_message_unref (message);
+
+ if (reply == NULL) {
+ g_warning ("%s : %s", error->name, error->message);
+ ibus_error_free (error);
+ return FALSE;
+ }
+
+ if ((error = ibus_error_new_from_message (reply)) != NULL) {
+ g_warning ("%s : %s", error->name, error->message);
+ ibus_error_free (error);
+ ibus_message_unref (reply);
+ return FALSE;
+ }
+
+ va_start (args, first_arg_type);
+
+ type = first_arg_type;
+
+ while (type != G_TYPE_INVALID) {
+ va_arg (args, gpointer);
+ type = va_arg (args, GType);
+ }
+
+ type = va_arg (args, GType);
+ if (type != G_TYPE_INVALID) {
+ retval = ibus_message_get_args_valist (reply, &error, type, args);
+ }
+ else {
+ retval = TRUE;
+ }
+ va_end (args);
+
+ ibus_message_unref (reply);
+
+ if (!retval) {
+ g_warning ("%s: %s", error->name, error->message);
+ ibus_error_free (error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+const gchar *
+ibus_bus_hello (IBusBus *bus)
+{
+ g_assert (IBUS_IS_BUS (bus));
+
+ gchar *unique_name = NULL;
+ gboolean result;
+
+ result = ibus_bus_call (bus,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS,
+ "Hello",
+ G_TYPE_INVALID,
+ G_TYPE_STRING, &unique_name,
+ G_TYPE_INVALID);
+
+ if (result)
+ return unique_name;
+
+ return NULL;
+}
+
+guint
+ibus_bus_request_name (IBusBus *bus,
+ const gchar *name,
+ guint flags)
+{
+ g_assert (IBUS_IS_BUS (bus));
+
+ guint retval;
+ gboolean result;
+
+ result = ibus_bus_call (bus,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS,
+ "RequestName",
+ G_TYPE_STRING, &name,
+ G_TYPE_UINT, &flags,
+ G_TYPE_INVALID,
+ G_TYPE_UINT, &retval,
+ G_TYPE_INVALID);
+
+ if (result)
+ return retval;
+
+ return 0;
+}
+
+guint
+ibus_bus_release_name (IBusBus *bus,
+ const gchar *name)
+{
+ g_assert (IBUS_IS_BUS (bus));
+
+ guint retval;
+ gboolean result;
+
+ result = ibus_bus_call (bus,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS,
+ "ReleaseName",
+ G_TYPE_STRING, &name,
+ G_TYPE_INVALID,
+ G_TYPE_UINT, &retval,
+ G_TYPE_INVALID);
+
+ if (result)
+ return retval;
+
+ return 0;
+}
+
+gboolean
+ibus_bus_name_has_owner (IBusBus *bus,
+ const gchar *name)
+{
+ g_assert (IBUS_IS_BUS (bus));
+
+ gboolean retval;
+ gboolean result;
+
+ result = ibus_bus_call (bus,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS,
+ "NameHasOwner",
+ G_TYPE_STRING, &name,
+ G_TYPE_INVALID,
+ G_TYPE_BOOLEAN, &retval,
+ G_TYPE_INVALID);
+
+ if (result)
+ return retval;
+
+ return FALSE;
+}
+
+GList *
+ibus_bus_list_names (IBusBus *bus)
+{
+ return NULL;
+}
+
+void
+ibus_bus_add_match (IBusBus *bus,
+ const gchar *rule)
+{
+ g_assert (IBUS_IS_BUS (bus));
+
+ gboolean result;
+
+ result = ibus_bus_call (bus,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS,
+ "AddMatch",
+ G_TYPE_STRING, &rule,
+ G_TYPE_INVALID,
+ G_TYPE_INVALID);
+}
+
+void
+ibus_bus_remove_match (IBusBus *bus,
+ const gchar *rule)
+{
+ g_assert (IBUS_IS_BUS (bus));
+
+ gboolean result;
+
+ result = ibus_bus_call (bus,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS,
+ "RemoveMatch",
+ G_TYPE_STRING, &rule,
+ G_TYPE_INVALID,
+ G_TYPE_INVALID);
+}
+
+const gchar *
+ibus_bus_get_name_owner (IBusBus *bus,
+ const gchar *name)
+{
+ g_assert (IBUS_IS_BUS (bus));
+
+ gchar *owner = NULL;
+ gboolean result;
+
+ result = ibus_bus_call (bus,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS,
+ "RemoveMatch",
+ G_TYPE_STRING, &name,
+ G_TYPE_INVALID,
+ G_TYPE_STRING, &owner,
+ G_TYPE_INVALID);
+
+ if (result)
+ return owner;
+
+ return NULL;
+}
+
+IBusConnection *
+ibus_bus_get_connection (IBusBus *bus)
+{
+ g_assert (IBUS_IS_BUS (bus));
+
+ IBusBusPrivate *priv;
+ priv = IBUS_BUS_GET_PRIVATE (bus);
+
+ return priv->connection;
+}
+
+gboolean
+ibus_bus_kill (IBusBus *bus)
+{
+ g_assert (IBUS_IS_BUS (bus));
+
+ gboolean result;
+ result = ibus_bus_call (bus,
+ IBUS_SERVICE_IBUS,
+ IBUS_PATH_IBUS,
+ IBUS_INTERFACE_IBUS,
+ "Kill",
+ G_TYPE_INVALID,
+ G_TYPE_INVALID);
+ return result;
+}
+
+gboolean
+ibus_bus_register_component (IBusBus *bus,
+ IBusComponent *component)
+{
+ g_assert (IBUS_IS_BUS (bus));
+ g_assert (IBUS_IS_COMPONENT (component));
+
+ gboolean result;
+
+ result = ibus_bus_call (bus,
+ IBUS_SERVICE_IBUS,
+ IBUS_PATH_IBUS,
+ IBUS_INTERFACE_IBUS,
+ "RegisterComponent",
+ IBUS_TYPE_COMPONENT, &component,
+ G_TYPE_INVALID,
+ G_TYPE_INVALID);
+
+ return result;
+
+
+#if 0
+ IBusMessage *message, *reply;
+ IBusError *error;
+
+ IBusBusPrivate *priv;
+ priv = IBUS_BUS_GET_PRIVATE (bus);
+
+ message = ibus_message_new_method_call (IBUS_SERVICE_IBUS,
+ IBUS_PATH_IBUS,
+ IBUS_INTERFACE_IBUS,
+ "RegisterComponent");
+
+ ibus_message_append_args (message,
+ IBUS_TYPE_COMPONENT, &component,
+ G_TYPE_INVALID);
+
+ reply = ibus_connection_send_with_reply_and_block (
+ priv->connection,
+ message,
+ -1,
+ &error);
+ ibus_message_unref (message);
+
+ if (reply == NULL) {
+ g_warning ("%s : %s", error->name, error->message);
+ ibus_error_free (error);
+ return FALSE;
+ }
+
+ if ((error = ibus_error_from_message (reply)) != NULL) {
+ g_warning ("%s : %s", error->name, error->message);
+ ibus_error_free (error);
+ ibus_message_unref (reply);
+ return FALSE;
+ }
+
+ return TRUE;
+#endif
+}
+
+GList *
+ibus_bus_list_engines (IBusBus *bus)
+{
+ return NULL;
+}
+
+GList *
+ibus_bus_list_active_engines (IBusBus *bus)
+{
+ return NULL;
+}