diff options
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | glib/dbus-gproxy.c | 334 |
2 files changed, 199 insertions, 140 deletions
@@ -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 (¶m_values[0]); + message = g_value_get_boxed (¶m_values[1]); + signature = g_value_get_string (¶m_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, - ¶ms)) - { - 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); } |