From d2c1a633d15611eb6ca757863c489ebf201d07cd Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Mon, 31 Jan 2005 02:55:12 +0000 Subject: 2005-01-30 Havoc Pennington * tools/dbus-names-model.c: dynamically watch NameOwnerChanged * autogen.sh: change to autotools 1.9 * glib/dbus-gproxy.c: completely change how signals work (dbus_g_proxy_add_signal): new function to specify signature of a signal (dbus_g_proxy_emit_received): marshal the dbus message to GValues, and g_warning if the incoming message has the wrong signature. --- ChangeLog | 12 ++ autogen.sh | 4 +- configure.in | 7 + dbus/dbus-glib.h | 3 + doc/TODO | 6 +- glib/Makefile.am | 11 ++ glib/dbus-gmarshal.c | 89 ++++++++++++ glib/dbus-gmarshal.h | 21 +++ glib/dbus-gmarshal.list | 1 + glib/dbus-gproxy.c | 345 ++++++++++++++++++++++++++++++++++++----------- tools/dbus-names-model.c | 99 +++++++++++++- 11 files changed, 510 insertions(+), 88 deletions(-) create mode 100644 glib/dbus-gmarshal.c create mode 100644 glib/dbus-gmarshal.h create mode 100644 glib/dbus-gmarshal.list diff --git a/ChangeLog b/ChangeLog index fe4fd043..22ab88b8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2005-01-30 Havoc Pennington + + * tools/dbus-names-model.c: dynamically watch NameOwnerChanged + + * autogen.sh: change to autotools 1.9 + + * glib/dbus-gproxy.c: completely change how signals work + (dbus_g_proxy_add_signal): new function to specify signature of a + signal + (dbus_g_proxy_emit_received): marshal the dbus message to GValues, + and g_warning if the incoming message has the wrong signature. + 2005-01-30 Havoc Pennington * tools/dbus-names-model.c (have_names_notify): fix this diff --git a/autogen.sh b/autogen.sh index 3e0a5853..6435fd5e 100755 --- a/autogen.sh +++ b/autogen.sh @@ -21,8 +21,8 @@ DIE=0 DIE=1 } -AUTOMAKE=automake-1.7 -ACLOCAL=aclocal-1.7 +AUTOMAKE=automake-1.9 +ACLOCAL=aclocal-1.9 ($AUTOMAKE --version) < /dev/null > /dev/null 2>&1 || { AUTOMAKE=automake diff --git a/configure.in b/configure.in index 1df76996..87f214b1 100644 --- a/configure.in +++ b/configure.in @@ -819,6 +819,13 @@ fi AM_CONDITIONAL(HAVE_GLIB, test x$have_glib = xyes) AM_CONDITIONAL(HAVE_GLIB_THREADS, test x$have_glib_threads = xyes) +if test x$have_glib = xyes; then + GLIB_GENMARSHAL=`$PKG_CONFIG --variable=glib_genmarshal glib-2.0` +else + GLIB_GENMARSHAL=glib-not-enabled-so-there-is-no-genmarshal +fi +AC_SUBST(GLIB_GENMARSHAL) + dnl GLib flags AC_SUBST(DBUS_GLIB_CFLAGS) AC_SUBST(DBUS_GLIB_LIBS) diff --git a/dbus/dbus-glib.h b/dbus/dbus-glib.h index 6c3c3c5f..5c002f49 100644 --- a/dbus/dbus-glib.h +++ b/dbus/dbus-glib.h @@ -149,6 +149,9 @@ DBusGProxy* dbus_g_proxy_new_for_name_owner (DBusGConnection *connect DBusGProxy* dbus_g_proxy_new_for_peer (DBusGConnection *connection, const char *path_name, const char *interface_name); +void dbus_g_proxy_add_signal (DBusGProxy *proxy, + const char *signal_name, + const char *signature); void dbus_g_proxy_connect_signal (DBusGProxy *proxy, const char *signal_name, GCallback handler, diff --git a/doc/TODO b/doc/TODO index 0590bb4e..b64409a0 100644 --- a/doc/TODO +++ b/doc/TODO @@ -55,9 +55,9 @@ Important for 1.0 GLib Bindings dbus_malloc() memory, only g_malloc(). dbus_g_proxy_end_call() is the major offender. - - dbus_gproxy_connect_signal() has to take a signature for the signal - so it can figure out how to invoke the callback, or we have to rely - on having introspection data. + - DBusGProxy signals feature is a complete fiasco; + right now the problem is that it dynamically creates + signals on the global DBusGProxy class and never frees them - DBusGProxy doesn't emit "destroy" when it should diff --git a/glib/Makefile.am b/glib/Makefile.am index 4db47de4..6a42e6f9 100644 --- a/glib/Makefile.am +++ b/glib/Makefile.am @@ -5,6 +5,8 @@ lib_LTLIBRARIES=libdbus-glib-1.la libdbus_glib_1_la_SOURCES = \ dbus-glib.c \ dbus-gmain.c \ + dbus-gmarshal.c \ + dbus-gmarshal.h \ dbus-gobject.c \ dbus-gproxy.c \ dbus-gtest.c \ @@ -41,6 +43,15 @@ dbus_binding_tool_SOURCES = \ dbus_binding_tool_LDADD= -lexpat libdbus-gtool.la +## we just rebuilt these manually and check them into cvs; easier than +## convincing automake/make to do this properly +regenerate-built-sources: + @GLIB_GENMARSHAL@ --prefix=_dbus_g_marshal dbus-gmarshal.list --header > dbus-gmarshal.h && \ + echo '#include "dbus-gmarshal.h"' > dbus-gmarshal.c && \ + @GLIB_GENMARSHAL@ --prefix=_dbus_g_marshal dbus-gmarshal.list --body >> dbus-gmarshal.c + +EXTRA_DIST=dbus-gmarshal.list + if DBUS_BUILD_TESTS ## we use noinst_PROGRAMS not check_PROGRAMS for TESTS so that we diff --git a/glib/dbus-gmarshal.c b/glib/dbus-gmarshal.c new file mode 100644 index 00000000..13e98b19 --- /dev/null +++ b/glib/dbus-gmarshal.c @@ -0,0 +1,89 @@ +#include "dbus-gmarshal.h" + +#include + + +#ifdef G_ENABLE_DEBUG +#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) +#define g_marshal_value_peek_char(v) g_value_get_char (v) +#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) +#define g_marshal_value_peek_int(v) g_value_get_int (v) +#define g_marshal_value_peek_uint(v) g_value_get_uint (v) +#define g_marshal_value_peek_long(v) g_value_get_long (v) +#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) +#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) +#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) +#define g_marshal_value_peek_enum(v) g_value_get_enum (v) +#define g_marshal_value_peek_flags(v) g_value_get_flags (v) +#define g_marshal_value_peek_float(v) g_value_get_float (v) +#define g_marshal_value_peek_double(v) g_value_get_double (v) +#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) +#define g_marshal_value_peek_param(v) g_value_get_param (v) +#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) +#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) +#define g_marshal_value_peek_object(v) g_value_get_object (v) +#else /* !G_ENABLE_DEBUG */ +/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. + * Do not access GValues directly in your code. Instead, use the + * g_value_get_*() functions + */ +#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int +#define g_marshal_value_peek_char(v) (v)->data[0].v_int +#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint +#define g_marshal_value_peek_int(v) (v)->data[0].v_int +#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint +#define g_marshal_value_peek_long(v) (v)->data[0].v_long +#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong +#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 +#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 +#define g_marshal_value_peek_enum(v) (v)->data[0].v_long +#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong +#define g_marshal_value_peek_float(v) (v)->data[0].v_float +#define g_marshal_value_peek_double(v) (v)->data[0].v_double +#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer +#endif /* !G_ENABLE_DEBUG */ + + +/* NONE:STRING,STRING,STRING (dbus-gmarshal.list:1) */ +void +_dbus_g_marshal_VOID__STRING_STRING_STRING (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__STRING_STRING_STRING) (gpointer data1, + gpointer arg_1, + gpointer arg_2, + gpointer arg_3, + gpointer data2); + register GMarshalFunc_VOID__STRING_STRING_STRING callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + + g_return_if_fail (n_param_values == 4); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__STRING_STRING_STRING) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + g_marshal_value_peek_string (param_values + 1), + g_marshal_value_peek_string (param_values + 2), + g_marshal_value_peek_string (param_values + 3), + data2); +} + diff --git a/glib/dbus-gmarshal.h b/glib/dbus-gmarshal.h new file mode 100644 index 00000000..2cdb3d7e --- /dev/null +++ b/glib/dbus-gmarshal.h @@ -0,0 +1,21 @@ + +#ifndef ___dbus_g_marshal_MARSHAL_H__ +#define ___dbus_g_marshal_MARSHAL_H__ + +#include + +G_BEGIN_DECLS + +/* NONE:STRING,STRING,STRING (dbus-gmarshal.list:1) */ +extern void _dbus_g_marshal_VOID__STRING_STRING_STRING (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); +#define _dbus_g_marshal_NONE__STRING_STRING_STRING _dbus_g_marshal_VOID__STRING_STRING_STRING + +G_END_DECLS + +#endif /* ___dbus_g_marshal_MARSHAL_H__ */ + diff --git a/glib/dbus-gmarshal.list b/glib/dbus-gmarshal.list new file mode 100644 index 00000000..12974e24 --- /dev/null +++ b/glib/dbus-gmarshal.list @@ -0,0 +1 @@ +NONE:STRING,STRING,STRING diff --git a/glib/dbus-gproxy.c b/glib/dbus-gproxy.c index c38c702d..01d67acf 100644 --- a/glib/dbus-gproxy.c +++ b/glib/dbus-gproxy.c @@ -23,6 +23,8 @@ #include #include #include "dbus-gutils.h" +#include "dbus-gmarshal.h" +#include "dbus-gvalue.h" #include /** @@ -48,6 +50,8 @@ struct DBusGProxy char *name; /**< Name messages go to or NULL */ char *path; /**< Path messages go to or NULL */ char *interface; /**< Interface messages go to or NULL */ + + GData *signal_signatures; /**< D-BUS signatures for each signal */ }; /** @@ -58,14 +62,13 @@ struct DBusGProxyClass GObjectClass parent_class; /**< Parent class */ }; -static void dbus_g_proxy_init (DBusGProxy *proxy); -static void dbus_g_proxy_class_init (DBusGProxyClass *klass); -static void dbus_g_proxy_finalize (GObject *object); -static void dbus_g_proxy_dispose (GObject *object); -static void dbus_g_proxy_destroy (DBusGProxy *proxy); -static void dbus_g_proxy_emit_received (DBusGProxy *proxy, - DBusMessage *message); - +static void dbus_g_proxy_init (DBusGProxy *proxy); +static void dbus_g_proxy_class_init (DBusGProxyClass *klass); +static void dbus_g_proxy_finalize (GObject *object); +static void dbus_g_proxy_dispose (GObject *object); +static void dbus_g_proxy_destroy (DBusGProxy *proxy); +static void dbus_g_proxy_emit_remote_signal (DBusGProxy *proxy, + DBusMessage *message); /** * A list of proxies with a given name+path+interface, used to @@ -641,7 +644,7 @@ dbus_g_proxy_manager_filter (DBusConnection *connection, proxy = DBUS_G_PROXY (tmp->data); UNLOCK_MANAGER (manager); - dbus_g_proxy_emit_received (proxy, message); + dbus_g_proxy_emit_remote_signal (proxy, message); g_object_unref (G_OBJECT (proxy)); LOCK_MANAGER (manager); @@ -670,7 +673,6 @@ dbus_g_proxy_manager_filter (DBusConnection *connection, enum { DESTROY, - RECEIVED, LAST_SIGNAL }; @@ -680,7 +682,7 @@ static guint signals[LAST_SIGNAL] = { 0 }; static void dbus_g_proxy_init (DBusGProxy *proxy) { - /* Nothing */ + g_datalist_init (&proxy->signal_signatures); } static void @@ -701,16 +703,6 @@ 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, - g_cclosure_marshal_VOID__BOXED, - G_TYPE_NONE, 1, - DBUS_TYPE_MESSAGE); } @@ -721,6 +713,8 @@ dbus_g_proxy_dispose (GObject *object) proxy = DBUS_G_PROXY (object); + g_datalist_clear (&proxy->signal_signatures); + g_signal_emit (object, signals[DESTROY], 0); G_OBJECT_CLASS (parent_class)->dispose (object); @@ -755,28 +749,102 @@ dbus_g_proxy_destroy (DBusGProxy *proxy) g_object_run_dispose (G_OBJECT (proxy)); } +/* this is to avoid people using g_signal_connect() directly, + * to avoid confusion with local signal names, and because + * of the horribly broken current setup (signals are added + * globally to all proxies) + */ static char* -create_signal_detail (const char *interface, - const char *signal) +create_signal_name (const char *interface, + const char *signal) { GString *str; + char *p; str = g_string_new (interface); - g_string_append (str, "."); - + g_string_append (str, "-"); + g_string_append (str, signal); + /* GLib will silently barf on '.' in signal names */ + p = str->str; + while (*p) + { + if (*p == '.') + *p = '-'; + ++p; + } + return g_string_free (str, FALSE); } static void -dbus_g_proxy_emit_received (DBusGProxy *proxy, - DBusMessage *message) +emit_remote_internal (DBusGProxy *proxy, + DBusMessage *message, + guint signal_id, + gboolean marshal_args) +{ +#define MAX_SIGNATURE_ARGS 20 + GValue values[MAX_SIGNATURE_ARGS]; + int arg; + int i; + + memset (&values[0], 0, sizeof (values)); + + arg = 0; + + g_value_init (&values[arg], G_TYPE_FROM_INSTANCE (proxy)); + g_value_set_instance (&values[arg], proxy); + ++arg; + + if (marshal_args) + { + DBusMessageIter iter; + int dtype; + + dbus_message_iter_init (message, &iter); + + while ((dtype = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID) + { + 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_signal_emitv (&values[0], + signal_id, + 0, + NULL); + + out: + i = 0; + while (i < arg) + { + g_value_unset (&values[i]); + ++i; + } +} + +static void +dbus_g_proxy_emit_remote_signal (DBusGProxy *proxy, + DBusMessage *message) { const char *interface; const char *signal; - char *detail; + char *name; GQuark q; interface = dbus_message_get_interface (message); @@ -785,21 +853,43 @@ dbus_g_proxy_emit_received (DBusGProxy *proxy, g_assert (interface != NULL); g_assert (signal != NULL); - detail = create_signal_detail (interface, signal); + name = create_signal_name (interface, signal); /* If the quark isn't preexisting, there's no way there * are any handlers connected. We don't want to create * extra quarks for every possible signal. */ - q = g_quark_try_string (detail); + q = g_quark_try_string (name); if (q != 0) - g_signal_emit (G_OBJECT (proxy), - signals[RECEIVED], - q, - message); + { + const char *signature; - g_free (detail); + signature = g_datalist_id_get_data (&proxy->signal_signatures, q); + if (signature == NULL) + { + g_warning ("Signal '%s' has not been added to this proxy object\n", + name); + } + else if (!dbus_message_has_signature (message, signature)) + { + g_warning ("Signature '%s' expected for signal '%s', actual signature '%s'\n", + signature, + name, + dbus_message_get_signature (message)); + } + 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_free (name); } /** @} End of DBusGLibInternals */ @@ -1264,8 +1354,8 @@ dbus_g_proxy_call_no_reply (DBusGProxy *proxy, * @param client_serial return location for message's serial, or #NULL */ void dbus_g_proxy_send (DBusGProxy *proxy, - DBusMessage *message, - dbus_uint32_t *client_serial) + DBusMessage *message, + dbus_uint32_t *client_serial) { g_return_if_fail (DBUS_IS_G_PROXY (proxy)); @@ -1289,15 +1379,103 @@ 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. + * + * @param proxy the proxy for a remote interface + * @param signal_name the name of the signal + * @param signature D-BUS signature of the signal + */ +void +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; + + g_return_if_fail (DBUS_IS_G_PROXY (proxy)); + g_return_if_fail (signal_name != NULL); + g_return_if_fail (signature != NULL); + + 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); + } +} + /** * Connect a signal handler to a proxy for a remote interface. When * the remote interface emits the specified signal, the proxy will * emit a corresponding GLib signal. * - * @todo Right now there's no way to specify the signature to use - * for invoking the GCallback. Need to either rely on introspection, - * or require signature here. - * * @param proxy a proxy for a remote interface * @param signal_name the DBus signal name to listen for * @param handler the handler to connect @@ -1306,27 +1484,40 @@ dbus_g_proxy_send (DBusGProxy *proxy, */ void dbus_g_proxy_connect_signal (DBusGProxy *proxy, - const char *signal_name, - GCallback handler, - void *data, - GClosureNotify free_data_func) + const char *signal_name, + GCallback handler, + void *data, + GClosureNotify free_data_func) { - GClosure *closure; - char *detail; + char *name; + guint signal_id; g_return_if_fail (DBUS_IS_G_PROXY (proxy)); g_return_if_fail (signal_name != NULL); g_return_if_fail (handler != NULL); - detail = create_signal_detail (proxy->interface, signal_name); - - closure = g_cclosure_new (G_CALLBACK (handler), data, free_data_func); - g_signal_connect_closure_by_id (G_OBJECT (proxy), - signals[RECEIVED], - g_quark_from_string (detail), - closure, FALSE); + name = create_signal_name (proxy->interface, signal_name); - g_free (detail); + 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 + { + g_warning ("You have to add signal '%s' with dbus_g_proxy_add_signal() before you can connect to it\n", + name); + } + + g_free (name); } /** @@ -1340,38 +1531,38 @@ dbus_g_proxy_connect_signal (DBusGProxy *proxy, */ void dbus_g_proxy_disconnect_signal (DBusGProxy *proxy, - const char *signal_name, - GCallback handler, - void *data) + const char *signal_name, + GCallback handler, + void *data) { - char *detail; - GQuark q; + char *name; + guint signal_id; g_return_if_fail (DBUS_IS_G_PROXY (proxy)); g_return_if_fail (signal_name != NULL); g_return_if_fail (handler != NULL); - detail = create_signal_detail (proxy->interface, signal_name); - q = g_quark_try_string (detail); - g_free (detail); + name = create_signal_name (proxy->interface, signal_name); -#ifndef G_DISABLE_CHECKS - if (q == 0) + signal_id = g_signal_lookup (name, G_OBJECT_TYPE (proxy)); + if (signal_id != 0) { - g_warning ("%s: No signal handlers for %s found on this DBusGProxy", - G_GNUC_FUNCTION, signal_name); - return; + g_signal_handlers_disconnect_matched (G_OBJECT (proxy), + G_SIGNAL_MATCH_DETAIL | + G_SIGNAL_MATCH_FUNC | + G_SIGNAL_MATCH_DATA, + signal_id, + 0, + NULL, + G_CALLBACK (handler), data); + } + else + { + g_warning ("Attempt to disconnect from signal '%s' which is not registered\n", + name); } -#endif - g_signal_handlers_disconnect_matched (G_OBJECT (proxy), - G_SIGNAL_MATCH_DETAIL | - G_SIGNAL_MATCH_FUNC | - G_SIGNAL_MATCH_DATA, - signals[RECEIVED], - q, - NULL, - G_CALLBACK (handler), data); + g_free (name); } /** @} End of DBusGLib public */ diff --git a/tools/dbus-names-model.c b/tools/dbus-names-model.c index 4353daa8..38c121bc 100644 --- a/tools/dbus-names-model.c +++ b/tools/dbus-names-model.c @@ -22,6 +22,7 @@ */ #include "dbus-names-model.h" #include +#include enum { @@ -112,6 +113,81 @@ have_names_notify (DBusGPendingCall *call, g_strfreev (names); } +static gboolean +names_model_find_name (NamesModel *names_model, + const char *name, + GtkTreeIter *iter_p) +{ + GtkTreeIter iter; + + if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (names_model), + &iter)) + return FALSE; + + do + { + char *s; + + gtk_tree_model_get (GTK_TREE_MODEL (names_model), + &iter, + MODEL_COLUMN_NAME, &s, + -1); + if (s && strcmp (s, name) == 0) + { + *iter_p = iter; + g_free (s); + return TRUE; + } + + g_free (s); + } + while (gtk_tree_model_iter_next (GTK_TREE_MODEL (names_model), + &iter)); + + return FALSE; +} + +static void +name_owner_changed (DBusGProxy *driver_proxy, + const char *name, + const char *old_owner, + const char *new_owner, + void *data) +{ + NamesModel *names_model = NAMES_MODEL (data); + +#if 0 + g_printerr ("Name '%s' changed owner '%s' -> '%s'\n", + name, old_owner, new_owner); +#endif + + if (*new_owner == '\0') + { + /* this name has vanished */ + GtkTreeIter iter; + + if (names_model_find_name (names_model, name, &iter)) + gtk_tree_store_remove (GTK_TREE_STORE (names_model), + &iter); + } + else if (*old_owner == '\0') + { + /* this name has been added */ + GtkTreeIter iter; + + if (!names_model_find_name (names_model, name, &iter)) + { + gtk_tree_store_append (GTK_TREE_STORE (names_model), + &iter, NULL); + + gtk_tree_store_set (GTK_TREE_STORE (names_model), + &iter, + MODEL_COLUMN_NAME, name, + -1); + } + } +} + static void names_model_reload (NamesModel *names_model) { @@ -144,8 +220,6 @@ static void names_model_set_connection (NamesModel *names_model, DBusGConnection *connection) { - const char *match_rule = "type='signal',member='NameOwnerChanged'"; - g_return_if_fail (IS_NAMES_MODEL (names_model)); if (connection == names_model->connection) @@ -153,10 +227,11 @@ names_model_set_connection (NamesModel *names_model, if (names_model->connection) { - dbus_g_proxy_call_no_reply (names_model->driver_proxy, - "RemoveMatch", - DBUS_TYPE_STRING, &match_rule, - DBUS_TYPE_INVALID); + dbus_g_proxy_disconnect_signal (names_model->driver_proxy, + "NameOwnerChanged", + G_CALLBACK (name_owner_changed), + names_model); + g_object_unref (names_model->driver_proxy); names_model->driver_proxy = NULL; dbus_g_connection_unref (names_model->connection); @@ -174,6 +249,18 @@ names_model_set_connection (NamesModel *names_model, DBUS_PATH_ORG_FREEDESKTOP_DBUS, DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS); g_assert (names_model->driver_proxy); + + dbus_g_proxy_add_signal (names_model->driver_proxy, + "NameOwnerChanged", + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_STRING_AS_STRING); + + dbus_g_proxy_connect_signal (names_model->driver_proxy, + "NameOwnerChanged", + G_CALLBACK (name_owner_changed), + names_model, + NULL); } names_model_reload (names_model); -- cgit