diff options
author | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2009-09-29 14:22:07 +0100 |
---|---|---|
committer | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2009-09-29 14:22:13 +0100 |
commit | 5e5a1c1930173dac0e331c2cb78a164c3565b0eb (patch) | |
tree | df770098e4bf6d1a96cfd82efaeef4b0cac6bcdf | |
parent | 2a4396b523912c3bf4d2a1ef6d6fa930c0871c67 (diff) | |
parent | 90e2199ac99f5b8ab0cd5f45dcb398ecf9af03d9 (diff) |
Merge remote branch 'wjt/duplicate-registrations'
Signed-off-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
-rw-r--r-- | dbus/dbus-gobject.c | 167 | ||||
-rw-r--r-- | test/core/test-dbus-glib.c | 41 | ||||
-rw-r--r-- | test/core/test-service-glib.c | 4 |
3 files changed, 162 insertions, 50 deletions
diff --git a/dbus/dbus-gobject.c b/dbus/dbus-gobject.c index 7b7a41e..1f4bb10 100644 --- a/dbus/dbus-gobject.c +++ b/dbus/dbus-gobject.c @@ -407,9 +407,18 @@ object_registration_free (ObjectRegistration *o) { if (o->object != NULL) { + GSList *registrations; + + /* Ok, the object is still around; clear out this particular registration + * from the registrations list. + */ + registrations = g_object_steal_data (o->object, "dbus_glib_object_registrations"); + registrations = g_slist_remove (registrations, o); + + if (registrations != NULL) + g_object_set_data (o->object, "dbus_glib_object_registrations", registrations); + g_object_weak_unref (o->object, object_registration_object_died, o); - g_object_steal_data (o->object, "dbus_glib_object_registration"); - o->object = NULL; } g_free (o->object_path); @@ -1741,30 +1750,19 @@ dbus_g_signal_closure_finalize (gpointer data, } static void -signal_emitter_marshaller (GClosure *closure, - GValue *retval, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data) +emit_signal_for_registration (ObjectRegistration *o, + DBusGSignalClosure *sigclosure, + GValue *retval, + guint n_param_values, + const GValue *param_values) { - DBusGSignalClosure *sigclosure; DBusMessage *signal; DBusMessageIter iter; guint i; - const char *path; - - sigclosure = (DBusGSignalClosure *) closure; - - g_assert (retval == NULL); - - path = _dbus_gobject_get_path (sigclosure->object); - g_assert (path != NULL); - - signal = dbus_message_new_signal (path, - sigclosure->sigiface, - sigclosure->signame); + signal = dbus_message_new_signal (o->object_path, + sigclosure->sigiface, + sigclosure->signame); if (!signal) { g_error ("out of memory"); @@ -1777,20 +1775,45 @@ signal_emitter_marshaller (GClosure *closure, for (i = 1; i < n_param_values; i++) { if (!_dbus_gvalue_marshal (&iter, - (GValue *) (&(param_values[i])))) - { - g_warning ("failed to marshal parameter %d for signal %s", - i, sigclosure->signame); - goto out; - } + (GValue *) (&(param_values[i])))) + { + g_warning ("failed to marshal parameter %d for signal %s", + i, sigclosure->signame); + goto out; + } } dbus_connection_send (DBUS_CONNECTION_FROM_G_CONNECTION (sigclosure->connection), - signal, NULL); - out: + signal, NULL); +out: dbus_message_unref (signal); } static void +signal_emitter_marshaller (GClosure *closure, + GValue *retval, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + DBusGSignalClosure *sigclosure; + GSList *registrations, *iter; + + sigclosure = (DBusGSignalClosure *) closure; + + g_assert (retval == NULL); + + registrations = g_object_get_data (sigclosure->object, "dbus_glib_object_registrations"); + + for (iter = registrations; iter; iter = iter->next) + { + ObjectRegistration *o = iter->data; + + emit_signal_for_registration (o, sigclosure, retval, n_param_values, param_values); + } +} + +static void export_signals (DBusGConnection *connection, const GList *info_list, GObject *object) { GType gtype; @@ -2092,14 +2115,24 @@ void dbus_g_connection_unregister_g_object (DBusGConnection *connection, GObject *object) { - ObjectRegistration *o; + GList *registrations, *iter; + + /* Copy the list before iterating it: it will be modified in + * object_registration_free() each time an object path is unregistered. + */ + registrations = g_list_copy (g_object_get_data (object, "dbus_glib_object_registrations")); - o = g_object_get_data (object, "dbus_glib_object_registration"); + g_return_if_fail (registrations != NULL); - g_return_if_fail (o != NULL); + for (iter = registrations; iter; iter = iter->next) + { + ObjectRegistration *o = iter->data; + dbus_connection_unregister_object_path (DBUS_CONNECTION_FROM_G_CONNECTION (o->connection), + o->object_path); + } - dbus_connection_unregister_object_path (DBUS_CONNECTION_FROM_G_CONNECTION (o->connection), - o->object_path); + g_list_free (registrations); + g_assert (g_object_get_data (object, "dbus_glib_object_registrations") == NULL); } /** @@ -2116,6 +2149,9 @@ dbus_g_connection_unregister_g_object (DBusGConnection *connection, * The registration will be cancelled if either the #DBusConnection or * the #GObject gets finalized, or if dbus_g_connection_unregister_g_object() * is used. + * + * Note: If an object is registered multiple times, the first registration + * takes priority for cases such as turning an object into an object path. */ void dbus_g_connection_register_g_object (DBusGConnection *connection, @@ -2123,28 +2159,44 @@ dbus_g_connection_register_g_object (DBusGConnection *connection, GObject *object) { GList *info_list; + GSList *registrations, *iter; ObjectRegistration *o; + gboolean is_first_registration; g_return_if_fail (connection != NULL); g_return_if_fail (at_path != NULL); g_return_if_fail (G_IS_OBJECT (object)); - info_list = lookup_object_info (object); - if (info_list == NULL) + /* This is a GSList of ObjectRegistration* */ + registrations = g_object_steal_data (object, "dbus_glib_object_registrations"); + + for (iter = registrations; iter; iter = iter->next) { - g_warning ("No introspection data registered for object class \"%s\"", - g_type_name (G_TYPE_FROM_INSTANCE (object))); - return; + o = iter->data; + + /* Silently ignore duplicate registrations */ + if (strcmp (o->object_path, at_path) == 0) + return; } - o = g_object_get_data (object, "dbus_glib_object_registration"); + is_first_registration = registrations == NULL; - if (o != NULL) + /* This is used to hook up signals below, but we do this check + * before trying to register the object to make sure we have + * introspection data for it. + */ + if (is_first_registration) { - g_warning ("Object already registered at %s, can't re-register at %s", - o->object_path, at_path); - return; + info_list = lookup_object_info (object); + if (info_list == NULL) + { + g_warning ("No introspection data registered for object class \"%s\"", + g_type_name (G_TYPE_FROM_INSTANCE (object))); + return; + } } + else + info_list = NULL; o = object_registration_new (connection, at_path, object); @@ -2155,12 +2207,22 @@ dbus_g_connection_register_g_object (DBusGConnection *connection, { g_error ("Failed to register GObject with DBusConnection"); object_registration_free (o); + g_list_free (info_list); return; } - export_signals (connection, info_list, object); - g_list_free (info_list); - g_object_set_data (object, "dbus_glib_object_registration", o); + if (is_first_registration) + { + /* This adds a hook into every signal for the object. Only do this + * on the first registration, because inside the signal marshaller + * we emit a signal for each registration. + */ + export_signals (connection, info_list, object); + g_list_free (info_list); + } + + registrations = g_slist_append (registrations, o); + g_object_set_data (object, "dbus_glib_object_registrations", registrations); } /** @@ -2539,15 +2601,20 @@ dbus_g_method_return_error (DBusGMethodInvocation *context, const GError *error) g_free (context); } -const char * _dbus_gobject_get_path (GObject *obj) +const char * +_dbus_gobject_get_path (GObject *obj) { + GSList *registrations; ObjectRegistration *o; - o = g_object_get_data (obj, "dbus_glib_object_registration"); + registrations = g_object_get_data (obj, "dbus_glib_object_registrations"); - if (o == NULL) + if (registrations == NULL) return NULL; + /* First one to have been registered wins */ + o = registrations->data; + return o->object_path; } diff --git a/test/core/test-dbus-glib.c b/test/core/test-dbus-glib.c index c6071a7..288606f 100644 --- a/test/core/test-dbus-glib.c +++ b/test/core/test-dbus-glib.c @@ -15,6 +15,7 @@ static const char *await_terminating_service = NULL; static int n_times_foo_received = 0; static int n_times_frobnicate_received = 0; static int n_times_frobnicate_received_2 = 0; +static int n_times_compat_frobnicate_received = 0; static int n_times_sig0_received = 0; static int n_times_sig1_received = 0; static int n_times_sig2_received = 0; @@ -139,6 +140,20 @@ frobnicate_signal_handler_2 (DBusGProxy *proxy, } static void +frobnicate_signal_handler_compat (DBusGProxy *proxy, + int val, + void *user_data) +{ + n_times_compat_frobnicate_received += 1; + + g_assert (val == 42); + g_print ("Got Frobnicate signal (compat)\n"); + + g_main_loop_quit (loop); + g_source_remove (exit_timeout); +} + +static void sig0_signal_handler (DBusGProxy *proxy, const char *str0, int val, @@ -1886,6 +1901,32 @@ main (int argc, char **argv) run_mainloop (); + /* Tests for a "compatibilty" object path. This is the same object as above, just + * at a different path. + */ + proxy = dbus_g_proxy_new_for_name_owner (connection, + "org.freedesktop.DBus.GLib.TestService", + "/org/freedesktop/DBus/GLib/Tests/Compat/MyTestObjectCompat", + "org.freedesktop.DBus.GLib.Tests.MyObject", + &error); + dbus_g_proxy_add_signal (proxy, "Frobnicate", G_TYPE_INT, G_TYPE_INVALID); + + dbus_g_proxy_connect_signal (proxy, "Frobnicate", + G_CALLBACK (frobnicate_signal_handler_compat), + NULL, NULL); + + g_print ("Calling EmitFrobnicate (compat)\n"); + if (!dbus_g_proxy_call (proxy, "EmitFrobnicate", &error, + G_TYPE_INVALID, G_TYPE_INVALID)) + lose_gerror ("Failed to complete EmitFrobnicate call on compat proxy", error); + + g_main_loop_run (loop); + + if (n_times_compat_frobnicate_received != 1) + lose ("Frobnicate signal received %d times for compat proxy, should have been 1", n_times_compat_frobnicate_received); + + g_object_unref (proxy); + /* Test introspection */ proxy = dbus_g_proxy_new_for_name_owner (connection, "org.freedesktop.DBus.GLib.TestService", diff --git a/test/core/test-service-glib.c b/test/core/test-service-glib.c index 1cdb0ac..fad2473 100644 --- a/test/core/test-service-glib.c +++ b/test/core/test-service-glib.c @@ -66,6 +66,10 @@ main (int argc, char **argv) dbus_g_connection_register_g_object (connection, "/org/freedesktop/DBus/GLib/Tests/MyTestObject", obj); + /* Register a second time; we want the object to also be reachable through this interface */ + dbus_g_connection_register_g_object (connection, + "/org/freedesktop/DBus/GLib/Tests/Compat/MyTestObjectCompat", + obj); dbus_g_connection_register_g_object (connection, "/org/freedesktop/DBus/GLib/Tests/MyTestObject2", obj2); |