diff options
| -rw-r--r-- | ChangeLog | 12 | ||||
| -rwxr-xr-x | autogen.sh | 4 | ||||
| -rw-r--r-- | configure.in | 7 | ||||
| -rw-r--r-- | dbus/dbus-glib.h | 3 | ||||
| -rw-r--r-- | doc/TODO | 6 | ||||
| -rw-r--r-- | glib/Makefile.am | 11 | ||||
| -rw-r--r-- | glib/dbus-gmarshal.c | 89 | ||||
| -rw-r--r-- | glib/dbus-gmarshal.h | 21 | ||||
| -rw-r--r-- | glib/dbus-gmarshal.list | 1 | ||||
| -rw-r--r-- | glib/dbus-gproxy.c | 345 | ||||
| -rw-r--r-- | tools/dbus-names-model.c | 99 | 
11 files changed, 510 insertions, 88 deletions
@@ -1,5 +1,17 @@  2005-01-30  Havoc Pennington  <hp@redhat.com> +	* 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  <hp@redhat.com> +  	* tools/dbus-names-model.c (have_names_notify): fix this  	* dbus/dbus-message.c (_dbus_message_iter_get_args_valist): clean @@ -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, @@ -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	<glib-object.h> + + +#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	<glib-object.h> + +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 <dbus/dbus-glib.h>  #include <dbus/dbus-glib-lowlevel.h>  #include "dbus-gutils.h" +#include "dbus-gmarshal.h" +#include "dbus-gvalue.h"  #include <string.h>  /** @@ -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 <glib/gi18n.h> +#include <string.h>  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);  | 
