[glib/gdbus: 3/6] Ensure _new_for_connection() variants work with an unopened connection



commit 007945d4759880623d2f5d0363331622369c97b0
Author: David Zeuthen <davidz redhat com>
Date:   Tue Apr 21 20:28:56 2009 -0400

    Ensure _new_for_connection() variants work with an unopened connection
    
    Also add g_bus_name_watcher_new_for_connection().
---
 docs/reference/gdbus/gdbus-sections.txt |    3 +
 gdbus/gbusnameowner.c                   |  411 ++++++++++++++++++++-----------
 gdbus/gbusnamewatcher.c                 |  287 +++++++++++++---------
 gdbus/gbusnamewatcher.h                 |    2 -
 gdbus/gdbus.symbols                     |    3 +
 gdbus/gdbusconnection.c                 |   45 ++++-
 gdbus/gdbusconnection.h                 |    1 +
 gdbus/tests/connection.c                |   81 ++++---
 8 files changed, 532 insertions(+), 301 deletions(-)

diff --git a/docs/reference/gdbus/gdbus-sections.txt b/docs/reference/gdbus/gdbus-sections.txt
index 0550195..7149c28 100644
--- a/docs/reference/gdbus/gdbus-sections.txt
+++ b/docs/reference/gdbus/gdbus-sections.txt
@@ -29,6 +29,8 @@ GBusNameWatcher
 GBusNameWatcherClass
 g_bus_name_watcher_new
 g_bus_name_watcher_new_finish
+g_bus_name_watcher_new_for_connection
+g_bus_name_watcher_new_for_connection_finish
 g_bus_name_watcher_get_name
 g_bus_name_watcher_get_name_owner
 g_bus_name_watcher_get_flags
@@ -57,6 +59,7 @@ g_dbus_connection_get_exit_on_close
 g_dbus_connection_set_exit_on_close
 g_dbus_connection_get_unique_name
 g_dbus_connection_get_is_open
+g_dbus_connection_get_is_opening
 g_dbus_connection_get_bus_type
 g_dbus_connection_get_dbus_1_connection
 <SUBSECTION Standard>
diff --git a/gdbus/gbusnameowner.c b/gdbus/gbusnameowner.c
index 9f6185a..4bf003b 100644
--- a/gdbus/gbusnameowner.c
+++ b/gdbus/gbusnameowner.c
@@ -52,7 +52,9 @@ struct _GBusNameOwnerPrivate
 
   gboolean owns_name;
 
-  gboolean in_construction_phase;
+  /* these variables are used to store async callbacks for users calling _new()  */
+  gboolean in_init_phase;
+  GPtrArray *init_phase_pending_simple_async_results;
 };
 
 enum
@@ -71,6 +73,11 @@ enum
   LAST_SIGNAL,
 };
 
