summaryrefslogtreecommitdiffstats
path: root/src/ibusproxy.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ibusproxy.c')
-rw-r--r--src/ibusproxy.c638
1 files changed, 638 insertions, 0 deletions
diff --git a/src/ibusproxy.c b/src/ibusproxy.c
new file mode 100644
index 0000000..5ef3b40
--- /dev/null
+++ b/src/ibusproxy.c
@@ -0,0 +1,638 @@
+/* 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 <stdarg.h>
+#include "ibusmessage.h"
+#include "ibusproxy.h"
+#include "ibusinternal.h"
+
+#define IBUS_PROXY_GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_PROXY, IBusProxyPrivate))
+
+enum {
+ IBUS_SIGNAL,
+ LAST_SIGNAL,
+};
+
+enum {
+ PROP_0,
+ PROP_NAME,
+ PROP_PATH,
+ PROP_INTERFACE,
+ PROP_CONNECTION,
+};
+
+
+/* IBusProxyPriv */
+struct _IBusProxyPrivate {
+ gchar *name;
+ gchar *path;
+ gchar *interface;
+ IBusConnection *connection;
+};
+typedef struct _IBusProxyPrivate IBusProxyPrivate;
+
+static guint proxy_signals[LAST_SIGNAL] = { 0 };
+
+/* functions prototype */
+static void ibus_proxy_class_init (IBusProxyClass *klass);
+static void ibus_proxy_init (IBusProxy *proxy);
+static GObject *ibus_proxy_constructor (GType type,
+ guint n_construct_params,
+ GObjectConstructParam *construct_params);
+static void ibus_proxy_destroy (IBusProxy *proxy);
+static void ibus_proxy_set_property(IBusProxy *proxy,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void ibus_proxy_get_property(IBusProxy *proxy,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static gboolean ibus_proxy_ibus_signal (IBusProxy *proxy,
+ IBusMessage *message);
+
+static IBusObjectClass *parent_class = NULL;
+
+GType
+ibus_proxy_get_type (void)
+{
+ static GType type = 0;
+
+ static const GTypeInfo type_info = {
+ sizeof (IBusProxyClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) ibus_proxy_class_init,
+ NULL, /* class finalize */
+ NULL, /* class data */
+ sizeof (IBusProxy),
+ 0,
+ (GInstanceInitFunc) ibus_proxy_init,
+ };
+
+ if (type == 0) {
+ type = g_type_register_static (IBUS_TYPE_OBJECT,
+ "IBusProxy",
+ &type_info,
+ (GTypeFlags)0);
+ }
+ return type;
+}
+
+IBusProxy *
+ibus_proxy_new (const gchar *name,
+ const gchar *path,
+ IBusConnection *connection)
+{
+ g_assert (name != NULL);
+ g_assert (path != NULL);
+ g_assert (IBUS_IS_CONNECTION (connection));
+
+ IBusProxy *proxy;
+
+ proxy = IBUS_PROXY (g_object_new (IBUS_TYPE_PROXY,
+ "name", name,
+ "path", path,
+ "connection", connection,
+ NULL));
+
+ return proxy;
+}
+
+static void
+ibus_proxy_class_init (IBusProxyClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (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 (IBusProxyPrivate));
+
+ gobject_class->constructor = ibus_proxy_constructor;
+ gobject_class->set_property = (GObjectSetPropertyFunc) ibus_proxy_set_property;
+ gobject_class->get_property = (GObjectGetPropertyFunc) ibus_proxy_get_property;
+
+ ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_proxy_destroy;
+
+ klass->ibus_signal = ibus_proxy_ibus_signal;
+
+ /* install properties */
+ g_object_class_install_property (gobject_class,
+ PROP_NAME,
+ g_param_spec_string ("name",
+ "service name",
+ "The service name of proxy object",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (gobject_class,
+ PROP_PATH,
+ g_param_spec_string ("path",
+ "object path",
+ "The path of proxy object",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (gobject_class,
+ PROP_INTERFACE,
+ g_param_spec_string ("interface",
+ "interface",
+ "The interface of proxy object",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (gobject_class,
+ PROP_CONNECTION,
+ g_param_spec_object ("connection",
+ "object path",
+ "The path of proxy object",
+ IBUS_TYPE_CONNECTION,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ /* install signals */
+ proxy_signals[IBUS_SIGNAL] =
+ g_signal_new (I_("ibus-signal"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (IBusProxyClass, ibus_signal),
+ NULL, NULL,
+ ibus_marshal_BOOLEAN__POINTER,
+ G_TYPE_BOOLEAN,
+ 1, G_TYPE_POINTER);
+
+}
+
+static gboolean
+_connection_ibus_signal_cb (IBusConnection *connection,
+ IBusMessage *message,
+ IBusProxy *proxy)
+{
+ if (ibus_proxy_handle_signal (proxy, message)) {
+ g_signal_stop_emission_by_name (connection, "ibus-signal");
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+_connection_destroy_cb (IBusConnection *connection,
+ IBusProxy *proxy)
+{
+ IBusProxyPrivate *priv;
+ priv = IBUS_PROXY_GET_PRIVATE (proxy);
+
+ g_assert (priv->connection == connection);
+
+ g_object_unref (connection);
+ priv->connection = NULL;
+
+ ibus_object_destroy ((IBusObject *) proxy);
+}
+
+static GObject *
+ibus_proxy_constructor (GType type,
+ guint n_construct_params,
+ GObjectConstructParam *construct_params)
+{
+ GObject *obj;
+ IBusProxy *proxy;
+ IBusProxyPrivate *priv;
+
+ obj = G_OBJECT_CLASS (parent_class)->constructor (type, n_construct_params, construct_params);
+
+ proxy = IBUS_PROXY (obj);
+ priv = IBUS_PROXY_GET_PRIVATE (proxy);
+
+ if (priv->connection != NULL) {
+ if (priv->name != NULL) {
+
+ IBusError *error;
+ gchar *rule;
+
+ rule = g_strdup_printf ("type='signal',"
+ "sender='" DBUS_SERVICE_DBUS "',"
+ "path='" DBUS_PATH_DBUS "',"
+ "interface='" DBUS_INTERFACE_DBUS "',"
+ "member='NameOwnerChanged',"
+ "arg0='%s'",
+ priv->name);
+
+ if (!ibus_connection_call (priv->connection,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS,
+ "AddMatch",
+ &error,
+ G_TYPE_STRING, &rule,
+ G_TYPE_INVALID,
+ G_TYPE_INVALID)) {
+ g_warning ("%s: %s", error->name, error->message);
+ ibus_error_free (error);
+ }
+ g_free (rule);
+ }
+ g_signal_connect (priv->connection,
+ "ibus-signal",
+ (GCallback) _connection_ibus_signal_cb,
+ proxy);
+
+ g_signal_connect (priv->connection,
+ "destroy",
+ (GCallback) _connection_destroy_cb,
+ proxy);
+ }
+
+ return obj;
+}
+
+static void
+ibus_proxy_init (IBusProxy *proxy)
+{
+ IBusProxyPrivate *priv;
+ priv = IBUS_PROXY_GET_PRIVATE (proxy);
+
+ priv->name = NULL;
+ priv->path = NULL;
+ priv->interface = NULL;
+ priv->connection = NULL;
+}
+
+static void
+ibus_proxy_destroy (IBusProxy *proxy)
+{
+ IBusProxyPrivate *priv;
+ priv = IBUS_PROXY_GET_PRIVATE (proxy);
+
+ if (priv->connection) {
+
+ g_signal_handlers_disconnect_by_func (priv->connection,
+ (GCallback) _connection_ibus_signal_cb,
+ proxy);
+ g_signal_handlers_disconnect_by_func (priv->connection,
+ (GCallback) _connection_destroy_cb,
+ proxy);
+
+ if (priv->name != NULL) {
+
+ IBusError *error;
+ gchar *rule;
+
+ rule = g_strdup_printf ("type='signal',"
+ "sender='" DBUS_SERVICE_DBUS "',"
+ "path='" DBUS_PATH_DBUS "',"
+ "interface='" DBUS_INTERFACE_DBUS "',"
+ "member='NameOwnerChanged',"
+ "arg0='%s'",
+ priv->name);
+
+ if (!ibus_connection_call (priv->connection,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS,
+ "RemoveMatch",
+ &error,
+ G_TYPE_STRING, &rule,
+ G_TYPE_INVALID,
+ G_TYPE_INVALID)) {
+
+ g_warning ("%s: %s", error->name, error->message);
+ ibus_error_free (error);
+ }
+ g_free (rule);
+ }
+ }
+
+ g_free (priv->name);
+ g_free (priv->path);
+ g_free (priv->interface);
+
+ priv->name = NULL;
+ priv->path = NULL;
+ priv->interface = NULL;
+
+ if (priv->connection) {
+ g_object_unref (priv->connection);
+ priv->connection = NULL;
+ }
+
+ IBUS_OBJECT_CLASS(parent_class)->destroy (IBUS_OBJECT (proxy));
+}
+
+static void
+ibus_proxy_set_property (IBusProxy *proxy,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ IBusProxyPrivate *priv;
+ priv = IBUS_PROXY_GET_PRIVATE (proxy);
+
+ switch (prop_id) {
+ case PROP_NAME:
+ g_assert (priv->name == NULL);
+ priv->name = g_strdup (g_value_get_string (value));
+ break;
+ case PROP_PATH:
+ g_assert (priv->path == NULL);
+ priv->path = g_strdup (g_value_get_string (value));
+ break;
+ case PROP_INTERFACE:
+ g_assert (priv->interface == NULL);
+ priv->interface = g_strdup (g_value_get_string (value));
+ break;
+ case PROP_CONNECTION:
+ g_assert (priv->connection == NULL);
+ priv->connection = IBUS_CONNECTION (g_value_get_object (value));
+ g_object_ref (priv->connection);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (proxy, prop_id, pspec);
+ }
+}
+
+static void
+ibus_proxy_get_property (IBusProxy *proxy,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id) {
+ case PROP_NAME:
+ g_value_set_string (value, ibus_proxy_get_name (proxy));
+ break;
+ case PROP_PATH:
+ g_value_set_string (value, ibus_proxy_get_path (proxy));
+ break;
+ case PROP_INTERFACE:
+ g_value_set_string (value, ibus_proxy_get_interface (proxy));
+ break;
+ case PROP_CONNECTION:
+ g_value_set_object (value, ibus_proxy_get_connection (proxy));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (proxy, prop_id, pspec);
+ }
+}
+
+
+gboolean
+ibus_proxy_handle_signal (IBusProxy *proxy,
+ DBusMessage *message)
+{
+ g_assert (IBUS_IS_PROXY (proxy));
+ g_assert (message != NULL);
+
+ gboolean retval = FALSE;
+ IBusProxyPrivate *priv;
+ priv = IBUS_PROXY_GET_PRIVATE (proxy);
+
+ if (ibus_message_is_signal (message, DBUS_SERVICE_DBUS, "NameOwnerChanged")) {
+ gchar *name, *old_name, *new_name;
+ IBusError *error;
+
+ if (!ibus_message_get_args (message,
+ &error,
+ G_TYPE_STRING, &name,
+ G_TYPE_STRING, &old_name,
+ G_TYPE_STRING, &new_name,
+ G_TYPE_INVALID)) {
+ g_warning ("%s :%s", error->name, error->message);
+ ibus_error_free (error);
+ }
+
+ if (g_strcmp0 (priv->name, old_name) == 0) {
+ ibus_object_destroy (IBUS_OBJECT (proxy));
+ return FALSE;
+ }
+ }
+
+ if (g_strcmp0 (ibus_message_get_path (message), priv->path) == 0) {
+ g_signal_emit (proxy, proxy_signals[IBUS_SIGNAL], 0, message, &retval);
+ }
+
+ return retval;
+}
+
+static gboolean
+ibus_proxy_ibus_signal (IBusProxy *proxy,
+ DBusMessage *message)
+{
+ return FALSE;
+}
+
+
+const gchar *
+ibus_proxy_get_name (IBusProxy *proxy)
+{
+ IBusProxyPrivate *priv;
+ priv = IBUS_PROXY_GET_PRIVATE (proxy);
+
+ return priv->name;
+}
+
+const gchar *
+ibus_proxy_get_path (IBusProxy *proxy)
+{
+ IBusProxyPrivate *priv;
+ priv = IBUS_PROXY_GET_PRIVATE (proxy);
+
+ return priv->path;
+}
+
+const gchar *
+ibus_proxy_get_interface (IBusProxy *proxy)
+{
+ IBusProxyPrivate *priv;
+ priv = IBUS_PROXY_GET_PRIVATE (proxy);
+
+ return priv->interface;
+}
+
+IBusConnection *
+ibus_proxy_get_connection (IBusProxy *proxy)
+{
+ IBusProxyPrivate *priv;
+ priv = IBUS_PROXY_GET_PRIVATE (proxy);
+
+ return priv->connection;
+}
+
+gboolean
+ibus_proxy_send (IBusProxy *proxy,
+ DBusMessage *message)
+{
+ g_assert (IBUS_IS_PROXY (proxy));
+ g_assert (message != NULL);
+
+ IBusProxyPrivate *priv;
+ priv = IBUS_PROXY_GET_PRIVATE (proxy);
+
+ g_return_val_if_fail (priv->connection, FALSE);
+ g_return_val_if_fail (ibus_connection_is_connected (priv->connection), FALSE);
+
+ return ibus_connection_send (priv->connection, message);
+}
+
+gboolean
+ibus_proxy_call (IBusProxy *proxy,
+ const gchar *method,
+ GType first_arg_type,
+ ...)
+{
+ g_assert (IBUS_IS_PROXY (proxy));
+ g_assert (method != NULL);
+
+ va_list args;
+ gboolean retval;
+ DBusMessage *message;
+
+ IBusProxyPrivate *priv;
+ priv = IBUS_PROXY_GET_PRIVATE (proxy);
+
+ g_return_val_if_fail (priv->connection, FALSE);
+ g_return_val_if_fail (ibus_connection_is_connected (priv->connection), FALSE);
+
+ message = ibus_message_new_method_call (priv->name,
+ priv->path,
+ priv->interface,
+ method);
+ va_start (args, first_arg_type);
+ retval = ibus_message_append_args_valist (message,
+ first_arg_type,
+ args);
+ if (!retval) {
+ ibus_message_unref (message);
+ g_return_val_if_reached (FALSE);
+ }
+
+ va_end (args);
+
+ retval = ibus_connection_send (priv->connection, message);
+
+ ibus_message_unref (message);
+
+ return retval;
+}
+
+gboolean
+ibus_proxy_call_with_reply (IBusProxy *proxy,
+ const gchar *method,
+ IBusPendingCall **pending,
+ gint timeout_milliseconds,
+ IBusError **error,
+ GType first_arg_type,
+ ...)
+{
+ g_assert (IBUS_IS_PROXY (proxy));
+ g_assert (pending != NULL);
+ g_assert (method != NULL);
+
+ va_list args;
+ gboolean retval;
+ DBusMessage *message;
+
+ IBusProxyPrivate *priv;
+ priv = IBUS_PROXY_GET_PRIVATE (proxy);
+
+ if (priv->connection == NULL || !ibus_connection_is_connected (priv->connection)) {
+ if (error) {
+ *error = ibus_error_new_from_printf (DBUS_ERROR_DISCONNECTED,
+ "Connection of %s was disconnected.",
+ G_OBJECT_TYPE_NAME (proxy));
+ }
+ return FALSE;
+ }
+
+ message = ibus_message_new_method_call (priv->name,
+ priv->path,
+ priv->interface,
+ method);
+ va_start (args, first_arg_type);
+ retval = ibus_message_append_args_valist (message,
+ first_arg_type,
+ args);
+ va_end (args);
+
+ *pending = NULL;
+ retval = ibus_connection_send_with_reply (priv->connection,
+ message,
+ pending,
+ timeout_milliseconds);
+ ibus_message_unref (message);
+
+ if (!retval && error != NULL) {
+ *error = ibus_error_new_from_printf (DBUS_ERROR_NO_MEMORY, "");
+ }
+
+ return retval;
+}
+
+
+IBusMessage *
+ibus_proxy_call_with_reply_and_block (IBusProxy *proxy,
+ const gchar *method,
+ gint timeout_milliseconds,
+ IBusError **error,
+ GType first_arg_type,
+ ...)
+{
+ g_assert (IBUS_IS_PROXY (proxy));
+ g_assert (method != NULL);
+
+ va_list args;
+ gboolean retval;
+ DBusMessage *message;
+ DBusMessage *reply_message;
+
+ IBusProxyPrivate *priv;
+ priv = IBUS_PROXY_GET_PRIVATE (proxy);
+
+ if (priv->connection == NULL || !ibus_connection_is_connected (priv->connection)) {
+ if (error) {
+ *error = ibus_error_new_from_printf (DBUS_ERROR_DISCONNECTED,
+ "Connection of %s was disconnected.",
+ G_OBJECT_TYPE_NAME (proxy));
+ }
+ return NULL;
+ }
+
+ message = ibus_message_new_method_call (priv->name,
+ priv->path,
+ priv->interface,
+ method);
+ va_start (args, first_arg_type);
+ retval = ibus_message_append_args_valist (message,
+ first_arg_type,
+ args);
+ va_end (args);
+
+ reply_message = ibus_connection_send_with_reply_and_block (
+ priv->connection,
+ message,
+ timeout_milliseconds,
+ error);
+ ibus_message_unref (message);
+
+ return reply_message;
+}