diff --git a/gio/gdbusobjectmanagerclient.c b/gio/gdbusobjectmanagerclient.c index 88fcff4fa..04c55995d 100644 --- a/gio/gdbusobjectmanagerclient.c +++ b/gio/gdbusobjectmanagerclient.c @@ -20,11 +20,13 @@ #include "config.h" +#include "gcancellable.h" #include "gdbusobjectmanager.h" #include "gdbusobjectmanagerclient.h" #include "gdbusobject.h" #include "gdbusprivate.h" #include "gioenumtypes.h" +#include "gioerror.h" #include "ginitable.h" #include "gasyncresult.h" #include "gasyncinitable.h" @@ -144,6 +146,7 @@ struct _GDBusObjectManagerClientPrivate gulong name_owner_signal_id; gulong signal_signal_id; + GCancellable *cancel; }; enum @@ -191,6 +194,20 @@ static void process_get_all_result (GDBusObjectManagerClient *manager, GVariant *value, const gchar *name_owner); +static void +g_dbus_object_manager_client_dispose (GObject *object) +{ + GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (object); + + if (manager->priv->cancel != NULL) + { + g_cancellable_cancel (manager->priv->cancel); + g_clear_object (&manager->priv->cancel); + } + + G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class)->dispose (object); +} + static void g_dbus_object_manager_client_finalize (GObject *object) { @@ -327,6 +344,7 @@ g_dbus_object_manager_client_class_init (GDBusObjectManagerClientClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + gobject_class->dispose = g_dbus_object_manager_client_dispose; gobject_class->finalize = g_dbus_object_manager_client_finalize; gobject_class->set_property = g_dbus_object_manager_client_set_property; gobject_class->get_property = g_dbus_object_manager_client_get_property; @@ -589,6 +607,7 @@ g_dbus_object_manager_client_init (GDBusObjectManagerClient *manager) g_str_equal, g_free, (GDestroyNotify) g_object_unref); + manager->priv->cancel = g_cancellable_new (); } /* ---------------------------------------------------------------------------------------------------- */ @@ -1244,6 +1263,75 @@ maybe_unsubscribe_signals (GDBusObjectManagerClient *manager) /* ---------------------------------------------------------------------------------------------------- */ +static GWeakRef * +weak_ref_new (GObject *object) +{ + GWeakRef *weak_ref = g_new0 (GWeakRef, 1); + g_weak_ref_init (weak_ref, object); + return g_steal_pointer (&weak_ref); +} + +static void +weak_ref_free (GWeakRef *weak_ref) +{ + g_weak_ref_clear (weak_ref); + g_free (weak_ref); +} + +static void +on_get_managed_objects_finish (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + + GDBusProxy *proxy = G_DBUS_PROXY (source); + GWeakRef *manager_weak = user_data; + GDBusObjectManagerClient *manager; + GError *error = NULL; + GVariant *value = NULL; + gchar *new_name_owner = NULL; + + value = g_dbus_proxy_call_finish (proxy, result, &error); + + manager = G_DBUS_OBJECT_MANAGER_CLIENT (g_weak_ref_get (manager_weak)); + /* Manager got disposed, nothing to do */ + if (manager == NULL) + { + goto out; + } + + new_name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy); + if (value == NULL) + { + maybe_unsubscribe_signals (manager); + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + g_warning ("Error calling GetManagedObjects() when name owner %s for name %s came back: %s", + new_name_owner, + manager->priv->name, + error->message); + } + } + else + { + process_get_all_result (manager, value, new_name_owner); + } + + /* do the :name-owner notify *AFTER* emitting ::object-proxy-added signals - this + * way the user knows that the signals were emitted because the name owner came back + */ + g_mutex_lock (&manager->priv->lock); + manager->priv->name_owner = g_steal_pointer (&new_name_owner); + g_mutex_unlock (&manager->priv->lock); + g_object_notify (G_OBJECT (manager), "name-owner"); + + g_object_unref (manager); + out: + g_clear_error (&error); + g_clear_pointer (&value, g_variant_unref); + weak_ref_free (manager_weak); +} + static void on_notify_g_name_owner (GObject *object, GParamSpec *pspec, @@ -1298,65 +1386,24 @@ on_notify_g_name_owner (GObject *object, if (new_name_owner != NULL) { - GError *error; - GVariant *value; - //g_debug ("repopulating for %s", new_name_owner); - /* TODO: do this async! */ subscribe_signals (manager, new_name_owner); - error = NULL; - value = g_dbus_proxy_call_sync (manager->priv->control_proxy, - "GetManagedObjects", - NULL, /* parameters */ - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - &error); - if (value == NULL) - { - maybe_unsubscribe_signals (manager); - g_warning ("Error calling GetManagedObjects() when name owner %s for name %s came back: %s", - new_name_owner, - manager->priv->name, - error->message); - g_error_free (error); - } - else - { - process_get_all_result (manager, value, new_name_owner); - g_variant_unref (value); - } - - /* do the :name-owner notify *AFTER* emitting ::object-proxy-added signals - this - * way the user knows that the signals were emitted because the name owner came back - */ - g_mutex_lock (&manager->priv->lock); - manager->priv->name_owner = new_name_owner; - g_mutex_unlock (&manager->priv->lock); - g_object_notify (G_OBJECT (manager), "name-owner"); - + g_dbus_proxy_call (manager->priv->control_proxy, + "GetManagedObjects", + NULL, /* parameters */ + G_DBUS_CALL_FLAGS_NONE, + -1, + manager->priv->cancel, + on_get_managed_objects_finish, + weak_ref_new (G_OBJECT (manager))); } + g_free (new_name_owner); g_free (old_name_owner); g_object_unref (manager); } -static GWeakRef * -weak_ref_new (GObject *object) -{ - GWeakRef *weak_ref = g_new0 (GWeakRef, 1); - g_weak_ref_init (weak_ref, object); - return g_steal_pointer (&weak_ref); -} - -static void -weak_ref_free (GWeakRef *weak_ref) -{ - g_weak_ref_clear (weak_ref); - g_free (weak_ref); -} - static gboolean initable_init (GInitable *initable, GCancellable *cancellable,