+G_LOCK_DEFINE_STATIC (owner_lock);
+
+static GBusNameOwner *singletons_get_owner (GDBusConnection *connection, const gchar *name);
+static void singletons_add_owner (GBusNameOwner *owner);
+static void singletons_remove_owner (GBusNameOwner *owner);
 
 static DBusHandlerResult
 filter_function (DBusConnection *dbus_1_connection,
@@ -113,6 +120,19 @@ static guint get_request_name_flags (GBusNameOwnerFlags flags);
 G_DEFINE_TYPE (GBusNameOwner, g_bus_name_owner, G_TYPE_OBJECT);
 
 static void
+g_bus_name_owner_dispose (GObject *object)
+{
+  GBusNameOwner *owner = G_BUS_NAME_OWNER (object);
+
+  G_LOCK (owner_lock);
+  singletons_remove_owner (owner);
+  G_UNLOCK (owner_lock);
+
+  if (G_OBJECT_CLASS (g_bus_name_owner_parent_class)->dispose != NULL)
+    G_OBJECT_CLASS (g_bus_name_owner_parent_class)->dispose (object);
+}
+
+static void
 g_bus_name_owner_finalize (GObject *object)
 {
   GBusNameOwner *owner = G_BUS_NAME_OWNER (object);
@@ -361,7 +381,7 @@ on_connection_opened (GDBusConnection *connection,
                                    NULL))
     _g_dbus_oom ();
 
-  if (owner->priv->in_construction_phase)
+  if (owner->priv->in_init_phase)
     return;
 
   /* ok, the bus suddenly came up.. so try to claim the name ASAP */
@@ -418,6 +438,7 @@ g_bus_name_owner_class_init (GBusNameOwnerClass *klass)
   g_type_class_add_private (klass, sizeof (GBusNameOwnerPrivate));
 
   gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->dispose     = g_bus_name_owner_dispose;
   gobject_class->finalize     = g_bus_name_owner_finalize;
   gobject_class->constructed  = g_bus_name_owner_constructed;
   gobject_class->get_property = g_bus_name_owner_get_property;
@@ -532,7 +553,8 @@ static void
 g_bus_name_owner_init (GBusNameOwner *owner)
 {
   owner->priv = G_TYPE_INSTANCE_GET_PRIVATE (owner, G_TYPE_BUS_NAME_OWNER, GBusNameOwnerPrivate);
-  owner->priv->in_construction_phase = TRUE;
+  owner->priv->in_init_phase = TRUE;
+  owner->priv->init_phase_pending_simple_async_results = g_ptr_array_new ();
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -865,112 +887,276 @@ bus_request_name_finish (GDBusConnection  *bus,
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
+/* routines used for singleton handling */
+
+/* maps from connection to GHashTable (that maps from names to GBusNameOwner) */
+static GHashTable *map_connection_to_map_of_owned_names_to_owner = NULL;
 
-typedef struct
+/* the following singletons_* functions must be called with owner_lock held */
+
+/* called from _new() before creating a GBusNameOwner - result is not reffed */
+static GBusNameOwner *
+singletons_get_owner (GDBusConnection *connection, const gchar *name)
 {
-  GAsyncReadyCallback   callback;
-  gpointer              user_data;
-  GBusNameOwner        *owner;
-  gboolean              is_for_connection;
-} ConstructData;
+  GBusNameOwner *ret;
+  GHashTable *map_of_owned_names_to_owner;
+
+  g_return_val_if_fail (connection != NULL, NULL);
+  g_return_val_if_fail (name != NULL, NULL);
+
+  ret = NULL;
+
+  if (map_connection_to_map_of_owned_names_to_owner == NULL)
+    goto out;
+
+  map_of_owned_names_to_owner = g_hash_table_lookup (map_connection_to_map_of_owned_names_to_owner,
+                                                         connection);
+  if (map_of_owned_names_to_owner == NULL)
+    goto out;
+
+  ret = g_hash_table_lookup (map_of_owned_names_to_owner,
+                             name);
+
+ out:
+  return ret;
+}
 
+/* called from _new() after creating the GBusNameOwner */
 static void
-construct_data_free (ConstructData *data)
+singletons_add_owner (GBusNameOwner *owner)
 {
-  g_free (data);
+  GHashTable *map_of_owned_names_to_owner;
+
+  g_return_if_fail (owner != NULL);
+
+  if (map_connection_to_map_of_owned_names_to_owner == NULL)
+    map_connection_to_map_of_owned_names_to_owner = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+  map_of_owned_names_to_owner = g_hash_table_lookup (map_connection_to_map_of_owned_names_to_owner,
+                                                         owner->priv->connection);
+  if (map_of_owned_names_to_owner == NULL)
+    {
+      map_of_owned_names_to_owner = g_hash_table_new (g_str_hash, g_str_equal);
+      g_hash_table_insert (map_connection_to_map_of_owned_names_to_owner,
+                           owner->priv->connection,
+                           map_of_owned_names_to_owner);
+    }
+
+  g_hash_table_insert (map_of_owned_names_to_owner,
+                       owner->priv->name,
+                       owner);
+}
+
+/* called from dispose() - ie. can be called multiple times so don't assert anything */
+static void
+singletons_remove_owner (GBusNameOwner *owner)
+{
+  GHashTable *map_of_owned_names_to_owner;
+
+  if (map_connection_to_map_of_owned_names_to_owner == NULL)
+    goto out;
+
+  map_of_owned_names_to_owner = g_hash_table_lookup (map_connection_to_map_of_owned_names_to_owner,
+                                                         owner->priv->connection);
+  if (map_of_owned_names_to_owner == NULL)
+    goto out;
+
+  if (!g_hash_table_remove (map_of_owned_names_to_owner,
+                            owner->priv->name))
+    goto out;
+
+  /* clean up as needed */
+  if (g_hash_table_size (map_of_owned_names_to_owner) == 0)
+    {
+      g_hash_table_remove (map_connection_to_map_of_owned_names_to_owner, owner->priv->connection);
+      g_hash_table_destroy (map_of_owned_names_to_owner);
+
+      if (g_hash_table_size (map_connection_to_map_of_owned_names_to_owner) == 0)
+        {
+          g_hash_table_destroy (map_connection_to_map_of_owned_names_to_owner);
+          map_connection_to_map_of_owned_names_to_owner = NULL;
+        }
+    }
+
+ out:
+  ;
 }
 
+/* ---------------------------------------------------------------------------------------------------- */
 static void
 request_name_cb (GDBusConnection *connection,
                  GAsyncResult    *result,
                  gpointer         user_data)
 {
-  ConstructData *data = user_data;
+  GBusNameOwner *owner = G_BUS_NAME_OWNER (user_data);
   GSimpleAsyncResult *simple;
   GError *error;
   guint reply;
-
-  simple = g_simple_async_result_new (G_OBJECT (data->owner),
-                                      data->callback,
-                                      data->user_data,
-                                      data->is_for_connection ? g_bus_name_owner_new_for_connection_finish : g_bus_name_owner_new_finish);
+  guint n;
 
   error = NULL;
   reply = bus_request_name_finish (connection,
                                    result,
                                    &error);
+  G_LOCK (owner_lock);
   if (error != NULL)
     {
-      g_simple_async_result_set_from_error (simple,
-                                            error);
+      /* report error back */
+      for (n = 0; n < owner->priv->init_phase_pending_simple_async_results->len; n++)
+        {
+          simple = G_SIMPLE_ASYNC_RESULT (owner->priv->init_phase_pending_simple_async_results->pdata[n]);
+          g_simple_async_result_set_from_error (simple, error);
+          g_simple_async_result_complete_in_idle (simple);
+          g_object_unref (simple);
+        }
       g_error_free (error);
     }
   else
     {
-      if (reply != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
-        {
-          g_simple_async_result_set_error (simple,
-                                           G_DBUS_ERROR,
-                                           G_DBUS_ERROR_FAILED,
-                                           _("Error acquiring name, RequestName() returned %d"),
-                                           reply);
-        }
-      else
+      if (reply == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
+        owner->priv->owns_name = TRUE;
+
+      /* complete operations without error */
+      for (n = 0; n < owner->priv->init_phase_pending_simple_async_results->len; n++)
         {
-          data->owner->priv->owns_name = TRUE;
-          g_signal_emit (data->owner, signals[NAME_ACQUIRED_SIGNAL], 0);
+          simple = G_SIMPLE_ASYNC_RESULT (owner->priv->init_phase_pending_simple_async_results->pdata[n]);
+          g_simple_async_result_complete_in_idle (simple);
+          g_object_unref (simple);
         }
     }
 
-  data->owner->priv->in_construction_phase = FALSE;
-  g_simple_async_result_complete_in_idle (simple);
-  g_object_unref (simple);
-  construct_data_free (data);
+  owner->priv->in_init_phase = FALSE;
+  g_ptr_array_free (owner->priv->init_phase_pending_simple_async_results, TRUE);
+  owner->priv->init_phase_pending_simple_async_results = NULL;
+  G_UNLOCK (owner_lock);
 }
 
 static void
-get_connection_cb (GDBusConnection *connection,
-                   GAsyncResult    *result,
-                   gpointer         user_data)
+on_notify_is_opening (GDBusConnection *connection,
+                      GParamSpec      *spec,
+                      gpointer         user_data)
 {
-  ConstructData *data = user_data;
-  GError *error;
+  GBusNameOwner *owner = G_BUS_NAME_OWNER (user_data);
 
-  error = NULL;
-  if (!g_dbus_connection_bus_get_finish (connection,
-                                         result,
-                                         &error))
-    {
-      GSimpleAsyncResult *simple;
-
-      /* connection is not open.. report back */
-      simple = g_simple_async_result_new (G_OBJECT (data->owner),
-                                          data->callback,
-                                          data->user_data,
-                                          g_bus_name_owner_new_finish);
-      g_simple_async_result_set_from_error (simple,
-                                            error);
-      g_error_free (error);
+  /* connection is not opening anymore.. try to own the name */
+  bus_request_name (owner->priv->connection,
+                    owner->priv->name,
+                    get_request_name_flags (owner->priv->flags),
+                    (GAsyncReadyCallback) request_name_cb,
+                    owner);
 
-      data->owner->priv->in_construction_phase = FALSE;
-      g_simple_async_result_complete_in_idle (simple);
-      g_object_unref (simple);
-      construct_data_free (data);
+  g_signal_handlers_disconnect_by_func (connection, on_notify_is_opening, owner);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static GBusNameOwner *
+g_bus_name_owner_new_internal (GMessageBusType        bus_type,
+                               GDBusConnection       *given_connection,
+                               const gchar           *name,
+                               GBusNameOwnerFlags     flags,
+                               GCancellable          *cancellable,
+                               GAsyncReadyCallback    callback,
+                               gpointer               user_data)
+{
+  GBusNameOwner *owner;
+  GDBusConnection *connection;
+  GSimpleAsyncResult *simple;
+  gpointer source_tag;
+
+  /* This is all a tad complicated since we support singletons... the problem here
+   * in a nutshell is that there's a window, an initialization phase, where we
+   *
+   *  - wait until the connection is no longer in an opening state
+   *  - and for the reply for the HasNameOwner() method invocation
+   *
+   * Now, suppose the user creates two owner objects with the same bus and name
+   * and no bus is up. The second one will just be a reference to the first one
+   * because we support singletons. So basically while we are initializing, just
+   * add the callback for the second owner to a list on the first one. Then
+   * when initialization is done, fire all callbacks.
+   */
+
+  if (given_connection != NULL)
+    {
+      source_tag = g_bus_name_owner_new_for_connection_finish;
+      connection = g_object_ref (given_connection);
     }
   else
     {
-      /* connection is open.. try to claim the name */
+      source_tag = g_bus_name_owner_new_finish;
+      connection = g_dbus_connection_bus_get (bus_type,
+                                              NULL,
+                                              NULL,
+                                              NULL);
+    }
+
+  G_LOCK (owner_lock);
+  /* check if a suitable owner already exists */
+  owner = singletons_get_owner (connection, name);
+  if (owner != NULL)
+    {
+      simple = g_simple_async_result_new (G_OBJECT (owner),
+                                          callback,
+                                          user_data,
+                                          source_tag);
+
+      if (owner->priv->in_init_phase)
+        {
+          /* if still initializing, defer callback until we know what stuff looks like */
+          g_ptr_array_add (owner->priv->init_phase_pending_simple_async_results, simple);
+        }
+      else
+        {
+          /* otherwise, return the result right away (e.g. in idle) */
+          g_simple_async_result_complete_in_idle (simple);
+          g_object_unref (simple);
+        }
+      g_object_ref (owner);
+      goto out;
+    }
+
+  owner = G_BUS_NAME_OWNER (g_object_new (G_TYPE_BUS_NAME_OWNER,
+                                          "name", name,
+                                          "flags", flags,
+                                          "connection", connection,
+                                          NULL));
+
+  simple = g_simple_async_result_new (G_OBJECT (owner),
+                                      callback,
+                                      user_data,
+                                      source_tag);
 
-      bus_request_name (data->owner->priv->connection,
-                        data->owner->priv->name,
-                        get_request_name_flags (data->owner->priv->flags),
+  g_ptr_array_add (owner->priv->init_phase_pending_simple_async_results, simple);
+
+  singletons_add_owner (owner);
+
+  if (g_dbus_connection_get_is_opening (connection))
+    {
+      /* connection is opening.. so wait until it is done opening */
+      g_signal_connect (connection,
+                        "notify::is-opening",
+                        G_CALLBACK (on_notify_is_opening),
+                        owner);
+    }
+  else
+    {
+      /* connection is not opening.. try to claim the name */
+      bus_request_name (owner->priv->connection,
+                        owner->priv->name,
+                        get_request_name_flags (owner->priv->flags),
                         (GAsyncReadyCallback) request_name_cb,
-                        data);
+                        owner);
     }
 
-}
 
-/* ---------------------------------------------------------------------------------------------------- */
+ out:
+  G_UNLOCK (owner_lock);
+
+  g_object_unref (connection);
+
+  return owner;
+}
 
 /**
  * g_bus_name_owner_new:
@@ -986,6 +1172,9 @@ get_connection_cb (GDBusConnection *connection,
  * finished, @callback will be invoked (on the main thread) and you
  * can use g_bus_name_owner_new_finish() to get the result.
  *
+ * Note that the returned object may be shared with other callers if
+ * @bus_type and @name matches.
+ *
  * This class is the preferred way to implement D-Bus
  * services. The canonical example follows.
  * <example><title>Using g_bus_name_owner_new()</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude"; parse="text" href="../../../../gdbus/example-gbusnameowner.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting></example>
@@ -1000,30 +1189,13 @@ g_bus_name_owner_new (GMessageBusType        bus_type,
                       GAsyncReadyCallback    callback,
                       gpointer               user_data)
 {
-  GBusNameOwner *owner;
-  GDBusConnection *connection;
-  ConstructData *data;
-
-  data = g_new0 (ConstructData, 1);
-  data->callback = callback;
-  data->user_data = user_data;
-
-  connection = g_dbus_connection_bus_get (bus_type,
-                                          cancellable,
-                                          (GAsyncReadyCallback) get_connection_cb,
-                                          data);
-
-  owner = G_BUS_NAME_OWNER (g_object_new (G_TYPE_BUS_NAME_OWNER,
-                                          "name", name,
-                                          "connection", connection,
-                                          "flags", flags,
-                                          NULL));
-
-  data->owner = owner;
-
-  g_object_unref (connection);
-
-  return owner;
+  return g_bus_name_owner_new_internal (bus_type,
+                                        NULL,
+                                        name,
+                                        flags,
+                                        cancellable,
+                                        callback,
+                                        user_data);
 }
 
 /**
@@ -1034,7 +1206,8 @@ g_bus_name_owner_new (GMessageBusType        bus_type,
  *
  * Finishes attempting to acquire a name.
  *
- * Returns: %TRUE if the name was acquired, otherwise %FALSE with @error set.
+ * Returns: %TRUE if the attempt to acquired the name succeed (the name may not have been
+ * acquired, check with g_bus_name_owner_get_owns_name()), otherwise %FALSE with @error set.
  **/
 gboolean
 g_bus_name_owner_new_finish (GBusNameOwner         *owner,
@@ -1042,16 +1215,12 @@ g_bus_name_owner_new_finish (GBusNameOwner         *owner,
                              GError               **error)
 {
   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
-
   g_return_val_if_fail (G_IS_BUS_NAME_OWNER (owner), FALSE);
-
   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_bus_name_owner_new_finish);
-
   return !g_simple_async_result_propagate_error (simple, error);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
-
 /**
  * g_bus_name_owner_new_for_connection:
  * @connection: A #GDBusConnection.
@@ -1074,52 +1243,13 @@ g_bus_name_owner_new_for_connection (GDBusConnection       *connection,
                                      GAsyncReadyCallback    callback,
                                      gpointer               user_data)
 {
-  GBusNameOwner *owner;
-
-  owner = G_BUS_NAME_OWNER (g_object_new (G_TYPE_BUS_NAME_OWNER,
-                                          "name", name,
-                                          "connection", connection,
-                                          "flags", flags,
-                                          NULL));
-
-  if (g_dbus_connection_get_is_open (connection))
-    {
-      ConstructData *data;
-      data = g_new0 (ConstructData, 1);
-      data->callback = callback;
-      data->user_data = user_data;
-      data->is_for_connection = TRUE;
-      data->owner = owner;
-
-      /* connection is open.. try to claim the name */
-      bus_request_name (data->owner->priv->connection,
-                        data->owner->priv->name,
-                        get_request_name_flags (data->owner->priv->flags),
-                        (GAsyncReadyCallback) request_name_cb,
-                        data);
-    }
-  else
-    {
-      GSimpleAsyncResult *simple;
-
-      /* connection is not open.. report back in idle
-       *
-       * TODO: maybe handle g_dbus_connection_is_connecting() or something...
-       */
-      simple = g_simple_async_result_new (G_OBJECT (owner),
-                                          callback,
-                                          user_data,
-                                          g_bus_name_owner_new_for_connection_finish);
-      g_simple_async_result_set_error (simple,
-                                       G_DBUS_ERROR,
-                                       G_DBUS_ERROR_FAILED,
-                                       _("Connection is not open"));
-
-      g_simple_async_result_complete_in_idle (simple);
-      g_object_unref (simple);
-    }
-
-  return owner;
+  return g_bus_name_owner_new_internal (G_MESSAGE_BUS_TYPE_NONE,
+                                        connection,
+                                        name,
+                                        flags,
+                                        cancellable,
+                                        callback,
+                                        user_data);
 }
 
 /**
@@ -1146,7 +1276,6 @@ g_bus_name_owner_new_for_connection_finish (GBusNameOwner         *owner,
 
   return !g_simple_async_result_propagate_error (simple, error);
 }
-
 /* ---------------------------------------------------------------------------------------------------- */
 
 /**
diff --git a/gdbus/gbusnamewatcher.c b/gdbus/gbusnamewatcher.c
index 2e9f778..d540040 100644
--- a/gdbus/gbusnamewatcher.c
+++ b/gdbus/gbusnamewatcher.c
@@ -497,6 +497,7 @@ g_bus_name_watcher_init (GBusNameWatcher *watcher)
 {
   watcher->priv = G_TYPE_INSTANCE_GET_PRIVATE (watcher, G_TYPE_BUS_NAME_WATCHER, GBusNameWatcherPrivate);
   watcher->priv->in_init_phase = TRUE;
+  watcher->priv->init_phase_pending_simple_async_results = g_ptr_array_new ();
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -912,23 +913,12 @@ singletons_remove_watcher (GBusNameWatcher *watcher)
 
 /* ---------------------------------------------------------------------------------------------------- */
 
-typedef struct
-{
-  GBusNameWatcher *watcher;
-} ConstructData;
-
-static void
-construct_data_free (ConstructData *data)
-{
-  g_free (data);
-}
-
 static void
 get_name_owner_cb (GDBusConnection *connection,
                    GAsyncResult    *result,
                    gpointer         user_data)
 {
-  ConstructData *data = user_data;
+  GBusNameWatcher *watcher = G_BUS_NAME_WATCHER (user_data);
   GSimpleAsyncResult *simple;
   GError *error;
   gchar *name_owner;
@@ -941,13 +931,12 @@ get_name_owner_cb (GDBusConnection *connection,
 
   G_LOCK (watcher_lock);
 
-  /* NAME_HAS_NO_OWNER error => don't report this as an error, it just means there is no name owner */
-  if (error != NULL && (error->domain != G_DBUS_ERROR && error->code != G_DBUS_ERROR_NAME_HAS_NO_OWNER))
+  if (error != NULL)
     {
       /* report error back */
-      for (n = 0; n < data->watcher->priv->init_phase_pending_simple_async_results->len; n++)
+      for (n = 0; n < watcher->priv->init_phase_pending_simple_async_results->len; n++)
         {
-          simple = G_SIMPLE_ASYNC_RESULT (data->watcher->priv->init_phase_pending_simple_async_results->pdata[n]);
+          simple = G_SIMPLE_ASYNC_RESULT (watcher->priv->init_phase_pending_simple_async_results->pdata[n]);
           g_simple_async_result_set_from_error (simple, error);
           g_simple_async_result_complete_in_idle (simple);
           g_object_unref (simple);
@@ -956,118 +945,54 @@ get_name_owner_cb (GDBusConnection *connection,
     }
   else
     {
-      g_free (data->watcher->priv->name_owner);
-      if (error != NULL)
-        {
-          g_error_free (error);
-          data->watcher->priv->name_owner = NULL;
-        }
-      else
-        {
-          data->watcher->priv->name_owner = name_owner; /* steals the returned string */
-        }
+      watcher->priv->name_owner = name_owner; /* steals the returned string */
 
       /* complete operations without error */
-      for (n = 0; n < data->watcher->priv->init_phase_pending_simple_async_results->len; n++)
+      for (n = 0; n < watcher->priv->init_phase_pending_simple_async_results->len; n++)
         {
-          simple = G_SIMPLE_ASYNC_RESULT (data->watcher->priv->init_phase_pending_simple_async_results->pdata[n]);
+          simple = G_SIMPLE_ASYNC_RESULT (watcher->priv->init_phase_pending_simple_async_results->pdata[n]);
           g_simple_async_result_complete_in_idle (simple);
           g_object_unref (simple);
         }
     }
 
-  data->watcher->priv->in_init_phase = FALSE;
-  g_ptr_array_free (data->watcher->priv->init_phase_pending_simple_async_results, TRUE);
+  watcher->priv->in_init_phase = FALSE;
+  g_ptr_array_free (watcher->priv->init_phase_pending_simple_async_results, TRUE);
+  watcher->priv->init_phase_pending_simple_async_results = NULL;
   G_UNLOCK (watcher_lock);
+}
 
 
-  construct_data_free (data);
-}
+/* ---------------------------------------------------------------------------------------------------- */
 
 static void
-get_connection_cb (GDBusConnection *connection,
-                   GAsyncResult    *result,
-                   gpointer         user_data)
+on_notify_is_opening (GDBusConnection *connection,
+                      GParamSpec      *spec,
+                      gpointer         user_data)
 {
-  ConstructData *data = user_data;
-  GError *error;
-
-  if (data->watcher == NULL)
-    goto out;
-
-  error = NULL;
-  if (!g_dbus_connection_bus_get_finish (connection,
-                                         result,
-                                         &error))
-    {
-      GSimpleAsyncResult *simple;
-      guint n;
-
-      G_LOCK (watcher_lock);
-      /* connection is not open.. report back */
-      for (n = 0; n < data->watcher->priv->init_phase_pending_simple_async_results->len; n++)
-        {
-          simple = G_SIMPLE_ASYNC_RESULT (data->watcher->priv->init_phase_pending_simple_async_results->pdata[n]);
-          g_simple_async_result_set_from_error (simple, error);
-          g_simple_async_result_complete_in_idle (simple);
-          g_object_unref (simple);
-        }
-      data->watcher->priv->in_init_phase = FALSE;
-      g_ptr_array_free (data->watcher->priv->init_phase_pending_simple_async_results, TRUE);
-      G_UNLOCK (watcher_lock);
-
-      g_error_free (error);
+  GBusNameWatcher *watcher = G_BUS_NAME_WATCHER (user_data);
 
-      construct_data_free (data);
-    }
-  else
-    {
-      /* connection is open.. check if the name exists */
-      bus_get_name_owner (data->watcher->priv->connection,
-                          data->watcher->priv->name,
-                          (GAsyncReadyCallback) get_name_owner_cb,
-                          data);
-    }
+  /* connection is open.. check if the name exists */
+  bus_get_name_owner (watcher->priv->connection,
+                      watcher->priv->name,
+                      (GAsyncReadyCallback) get_name_owner_cb,
+                      watcher);
 
- out:
-  ;
+  g_signal_handlers_disconnect_by_func (connection, on_notify_is_opening, watcher);
 }
 
-/* ---------------------------------------------------------------------------------------------------- */
-
-/**
- * g_bus_name_watcher_new:
- * @bus_type: A #GMessageBusType specifying what message bus to connect to.
- * @name: A bus name (well-known or unique).
- * @cancellable: %NULL or a #GCancellable.
- * @callback: The callback function to invoke when finished acquiring the name.
- * @user_data: User data to pass to @callback.
- *
- * Creates a new #GBusNameWatcher and then check if someone owns @name
- * on the bus specified by @bus_type. When the check is finished,
- * @callback will be invoked (on the main thread) and you can use
- * g_bus_name_watcher_new_finish() to get the result.
- *
- * Note that the returned object may be shared with other callers if
- * @bus_type and @name matches.
- *
- * This class is the preferred way to implement D-Bus clients.
- * The canonical example follows.
- * <example><title>Using g_bus_name_watcher_new()</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude"; parse="text" href="../../../../gdbus/example-gbusnamewatcher.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting></example>
- *
- * Returns: A #GBusNameWatcher object. Free with g_object_unref().
- **/
-GBusNameWatcher *
-g_bus_name_watcher_new (GMessageBusType        bus_type,
-                        const gchar           *name,
-                        GCancellable          *cancellable,
-                        GAsyncReadyCallback    callback,
-                        gpointer               user_data)
+static GBusNameWatcher *
+g_bus_name_watcher_new_internal (GMessageBusType        bus_type,
+                                 GDBusConnection       *given_connection,
+                                 const gchar           *name,
+                                 GCancellable          *cancellable,
+                                 GAsyncReadyCallback    callback,
+                                 gpointer               user_data)
 {
   GBusNameWatcher *watcher;
   GDBusConnection *connection;
-  ConstructData *data;
   GSimpleAsyncResult *simple;
+  gpointer source_tag;
 
   /* This is all a tad complicated since we support singletons... the problem here
    * in a nutshell is that there's a window, an initialization phase, where we wait
@@ -1083,12 +1008,19 @@ g_bus_name_watcher_new (GMessageBusType        bus_type,
    * when initialization is done, fire all callbacks.
    */
 
-  data = g_new0 (ConstructData, 1);
-
-  connection = g_dbus_connection_bus_get (bus_type,
-                                          cancellable,
-                                          (GAsyncReadyCallback) get_connection_cb,
-                                          data);
+  if (given_connection != NULL)
+    {
+      source_tag = g_bus_name_watcher_new_for_connection_finish;
+      connection = g_object_ref (given_connection);
+    }
+  else
+    {
+      source_tag = g_bus_name_watcher_new_finish;
+      connection = g_dbus_connection_bus_get (bus_type,
+                                              NULL,
+                                              NULL,
+                                              NULL);
+    }
 
   G_LOCK (watcher_lock);
   /* check if a suitable watcher already exists */
@@ -1098,7 +1030,7 @@ g_bus_name_watcher_new (GMessageBusType        bus_type,
       simple = g_simple_async_result_new (G_OBJECT (watcher),
                                           callback,
                                           user_data,
-                                          g_bus_name_watcher_new_finish);
+                                          source_tag);
 
       if (watcher->priv->in_init_phase)
         {
@@ -1120,19 +1052,32 @@ g_bus_name_watcher_new (GMessageBusType        bus_type,
                                               "connection", connection,
                                               NULL));
 
-  data->watcher = watcher;
-  watcher->priv->in_init_phase = TRUE;
-  watcher->priv->init_phase_pending_simple_async_results = g_ptr_array_new ();
-
   simple = g_simple_async_result_new (G_OBJECT (watcher),
                                       callback,
                                       user_data,
-                                      g_bus_name_watcher_new_finish);
+                                      source_tag);
 
   g_ptr_array_add (watcher->priv->init_phase_pending_simple_async_results, simple);
 
   singletons_add_watcher (watcher);
 
+  if (g_dbus_connection_get_is_opening (connection))
+    {
+      /* connection is opening.. so wait until it is done opening */
+      g_signal_connect (connection,
+                        "notify::is-opening",
+                        G_CALLBACK (on_notify_is_opening),
+                        watcher);
+    }
+  else
+    {
+      /* connection is open.. check if the name exists */
+      bus_get_name_owner (watcher->priv->connection,
+                          watcher->priv->name,
+                          (GAsyncReadyCallback) get_name_owner_cb,
+                          watcher);
+    }
+
  out:
   G_UNLOCK (watcher_lock);
 
@@ -1141,17 +1086,57 @@ g_bus_name_watcher_new (GMessageBusType        bus_type,
   return watcher;
 }
 
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * g_bus_name_watcher_new:
+ * @bus_type: A #GMessageBusType specifying what message bus to connect to.
+ * @name: A bus name (well-known or unique).
+ * @cancellable: %NULL or a #GCancellable.
+ * @callback: The callback function to invoke when finished acquiring the name.
+ * @user_data: User data to pass to @callback.
+ *
+ * Creates a new #GBusNameWatcher and then check if someone owns @name
+ * on the bus specified by @bus_type. When the check is finished,
+ * @callback will be invoked (on the main thread) and you can use
+ * g_bus_name_watcher_new_finish() to get the result.
+ *
+ * Note that the returned object may be shared with other callers if
+ * @bus_type and @name matches.
+ *
+ * This class is the preferred way to implement D-Bus clients.
+ * The canonical example follows.
+ * <example><title>Using g_bus_name_watcher_new()</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude"; parse="text" href="../../../../gdbus/example-gbusnamewatcher.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting></example>
+ *
+ * Returns: A #GBusNameWatcher object. Free with g_object_unref().
+ **/
+GBusNameWatcher *
+g_bus_name_watcher_new (GMessageBusType        bus_type,
+                        const gchar           *name,
+                        GCancellable          *cancellable,
+                        GAsyncReadyCallback    callback,
+                        gpointer               user_data)
+{
+  return g_bus_name_watcher_new_internal (bus_type,
+                                          NULL,
+                                          name,
+                                          cancellable,
+                                          callback,
+                                          user_data);
+}
+
 /**
  * g_bus_name_watcher_new_finish:
  * @watcher: A #GBusNameWatcher.
- * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to g_bus_name_watcher_get().
+ * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to g_bus_name_watcher_new().
  * @error: Return location for error or %NULL.
  *
  * Finishes attempting to determine the owner of the name being
  * watched.
  *
- * Returns: %TRUE if the name being watched has an owner or %FALSE if
- * there is no name owner or @error is set.
+ * Returns: %TRUE if it was possible to check if name has an owner (the name may not have an
+ * owner, check with g_dbus_name_watcher_get_name_owner()), otherwise %FALSE with @error
+ * set.
  **/
 gboolean
 g_bus_name_watcher_new_finish (GBusNameWatcher       *watcher,
@@ -1173,6 +1158,66 @@ g_bus_name_watcher_new_finish (GBusNameWatcher       *watcher,
 /* ---------------------------------------------------------------------------------------------------- */
 
 /**
+ * g_bus_name_watcher_new_for_connection:
+ * @connection: A #GDBusConnection.
+ * @name: A bus name (well-known or unique).
+ * @cancellable: %NULL or a #GCancellable.
+ * @callback: The callback function to invoke when finished acquiring the name.
+ * @user_data: User data to pass to @callback.
+ *
+ * Like g_bus_name_watcher_new() but allows you to supply a
+ * #GDBusConnection.
+ *
+ * Returns: A #GBusNameWatcher object. Free with g_object_unref().
+ **/
+GBusNameWatcher *
+g_bus_name_watcher_new_for_connection (GDBusConnection       *connection,
+                                       const gchar           *name,
+                                       GCancellable          *cancellable,
+                                       GAsyncReadyCallback    callback,
+                                       gpointer               user_data)
+{
+  return g_bus_name_watcher_new_internal (G_MESSAGE_BUS_TYPE_NONE,
+                                          connection,
+                                          name,
+                                          cancellable,
+                                          callback,
+                                          user_data);
+}
+
+/**
+ * g_bus_name_watcher_new_for_connection_finish:
+ * @watcher: A #GBusNameWatcher.
+ * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to g_bus_name_watcher_new_for_connection().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes attempting to determine the owner of the name being
+ * watched.
+ *
+ * Returns: %TRUE if it was possible to check if name has an owner (the name may not have an
+ * owner, check with g_dbus_name_watcher_get_name_owner()), otherwise %FALSE with @error
+ * set.
+ **/
+gboolean
+g_bus_name_watcher_new_for_connection_finish (GBusNameWatcher       *watcher,
+                                              GAsyncResult          *res,
+                                              GError               **error)
+{
+  GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+
+  g_return_val_if_fail (G_IS_BUS_NAME_WATCHER (watcher), FALSE);
+
+  g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_bus_name_watcher_new_finish);
+
+  if (g_simple_async_result_propagate_error (simple, error))
+    return FALSE;
+
+  return watcher->priv->name_owner != NULL;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
  * g_bus_name_watcher_get_name:
  * @watcher: A #GBusNameWatcher.
  *
diff --git a/gdbus/gbusnamewatcher.h b/gdbus/gbusnamewatcher.h
index 544f988..90f58b9 100644
--- a/gdbus/gbusnamewatcher.h
+++ b/gdbus/gbusnamewatcher.h
@@ -94,7 +94,6 @@ GBusNameWatcher    *g_bus_name_watcher_new                       (GMessageBusTyp
 gboolean            g_bus_name_watcher_new_finish                (GBusNameWatcher       *watcher,
                                                                   GAsyncResult          *res,
                                                                   GError               **error);
-#if 0
 GBusNameWatcher    *g_bus_name_watcher_new_for_connection        (GDBusConnection       *connection,
                                                                   const gchar           *name,
                                                                   GCancellable          *cancellable,
@@ -103,7 +102,6 @@ GBusNameWatcher    *g_bus_name_watcher_new_for_connection        (GDBusConnectio
 gboolean            g_bus_name_watcher_new_for_connection_finish (GBusNameWatcher       *watcher,
                                                                   GAsyncResult          *res,
                                                                   GError               **error);
-#endif
 const gchar        *g_bus_name_watcher_get_name                  (GBusNameWatcher       *watcher);
 const gchar        *g_bus_name_watcher_get_name_owner            (GBusNameWatcher       *watcher);
 GDBusConnection    *g_bus_name_watcher_get_connection            (GBusNameWatcher       *watcher);
diff --git a/gdbus/gdbus.symbols b/gdbus/gdbus.symbols
index 018250c..c68b694 100644
--- a/gdbus/gdbus.symbols
+++ b/gdbus/gdbus.symbols
@@ -22,6 +22,7 @@ g_dbus_connection_bus_get_private
 g_dbus_connection_bus_get_private_finish
 g_dbus_connection_get_unique_name
 g_dbus_connection_get_is_open
+g_dbus_connection_get_is_opening
 g_dbus_connection_get_bus_type
 g_dbus_connection_get_dbus_1_connection
 g_dbus_connection_get_exit_on_close
@@ -47,6 +48,8 @@ g_bus_name_owner_get_type
 #if IN_FILE(__G_BUS_NAME_WATCHER_C__)
 g_bus_name_watcher_new
 g_bus_name_watcher_new_finish
+g_bus_name_watcher_new_for_connection
+g_bus_name_watcher_new_for_connection_finish
 g_bus_name_watcher_get_connection
 g_bus_name_watcher_get_name
 g_bus_name_watcher_get_name_owner
diff --git a/gdbus/gdbusconnection.c b/gdbus/gdbusconnection.c
index 5c4b5a3..533953a 100644
--- a/gdbus/gdbusconnection.c
+++ b/gdbus/gdbusconnection.c
@@ -79,6 +79,7 @@ enum
   PROP_BUS_TYPE,
   PROP_UNIQUE_NAME,
   PROP_IS_OPEN,
+  PROP_IS_OPENING,
   PROP_EXIT_ON_CLOSE,
   PROP_DBUS_1_CONNECTION,
 };
@@ -159,6 +160,10 @@ g_dbus_connection_get_property (GObject    *object,
       g_value_set_boolean (value, g_dbus_connection_get_is_open (connection));
       break;
 
+    case PROP_IS_OPENING:
+      g_value_set_boolean (value, g_dbus_connection_get_is_opening (connection));
+      break;
+
     case PROP_EXIT_ON_CLOSE:
       g_value_set_boolean (value, g_dbus_connection_get_exit_on_close (connection));
       break;
@@ -263,7 +268,7 @@ g_dbus_connection_class_init (GDBusConnectionClass *klass)
    * connection is closed or not a message bus connection.
    */
   g_object_class_install_property (gobject_class,
-                                   PROP_IS_OPEN,
+                                   PROP_UNIQUE_NAME,
                                    g_param_spec_string ("unique-name",
                                                         _("unique-name"),
                                                         _("Unique name of bus connection"),
@@ -290,6 +295,22 @@ g_dbus_connection_class_init (GDBusConnectionClass *klass)
                                                          G_PARAM_STATIC_NICK));
 
   /**
+   * GDBusConnection:is-opening:
+   *
+   * A boolean specifying whether the connection is currently being opened.
+   */
+  g_object_class_install_property (gobject_class,
+                                   PROP_IS_OPENING,
+                                   g_param_spec_boolean ("is-opening",
+                                                         _("is-opening"),
+                                                         _("Whether the connection is being opened"),
+                                                         FALSE,
+                                                         G_PARAM_READABLE |
+                                                         G_PARAM_STATIC_NAME |
+                                                         G_PARAM_STATIC_BLURB |
+                                                         G_PARAM_STATIC_NICK));
+
+  /**
    * GDBusConnection:exit-on-close:
    *
    * A boolean specifying whether _exit() should be called when the
@@ -346,6 +367,7 @@ g_dbus_connection_init (GDBusConnection *connection)
 {
   connection->priv = G_TYPE_INSTANCE_GET_PRIVATE (connection, G_TYPE_DBUS_CONNECTION, GDBusConnectionPrivate);
   connection->priv->in_init_phase = TRUE;
+  connection->priv->init_phase_pending_simple_async_results = g_ptr_array_new ();
 }
 
 /**
@@ -395,6 +417,22 @@ g_dbus_connection_get_is_open (GDBusConnection *connection)
 }
 
 /**
+ * g_dbus_connection_get_is_opening:
+ * @connection: A #GDBusConnection.
+ *
+ * Gets whether a connection is currently opening.
+ *
+ * Returns: %TRUE if the connection is currently opening, %FALSE otherwise.
+ **/
+gboolean
+g_dbus_connection_get_is_opening (GDBusConnection *connection)
+{
+  g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
+
+  return connection->priv->in_init_phase;
+}
+
+/**
  * g_dbus_connection_get_dbus_1_connection:
  * @connection: A #GDBusConnection.
  *
@@ -647,8 +685,12 @@ open_bus_connection (gpointer user_data)
     }
   connection->priv->in_init_phase = FALSE;
   g_ptr_array_free (connection->priv->init_phase_pending_simple_async_results, TRUE);
+  connection->priv->init_phase_pending_simple_async_results = NULL;
   G_UNLOCK (connection_lock);
 
+  /* let others know that they can now trust g_dbus_connection_get_is_open() */
+  g_object_notify (G_OBJECT (connection), "is-opening");
+
   return FALSE;
 }
 
@@ -774,7 +816,6 @@ g_dbus_connection_bus_get_internal (GMessageBusType                bus_type,
                                       callback,
                                       user_data,
                                       private ? g_dbus_connection_bus_get_private_finish : g_dbus_connection_bus_get_finish);
-  connection->priv->init_phase_pending_simple_async_results = g_ptr_array_new ();
   g_ptr_array_add (connection->priv->init_phase_pending_simple_async_results, simple);
   G_UNLOCK (connection_lock);
 
diff --git a/gdbus/gdbusconnection.h b/gdbus/gdbusconnection.h
index a1688f1..fe97ae7 100644
--- a/gdbus/gdbusconnection.h
+++ b/gdbus/gdbusconnection.h
@@ -105,6 +105,7 @@ gboolean         g_dbus_connection_bus_get_private_finish (GDBusConnection     *
 
 GMessageBusType  g_dbus_connection_get_bus_type           (GDBusConnection *connection);
 gboolean         g_dbus_connection_get_is_open            (GDBusConnection *connection);
+gboolean         g_dbus_connection_get_is_opening         (GDBusConnection *connection);
 DBusConnection  *g_dbus_connection_get_dbus_1_connection  (GDBusConnection *connection);
 const gchar     *g_dbus_connection_get_unique_name        (GDBusConnection *connection);
 gboolean         g_dbus_connection_get_exit_on_close      (GDBusConnection *connection);
diff --git a/gdbus/tests/connection.c b/gdbus/tests/connection.c
index 05118f9..0190275 100644
--- a/gdbus/tests/connection.c
+++ b/gdbus/tests/connection.c
@@ -659,6 +659,7 @@ on_owner_cb_expect_failure (GBusNameOwner *owner,
   _g_assert_error_domain (error, G_DBUS_ERROR);
   g_error_free (error);
   g_assert (!ret);
+  g_assert (!g_bus_name_owner_get_owns_name (owner));
 
   *val = TRUE;
   g_main_loop_quit (loop);
@@ -697,6 +698,7 @@ on_owner_cb_expect_success (GBusNameOwner *owner,
                                      &error);
   g_assert_no_error (error);
   g_assert (ret);
+  g_assert (g_bus_name_owner_get_owns_name (owner));
 
   *val = TRUE;
   g_main_loop_quit (loop);
@@ -743,16 +745,15 @@ on_owner_cb_expect_failure2 (GBusNameOwner *owner,
   ret = g_bus_name_owner_new_finish (owner,
                                      result,
                                      &error);
-  g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED);
-  g_error_free (error);
-  g_assert (!ret);
+  g_assert_no_error (error);
+  g_assert (ret);
+  g_assert (!g_bus_name_owner_get_owns_name (owner));
 
   *val = TRUE;
   g_main_loop_quit (loop);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
-
 static void
 on_owner_for_connection_cb_expect_failure (GBusNameOwner *owner,
                                            GAsyncResult  *result,
@@ -766,14 +767,13 @@ on_owner_for_connection_cb_expect_failure (GBusNameOwner *owner,
   ret = g_bus_name_owner_new_for_connection_finish (owner,
                                                     result,
                                                     &error);
-  g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED);
-  g_error_free (error);
-  g_assert (!ret);
+  g_assert_no_error (error);
+  g_assert (ret);
+  g_assert (!g_bus_name_owner_get_owns_name (owner));
 
   *val = TRUE;
   g_main_loop_quit (loop);
 }
-
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
@@ -841,15 +841,18 @@ test_bus_name_owner (void)
   g_assert (val);
   g_assert (val2);
 
-  /* try owning the same name again... the should fail because o is still alive */
+  /* try owning the same name again... this should not fail, we should get the same object
+   * as o because of singleton handling
+   */
   o2 = g_bus_name_owner_new (G_MESSAGE_BUS_TYPE_SESSION,
                              "org.gtk.Test.Name1",
                              G_BUS_NAME_OWNER_FLAGS_NONE,
                              NULL,
-                             (GAsyncReadyCallback) on_owner_cb_expect_failure2,
+                             (GAsyncReadyCallback) on_owner_cb_expect_success,
                              &val);
   g_main_loop_run (loop);
   g_assert (val);
+  g_assert (o2 == o);
   g_object_unref (o2);
 
   /* now kill o.. and then attempt to own the same name again.. */
@@ -895,6 +898,9 @@ test_bus_name_owner (void)
                                                           (GAsyncReadyCallback) get_connection_callback_private,
                                                           NULL);                           /* user_data */
   g_main_loop_run (loop);
+  g_debug ("orig %s, private %s",
+           g_dbus_connection_get_unique_name (g_bus_name_owner_get_connection (o)),
+           g_dbus_connection_get_unique_name (private_connection));
   val = FALSE;
   o2 = g_bus_name_owner_new_for_connection (private_connection,
                                             "org.gtk.Test.Name1",
@@ -968,15 +974,16 @@ bnw_cb_expect_error (GBusNameWatcher *watcher,
                      gpointer         user_data)
 {
   GError *error;
-  gboolean has_name_owner;
+  gboolean ret;
 
   error = NULL;
-  has_name_owner = g_bus_name_watcher_new_finish (watcher,
-                                                  res,
-                                                  &error);
+  ret = g_bus_name_watcher_new_finish (watcher,
+                                       res,
+                                       &error);
   _g_assert_error_domain (error, G_DBUS_ERROR);
   g_error_free (error);
-  g_assert (!has_name_owner);
+  g_assert (!ret);
+  g_assert_cmpstr (g_bus_name_watcher_get_name_owner (watcher), ==, NULL);
 
   g_main_loop_quit (loop);
 }
@@ -989,14 +996,15 @@ bnw_cb_expect_null_owner (GBusNameWatcher *watcher,
                           gpointer         user_data)
 {
   GError *error;
-  gboolean has_name_owner;
+  gboolean ret;
 
   error = NULL;
-  has_name_owner = g_bus_name_watcher_new_finish (watcher,
-                                                  res,
-                                                  &error);
-  g_assert_no_error (error);
-  g_assert (!has_name_owner);
+  ret = g_bus_name_watcher_new_finish (watcher,
+                                       res,
+                                       &error);
+  _g_assert_error_domain (error, G_DBUS_ERROR);
+  g_assert (!ret);
+  g_assert_cmpstr (g_bus_name_watcher_get_name_owner (watcher), ==, NULL);
 
   g_main_loop_quit (loop);
 }
@@ -1004,7 +1012,7 @@ bnw_cb_expect_null_owner (GBusNameWatcher *watcher,
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
-nbw_on_owner_cb_expect_success (GBusNameOwner *owner,
+bnw_on_owner_cb_expect_success (GBusNameOwner *owner,
                                 GAsyncResult  *result,
                                 gpointer       user_data)
 {
@@ -1017,6 +1025,7 @@ nbw_on_owner_cb_expect_success (GBusNameOwner *owner,
                                      &error);
   g_assert_no_error (error);
   g_assert (ret);
+  g_assert (g_bus_name_owner_get_owns_name (owner));
 
   g_main_loop_quit (loop);
 }
@@ -1029,14 +1038,15 @@ bnw_cb_expect_owner (GBusNameWatcher *watcher,
                      gpointer         user_data)
 {
   GError *error;
-  gboolean has_name_owner;
+  gboolean ret;
 
   error = NULL;
-  has_name_owner = g_bus_name_watcher_new_finish (watcher,
-                                                  res,
-                                                  &error);
+  ret = g_bus_name_watcher_new_finish (watcher,
+                                       res,
+                                       &error);
   g_assert_no_error (error);
-  g_assert (has_name_owner);
+  g_assert (ret);
+  g_assert_cmpstr (g_bus_name_watcher_get_name_owner (watcher), !=, NULL);
 
   g_main_loop_quit (loop);
 }
@@ -1068,14 +1078,15 @@ bnw_cb_singleton (GBusNameWatcher *watcher,
 {
   gboolean *val = user_data;
   GError *error;
-  gboolean has_name_owner;
+  gboolean ret;
 
   error = NULL;
-  has_name_owner = g_bus_name_watcher_new_finish (watcher,
-                                                  res,
-                                                  &error);
+  ret = g_bus_name_watcher_new_finish (watcher,
+                                       res,
+                                       &error);
   g_assert_no_error (error);
-  g_assert (has_name_owner);
+  g_assert (ret);
+  g_assert_cmpstr (g_bus_name_watcher_get_name_owner (watcher), !=, NULL);
 
   *val = TRUE;
 
@@ -1092,7 +1103,7 @@ test_bus_name_watcher (void)
   GBusNameOwner *o;
   gboolean val;
 
-  /* if no session bus is available, expect the callback to fail */
+  /* if no session bus is available, expect the callback to expect an error */
   w = g_bus_name_watcher_new (G_MESSAGE_BUS_TYPE_SESSION,
                               "org.gtk.Test.Name1",
                               NULL,
@@ -1102,7 +1113,7 @@ test_bus_name_watcher (void)
   g_dbus_connection_set_exit_on_close (g_bus_name_watcher_get_connection (w), FALSE);
   g_object_unref (w);
 
-  /* if a session bus is available, expect the callback to succeed with name_owner==NULL */
+  /* if a session bus is available, expect the callback to fail */
   session_bus_up ();
   w = g_bus_name_watcher_new (G_MESSAGE_BUS_TYPE_SESSION,
                               "org.gtk.Test.Name1",
@@ -1118,7 +1129,7 @@ test_bus_name_watcher (void)
                             "org.gtk.Test.Name1",
                             G_BUS_NAME_OWNER_FLAGS_NONE,
                             NULL,
-                            (GAsyncReadyCallback) nbw_on_owner_cb_expect_success,
+                            (GAsyncReadyCallback) bnw_on_owner_cb_expect_success,
                             NULL);
   g_main_loop_run (loop);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]