summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--glib/dbus-gproxy.c334
2 files changed, 199 insertions, 140 deletions
diff --git a/ChangeLog b/ChangeLog
index 15eb9106..01b497ed 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2005-01-31 Havoc Pennington <hp@redhat.com>
+
+ * glib/dbus-gproxy.c: rewrite how signals work again, this time I
+ think it's sort of right
+
2005-01-30 Havoc Pennington <hp@redhat.com>
* tools/dbus-viewer.c: kind of half-ass hook up the option menu.
diff --git a/glib/dbus-gproxy.c b/glib/dbus-gproxy.c
index 01d67acf..0e3cd783 100644
--- a/glib/dbus-gproxy.c
+++ b/glib/dbus-gproxy.c
@@ -1,7 +1,7 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
-/* dbus-gcall.c convenience routines for calling methods, etc.
+/* dbus-gproxy.c Proxy for remote objects
*
- * Copyright (C) 2003, 2004 Red Hat, Inc.
+ * Copyright (C) 2003, 2004, 2005 Red Hat, Inc.
*
* Licensed under the Academic Free License version 2.1
*
@@ -668,11 +668,18 @@ dbus_g_proxy_manager_filter (DBusConnection *connection,
/* ---------- DBusGProxy -------------- */
-
+static void
+marshal_dbus_message_to_g_marshaller (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
enum
{
DESTROY,
+ RECEIVED,
LAST_SIGNAL
};
@@ -703,8 +710,16 @@ dbus_g_proxy_class_init (DBusGProxyClass *klass)
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
-}
+ signals[RECEIVED] =
+ g_signal_new ("received",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ 0,
+ NULL, NULL,
+ marshal_dbus_message_to_g_marshaller,
+ G_TYPE_NONE, 2, DBUS_TYPE_MESSAGE, G_TYPE_STRING);
+}
static void
dbus_g_proxy_dispose (GObject *object)
@@ -779,61 +794,154 @@ create_signal_name (const char *interface,
return g_string_free (str, FALSE);
}
+static GSignalCMarshaller
+lookup_g_marshaller (DBusGProxy *proxy,
+ const char *signature)
+{
+ /* The "proxy" arg would eventually be used if you could provide
+ * a marshaller when adding a signal to the proxy
+ */
+
+#define MATCH1(sig, t0) ((sig)[0] == (DBUS_TYPE_##t0) && (sig)[1] == '\0')
+#define MATCH2(sig, t0, t1) ((sig)[0] == (DBUS_TYPE_##t0) && (sig)[1] == (DBUS_TYPE_##t1) && (sig)[2] == '\0')
+#define MATCH3(sig, t0, t1, t2) ((sig)[0] == (DBUS_TYPE_##t0) && (sig)[1] == (DBUS_TYPE_##t1) && (sig)[2] == (DBUS_TYPE_##t2) && (sig)[3] == '\0')
+
+ switch (*signature)
+ {
+ case '\0':
+ return g_cclosure_marshal_VOID__VOID;
+
+ case DBUS_TYPE_BOOLEAN:
+ if (MATCH1 (signature, BOOLEAN))
+ return g_cclosure_marshal_VOID__BOOLEAN;
+ break;
+
+ case DBUS_TYPE_BYTE:
+ if (MATCH1 (signature, BYTE))
+ return g_cclosure_marshal_VOID__UCHAR;
+ break;
+
+ case DBUS_TYPE_INT16:
+ if (MATCH1 (signature, INT16))
+ return g_cclosure_marshal_VOID__INT;
+ break;
+
+ case DBUS_TYPE_UINT16:
+ if (MATCH1 (signature, UINT16))
+ return g_cclosure_marshal_VOID__UINT;
+ break;
+
+ case DBUS_TYPE_INT32:
+ if (MATCH1 (signature, INT32))
+ return g_cclosure_marshal_VOID__INT;
+ break;
+
+ case DBUS_TYPE_UINT32:
+ if (MATCH1 (signature, UINT32))
+ return g_cclosure_marshal_VOID__UINT;
+ break;
+
+ case DBUS_TYPE_DOUBLE:
+ if (MATCH1 (signature, DOUBLE))
+ return g_cclosure_marshal_VOID__DOUBLE;
+ break;
+
+ case DBUS_TYPE_OBJECT_PATH:
+ if (MATCH1 (signature, OBJECT_PATH))
+ return g_cclosure_marshal_VOID__STRING;
+ break;
+
+ case DBUS_TYPE_SIGNATURE:
+ if (MATCH1 (signature, SIGNATURE))
+ return g_cclosure_marshal_VOID__STRING;
+ break;
+
+ case DBUS_TYPE_STRING:
+ if (MATCH1 (signature, STRING))
+ return g_cclosure_marshal_VOID__STRING;
+ /* This is for NameOwnerChanged */
+ else if (MATCH3 (signature, STRING, STRING, STRING))
+ return _dbus_g_marshal_NONE__STRING_STRING_STRING;
+ break;
+ }
+
+ return NULL;
+}
+
static void
-emit_remote_internal (DBusGProxy *proxy,
- DBusMessage *message,
- guint signal_id,
- gboolean marshal_args)
+marshal_dbus_message_to_g_marshaller (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
{
+ /* Incoming here we have three params, the instance (Proxy), the
+ * DBusMessage, the signature. We want to convert that to an
+ * expanded GValue array, then call an appropriate normal GLib
+ * marshaller.
+ */
#define MAX_SIGNATURE_ARGS 20
- GValue values[MAX_SIGNATURE_ARGS];
+ GValue expanded[MAX_SIGNATURE_ARGS];
int arg;
int i;
+ DBusMessageIter iter;
+ int dtype;
+ GSignalCMarshaller c_marshaller;
+ DBusGProxy *proxy;
+ DBusMessage *message;
+ const char *signature;
- memset (&values[0], 0, sizeof (values));
+ g_assert (n_param_values == 3);
+
+ proxy = g_value_get_object (&param_values[0]);
+ message = g_value_get_boxed (&param_values[1]);
+ signature = g_value_get_string (&param_values[2]);
+
+ g_return_if_fail (DBUS_IS_G_PROXY (proxy));
+ g_return_if_fail (message != NULL);
+ g_return_if_fail (signature != NULL);
+
+ c_marshaller = lookup_g_marshaller (proxy, signature);
+
+ g_return_if_fail (c_marshaller != NULL);
+
+ memset (&expanded[0], 0, sizeof (expanded));
arg = 0;
- g_value_init (&values[arg], G_TYPE_FROM_INSTANCE (proxy));
- g_value_set_instance (&values[arg], proxy);
+ g_value_init (&expanded[arg], G_TYPE_FROM_INSTANCE (proxy));
+ g_value_set_instance (&expanded[arg], proxy);
++arg;
-
- if (marshal_args)
+
+ dbus_message_iter_init (message, &iter);
+
+ while ((dtype = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID)
{
- DBusMessageIter iter;
- int dtype;
-
- dbus_message_iter_init (message, &iter);
+ if (arg == MAX_SIGNATURE_ARGS)
+ {
+ g_warning ("Don't support more than %d signal args\n", MAX_SIGNATURE_ARGS);
+ goto out;
+ }
- while ((dtype = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID)
+ if (!dbus_gvalue_demarshal (&iter, &expanded[arg]))
{
- if (arg == MAX_SIGNATURE_ARGS)
- {
- g_warning ("Don't support more than %d signal args\n", MAX_SIGNATURE_ARGS);
- goto out;
- }
-
- if (!dbus_gvalue_demarshal (&iter, &values[arg]))
- {
- g_warning ("Unable to convert arg type %d to GValue to emit DBusGProxy signal", dtype);
- goto out;
- }
-
- ++arg;
- dbus_message_iter_next (&iter);
+ g_warning ("Unable to convert arg type %d to GValue to emit DBusGProxy signal", dtype);
+ goto out;
}
- }
- g_signal_emitv (&values[0],
- signal_id,
- 0,
- NULL);
+ ++arg;
+ dbus_message_iter_next (&iter);
+ }
+ (* c_marshaller) (closure, return_value, arg, &expanded[0],
+ invocation_hint, marshal_data);
+
out:
i = 0;
while (i < arg)
{
- g_value_unset (&values[i]);
+ g_value_unset (&expanded[i]);
++i;
}
}
@@ -880,12 +988,11 @@ dbus_g_proxy_emit_remote_signal (DBusGProxy *proxy,
}
else
{
- guint signal_id;
-
- signal_id = g_signal_lookup (name, G_OBJECT_TYPE (proxy));
- g_assert (signal_id != 0); /* because we have the signature */
-
- emit_remote_internal (proxy, message, signal_id, signature != NULL);
+ g_signal_emit (proxy,
+ signals[RECEIVED],
+ q,
+ message,
+ signature);
}
}
@@ -1379,33 +1486,6 @@ dbus_g_proxy_send (DBusGProxy *proxy,
g_error ("Out of memory\n");
}
-static gboolean
-siginfo_from_signature (const char *signature,
- GSignalCMarshaller *c_marshaller,
- GType *return_type,
- guint *n_params,
- GType **param_types)
-{
- /* FIXME (which marshalers should we include?
- * probably need public API to add your own
- */
-
- if (strcmp (signature, "sss") == 0)
- {
- *c_marshaller = _dbus_g_marshal_NONE__STRING_STRING_STRING;
- *return_type = G_TYPE_NONE;
- *n_params = 3;
- *param_types = g_new0 (GType, *n_params);
- (*param_types)[0] = G_TYPE_STRING;
- (*param_types)[1] = G_TYPE_STRING;
- (*param_types)[2] = G_TYPE_STRING;
-
- return TRUE;
- }
-
- return FALSE;
-}
-
/**
* Specifies the signature of a signal, such that it's possible to
* connect to the signal on this proxy.
@@ -1419,56 +1499,29 @@ dbus_g_proxy_add_signal (DBusGProxy *proxy,
const char *signal_name,
const char *signature)
{
- GSignalCMarshaller c_marshaller;
- GType return_type;
- int n_params;
- GType *params;
-
+ GQuark q;
+ char *name;
+
g_return_if_fail (DBUS_IS_G_PROXY (proxy));
g_return_if_fail (signal_name != NULL);
g_return_if_fail (signature != NULL);
+#ifndef G_DISABLE_CHECKS
+ if (lookup_g_marshaller (proxy, signature) == NULL)
+ g_warning ("No marshaller for signature '%s', we need to add API for providing your own",
+ signature);
+#endif
+
+ name = create_signal_name (proxy->interface, signal_name);
+
+ q = g_quark_from_string (name);
+
+ g_return_if_fail (g_datalist_id_get_data (&proxy->signal_signatures, q) == NULL);
+
+ g_datalist_id_set_data_full (&proxy->signal_signatures,
+ q, g_strdup (signature),
+ g_free);
- if (siginfo_from_signature (signature,
- &c_marshaller,
- &return_type,
- &n_params,
- &params))
- {
- GQuark q;
- char *name;
-
- name = create_signal_name (proxy->interface, signal_name);
-
- q = g_quark_from_string (name);
-
- g_return_if_fail (g_datalist_id_get_data (&proxy->signal_signatures, q) == NULL);
-
- g_datalist_id_set_data_full (&proxy->signal_signatures,
- q, g_strdup (signature),
- g_free);
-
- /* hackaround global nature of g_signal_newv()... this whole thing needs unhosing */
-
- if (g_signal_lookup (name,
- G_OBJECT_TYPE (proxy)) == 0)
- {
- g_signal_newv (name,
- G_OBJECT_TYPE (proxy),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL, NULL,
- c_marshaller,
- return_type, n_params, params);
- }
-
- g_free (params);
- g_free (name);
- }
- else
- {
- g_warning ("DBusGProxy doesn't know how to create a signal with signature '%s'\n",
- signature);
- }
+ g_free (name);
}
/**
@@ -1490,7 +1543,8 @@ dbus_g_proxy_connect_signal (DBusGProxy *proxy,
GClosureNotify free_data_func)
{
char *name;
- guint signal_id;
+ GClosure *closure;
+ GQuark q;
g_return_if_fail (DBUS_IS_G_PROXY (proxy));
g_return_if_fail (signal_name != NULL);
@@ -1498,24 +1552,23 @@ dbus_g_proxy_connect_signal (DBusGProxy *proxy,
name = create_signal_name (proxy->interface, signal_name);
- g_printerr ("Looking up signal '%s'\n", name);
- signal_id = g_signal_lookup (name,
- G_OBJECT_TYPE (proxy));
- if (signal_id != 0)
- {
- GClosure *closure;
-
- closure = g_cclosure_new (G_CALLBACK (handler), data, free_data_func);
- g_signal_connect_closure_by_id (G_OBJECT (proxy),
- signal_id,
- 0,
- closure, FALSE);
- }
- else
+ q = g_quark_from_string (name);
+
+#ifndef G_DISABLE_CHECKS
+ if (g_datalist_id_get_data (&proxy->signal_signatures, q) == NULL)
{
- g_warning ("You have to add signal '%s' with dbus_g_proxy_add_signal() before you can connect to it\n",
- name);
+ g_warning ("Must add the signal '%s' with dbus_g_proxy_add_signal() prior to connecting to it\n", name);
+ g_free (name);
+ return;
}
+#endif
+
+ closure = g_cclosure_new (G_CALLBACK (handler), data, free_data_func);
+
+ g_signal_connect_closure_by_id (G_OBJECT (proxy),
+ signals[RECEIVED],
+ q,
+ closure, FALSE);
g_free (name);
}
@@ -1536,7 +1589,7 @@ dbus_g_proxy_disconnect_signal (DBusGProxy *proxy,
void *data)
{
char *name;
- guint signal_id;
+ GQuark q;
g_return_if_fail (DBUS_IS_G_PROXY (proxy));
g_return_if_fail (signal_name != NULL);
@@ -1544,15 +1597,16 @@ dbus_g_proxy_disconnect_signal (DBusGProxy *proxy,
name = create_signal_name (proxy->interface, signal_name);
- signal_id = g_signal_lookup (name, G_OBJECT_TYPE (proxy));
- if (signal_id != 0)
+ q = g_quark_from_string (name);
+
+ if (q != 0)
{
g_signal_handlers_disconnect_matched (G_OBJECT (proxy),
G_SIGNAL_MATCH_DETAIL |
G_SIGNAL_MATCH_FUNC |
G_SIGNAL_MATCH_DATA,
- signal_id,
- 0,
+ signals[RECEIVED],
+ q,
NULL,
G_CALLBACK (handler), data);
}