summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2005-01-31 02:55:12 +0000
committerHavoc Pennington <hp@redhat.com>2005-01-31 02:55:12 +0000
commitd2c1a633d15611eb6ca757863c489ebf201d07cd (patch)
treecbe676973f4cd3d5b79629aae343240a2a3e12a6
parentd5b7d7a78c0fb2e41d5966a0778b08f8d8e35ea4 (diff)
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.
-rw-r--r--ChangeLog12
-rwxr-xr-xautogen.sh4
-rw-r--r--configure.in7
-rw-r--r--dbus/dbus-glib.h3
-rw-r--r--doc/TODO6
-rw-r--r--glib/Makefile.am11
-rw-r--r--glib/dbus-gmarshal.c89
-rw-r--r--glib/dbus-gmarshal.h21
-rw-r--r--glib/dbus-gmarshal.list1
-rw-r--r--glib/dbus-gproxy.c345
-rw-r--r--tools/dbus-names-model.c99
11 files changed, 510 insertions, 88 deletions
diff --git a/ChangeLog b/ChangeLog
index fe4fd043..22ab88b8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
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 <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,
+ &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);
+ }
+}
+
/**
* 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);