[glib/gdbus] Rework low-level API for getting connections and watching/owning names



commit e68584b11dc6bcf8e515ed8df6322cadf918d648
Author: David Zeuthen <davidz redhat com>
Date:   Sun Apr 26 22:02:38 2009 -0400

    Rework low-level API for getting connections and watching/owning names
    
    Specifically avoid having code in the _new() functions (nicer for
    language bindings) and use an ::initialized signal instead of a
    GAsyncReadyCallback.
    
    This makes the code much easier to read and hopefully more robust.
    
    Also rework the test suite with some new macros for watching for
    signals and property notifications. This change should make the tests
    much easier to read.
---
 docs/reference/gdbus/gdbus-sections.txt |   95 ++--
 gdbus/Makefile.am                       |    6 +-
 gdbus/gbusnameowner.c                   |  644 +++++++++++----------
 gdbus/gbusnameowner.h                   |   20 +-
 gdbus/gbusnamewatcher.c                 |  724 ++++++++++++------------
 gdbus/gbusnamewatcher.h                 |   22 +-
 gdbus/gdbus.symbols                     |   43 +-
 gdbus/gdbusconnection.c                 |  579 ++++++++-----------
 gdbus/gdbusconnection.h                 |   25 +-
 gdbus/gdbusnameowning.c                 |  138 +++--
 gdbus/gdbusnamewatching.c               |  131 +++--
 gdbus/tests/Makefile.am                 |   14 +-
 gdbus/tests/connection.c                |  399 +++++--------
 gdbus/tests/names.c                     |  937 +++++++++++++++----------------
 gdbus/tests/tests.c                     |  131 +++++
 gdbus/tests/tests.h                     |   74 +++
 16 files changed, 2012 insertions(+), 1970 deletions(-)

diff --git a/docs/reference/gdbus/gdbus-sections.txt b/docs/reference/gdbus/gdbus-sections.txt
index a4b9ead..ac0ff7f 100644
--- a/docs/reference/gdbus/gdbus-sections.txt
+++ b/docs/reference/gdbus/gdbus-sections.txt
@@ -5,12 +5,12 @@ GBusNameOwnerFlags
 GBusNameOwner
 GBusNameOwnerClass
 g_bus_name_owner_new
-g_bus_name_owner_new_finish
 g_bus_name_owner_new_for_connection
-g_bus_name_owner_new_for_connection_finish
 g_bus_name_owner_get_owns_name
 g_bus_name_owner_get_name
+g_bus_name_owner_get_bus_type
 g_bus_name_owner_get_flags
+g_bus_name_owner_get_is_initialized
 g_bus_name_owner_get_connection
 <SUBSECTION Standard>
 G_BUS_NAME_OWNER
@@ -23,49 +23,26 @@ G_BUS_NAME_OWNER_GET_CLASS
 </SECTION>
 
 <SECTION>
-<FILE>gbusnamewatcher</FILE>
-<TITLE>GBusNameWatcher</TITLE>
-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_connection
-<SUBSECTION Standard>
-G_BUS_NAME_WATCHER
-G_IS_BUS_NAME_WATCHER
-G_TYPE_BUS_NAME_WATCHER
-g_bus_name_watcher_get_type
-G_BUS_NAME_WATCHER_CLASS
-G_IS_BUS_NAME_WATCHER_CLASS
-G_BUS_NAME_WATCHER_GET_CLASS
-</SECTION>
-
-<SECTION>
 <FILE>gdbusconnection</FILE>
 <TITLE>GDBusConnection</TITLE>
 GBusType
 GDBusConnection
 GDBusConnectionClass
 g_dbus_connection_bus_get
-g_dbus_connection_bus_get_finish
 g_dbus_connection_bus_get_private
-g_dbus_connection_bus_get_private_finish
+g_dbus_connection_get_bus_type
+g_dbus_connection_get_is_open
+g_dbus_connection_get_is_private
+g_dbus_connection_get_unique_name
 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_is_initialized
 g_dbus_connection_get_dbus_1_connection
 g_dbus_connection_send_dbus_1_message
 g_dbus_connection_send_dbus_1_message_with_reply
-g_dbus_connection_send_dbus_1_message_with_reply_finish
 g_dbus_connection_send_dbus_1_message_block
 g_dbus_connection_send_dbus_1_message_cancel
+g_dbus_connection_send_dbus_1_message_with_reply_finish
 <SUBSECTION Standard>
 G_DBUS_CONNECTION
 G_IS_DBUS_CONNECTION
@@ -77,23 +54,25 @@ G_DBUS_CONNECTION_GET_CLASS
 </SECTION>
 
 <SECTION>
-<FILE>gdbusmainloop</FILE>
-g_dbus_integrate_dbus_1_connection
-g_dbus_unintegrate_dbus_1_connection
-g_dbus_integrate_dbus_1_server
-g_dbus_unintegrate_dbus_1_server
-</SECTION>
-
-<SECTION>
-<FILE>gdbuserror</FILE>
-G_DBUS_ERROR
-GDBusError
-g_dbus_error_get_remote_exception
-g_dbus_error_new_for_dbus_error
-g_dbus_error_new_for_dbus_error_valist
-g_dbus_error_set_dbus_error
-g_dbus_error_set_dbus_error_valist
-g_dbus_error_new_for_gerror
+<FILE>gbusnamewatcher</FILE>
+<TITLE>GBusNameWatcher</TITLE>
+GBusNameWatcher
+GBusNameWatcherClass
+g_bus_name_watcher_new
+g_bus_name_watcher_new_for_connection
+g_bus_name_watcher_get_name_owner
+g_bus_name_watcher_get_name
+g_bus_name_watcher_get_bus_type
+g_bus_name_watcher_get_is_initialized
+g_bus_name_watcher_get_connection
+<SUBSECTION Standard>
+G_BUS_NAME_WATCHER
+G_IS_BUS_NAME_WATCHER
+G_TYPE_BUS_NAME_WATCHER
+g_bus_name_watcher_get_type
+G_BUS_NAME_WATCHER_CLASS
+G_IS_BUS_NAME_WATCHER_CLASS
+G_BUS_NAME_WATCHER_GET_CLASS
 </SECTION>
 
 <SECTION>
@@ -105,6 +84,14 @@ g_bus_unwatch_name
 </SECTION>
 
 <SECTION>
+<FILE>gdbusmainloop</FILE>
+g_dbus_integrate_dbus_1_connection
+g_dbus_unintegrate_dbus_1_connection
+g_dbus_integrate_dbus_1_server
+g_dbus_unintegrate_dbus_1_server
+</SECTION>
+
+<SECTION>
 <FILE>gdbusnameowning</FILE>
 GBusNameAcquiredCallback
 GBusNameLostCallback
@@ -113,6 +100,18 @@ g_bus_unown_name
 </SECTION>
 
 <SECTION>
+<FILE>gdbuserror</FILE>
+GDBusError
+G_DBUS_ERROR
+g_dbus_error_get_remote_exception
+g_dbus_error_new_for_dbus_error_valist
+g_dbus_error_new_for_dbus_error
+g_dbus_error_set_dbus_error
+g_dbus_error_set_dbus_error_valist
+g_dbus_error_new_for_gerror
+</SECTION>
+
+<SECTION>
 <FILE>gdbusproxy</FILE>
 <TITLE>GDBusProxy</TITLE>
 GDBusProxy
diff --git a/gdbus/Makefile.am b/gdbus/Makefile.am
index 5b5964c..43a3e0b 100644
--- a/gdbus/Makefile.am
+++ b/gdbus/Makefile.am
@@ -101,10 +101,10 @@ libgdbus_2_0_la_SOURCES =						\
 	gbusnamewatcher.h		gbusnamewatcher.c		\
 	gdbusnamewatching.h		gdbusnamewatching.c		\
 	gdbusnameowning.h		gdbusnameowning.c		\
-	gdbusprivate.h			gdbusprivate.c			\
 	gdbusproxy.h			gdbusproxy.c			\
 	gdbusstructure.h		gdbusstructure.c		\
 	gdbusvariant.h			gdbusvariant.c			\
+	gdbusprivate.h			gdbusprivate.c			\
 	gdbusalias.h 							\
 	gdbusaliasdef.c							\
 	$(NULL)
@@ -197,7 +197,9 @@ gdbusenumtypes.c: $(gdbus_headers) gdbusenumtypes.c.template Makefile.am
 gdbus-2.0.lib: libgdbus-2.0.la gdbus.def
 	lib -machine:@LIB_EXE_MACHINE_FLAG@ -name:libgdbus-2.0-$(LT_CURRENT_MINUS_AGE).dll -def:gdbus.def -out:$@
 
-noinst_PROGRAMS = example-watch-name example-own-name
+noinst_PROGRAMS =
+noinst_PROGRAMS += example-own-name
+noinst_PROGRAMS += example-watch-name
 
 example_watch_name_SOURCES = example-watch-name.c
 example_watch_name_CFLAGS  = $(DBUS_CFLAGS)
diff --git a/gdbus/gbusnameowner.c b/gdbus/gbusnameowner.c
index feee26b..9db45c1 100644
--- a/gdbus/gbusnameowner.c
+++ b/gdbus/gbusnameowner.c
@@ -39,22 +39,25 @@
  * @short_description: Own a well-known name on a bus
  * @include: gdbus/gdbus.h
  *
- * #GBusNameOwner is a utility class that makes it easy to implement
- * D-Bus services. See g_bus_name_owner_new() for an example.
+ * <para><note>
+ * This class is rarely used directly. If you are writing an application, it is often
+ * easier to use the g_bus_own_name() or g_bus_watch_name() APIs.
+ * </note></para>
+ * #GBusNameOwner is a utility class for owning well-known names on a
+ * message bus.
  */
 
 struct _GBusNameOwnerPrivate
 {
   gchar *name;
+  GBusType bus_type;
   GBusNameOwnerFlags flags;
 
   GDBusConnection *connection;
 
   gboolean owns_name;
 
-  /* these variables are used to store async callbacks for users calling _new()  */
-  gboolean in_init_phase;
-  GPtrArray *init_phase_pending_simple_async_results;
+  gboolean is_initialized;
 };
 
 enum
@@ -62,7 +65,9 @@ enum
   PROP_0,
   PROP_NAME,
   PROP_FLAGS,
+  PROP_BUS_TYPE,
   PROP_OWNS_NAME,
+  PROP_IS_INITIALIZED,
   PROP_CONNECTION,
 };
 
@@ -70,13 +75,19 @@ enum
 {
   NAME_LOST_SIGNAL,
   NAME_ACQUIRED_SIGNAL,
+  INITIALIZED_SIGNAL,
   LAST_SIGNAL,
 };
 
 G_LOCK_DEFINE_STATIC (owner_lock);
 
+static GObject *g_bus_name_owner_constructor (GType                  type,
+                                              guint                  n_construct_properties,
+                                              GObjectConstructParam *construct_properties);
+static void g_bus_name_owner_constructed (GObject *object);
+
 static GBusNameOwner *singletons_get_owner (GDBusConnection *connection, const gchar *name);
-static void singletons_add_owner (GBusNameOwner *owner);
+static void singletons_add_owner (GBusNameOwner *owner, GDBusConnection *connection, const gchar *name);
 static void singletons_remove_owner (GBusNameOwner *owner);
 
 static DBusHandlerResult
@@ -92,6 +103,9 @@ static void on_connection_opened (GDBusConnection *connection,
 static void on_connection_closed (GDBusConnection *connection,
                                   gpointer         user_data);
 
+static void on_connection_initialized (GDBusConnection *connection,
+                                       gpointer         user_data);
+
 static guint get_request_name_flags (GBusNameOwnerFlags flags);
 
 G_DEFINE_TYPE (GBusNameOwner, g_bus_name_owner, G_TYPE_OBJECT);
@@ -135,6 +149,7 @@ g_bus_name_owner_finalize (GObject *object)
 
       g_signal_handlers_disconnect_by_func (owner->priv->connection, on_connection_opened, owner);
       g_signal_handlers_disconnect_by_func (owner->priv->connection, on_connection_closed, owner);
+      g_signal_handlers_disconnect_by_func (owner->priv->connection, on_connection_initialized, owner);
 
       if (g_dbus_connection_get_is_open (owner->priv->connection))
         {
@@ -165,6 +180,10 @@ g_bus_name_owner_get_property (GObject    *object,
       g_value_set_string (value, g_bus_name_owner_get_name (owner));
       break;
 
+    case PROP_BUS_TYPE:
+      g_value_set_enum (value, g_bus_name_owner_get_bus_type (owner));
+      break;
+
     case PROP_FLAGS:
       g_value_set_flags (value, g_bus_name_owner_get_flags (owner));
       break;
@@ -173,6 +192,10 @@ g_bus_name_owner_get_property (GObject    *object,
       g_value_set_boolean (value, g_bus_name_owner_get_owns_name (owner));
       break;
 
+    case PROP_IS_INITIALIZED:
+      g_value_set_boolean (value, g_bus_name_owner_get_is_initialized (owner));
+      break;
+
     case PROP_CONNECTION:
       g_value_set_object (value, g_bus_name_owner_get_connection (owner));
       break;
@@ -197,6 +220,10 @@ g_bus_name_owner_set_property (GObject      *object,
       owner->priv->name = g_value_dup_string (value);
       break;
 
+    case PROP_BUS_TYPE:
+      owner->priv->bus_type = g_value_get_enum (value);
+      break;
+
     case PROP_FLAGS:
       owner->priv->flags = g_value_get_flags (value);
       break;
@@ -289,7 +316,6 @@ filter_function (DBusConnection *dbus_1_connection,
               else
                 {
                   /* This is not unexpected.. it can happen when releasing a name only to claim it right again */
-                  /*g_warning ("Got unexpected NameLost signal for the name %s", owner->priv->name);*/
                 }
             }
         }
@@ -321,8 +347,7 @@ filter_function (DBusConnection *dbus_1_connection,
                 }
               else
                 {
-                  g_warning ("Got unexpected NameAcquired signal for the name %s",
-                             owner->priv->name);
+                  /* This is not unexpected.. it can happen when processing the Reply from the RequestName() method */
                 }
             }
         }
@@ -337,6 +362,90 @@ filter_function (DBusConnection *dbus_1_connection,
 }
 
 static void
+request_name_cb (GDBusConnection *connection,
+                 GAsyncResult    *res,
+                 gpointer         user_data)
+{
+  GBusNameOwner *owner = G_BUS_NAME_OWNER (user_data);
+  DBusMessage *reply;
+  DBusError dbus_error;
+  dbus_uint32_t request_name_reply;
+  gboolean old_owns_name;
+  gboolean old_is_initialized;
+
+  old_owns_name = owner->priv->owns_name;
+  old_is_initialized = owner->priv->is_initialized;
+
+  reply = g_dbus_connection_send_dbus_1_message_with_reply_finish (connection,
+                                                                   res,
+                                                                   NULL);
+  if (reply == NULL)
+    goto out;
+
+  dbus_error_init (&dbus_error);
+  if (!dbus_set_error_from_message (&dbus_error, reply))
+    {
+      dbus_message_get_args (reply,
+                             &dbus_error,
+                             DBUS_TYPE_UINT32, &request_name_reply,
+                             DBUS_TYPE_INVALID);
+    }
+  if (dbus_error_is_set (&dbus_error))
+    {
+      dbus_error_free (&dbus_error);
+    }
+  else
+    {
+      if (request_name_reply == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
+        {
+          owner->priv->owns_name = TRUE;
+          if (owner->priv->owns_name != old_owns_name)
+            {
+              g_object_notify (G_OBJECT (owner), "owns-name");
+              g_signal_emit (owner, signals[NAME_ACQUIRED_SIGNAL], 0);
+            }
+        }
+    }
+
+ out:
+  /* we're now initialized */
+  owner->priv->is_initialized = TRUE;
+  if (old_is_initialized != owner->priv->is_initialized)
+    {
+      g_object_notify (G_OBJECT (owner), "is-initialized");
+      g_signal_emit (owner, signals[INITIALIZED_SIGNAL], 0);
+    }
+  if (reply != NULL)
+    dbus_message_unref (reply);
+  g_object_unref (owner);
+}
+
+static void
+on_connection_initialized (GDBusConnection *connection,
+                           gpointer         user_data)
+{
+  GBusNameOwner *owner = G_BUS_NAME_OWNER (user_data);
+
+  /* This can only fire a single time */
+  g_assert (!owner->priv->is_initialized);
+
+  if (g_dbus_connection_get_is_open (connection))
+    {
+      /* if the connection is now open then on_connection_opened() will fire
+       * and we'll try to request the name from there
+       */
+    }
+  else
+    {
+      /* connection failed to open so we are now initialized */
+      owner->priv->is_initialized = TRUE;
+      g_object_notify (G_OBJECT (owner), "is-initialized");
+      g_signal_emit (owner, signals[INITIALIZED_SIGNAL], 0);
+    }
+}
+
+/* note that this is also called from g_bus_name_owner_constructed() if the connection is open */
+static void
 on_connection_opened (GDBusConnection *connection,
                       gpointer         user_data)
 {
@@ -344,6 +453,8 @@ on_connection_opened (GDBusConnection *connection,
   DBusMessage *message;
   dbus_uint32_t flags;
 
+  g_assert (g_dbus_connection_get_is_open (owner->priv->connection));
+
   /* set up a filter function for listening on NameLost and NameAcquired messages on the DBusConnection */
   if (!dbus_connection_add_filter (g_dbus_connection_get_dbus_1_connection (owner->priv->connection),
                                    filter_function,
@@ -351,16 +462,8 @@ on_connection_opened (GDBusConnection *connection,
                                    NULL))
     _g_dbus_oom ();
 
-  if (owner->priv->in_init_phase)
-    return;
-
-  /* ok, the bus suddenly came up.. so try to claim the name ASAP */
-
   g_assert (!owner->priv->owns_name);
 
-  /* we don't care about the reply.. we'll know soon enough, via a NameAcquired
-   * signal, if we managed to claim the name
-   */
   flags = get_request_name_flags (owner->priv->flags);
   if ((message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
                                                DBUS_PATH_DBUS,
@@ -372,7 +475,12 @@ on_connection_opened (GDBusConnection *connection,
                                  DBUS_TYPE_UINT32, &flags,
                                  DBUS_TYPE_INVALID))
     _g_dbus_oom ();
-  g_dbus_connection_send_dbus_1_message (owner->priv->connection, message);
+  g_dbus_connection_send_dbus_1_message_with_reply (owner->priv->connection,
+                                                    message,
+                                                    -1,
+                                                    NULL,
+                                                    (GAsyncReadyCallback) request_name_cb,
+                                                    g_object_ref (owner));
   dbus_message_unref (message);
 }
 
@@ -395,20 +503,6 @@ on_connection_closed (GDBusConnection *connection,
 }
 
 static void
-g_bus_name_owner_constructed (GObject *object)
-{
-  GBusNameOwner *owner = G_BUS_NAME_OWNER (object);
-
-  g_signal_connect (owner->priv->connection, "opened", G_CALLBACK (on_connection_opened), owner);
-  g_signal_connect (owner->priv->connection, "closed", G_CALLBACK (on_connection_closed), owner);
-  if (g_dbus_connection_get_is_open (owner->priv->connection))
-    on_connection_opened (owner->priv->connection, owner);
-
-  if (G_OBJECT_CLASS (g_bus_name_owner_parent_class)->constructed != NULL)
-    G_OBJECT_CLASS (g_bus_name_owner_parent_class)->constructed (object);
-}
-
-static void
 g_bus_name_owner_class_init (GBusNameOwnerClass *klass)
 {
   GObjectClass *gobject_class;
@@ -416,7 +510,8 @@ 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->constructor  = g_bus_name_owner_constructor;
+  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;
@@ -463,7 +558,7 @@ g_bus_name_owner_class_init (GBusNameOwnerClass *klass)
   /**
    * GBusNameOwner:owns-name:
    *
-   * Whether the name is currently owned.
+   * %TRUE if the name is currently owned.
    */
   g_object_class_install_property (gobject_class,
                                    PROP_OWNS_NAME,
@@ -477,6 +572,47 @@ g_bus_name_owner_class_init (GBusNameOwnerClass *klass)
                                                          G_PARAM_STATIC_NICK));
 
   /**
+   * GBusNameOwner:is-initialized:
+   *
+   * %TRUE if the name owner object is initialized.
+   */
+  g_object_class_install_property (gobject_class,
+                                   PROP_IS_INITIALIZED,
+                                   g_param_spec_boolean ("is-initialized",
+                                                         _("is-initialized"),
+                                                         _("Whether the object is initialized"),
+                                                         FALSE,
+                                                         G_PARAM_READABLE |
+                                                         G_PARAM_STATIC_NAME |
+                                                         G_PARAM_STATIC_BLURB |
+                                                         G_PARAM_STATIC_NICK));
+
+  /**
+   * GBusOwner:bus-type:
+   *
+   * When constructing, set to the type of the message bus the owner
+   * object is for. It will be ignored if #GBusNameOnwer:connection is
+   * also set upon construction.
+   *
+   * When reading, the actual type (never #G_BUS_TYPE_STARTER) of the message
+   * bus the owner object is for or #G_TYPE_BUS_NONE if the owner object is
+   * not for a known message bus type.
+   */
+  g_object_class_install_property (gobject_class,
+                                   PROP_BUS_TYPE,
+                                   g_param_spec_enum ("bus-type",
+                                                      _("bus-type"),
+                                                      _("The type of message bus the owner object is for"),
+                                                      G_TYPE_BUS_TYPE,
+                                                      G_BUS_TYPE_NONE,
+                                                      G_PARAM_READABLE |
+                                                      G_PARAM_WRITABLE |
+                                                      G_PARAM_CONSTRUCT_ONLY |
+                                                      G_PARAM_STATIC_NAME |
+                                                      G_PARAM_STATIC_BLURB |
+                                                      G_PARAM_STATIC_NICK));
+
+  /**
    * GBusNameOwner:connection:
    *
    * The #GMessageBusConnection that the name will be owned on.
@@ -525,14 +661,29 @@ g_bus_name_owner_class_init (GBusNameOwnerClass *klass)
                                                 g_cclosure_marshal_VOID__VOID,
                                                 G_TYPE_NONE,
                                                 0);
+
+  /**
+   * GBusNameOwner::initialized:
+   * @owner: The #GBusNameOwner emitting the signal.
+   *
+   * Emitted when @owner is initialized.
+   **/
+  signals[INITIALIZED_SIGNAL] = g_signal_new ("initialized",
+                                              G_TYPE_BUS_NAME_OWNER,
+                                              G_SIGNAL_RUN_LAST,
+                                              G_STRUCT_OFFSET (GBusNameOwnerClass, initialized),
+                                              NULL,
+                                              NULL,
+                                              g_cclosure_marshal_VOID__VOID,
+                                              G_TYPE_NONE,
+                                              0);
 }
 
 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_init_phase = TRUE;
-  owner->priv->init_phase_pending_simple_async_results = g_ptr_array_new ();
+  owner->priv->is_initialized = FALSE;
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -559,7 +710,7 @@ static GHashTable *map_connection_to_map_of_owned_names_to_owner = NULL;
 
 /* the following singletons_* functions must be called with owner_lock held */
 
-/* called from _new() before creating a GBusNameOwner - result is not reffed */
+/* called from _constructor() before creating a new object - result is not reffed */
 static GBusNameOwner *
 singletons_get_owner (GDBusConnection *connection, const gchar *name)
 {
@@ -581,14 +732,13 @@ singletons_get_owner (GDBusConnection *connection, const gchar *name)
 
   ret = g_hash_table_lookup (map_of_owned_names_to_owner,
                              name);
-
  out:
   return ret;
 }
 
-/* called from _new() after creating the GBusNameOwner */
+/* called from _constructor() */
 static void
-singletons_add_owner (GBusNameOwner *owner)
+singletons_add_owner (GBusNameOwner *owner, GDBusConnection *connection, const gchar *name)
 {
   GHashTable *map_of_owned_names_to_owner;
 
@@ -598,17 +748,20 @@ singletons_add_owner (GBusNameOwner *owner)
     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);
+                                                     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);
+      map_of_owned_names_to_owner = g_hash_table_new_full (g_str_hash,
+                                                           g_str_equal,
+                                                           g_free,
+                                                           NULL);
       g_hash_table_insert (map_connection_to_map_of_owned_names_to_owner,
-                           owner->priv->connection,
+                           connection,
                            map_of_owned_names_to_owner);
     }
 
   g_hash_table_insert (map_of_owned_names_to_owner,
-                       owner->priv->name,
+                       g_strdup (name),
                        owner);
 }
 
@@ -648,357 +801,210 @@ singletons_remove_owner (GBusNameOwner *owner)
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
+
 static void
-request_name_cb (GDBusConnection *connection,
-                 GAsyncResult    *result,
-                 gpointer         user_data)
+g_bus_name_owner_constructed (GObject *object)
 {
-  GBusNameOwner *owner = G_BUS_NAME_OWNER (user_data);
-  GSimpleAsyncResult *simple;
-  GError *error;
-  DBusMessage *reply;
-  DBusError dbus_error;
-  dbus_uint32_t request_name_reply;
-  guint n;
+  GBusNameOwner *owner = G_BUS_NAME_OWNER (object);
 
-  error = NULL;
-  reply = g_dbus_connection_send_dbus_1_message_with_reply_finish (connection,
-                                                                   result,
-                                                                   &error);
-  if (reply != NULL)
+  if (owner->priv->connection == NULL)
     {
-      dbus_error_init (&dbus_error);
-      if (!dbus_set_error_from_message (&dbus_error, reply))
-        {
-          dbus_message_get_args (reply,
-                                 &dbus_error,
-                                 DBUS_TYPE_UINT32, &request_name_reply,
-                                 DBUS_TYPE_INVALID);
-        }
-      if (dbus_error_is_set (&dbus_error))
-        {
-          error = g_dbus_error_new_for_dbus_error (&dbus_error, NULL, NULL);
-          dbus_error_free (&dbus_error);
-        }
+      g_assert (owner->priv->bus_type != G_BUS_TYPE_NONE);
+      owner->priv->connection = g_dbus_connection_bus_get (owner->priv->bus_type);
+      /* readjust e.g. G_BUS_TYPE_STARTER */
+      owner->priv->bus_type = g_dbus_connection_get_bus_type (owner->priv->connection);
     }
 
-  G_LOCK (owner_lock);
-  if (error != NULL)
+  g_signal_connect (owner->priv->connection, "opened", G_CALLBACK (on_connection_opened), owner);
+  g_signal_connect (owner->priv->connection, "closed", G_CALLBACK (on_connection_closed), owner);
+  g_signal_connect (owner->priv->connection, "initialized", G_CALLBACK (on_connection_initialized), owner);
+  if (g_dbus_connection_get_is_open (owner->priv->connection))
     {
-      /* 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);
+      /* if the connection is already open, then do RequestName right away */
+      on_connection_opened (owner->priv->connection, owner);
     }
   else
     {
-      if (request_name_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++)
+      if (!g_dbus_connection_get_is_initialized (owner->priv->connection))
+        {
+          /* if the connection is not yet initialized, we are not until the connection is
+           */
+        }
+      else
         {
-          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);
+          /* connection is not open but it is initialized so we are initialized too (no need to emit
+           * signals since no-one has a reference to us)
+           */
+          owner->priv->is_initialized = FALSE;
         }
     }
 
-  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);
-
-  if (reply != NULL)
-    dbus_message_unref (reply);
-}
-
-static void
-do_request_name (GBusNameOwner *owner)
-{
-  DBusMessage *message;
-  dbus_uint32_t flags;
-
-  flags = get_request_name_flags (owner->priv->flags);
-  if ((message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
-                                               DBUS_PATH_DBUS,
-                                               DBUS_INTERFACE_DBUS,
-                                               "RequestName")) == NULL)
-    _g_dbus_oom ();
-  if (!dbus_message_append_args (message,
-                                 DBUS_TYPE_STRING, &owner->priv->name,
-                                 DBUS_TYPE_UINT32, &flags,
-                                 DBUS_TYPE_INVALID))
-    _g_dbus_oom ();
-  g_dbus_connection_send_dbus_1_message_with_reply (owner->priv->connection,
-                                                    message,
-                                                    -1,
-                                                    NULL,
-                                                    (GAsyncReadyCallback) request_name_cb,
-                                                    owner);
-  dbus_message_unref (message);
-}
-
-static void
-on_notify_is_opening (GDBusConnection *connection,
-                      GParamSpec      *spec,
-                      gpointer         user_data)
-{
-  GBusNameOwner *owner = G_BUS_NAME_OWNER (user_data);
-
-  /* connection is not opening anymore.. try to own the name */
-  do_request_name (owner);
-
-  g_signal_handlers_disconnect_by_func (connection, on_notify_is_opening, owner);
+  if (G_OBJECT_CLASS (g_bus_name_owner_parent_class)->constructed != NULL)
+    G_OBJECT_CLASS (g_bus_name_owner_parent_class)->constructed (object);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
 
-static GBusNameOwner *
-g_bus_name_owner_new_internal (GBusType               bus_type,
-                               GDBusConnection       *given_connection,
-                               const gchar           *name,
-                               GBusNameOwnerFlags     flags,
-                               GCancellable          *cancellable,
-                               GAsyncReadyCallback    callback,
-                               gpointer               user_data)
+static GObject *
+g_bus_name_owner_constructor (GType                  type,
+                              guint                  n_construct_properties,
+                              GObjectConstructParam *construct_properties)
 {
-  GBusNameOwner *owner;
+  GObject *object;
   GDBusConnection *connection;
-  GSimpleAsyncResult *simple;
-  gpointer source_tag;
+  const gchar *name;
+  guint n;
 
-  /* 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.
-   */
+  G_LOCK (owner_lock);
 
-  if (given_connection != NULL)
-    {
-      source_tag = g_bus_name_owner_new_for_connection_finish;
-      connection = g_object_ref (given_connection);
-    }
-  else
-    {
-      source_tag = g_bus_name_owner_new_finish;
-      connection = g_dbus_connection_bus_get (bus_type,
-                                              NULL,
-                                              NULL,
-                                              NULL);
-    }
+  connection = NULL;
+  name = NULL;
+  object = NULL;
 
-  G_LOCK (owner_lock);
-  /* check if a suitable owner already exists */
-  owner = singletons_get_owner (connection, name);
-  if (owner != NULL)
+  for (n = 0; n < n_construct_properties; n++)
     {
-      simple = g_simple_async_result_new (G_OBJECT (owner),
-                                          callback,
-                                          user_data,
-                                          source_tag);
-
-      if (owner->priv->in_init_phase)
+      if (g_strcmp0 (construct_properties[n].pspec->name, "bus-type") == 0)
         {
-          /* 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);
+          GBusType bus_type;
+          bus_type = g_value_get_enum (construct_properties[n].value);
+          if (bus_type != G_BUS_TYPE_NONE)
+            connection = g_dbus_connection_bus_get (bus_type);
         }
-      else
+      else if (g_strcmp0 (construct_properties[n].pspec->name, "connection") == 0)
         {
-          /* otherwise, return the result right away (e.g. in idle) */
-          g_simple_async_result_complete_in_idle (simple);
-          g_object_unref (simple);
+          GDBusConnection *given_connection;
+          given_connection = g_value_get_object (construct_properties[n].value);
+          if (given_connection != NULL)
+            {
+              if (connection != NULL)
+                g_object_unref (connection);
+              connection = g_object_ref (given_connection);
+            }
+        }
+      else if (g_strcmp0 (construct_properties[n].pspec->name, "name") == 0)
+        {
+          name = g_value_get_string (construct_properties[n].value);
         }
-      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);
-
-  g_ptr_array_add (owner->priv->init_phase_pending_simple_async_results, simple);
+  g_assert (connection != NULL);
+  g_assert (name != NULL);
 
-  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
+  object = G_OBJECT (singletons_get_owner (connection, name));
+  if (object != NULL)
     {
-      /* connection is not opening.. try to claim the name */
-      do_request_name (owner);
+      g_object_ref (object);
+      goto out;
     }
 
+  object = G_OBJECT_CLASS (g_bus_name_owner_parent_class)->constructor (type,
+                                                                        n_construct_properties,
+                                                                        construct_properties);
+
+  singletons_add_owner (G_BUS_NAME_OWNER (object), connection, name);
 
  out:
-  G_UNLOCK (owner_lock);
 
   g_object_unref (connection);
-
-  return owner;
+  G_UNLOCK (owner_lock);
+  return object;
 }
 
+/* ---------------------------------------------------------------------------------------------------- */
+
 /**
  * g_bus_name_owner_new:
- * @bus_type: A #GBusType specifying what message bus to connect to.
+ * @bus_type: The type of bus to own the name on.
  * @name: A well-known name to acquire.
  * @flags: A set of flags from the #GBusNameOwnerFlags enumeration.
- * @cancellable: %NULL or a #GCancellable.
- * @callback: The callback function to invoke when finished acquiring the name.
- * @user_data: User data to pass to @callback.
- *
- * <note><para>This class is intended for language bindings and object
- *             mappings. If you are implementing an application, it's
- *             easier to use the high-level g_bus_name_own() function.
- * </para></note>
  *
- * Creates a new #GBusNameOwner and then attempts to own @name on the
- * bus specified by @bus_type. When the attempt to own the name is
- * finished, @callback will be invoked (on the main thread) and you
- * can use g_bus_name_owner_new_finish() to get the result.
+ * Get a new #GBusNameOwner object for owning @name on the message bus
+ * specified by @bus_type.
  *
- * Once you have the result, you can connect to the #GBusNameOwner::name-acquired
- * and #GBusNameOwner::name-lost signals to track changes.
+ * Since owning a name is an asynchronous operation, the returned
+ * object is not guaranteed to return correct information until it has
+ * been initialized. Use g_bus_name_owner_get_is_initialized() to check
+ * whether the object is initialized and connect to the
+ * #GBusNameOwner::initialized signal or listen for notifications on
+ * the #GBusNameOwner:is-initialized property to get informed when it
+ * is.
  *
- * If the connection is closed and then opened again, the #GBusNameOwner
- * class will attempt to acquire the name.
+ * Note that the returned object may have different
+ * #GBusNameOwnerFlags flags than requested with @flags. This is
+ * because #GBusNameOwner objects are shared between all callers, e.g.
+ * if two separate parts of a process calls this function with the
+ * same @bus_type and @name, they will share the same object. This
+ * also means that the object may already be initialized when it
+ * is returned.
  *
- * Note that the returned object may be shared with other callers if
- * @bus_type and @name matches a previously constructed object. Also
- * note that @flags is not used in this comparison so it's entirely
- * possible to get a owner object that has different flags from what
- * was passed to this function (the first one to construct the owner
- * wins).
+ * #GBusNameOwner deals gracefully with the underlying connection
+ * closing and opening by attempting to request the name when the
+ * connection is back up.
  *
  * Returns: A #GBusNameOwner object. Free with g_object_unref().
  **/
 GBusNameOwner *
 g_bus_name_owner_new (GBusType               bus_type,
                       const gchar           *name,
-                      GBusNameOwnerFlags     flags,
-                      GCancellable          *cancellable,
-                      GAsyncReadyCallback    callback,
-                      gpointer               user_data)
+                      GBusNameOwnerFlags     flags)
 {
-  return g_bus_name_owner_new_internal (bus_type,
-                                        NULL,
-                                        name,
-                                        flags,
-                                        cancellable,
-                                        callback,
-                                        user_data);
+  return G_BUS_NAME_OWNER (g_object_new (G_TYPE_BUS_NAME_OWNER,
+                                         "bus-type", bus_type,
+                                         "name", name,
+                                         "flags", flags,
+                                         NULL));
 }
 
 /**
- * g_bus_name_owner_new_finish:
- * @owner: A #GBusNameOwner.
- * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to g_bus_name_owner_get().
- * @error: Return location for error or %NULL.
- *
- * Finishes attempting to acquire a name.
- *
- * 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,
-                             GAsyncResult          *res,
-                             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.
  * @name: A well-known name to acquire.
  * @flags: A set of flags from the #GBusNameOwnerFlags enumeration.
- * @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_owner_new() but allows you to pass in a
- * #GDBusConnection.
+ * #GDBusConnection instead of a #GBusType.
  *
  * Returns: A #GBusNameOwner object. Free with g_object_unref().
  **/
 GBusNameOwner *
 g_bus_name_owner_new_for_connection (GDBusConnection       *connection,
                                      const gchar           *name,
-                                     GBusNameOwnerFlags     flags,
-                                     GCancellable          *cancellable,
-                                     GAsyncReadyCallback    callback,
-                                     gpointer               user_data)
+                                     GBusNameOwnerFlags     flags)
 {
-  return g_bus_name_owner_new_internal (G_BUS_TYPE_NONE,
-                                        connection,
-                                        name,
-                                        flags,
-                                        cancellable,
-                                        callback,
-                                        user_data);
+  return G_BUS_NAME_OWNER (g_object_new (G_TYPE_BUS_NAME_OWNER,
+                                         "connection", connection,
+                                         "name", name,
+                                         "flags", flags,
+                                         NULL));
 }
 
+/* ---------------------------------------------------------------------------------------------------- */
+
 /**
- * g_bus_name_owner_new_for_connection_finish:
+ * g_bus_name_owner_get_is_initialized:
  * @owner: A #GBusNameOwner.
- * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback
- * function passed to g_bus_name_owner_get_for_connection().
- * @error: Return location for error or %NULL.
  *
- * Finishes attempting to acquire a name.
+ * Gets whether @owner is is initialized.
  *
- * Returns: %TRUE if the name was acquired, otherwise %FALSE with @error set.
+ * You can track changes to this value by connecting to the
+ * #GBusNameOwner::initialized signal or by listening to changes on
+ * the #GBusNameOwner:is-initialized property.
+ *
+ * Returns: %TRUE if @owner is initialized, %FALSE otherwise.
  **/
 gboolean
-g_bus_name_owner_new_for_connection_finish (GBusNameOwner         *owner,
-                                            GAsyncResult          *res,
-                                            GError               **error)
+g_bus_name_owner_get_is_initialized (GBusNameOwner *owner)
 {
-  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_for_connection_finish);
-
-  return !g_simple_async_result_propagate_error (simple, error);
+  return owner->priv->is_initialized;
 }
-/* ---------------------------------------------------------------------------------------------------- */
 
 /**
  * g_bus_name_owner_get_owns_name:
  * @owner: A #GBusNameOwner.
  *
- * Gets whether @owner currently owns the name it was constructed with.
+ * Gets whether @owner currently owns the well-known name.
  *
  * You can track changes to this value by listening to the
  * #GBusNameOwner::name-acquired and #GBusNameOwner::name-lost signals
@@ -1019,10 +1025,10 @@ g_bus_name_owner_get_owns_name (GBusNameOwner *owner)
  * g_bus_name_owner_get_name:
  * @owner: A #GBusNameOwner.
  *
- * Gets the well-known name that @owner was constructed with.
+ * Gets the well-known name that @owner is attempting to own.
  *
- * Returns: The well-known name for @owner. Do not free this string,
- * it is owned by @owner.
+ * Returns: The well-known name that @owner is attempting to own. Do
+ * not free this string, it is owned by @owner.
  **/
 const gchar *
 g_bus_name_owner_get_name (GBusNameOwner *owner)
@@ -1033,6 +1039,24 @@ g_bus_name_owner_get_name (GBusNameOwner *owner)
 }
 
 /**
+ * g_bus_name_owner_get_bus_type:
+ * @owner: A #GBusNameOwner.
+ *
+ * Gets the type (never #G_BUS_TYPE_STARTER) of the message bus the
+ * owner object is for or #G_TYPE_BUS_NONE if the owner object is not
+ * for a known message bus type.
+ *
+ * Returns: A #GBusType.
+ **/
+GBusType
+g_bus_name_owner_get_bus_type (GBusNameOwner *owner)
+{
+  g_return_val_if_fail (G_IS_BUS_NAME_OWNER (owner), 0);
+
+  return owner->priv->bus_type;
+}
+
+/**
  * g_bus_name_owner_get_flags:
  * @owner: A #GBusNameOwner.
  *
diff --git a/gdbus/gbusnameowner.h b/gdbus/gbusnameowner.h
index b8d938f..7151326 100644
--- a/gdbus/gbusnameowner.h
+++ b/gdbus/gbusnameowner.h
@@ -59,6 +59,7 @@ struct _GBusNameOwner
  * GBusNameOwnerClass:
  * @name_acquired: Signal class handler for the #GBusNameOwner::name-acquired signal.
  * @name_lost: Signal class handler for the #GBusNameOwner::name-lost signal.
+ * @initialized: Signal class handler for the #GBusNameOwner::initialized signal.
  *
  * Class structure for #GBusNameOwner.
  */
@@ -72,6 +73,7 @@ struct _GBusNameOwnerClass
   /* Signals */
   void (*name_acquired) (GBusNameOwner *owner);
   void (*name_lost)     (GBusNameOwner *owner);
+  void (*initialized)   (GBusNameOwner *owner);
 
   /*< private >*/
   /* Padding for future expansion */
@@ -88,25 +90,15 @@ struct _GBusNameOwnerClass
 GType               g_bus_name_owner_get_type                  (void) G_GNUC_CONST;
 GBusNameOwner      *g_bus_name_owner_new                       (GBusType               bus_type,
                                                                 const gchar           *name,
-                                                                GBusNameOwnerFlags     flags,
-                                                                GCancellable          *cancellable,
-                                                                GAsyncReadyCallback    callback,
-                                                                gpointer               user_data);
-gboolean            g_bus_name_owner_new_finish                (GBusNameOwner         *owner,
-                                                                GAsyncResult          *res,
-                                                                GError               **error);
+                                                                GBusNameOwnerFlags     flags);
 GBusNameOwner      *g_bus_name_owner_new_for_connection        (GDBusConnection       *connection,
                                                                 const gchar           *name,
-                                                                GBusNameOwnerFlags     flags,
-                                                                GCancellable          *cancellable,
-                                                                GAsyncReadyCallback    callback,
-                                                                gpointer               user_data);
-gboolean            g_bus_name_owner_new_for_connection_finish (GBusNameOwner         *owner,
-                                                                GAsyncResult          *res,
-                                                                GError               **error);
+                                                                GBusNameOwnerFlags     flags);
 gboolean            g_bus_name_owner_get_owns_name             (GBusNameOwner         *owner);
 const gchar        *g_bus_name_owner_get_name                  (GBusNameOwner         *owner);
+GBusType            g_bus_name_owner_get_bus_type              (GBusNameOwner         *owner);
 GBusNameOwnerFlags  g_bus_name_owner_get_flags                 (GBusNameOwner         *owner);
+gboolean            g_bus_name_owner_get_is_initialized        (GBusNameOwner         *owner);
 GDBusConnection    *g_bus_name_owner_get_connection            (GBusNameOwner         *owner);
 
 G_END_DECLS
diff --git a/gdbus/gbusnamewatcher.c b/gdbus/gbusnamewatcher.c
index 914d8f6..e0a4321 100644
--- a/gdbus/gbusnamewatcher.c
+++ b/gdbus/gbusnamewatcher.c
@@ -36,17 +36,21 @@
 
 /**
  * SECTION:gbusnamewatcher
- * @short_description: Watch names on the bus
+ * @short_description: Watch names on a bus
  * @include: gdbus/gdbus.h
  *
- * #GBusNameWatcher is a utility class that makes it easy to track
- * whether a name exists on a message bus. See
- * g_bus_name_watcher_new() for an example.
+ * <para><note>
+ * This class is rarely used directly. If you are writing an application, it is often
+ * easier to use the g_bus_own_name() or g_bus_watch_name() APIs.
+ * </note></para>
+ * #GBusNameWatcher is a utility class for watching names on a message
+ * bus.
  */
 
 struct _GBusNameWatcherPrivate
 {
   gchar *name;
+  GBusType bus_type;
 
   GDBusConnection *connection;
 
@@ -54,16 +58,17 @@ struct _GBusNameWatcherPrivate
 
   gchar *match_rule;
 
-  /* these variables are used to store async callbacks for users calling _new()  */
-  gboolean   in_init_phase;
-  GPtrArray *init_phase_pending_simple_async_results;
+  gboolean is_initialized;
 };
 
 enum
 {
   PROP_0,
   PROP_NAME,
+  PROP_FLAGS,
+  PROP_BUS_TYPE,
   PROP_NAME_OWNER,
+  PROP_IS_INITIALIZED,
   PROP_CONNECTION,
 };
 
@@ -71,11 +76,21 @@ enum
 {
   NAME_APPEARED_SIGNAL,
   NAME_VANISHED_SIGNAL,
+  INITIALIZED_SIGNAL,
   LAST_SIGNAL,
 };
 
 G_LOCK_DEFINE_STATIC (watcher_lock);
 
+static GObject *g_bus_name_watcher_constructor (GType                  type,
+                                                guint                  n_construct_properties,
+                                                GObjectConstructParam *construct_properties);
+static void g_bus_name_watcher_constructed (GObject *object);
+
+static GBusNameWatcher *singletons_get_watcher (GDBusConnection *connection, const gchar *name);
+static void singletons_add_watcher (GBusNameWatcher *watcher, GDBusConnection *connection, const gchar *name);
+static void singletons_remove_watcher (GBusNameWatcher *watcher);
+
 static DBusHandlerResult
 filter_function (DBusConnection *dbus_1_connection,
                  DBusMessage    *message,
@@ -83,16 +98,15 @@ filter_function (DBusConnection *dbus_1_connection,
 
 static guint signals[LAST_SIGNAL] = { 0 };
 
-static GBusNameWatcher *singletons_get_watcher (GDBusConnection *connection, const gchar *name);
-static void singletons_add_watcher (GBusNameWatcher *watcher);
-static void singletons_remove_watcher (GBusNameWatcher *watcher);
-
 static void on_connection_opened (GDBusConnection *connection,
                                   gpointer         user_data);
 
 static void on_connection_closed (GDBusConnection *connection,
                                   gpointer         user_data);
 
+static void on_connection_initialized (GDBusConnection *connection,
+                                       gpointer         user_data);
+
 G_DEFINE_TYPE (GBusNameWatcher, g_bus_name_watcher, G_TYPE_OBJECT);
 
 static void
@@ -117,10 +131,12 @@ g_bus_name_watcher_finalize (GObject *object)
     {
       g_signal_handlers_disconnect_by_func (watcher->priv->connection, on_connection_opened, watcher);
       g_signal_handlers_disconnect_by_func (watcher->priv->connection, on_connection_closed, watcher);
+      g_signal_handlers_disconnect_by_func (watcher->priv->connection, on_connection_initialized, watcher);
 
       if (g_dbus_connection_get_is_open (watcher->priv->connection))
         {
           DBusMessage *message;
+
           if ((message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
                                                        DBUS_PATH_DBUS,
                                                        DBUS_INTERFACE_DBUS,
@@ -132,16 +148,17 @@ g_bus_name_watcher_finalize (GObject *object)
             _g_dbus_oom ();
           g_dbus_connection_send_dbus_1_message (watcher->priv->connection, message);
           dbus_message_unref (message);
+
           dbus_connection_remove_filter (g_dbus_connection_get_dbus_1_connection (watcher->priv->connection),
                                          filter_function,
                                          watcher);
         }
+      g_free (watcher->priv->match_rule);
 
       g_object_unref (watcher->priv->connection);
     }
   g_free (watcher->priv->name);
   g_free (watcher->priv->name_owner);
-  g_free (watcher->priv->match_rule);
 
   if (G_OBJECT_CLASS (g_bus_name_watcher_parent_class)->finalize != NULL)
     G_OBJECT_CLASS (g_bus_name_watcher_parent_class)->finalize (object);
@@ -161,10 +178,18 @@ g_bus_name_watcher_get_property (GObject    *object,
       g_value_set_string (value, g_bus_name_watcher_get_name (watcher));
       break;
 
+    case PROP_BUS_TYPE:
+      g_value_set_enum (value, g_bus_name_watcher_get_bus_type (watcher));
+      break;
+
     case PROP_NAME_OWNER:
       g_value_set_string (value, g_bus_name_watcher_get_name_owner (watcher));
       break;
 
+    case PROP_IS_INITIALIZED:
+      g_value_set_boolean (value, g_bus_name_watcher_get_is_initialized (watcher));
+      break;
+
     case PROP_CONNECTION:
       g_value_set_object (value, g_bus_name_watcher_get_connection (watcher));
       break;
@@ -189,6 +214,10 @@ g_bus_name_watcher_set_property (GObject      *object,
       watcher->priv->name = g_value_dup_string (value);
       break;
 
+    case PROP_BUS_TYPE:
+      watcher->priv->bus_type = g_value_get_enum (value);
+      break;
+
     case PROP_CONNECTION:
       watcher->priv->connection = g_value_dup_object (value);
       break;
@@ -244,12 +273,11 @@ filter_function (DBusConnection *dbus_1_connection,
                  void           *user_data)
 {
   GBusNameWatcher *watcher = G_BUS_NAME_WATCHER (user_data);
-  DBusError dbus_error;
   const gchar *name;
   const gchar *old_owner;
   const gchar *new_owner;
+  DBusError dbus_error;
 
-  //g_debug ("in bus-name-watcher's filter_function for dbus_1_connection %p", dbus_1_connection);
   //PRINT_MESSAGE (message);
 
   /* we only care about NameOwnerChanged */
@@ -297,18 +325,103 @@ filter_function (DBusConnection *dbus_1_connection,
     }
 
  out:
-
   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 }
 
 static void
+get_name_owner_cb (GDBusConnection *connection,
+                   GAsyncResult    *res,
+                   gpointer         user_data)
+{
+  GBusNameWatcher *watcher = G_BUS_NAME_WATCHER (user_data);
+  DBusMessage *reply;
+  DBusError dbus_error;
+  const gchar *name_owner;
+  gchar *old_name_owner;
+  gboolean old_is_initialized;
+
+  old_name_owner = g_strdup (watcher->priv->name_owner);
+  old_is_initialized = watcher->priv->is_initialized;
+
+  reply = g_dbus_connection_send_dbus_1_message_with_reply_finish (connection,
+                                                                   res,
+                                                                   NULL);
+  if (reply == NULL)
+    goto out;
+
+  dbus_error_init (&dbus_error);
+  if (!dbus_set_error_from_message (&dbus_error, reply))
+    {
+      dbus_message_get_args (reply,
+                             &dbus_error,
+                             DBUS_TYPE_STRING, &name_owner,
+                             DBUS_TYPE_INVALID);
+    }
+  if (dbus_error_is_set (&dbus_error))
+    {
+      dbus_error_free (&dbus_error);
+    }
+  else
+    {
+      g_free (watcher->priv->name_owner);
+      watcher->priv->name_owner = g_strdup (name_owner);
+      if (g_strcmp0 (watcher->priv->name_owner, old_name_owner) != 0)
+        {
+          g_object_notify (G_OBJECT (watcher), "name-owner");
+          g_signal_emit (watcher, signals[NAME_APPEARED_SIGNAL], 0);
+        }
+    }
+
+ out:
+  /* we're now initialized */
+  watcher->priv->is_initialized = TRUE;
+  if (old_is_initialized != watcher->priv->is_initialized)
+    {
+      g_object_notify (G_OBJECT (watcher), "is-initialized");
+      g_signal_emit (watcher, signals[INITIALIZED_SIGNAL], 0);
+    }
+  if (reply != NULL)
+    dbus_message_unref (reply);
+  g_object_unref (watcher);
+  g_free (old_name_owner);
+}
+
+static void
+on_connection_initialized (GDBusConnection *connection,
+                           gpointer         user_data)
+{
+  GBusNameWatcher *watcher = G_BUS_NAME_WATCHER (user_data);
+
+  /* This can only fire once */
+  g_assert (!watcher->priv->is_initialized);
+
+  if (g_dbus_connection_get_is_open (connection))
+    {
+      /* if the connection is now open then on_connection_opened() will fire
+       * and we'll try to get the name owner from there
+       */
+    }
+  else
+    {
+      /* connection failed to open so we are now initialized */
+      watcher->priv->is_initialized = TRUE;
+      g_object_notify (G_OBJECT (watcher), "is-initialized");
+      g_signal_emit (watcher, signals[INITIALIZED_SIGNAL], 0);
+    }
+}
+
+/* note that this is also called from g_bus_name_watcher_constructed() if the connection is open */
+static void
 on_connection_opened (GDBusConnection *connection,
                       gpointer         user_data)
 {
   GBusNameWatcher *watcher = G_BUS_NAME_WATCHER (user_data);
   DBusMessage *message;
 
-  /* set up a filter function for listening on (some) NameOwnerChanged messages on the DBusConnection */
+  g_assert (g_dbus_connection_get_is_open (watcher->priv->connection));
+  g_assert (watcher->priv->name_owner == NULL);
+
+  /* set up a filter function for listening on NameOwnerChanged messages on the DBusConnection */
   if (!dbus_connection_add_filter (g_dbus_connection_get_dbus_1_connection (watcher->priv->connection),
                                    filter_function,
                                    watcher,
@@ -328,10 +441,22 @@ on_connection_opened (GDBusConnection *connection,
   g_dbus_connection_send_dbus_1_message (watcher->priv->connection, message);
   dbus_message_unref (message);
 
-  /* TODO: if this is for a bus reconnection, we actually need check bus
-   * name again since someone may acquire the name before our match
-   * rules are added
-   */
+  if ((message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
+                                               DBUS_PATH_DBUS,
+                                               DBUS_INTERFACE_DBUS,
+                                               "GetNameOwner")) == NULL)
+    _g_dbus_oom ();
+  if (!dbus_message_append_args (message,
+                                 DBUS_TYPE_STRING, &watcher->priv->name,
+                                 DBUS_TYPE_INVALID))
+    _g_dbus_oom ();
+  g_dbus_connection_send_dbus_1_message_with_reply (watcher->priv->connection,
+                                                    message,
+                                                    -1,
+                                                    NULL,
+                                                    (GAsyncReadyCallback) get_name_owner_cb,
+                                                    g_object_ref (watcher));
+  dbus_message_unref (message);
 }
 
 static void
@@ -342,7 +467,7 @@ on_connection_closed (GDBusConnection *connection,
 
   /* no need to remove filter; it is removed when the DBusConnection is destroyed */
 
-  /* bus went down.. so emit ::name-vanished */
+  /* if we currently have a name owner then nuke it */
   if (watcher->priv->name_owner != NULL)
     {
       g_free (watcher->priv->name_owner);
@@ -353,26 +478,6 @@ on_connection_closed (GDBusConnection *connection,
 }
 
 static void
-g_bus_name_watcher_constructed (GObject *object)
-{
-  GBusNameWatcher *watcher = G_BUS_NAME_WATCHER (object);
-
-  watcher->priv->match_rule = g_strdup_printf ("type='signal',"
-                                               "sender='org.freedesktop.DBus',"
-                                               "member='NameOwnerChanged',"
-                                               "arg0='%s'",
-                                               watcher->priv->name);
-
-  g_signal_connect (watcher->priv->connection, "opened", G_CALLBACK (on_connection_opened), watcher);
-  g_signal_connect (watcher->priv->connection, "closed", G_CALLBACK (on_connection_closed), watcher);
-  if (g_dbus_connection_get_is_open (watcher->priv->connection))
-    on_connection_opened (watcher->priv->connection, watcher);
-
-  if (G_OBJECT_CLASS (g_bus_name_watcher_parent_class)->constructed != NULL)
-    G_OBJECT_CLASS (g_bus_name_watcher_parent_class)->constructed (object);
-}
-
-static void
 g_bus_name_watcher_class_init (GBusNameWatcherClass *klass)
 {
   GObjectClass *gobject_class;
@@ -380,6 +485,7 @@ g_bus_name_watcher_class_init (GBusNameWatcherClass *klass)
   g_type_class_add_private (klass, sizeof (GBusNameWatcherPrivate));
 
   gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->constructor  = g_bus_name_watcher_constructor;
   gobject_class->dispose      = g_bus_name_watcher_dispose;
   gobject_class->finalize     = g_bus_name_watcher_finalize;
   gobject_class->constructed  = g_bus_name_watcher_constructed;
@@ -389,7 +495,7 @@ g_bus_name_watcher_class_init (GBusNameWatcherClass *klass)
   /**
    * GBusNameWatcher:name:
    *
-   * The name (well-known or unique) to watch.
+   * The well-known or unique name to watch.
    */
   g_object_class_install_property (gobject_class,
                                    PROP_NAME,
@@ -404,24 +510,63 @@ g_bus_name_watcher_class_init (GBusNameWatcherClass *klass)
                                                         G_PARAM_STATIC_BLURB |
                                                         G_PARAM_STATIC_NICK));
 
-
   /**
    * GBusNameWatcher:name-owner:
    *
    * The unique name of the owner of the name being watched or %NULL
-   * if no-one is owning the name.
+   * if there is no name owner.
    */
   g_object_class_install_property (gobject_class,
                                    PROP_NAME_OWNER,
-                                   g_param_spec_string ("name-owner",
-                                                        _("name-owner"),
-                                                        _("Owner of the name being watched"),
-                                                        NULL,
-                                                        G_PARAM_READABLE |
-                                                        G_PARAM_STATIC_NAME |
-                                                        G_PARAM_STATIC_BLURB |
-                                                        G_PARAM_STATIC_NICK));
+                                   g_param_spec_boolean ("name-owner",
+                                                         _("name-owner"),
+                                                         _("The unique name of the owner of the name being watched"),
+                                                         FALSE,
+                                                         G_PARAM_READABLE |
+                                                         G_PARAM_STATIC_NAME |
+                                                         G_PARAM_STATIC_BLURB |
+                                                         G_PARAM_STATIC_NICK));
 
+  /**
+   * GBusNameWatcher:is-initialized:
+   *
+   * %TRUE if the name watcher object is initialized.
+   */
+  g_object_class_install_property (gobject_class,
+                                   PROP_IS_INITIALIZED,
+                                   g_param_spec_boolean ("is-initialized",
+                                                         _("is-initialized"),
+                                                         _("Whether the object is initialized"),
+                                                         FALSE,
+                                                         G_PARAM_READABLE |
+                                                         G_PARAM_STATIC_NAME |
+                                                         G_PARAM_STATIC_BLURB |
+                                                         G_PARAM_STATIC_NICK));
+
+  /**
+   * GBusWatcher:bus-type:
+   *
+   * When constructing, set to the type of the message bus the watcher
+   * object is for. It will be ignored if #GBusNameOnwer:connection is
+   * also set upon construction.
+   *
+   * When reading, the actual type (never #G_BUS_TYPE_STARTER) of the message
+   * bus the watcher object is for or #G_TYPE_BUS_NONE if the watcher object is
+   * not for a known message bus type.
+   */
+  g_object_class_install_property (gobject_class,
+                                   PROP_BUS_TYPE,
+                                   g_param_spec_enum ("bus-type",
+                                                      _("bus-type"),
+                                                      _("The type of message bus the watcher object is for"),
+                                                      G_TYPE_BUS_TYPE,
+                                                      G_BUS_TYPE_NONE,
+                                                      G_PARAM_READABLE |
+                                                      G_PARAM_WRITABLE |
+                                                      G_PARAM_CONSTRUCT_ONLY |
+                                                      G_PARAM_STATIC_NAME |
+                                                      G_PARAM_STATIC_BLURB |
+                                                      G_PARAM_STATIC_NICK));
 
   /**
    * GBusNameWatcher:connection:
@@ -432,7 +577,7 @@ g_bus_name_watcher_class_init (GBusNameWatcherClass *klass)
                                    PROP_CONNECTION,
                                    g_param_spec_object ("connection",
                                                         _("connection"),
-                                                        _("The connection used for watching the name"),
+                                                        _("The connection the name will be watched on"),
                                                         G_TYPE_DBUS_CONNECTION,
                                                         G_PARAM_READABLE |
                                                         G_PARAM_WRITABLE |
@@ -445,7 +590,7 @@ g_bus_name_watcher_class_init (GBusNameWatcherClass *klass)
    * GBusNameWatcher::name-vanished:
    * @watcher: The #GBusNameWatcher emitting the signal.
    *
-   * Emitted when the name being watched vanishes or the connection is closed.
+   * Emitted when the name being watched vanishes.
    **/
   signals[NAME_VANISHED_SIGNAL] = g_signal_new ("name-vanished",
                                                 G_TYPE_BUS_NAME_WATCHER,
@@ -461,7 +606,7 @@ g_bus_name_watcher_class_init (GBusNameWatcherClass *klass)
    * GBusNameWatcher::name-appeared:
    * @watcher: The #GBusNameWatcher emitting the signal.
    *
-   * Emitted when the name being watched appears or the connection is opened.
+   * Emitted when the name being watched appears.
    **/
   signals[NAME_APPEARED_SIGNAL] = g_signal_new ("name-appeared",
                                                 G_TYPE_BUS_NAME_WATCHER,
@@ -472,14 +617,29 @@ g_bus_name_watcher_class_init (GBusNameWatcherClass *klass)
                                                 g_cclosure_marshal_VOID__VOID,
                                                 G_TYPE_NONE,
                                                 0);
+
+  /**
+   * GBusNameWatcher::initialized:
+   * @watcher: The #GBusNameWatcher emitting the signal.
+   *
+   * Emitted when @watcher is initialized.
+   **/
+  signals[INITIALIZED_SIGNAL] = g_signal_new ("initialized",
+                                              G_TYPE_BUS_NAME_WATCHER,
+                                              G_SIGNAL_RUN_LAST,
+                                              G_STRUCT_OFFSET (GBusNameWatcherClass, initialized),
+                                              NULL,
+                                              NULL,
+                                              g_cclosure_marshal_VOID__VOID,
+                                              G_TYPE_NONE,
+                                              0);
 }
 
 static void
 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 ();
+  watcher->priv->is_initialized = FALSE;
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -490,7 +650,7 @@ static GHashTable *map_connection_to_map_of_watched_names_to_watcher = NULL;
 
 /* the following singletons_* functions must be called with watcher_lock held */
 
-/* called from _new() before creating a GBusNameWatcher - result is not reffed */
+/* called from _constructor() before creating a new object - result is not reffed */
 static GBusNameWatcher *
 singletons_get_watcher (GDBusConnection *connection, const gchar *name)
 {
@@ -512,14 +672,13 @@ singletons_get_watcher (GDBusConnection *connection, const gchar *name)
 
   ret = g_hash_table_lookup (map_of_watched_names_to_watcher,
                              name);
-
  out:
   return ret;
 }
 
-/* called from _new() after creating the GBusNameWatcher */
+/* called from _constructor() */
 static void
-singletons_add_watcher (GBusNameWatcher *watcher)
+singletons_add_watcher (GBusNameWatcher *watcher, GDBusConnection *connection, const gchar *name)
 {
   GHashTable *map_of_watched_names_to_watcher;
 
@@ -529,17 +688,20 @@ singletons_add_watcher (GBusNameWatcher *watcher)
     map_connection_to_map_of_watched_names_to_watcher = g_hash_table_new (g_direct_hash, g_direct_equal);
 
   map_of_watched_names_to_watcher = g_hash_table_lookup (map_connection_to_map_of_watched_names_to_watcher,
-                                                         watcher->priv->connection);
+                                                     connection);
   if (map_of_watched_names_to_watcher == NULL)
     {
-      map_of_watched_names_to_watcher = g_hash_table_new (g_str_hash, g_str_equal);
+      map_of_watched_names_to_watcher = g_hash_table_new_full (g_str_hash,
+                                                           g_str_equal,
+                                                           g_free,
+                                                           NULL);
       g_hash_table_insert (map_connection_to_map_of_watched_names_to_watcher,
-                           watcher->priv->connection,
+                           connection,
                            map_of_watched_names_to_watcher);
     }
 
   g_hash_table_insert (map_of_watched_names_to_watcher,
-                       watcher->priv->name,
+                       g_strdup (name),
                        watcher);
 }
 
@@ -581,364 +743,230 @@ singletons_remove_watcher (GBusNameWatcher *watcher)
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
-get_name_owner_cb (GDBusConnection *connection,
-                   GAsyncResult    *result,
-                   gpointer         user_data)
+g_bus_name_watcher_constructed (GObject *object)
 {
-  GBusNameWatcher *watcher = G_BUS_NAME_WATCHER (user_data);
-  GSimpleAsyncResult *simple;
-  GError *error;
-  DBusMessage *reply;
-  DBusError dbus_error;
-  const gchar *name_owner;
-  guint n;
+  GBusNameWatcher *watcher = G_BUS_NAME_WATCHER (object);
 
-  error = NULL;
-  reply = g_dbus_connection_send_dbus_1_message_with_reply_finish (connection,
-                                                                   result,
-                                                                   &error);
-  name_owner = NULL;
-  if (reply != NULL)
+  if (watcher->priv->connection == NULL)
     {
-      dbus_error_init (&dbus_error);
-      if (!dbus_set_error_from_message (&dbus_error, reply))
-        {
-          dbus_message_get_args (reply,
-                                 &dbus_error,
-                                 DBUS_TYPE_STRING, &name_owner,
-                                 DBUS_TYPE_INVALID);
-        }
-      if (dbus_error_is_set (&dbus_error))
-        {
-          error = g_dbus_error_new_for_dbus_error (&dbus_error, NULL, NULL);
-          dbus_error_free (&dbus_error);
-        }
+      g_assert (watcher->priv->bus_type != G_BUS_TYPE_NONE);
+      watcher->priv->connection = g_dbus_connection_bus_get (watcher->priv->bus_type);
+      /* readjust e.g. G_BUS_TYPE_STARTER */
+      watcher->priv->bus_type = g_dbus_connection_get_bus_type (watcher->priv->connection);
     }
 
-  G_LOCK (watcher_lock);
+  watcher->priv->match_rule = g_strdup_printf ("type='signal',"
+                                               "sender='org.freedesktop.DBus',"
+                                               "member='NameOwnerChanged',"
+                                               "arg0='%s'",
+                                               watcher->priv->name);
 
-  if (error != NULL)
+  g_signal_connect (watcher->priv->connection, "opened", G_CALLBACK (on_connection_opened), watcher);
+  g_signal_connect (watcher->priv->connection, "closed", G_CALLBACK (on_connection_closed), watcher);
+  g_signal_connect (watcher->priv->connection, "initialized", G_CALLBACK (on_connection_initialized), watcher);
+  if (g_dbus_connection_get_is_open (watcher->priv->connection))
     {
-      /* report error back */
-      for (n = 0; n < watcher->priv->init_phase_pending_simple_async_results->len; 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);
-        }
-      g_error_free (error);
+      /* if the connection is already open, then do RequestName right away */
+      on_connection_opened (watcher->priv->connection, watcher);
     }
   else
     {
-      watcher->priv->name_owner = g_strdup (name_owner);
-
-      /* complete operations without error */
-      for (n = 0; n < watcher->priv->init_phase_pending_simple_async_results->len; n++)
+      if (!g_dbus_connection_get_is_initialized (watcher->priv->connection))
         {
-          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);
+          /* if the connection is not initialized, we are not initialized until we know if it could
+           * be opened
+           */
+        }
+      else
+        {
+          /* connection is not open but it is initialized so we are now initialized (no need to emit
+           * signals since no-one has a reference to us)
+           */
+          watcher->priv->is_initialized = 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);
-
-  if (reply != NULL)
-    dbus_message_unref (reply);
+  if (G_OBJECT_CLASS (g_bus_name_watcher_parent_class)->constructed != NULL)
+    G_OBJECT_CLASS (g_bus_name_watcher_parent_class)->constructed (object);
 }
 
-
 /* ---------------------------------------------------------------------------------------------------- */
 
-static void
-do_get_name_owner (GBusNameWatcher *watcher)
-{
-  DBusMessage *message;
-
-  if ((message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
-                                               DBUS_PATH_DBUS,
-                                               DBUS_INTERFACE_DBUS,
-                                               "GetNameOwner")) == NULL)
-    _g_dbus_oom ();
-  if (!dbus_message_append_args (message,
-                                 DBUS_TYPE_STRING, &watcher->priv->name,
-                                 DBUS_TYPE_INVALID))
-    _g_dbus_oom ();
-  g_dbus_connection_send_dbus_1_message_with_reply (watcher->priv->connection,
-                                                    message,
-                                                    -1,
-                                                    NULL,
-                                                    (GAsyncReadyCallback) get_name_owner_cb,
-                                                    watcher);
-  dbus_message_unref (message);
-}
-
-static void
-on_notify_is_opening (GDBusConnection *connection,
-                      GParamSpec      *spec,
-                      gpointer         user_data)
-{
-  GBusNameWatcher *watcher = G_BUS_NAME_WATCHER (user_data);
-
-  /* connection is not opening anymore.. get the name owner */
-  do_get_name_owner (watcher);
-
-  g_signal_handlers_disconnect_by_func (connection, on_notify_is_opening, watcher);
-}
-
-static GBusNameWatcher *
-g_bus_name_watcher_new_internal (GBusType               bus_type,
-                                 GDBusConnection       *given_connection,
-                                 const gchar           *name,
-                                 GCancellable          *cancellable,
-                                 GAsyncReadyCallback    callback,
-                                 gpointer               user_data)
+static GObject *
+g_bus_name_watcher_constructor (GType                  type,
+                              guint                  n_construct_properties,
+                              GObjectConstructParam *construct_properties)
 {
-  GBusNameWatcher *watcher;
+  GObject *object;
   GDBusConnection *connection;
-  GSimpleAsyncResult *simple;
-  gpointer source_tag;
+  const gchar *name;
+  guint n;
 
-  /* 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
-   * for two things
-   *
-   *  - the connection for the bus to come up
-   *  - HasNameOwner() to return
-   *
-   * Now, suppose the user creates two watcher 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 watcher to a list on the first one. Then
-   * when initialization is done, fire all callbacks.
-   */
+  G_LOCK (watcher_lock);
 
-  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);
-    }
+  connection = NULL;
+  name = NULL;
+  object = NULL;
 
-  G_LOCK (watcher_lock);
-  /* check if a suitable watcher already exists */
-  watcher = singletons_get_watcher (connection, name);
-  if (watcher != NULL)
+  for (n = 0; n < n_construct_properties; n++)
     {
-      simple = g_simple_async_result_new (G_OBJECT (watcher),
-                                          callback,
-                                          user_data,
-                                          source_tag);
-
-      if (watcher->priv->in_init_phase)
+      if (g_strcmp0 (construct_properties[n].pspec->name, "bus-type") == 0)
         {
-          /* if still initializing, defer callback until we know what stuff looks like */
-          g_ptr_array_add (watcher->priv->init_phase_pending_simple_async_results, simple);
+          GBusType bus_type;
+          bus_type = g_value_get_enum (construct_properties[n].value);
+          if (bus_type != G_BUS_TYPE_NONE)
+            connection = g_dbus_connection_bus_get (bus_type);
         }
-      else
+      else if (g_strcmp0 (construct_properties[n].pspec->name, "connection") == 0)
         {
-          /* otherwise, return the result right away (e.g. in idle) */
-          g_simple_async_result_complete_in_idle (simple);
-          g_object_unref (simple);
+          GDBusConnection *given_connection;
+          given_connection = g_value_get_object (construct_properties[n].value);
+          if (given_connection != NULL)
+            {
+              if (connection != NULL)
+                g_object_unref (connection);
+              connection = g_object_ref (given_connection);
+            }
+        }
+      else if (g_strcmp0 (construct_properties[n].pspec->name, "name") == 0)
+        {
+          name = g_value_get_string (construct_properties[n].value);
         }
-      g_object_ref (watcher);
-      goto out;
     }
 
-  watcher = G_BUS_NAME_WATCHER (g_object_new (G_TYPE_BUS_NAME_WATCHER,
-                                              "name", name,
-                                              "connection", connection,
-                                              NULL));
-
-  simple = g_simple_async_result_new (G_OBJECT (watcher),
-                                      callback,
-                                      user_data,
-                                      source_tag);
-
-  g_ptr_array_add (watcher->priv->init_phase_pending_simple_async_results, simple);
-
-  singletons_add_watcher (watcher);
+  g_assert (connection != NULL);
+  g_assert (name != NULL);
 
-  if (g_dbus_connection_get_is_opening (connection))
+  object = G_OBJECT (singletons_get_watcher (connection, name));
+  if (object != NULL)
     {
-      /* 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 */
-      do_get_name_owner (watcher);
+      g_object_ref (object);
+      goto out;
     }
 
+  object = G_OBJECT_CLASS (g_bus_name_watcher_parent_class)->constructor (type,
+                                                                        n_construct_properties,
+                                                                        construct_properties);
+
+  singletons_add_watcher (G_BUS_NAME_WATCHER (object), connection, name);
+
  out:
-  G_UNLOCK (watcher_lock);
 
   g_object_unref (connection);
-
-  return watcher;
+  G_UNLOCK (watcher_lock);
+  return object;
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
 
 /**
  * g_bus_name_watcher_new:
- * @bus_type: A #GBusType 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.
- *
- * <note><para>This class is intended for language bindings and object
- *             mappings. If you are implementing an application, it's
- *             easier to use the high-level g_bus_name_watch() function.
- * </para></note>
+ * @bus_type: The type of bus to watch the name on
+ * @name: The name to watch.
  *
- * 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.
+ * Get a new #GBusNameWatcher object for watching @name on the message
+ * bus specified by @bus_type.
  *
- * Once you have the result you can connect to the #GBusNameWatcher::name-appeared
- * and #GBusNameWatcher::name-vanished signals to track changes.
+ * Since watching a name is an asynchronous operation, the returned
+ * object is not guaranteed to return correct information until it has
+ * been initialized.
+ * Use g_bus_name_watcher_get_is_initialized() to check whether the object
+ * is initialized and connect to the #GBusNameWatcher::initialized signal or
+ * listen for notifications on the #GBusNameWatcher:is-initialized property
+ * to get informed when it is.
  *
- * If the connection is closed and then opened again, the
- * #GBusNameWatcher class will attempt to check the if it has an
- * owner.
+ * Note that the returned object may shared with other callers, e.g.
+ * if two separate parts of a process calls this function with the
+ * same @bus_type and @name, they will share the same object. As such,
+ * the object may already have been initialized when it is returned.
  *
- * Note that the returned object may be shared with other callers if
- * @bus_type and @name matches a previously constructed object.
+ * #GBusNameOwner deals gracefully with the underlying connection
+ * closing and opening by checking the owner of the name when the
+ * connection is back up.
  *
  * Returns: A #GBusNameWatcher object. Free with g_object_unref().
  **/
 GBusNameWatcher *
 g_bus_name_watcher_new (GBusType               bus_type,
-                        const gchar           *name,
-                        GCancellable          *cancellable,
-                        GAsyncReadyCallback    callback,
-                        gpointer               user_data)
+                        const gchar           *name)
 {
-  return g_bus_name_watcher_new_internal (bus_type,
-                                          NULL,
-                                          name,
-                                          cancellable,
-                                          callback,
-                                          user_data);
+  return G_BUS_NAME_WATCHER (g_object_new (G_TYPE_BUS_NAME_WATCHER,
+                                           "bus-type", bus_type,
+                                           "name", name,
+                                           NULL));
 }
 
 /**
- * g_bus_name_watcher_new_finish:
- * @watcher: A #GBusNameWatcher.
- * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to g_bus_name_watcher_new().
- * @error: Return location for error or %NULL.
+ * g_bus_name_watcher_new_for_connection:
+ * @connection: A #GDBusConnection.
+ * @name: The name to watch.
  *
- * Finishes attempting to determine the owner of the name being
- * watched.
+ * Like g_bus_name_watcher_new() but allows you to pass in a
+ * #GDBusConnection instead of a #GBusType.
  *
- * Returns: %TRUE if it was possible to check if name has an owner (the name may not have an
- * owner, check with g_bus_name_watcher_get_name_owner()), otherwise %FALSE with @error
- * set.
+ * Returns: A #GBusNameWatcher object. Free with g_object_unref().
  **/
-gboolean
-g_bus_name_watcher_new_finish (GBusNameWatcher       *watcher,
-                               GAsyncResult          *res,
-                               GError               **error)
+GBusNameWatcher *
+g_bus_name_watcher_new_for_connection (GDBusConnection       *connection,
+                                       const gchar           *name)
 {
-  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;
+  return G_BUS_NAME_WATCHER (g_object_new (G_TYPE_BUS_NAME_WATCHER,
+                                           "connection", connection,
+                                           "name", name,
+                                           NULL));
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
 
 /**
- * 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.
+ * g_bus_name_watcher_get_is_initialized:
+ * @watcher: A #GBusNameWatcher.
  *
- * Like g_bus_name_watcher_new() but allows you to supply a
- * #GDBusConnection.
+ * Gets whether @watcher is initialized.
  *
- * Returns: A #GBusNameWatcher object. Free with g_object_unref().
+ * You can track changes to this value by connecting to the
+ * #GBusNameWatcher::initialized signal or by listening to changes on
+ * the #GBusNameWatcher:is-initialized property.
+ *
+ * Returns: %TRUE if @watcher is initialized, %FALSE otherwise.
  **/
-GBusNameWatcher *
-g_bus_name_watcher_new_for_connection (GDBusConnection       *connection,
-                                       const gchar           *name,
-                                       GCancellable          *cancellable,
-                                       GAsyncReadyCallback    callback,
-                                       gpointer               user_data)
+gboolean
+g_bus_name_watcher_get_is_initialized (GBusNameWatcher *watcher)
 {
-  return g_bus_name_watcher_new_internal (G_BUS_TYPE_NONE,
-                                          connection,
-                                          name,
-                                          cancellable,
-                                          callback,
-                                          user_data);
+  g_return_val_if_fail (G_IS_BUS_NAME_WATCHER (watcher), FALSE);
+
+  return watcher->priv->is_initialized;
 }
 
 /**
- * g_bus_name_watcher_new_for_connection_finish:
+ * g_bus_name_watcher_get_name_owner:
  * @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.
+ * Gets the unique name of 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.
+ * You can track changes to this value by listening to the
+ * #GBusNameWatcher::name-appeared and #GBusNameWatcher::name-vanished signals
+ * or by listning to changes on the #GBusNameWatcher:name-owner property.
+ *
+ * Returns: The unique name of the owner of the name being watched or
+ * %NULL if no-one owns the name.
  **/
-gboolean
-g_bus_name_watcher_new_for_connection_finish (GBusNameWatcher       *watcher,
-                                              GAsyncResult          *res,
-                                              GError               **error)
+const gchar *
+g_bus_name_watcher_get_name_owner (GBusNameWatcher *watcher)
 {
-  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;
+  return watcher->priv->name_owner;
 }
 
-/* ---------------------------------------------------------------------------------------------------- */
-
 /**
  * g_bus_name_watcher_get_name:
  * @watcher: A #GBusNameWatcher.
  *
- * Gets the name that @watcher is watching.
+ * Gets the name being watched.
  *
- * Returns: The name that @watcher is watching. Do not free this
- * string, it is owned by @watcher.
+ * Returns: The name being watched. Do not free this string,
+ * it is owned by @watcher.
  **/
 const gchar *
 g_bus_name_watcher_get_name (GBusNameWatcher *watcher)
@@ -949,25 +977,21 @@ g_bus_name_watcher_get_name (GBusNameWatcher *watcher)
 }
 
 /**
- * g_bus_name_watcher_get_name_owner:
+ * g_bus_name_watcher_get_bus_type:
  * @watcher: A #GBusNameWatcher.
  *
- * Gets the unique name of the owner for the name that @watcher is watching, if any.
- *
- * To listen for changes, connect to the #GBusNameWatcher::name-appeared
- * and #GBusNameWatcher::name-vanished signals or listen for notifications
- * on the #GBusNameWatcher:name-owner property.
+ * Gets the type (never #G_BUS_TYPE_STARTER) of the message bus the
+ * watcher object is for or #G_TYPE_BUS_NONE if the watcher object is not
+ * for a known message bus type.
  *
- * Returns: The unique name for the owner of the name that @watcher is
- * watching or %NULL if there is no owner. Do not free this string, it
- * is owned by @watcher.
+ * Returns: A #GBusType.
  **/
-const gchar *
-g_bus_name_watcher_get_name_owner (GBusNameWatcher *watcher)
+GBusType
+g_bus_name_watcher_get_bus_type (GBusNameWatcher *watcher)
 {
-  g_return_val_if_fail (G_IS_BUS_NAME_WATCHER (watcher), NULL);
+  g_return_val_if_fail (G_IS_BUS_NAME_WATCHER (watcher), 0);
 
-  return watcher->priv->name_owner;
+  return watcher->priv->bus_type;
 }
 
 /**
diff --git a/gdbus/gbusnamewatcher.h b/gdbus/gbusnamewatcher.h
index f94d7f8..06ae840 100644
--- a/gdbus/gbusnamewatcher.h
+++ b/gdbus/gbusnamewatcher.h
@@ -59,6 +59,7 @@ struct _GBusNameWatcher
  * GBusNameWatcherClass:
  * @name_appeared: Signal class handler for the #GBusNameWatcher::name-appeared signal.
  * @name_vanished: Signal class handler for the #GBusNameWatcher::name-vanished signal.
+ * @initialized: Signal class handler for the #GBusNameWatcher::initialized signal.
  *
  * Class structure for #GBusNameWatcher.
  */
@@ -72,6 +73,7 @@ struct _GBusNameWatcherClass
   /* Signals */
   void (*name_appeared) (GBusNameWatcher *watcher);
   void (*name_vanished) (GBusNameWatcher *watcher);
+  void (*initialized)   (GBusNameWatcher *watcher);
 
   /*< private >*/
   /* Padding for future expansion */
@@ -87,23 +89,13 @@ struct _GBusNameWatcherClass
 
 GType               g_bus_name_watcher_get_type                  (void) G_GNUC_CONST;
 GBusNameWatcher    *g_bus_name_watcher_new                       (GBusType               bus_type,
-                                                                  const gchar           *name,
-                                                                  GCancellable          *cancellable,
-                                                                  GAsyncReadyCallback    callback,
-                                                                  gpointer               user_data);
-gboolean            g_bus_name_watcher_new_finish                (GBusNameWatcher       *watcher,
-                                                                  GAsyncResult          *res,
-                                                                  GError               **error);
+                                                                  const gchar           *name);
 GBusNameWatcher    *g_bus_name_watcher_new_for_connection        (GDBusConnection       *connection,
-                                                                  const gchar           *name,
-                                                                  GCancellable          *cancellable,
-                                                                  GAsyncReadyCallback    callback,
-                                                                  gpointer               user_data);
-gboolean            g_bus_name_watcher_new_for_connection_finish (GBusNameWatcher       *watcher,
-                                                                  GAsyncResult          *res,
-                                                                  GError               **error);
-const gchar        *g_bus_name_watcher_get_name                  (GBusNameWatcher       *watcher);
+                                                                  const gchar           *name);
 const gchar        *g_bus_name_watcher_get_name_owner            (GBusNameWatcher       *watcher);
+const gchar        *g_bus_name_watcher_get_name                  (GBusNameWatcher       *watcher);
+GBusType            g_bus_name_watcher_get_bus_type              (GBusNameWatcher       *watcher);
+gboolean            g_bus_name_watcher_get_is_initialized        (GBusNameWatcher       *watcher);
 GDBusConnection    *g_bus_name_watcher_get_connection            (GBusNameWatcher       *watcher);
 
 G_END_DECLS
diff --git a/gdbus/gdbus.symbols b/gdbus/gdbus.symbols
index 19c6d3b..9ba1840 100644
--- a/gdbus/gdbus.symbols
+++ b/gdbus/gdbus.symbols
@@ -17,15 +17,14 @@
 #if IN_FILE(__G_DBUS_CONNECTION_C__)
 g_dbus_connection_get_type G_GNUC_CONST
 g_dbus_connection_bus_get
-g_dbus_connection_bus_get_finish
 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_is_private
 g_dbus_connection_get_bus_type
 g_dbus_connection_get_exit_on_close
 g_dbus_connection_set_exit_on_close
+g_dbus_connection_get_is_initialized
 g_dbus_connection_get_dbus_1_connection
 g_dbus_connection_send_dbus_1_message
 g_dbus_connection_send_dbus_1_message_with_reply
@@ -35,17 +34,26 @@ g_dbus_connection_send_dbus_1_message_cancel
 #endif
 #endif
 
+#if IN_HEADER(__G_DBUS_MAINLOOP_H__)
+#if IN_FILE(__G_DBUS_MAINLOOP_C__)
+g_dbus_integrate_dbus_1_connection
+g_dbus_unintegrate_dbus_1_connection
+g_dbus_integrate_dbus_1_server
+g_dbus_unintegrate_dbus_1_server
+#endif
+#endif
+
 #if IN_HEADER(__G_BUS_NAME_OWNER_H__)
 #if IN_FILE(__G_BUS_NAME_OWNER_C__)
 g_bus_name_owner_get_type G_GNUC_CONST
 g_bus_name_owner_new
-g_bus_name_owner_new_finish
 g_bus_name_owner_new_for_connection
-g_bus_name_owner_new_for_connection_finish
-g_bus_name_owner_get_connection
-g_bus_name_owner_get_flags
-g_bus_name_owner_get_name
 g_bus_name_owner_get_owns_name
+g_bus_name_owner_get_name
+g_bus_name_owner_get_bus_type
+g_bus_name_owner_get_flags
+g_bus_name_owner_get_is_initialized
+g_bus_name_owner_get_connection
 #endif
 #endif
 
@@ -53,21 +61,12 @@ g_bus_name_owner_get_owns_name
 #if IN_FILE(__G_BUS_NAME_WATCHER_C__)
 g_bus_name_watcher_get_type G_GNUC_CONST
 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
-#endif
-#endif
-
-#if IN_HEADER(__G_DBUS_MAINLOOP_H__)
-#if IN_FILE(__G_DBUS_MAINLOOP_C__)
-g_dbus_integrate_dbus_1_connection
-g_dbus_unintegrate_dbus_1_connection
-g_dbus_integrate_dbus_1_server
-g_dbus_unintegrate_dbus_1_server
+g_bus_name_watcher_get_name
+g_bus_name_watcher_get_bus_type
+g_bus_name_watcher_get_is_initialized
+g_bus_name_watcher_get_connection
 #endif
 #endif
 
@@ -75,7 +74,7 @@ g_dbus_unintegrate_dbus_1_server
 #if IN_FILE(__G_DBUS_ENUM_TYPES_C__)
 g_dbus_error_get_type G_GNUC_CONST
 g_bus_type_get_type G_GNUC_CONST
-g_bus_name_owner_flags_get_type
+g_bus_name_owner_flags_get_type G_GNUC_CONST
 #endif
 #endif
 
diff --git a/gdbus/gdbusconnection.c b/gdbus/gdbusconnection.c
index c722456..a2ad3c9 100644
--- a/gdbus/gdbusconnection.c
+++ b/gdbus/gdbusconnection.c
@@ -39,6 +39,10 @@
  * @short_description: D-Bus Connections
  * @include: gdbus/gdbus.h
  *
+ * <para><note>
+ * This class is rarely used directly. If you are writing an application, it is often
+ * easier to use the g_bus_own_name() or g_bus_watch_name() APIs.
+ * </note></para>
  * #GDBusConnection is a thin wrapper class for the #DBusConnection
  * type that integrates with the GLib type system. The connection
  * state of the underlying connection is tracked and upon
@@ -50,21 +54,18 @@
 
 struct _GDBusConnectionPrivate
 {
+  /* construct properties */
   DBusConnection *dbus_1_connection;
+  GBusType        bus_type;
+  gboolean        is_private;
 
-  GBusType bus_type;
+  gboolean        is_initialized;
 
   guint reconnect_timer_id;
 
   /* unfortunately there is no dbus_connection_get_exit_on_disconnect() so we need to track this ourselves */
   gboolean exit_on_close;
 
-  gboolean is_private;
-
-  /* these variables are used to store async callbacks for users calling _new()  */
-  gboolean   in_init_phase;
-  GPtrArray *init_phase_pending_simple_async_results;
-
   guint global_pending_call_id;
   GHashTable *pending_call_id_to_simple;
 };
@@ -73,6 +74,7 @@ enum
 {
   OPENED_SIGNAL,
   CLOSED_SIGNAL,
+  INITIALIZED_SIGNAL,
   LAST_SIGNAL,
 };
 
@@ -80,9 +82,10 @@ enum
 {
   PROP_0,
   PROP_BUS_TYPE,
+  PROP_IS_PRIVATE,
   PROP_UNIQUE_NAME,
   PROP_IS_OPEN,
-  PROP_IS_OPENING,
+  PROP_IS_INITIALIZED,
   PROP_EXIT_ON_CLOSE,
   PROP_DBUS_1_CONNECTION,
 };
@@ -91,6 +94,11 @@ G_LOCK_DEFINE_STATIC (connection_lock);
 static GDBusConnection *the_session_bus = NULL;
 static GDBusConnection *the_system_bus = NULL;
 
+static GObject *g_dbus_connection_constructor (GType                  type,
+                                               guint                  n_construct_properties,
+                                               GObjectConstructParam *construct_properties);
+static void g_dbus_connection_constructed (GObject *object);
+
 static DBusHandlerResult
 filter_function (DBusConnection *dbus_1_connection,
                  DBusMessage    *message,
@@ -157,6 +165,10 @@ g_dbus_connection_get_property (GObject    *object,
       g_value_set_enum (value, g_dbus_connection_get_bus_type (connection));
       break;
 
+    case PROP_IS_PRIVATE:
+      g_value_set_boolean (value, g_dbus_connection_get_is_private (connection));
+      break;
+
     case PROP_UNIQUE_NAME:
       g_value_set_string (value, g_dbus_connection_get_unique_name (connection));
       break;
@@ -165,8 +177,8 @@ 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));
+    case PROP_IS_INITIALIZED:
+      g_value_set_boolean (value, g_dbus_connection_get_is_initialized (connection));
       break;
 
     case PROP_EXIT_ON_CLOSE:
@@ -197,6 +209,10 @@ g_dbus_connection_set_property (GObject      *object,
       connection->priv->bus_type = g_value_get_enum (value);
       break;
 
+    case PROP_IS_PRIVATE:
+      connection->priv->is_private = g_value_get_boolean (value);
+      break;
+
     case PROP_EXIT_ON_CLOSE:
       g_dbus_connection_set_exit_on_close (connection, g_value_get_boolean (value));
       break;
@@ -216,6 +232,8 @@ g_dbus_connection_class_init (GDBusConnectionClass *klass)
 
   gobject_class = G_OBJECT_CLASS (klass);
 
+  gobject_class->constructor  = g_dbus_connection_constructor;
+  gobject_class->constructed  = g_dbus_connection_constructed;
   gobject_class->finalize     = g_dbus_connection_finalize;
   gobject_class->dispose      = g_dbus_connection_dispose;
   gobject_class->set_property = g_dbus_connection_set_property;
@@ -242,15 +260,14 @@ g_dbus_connection_class_init (GDBusConnectionClass *klass)
   /**
    * GDBusConnection:bus-type:
    *
-   * Type type of the message bus the connection is for or
-   * #G_BUS_TYPE_NONE if the connection is not to a message
-   * bus.
+   * When constructing an object, set this to the type of the message bus
+   * the connection is for or #G_BUS_TYPE_NONE if the connection is not
+   * a message bus connection.
+   * This property is ignored if #GDBusConnection:dbus-1-connection is set upon construction.
    *
-   * This property is never #G_BUS_TYPE_STARTER. If
-   * #G_BUS_TYPE_STARTER was passed to g_dbus_connection_get()
-   * then this property will be either #G_BUS_TYPE_SESSION or
-   * #G_BUS_TYPE_SYSTEM depending on what bus started the
-   * process.
+   * When reading, this property is never #G_BUS_TYPE_STARTER - if #G_BUS_TYPE_STARTER
+   * was passed as a construction property, then this property will be either #G_BUS_TYPE_SESSION
+   * or #G_BUS_TYPE_SYSTEM depending on what message bus activated the process.
    */
   g_object_class_install_property (gobject_class,
                                    PROP_BUS_TYPE,
@@ -267,10 +284,34 @@ g_dbus_connection_class_init (GDBusConnectionClass *klass)
                                                       G_PARAM_STATIC_NICK));
 
   /**
+   * GDBusConnection:is-private:
+   *
+   * When constructing an object and #GDBusConnection:bus-type is set to something
+   * other than #G_BUS_TYPE_NONE, specifies whether the connection to the requested
+   * message bus should be a private connection.
+   * This property is ignored if #GDBusConnection:dbus-1-connection is set upon construction.
+   *
+   * When reading, specifies if connection to the message bus is
+   * private or shared with others.
+   */
+  g_object_class_install_property (gobject_class,
+                                   PROP_IS_PRIVATE,
+                                   g_param_spec_boolean ("is-private",
+                                                         _("is-private"),
+                                                         _("Whether the connection to the message bus is private"),
+                                                         FALSE,
+                                                         G_PARAM_READABLE |
+                                                         G_PARAM_WRITABLE |
+                                                         G_PARAM_CONSTRUCT_ONLY |
+                                                         G_PARAM_STATIC_NAME |
+                                                         G_PARAM_STATIC_BLURB |
+                                                         G_PARAM_STATIC_NICK));
+
+  /**
    * GDBusConnection:unique-name:
    *
    * The unique name as assigned by the message bus or %NULL if the
-   * connection is closed or not a message bus connection.
+   * connection is not open or not a message bus connection.
    */
   g_object_class_install_property (gobject_class,
                                    PROP_UNIQUE_NAME,
@@ -300,15 +341,16 @@ g_dbus_connection_class_init (GDBusConnectionClass *klass)
                                                          G_PARAM_STATIC_NICK));
 
   /**
-   * GDBusConnection:is-opening:
+   * GDBusConnection:is-initialized:
    *
-   * A boolean specifying whether the connection is currently being opened.
+   * A boolean specifying whether the connection is initialized. You are guaranteed that
+   * this signal fires only once.
    */
   g_object_class_install_property (gobject_class,
-                                   PROP_IS_OPENING,
-                                   g_param_spec_boolean ("is-opening",
-                                                         _("is-opening"),
-                                                         _("Whether the connection is being opened"),
+                                   PROP_IS_INITIALIZED,
+                                   g_param_spec_boolean ("is-initialized",
+                                                         _("is-initialized"),
+                                                         _("Whether the connection is initialized"),
                                                          FALSE,
                                                          G_PARAM_READABLE |
                                                          G_PARAM_STATIC_NAME |
@@ -338,7 +380,7 @@ g_dbus_connection_class_init (GDBusConnectionClass *klass)
    * GDBusConnection::opened:
    * @connection: The #GDBusConnection emitting the signal.
    *
-   * Emitted when the connection is established.
+   * Emitted when the connection has been opened.
    **/
   signals[OPENED_SIGNAL] = g_signal_new ("opened",
                                          G_TYPE_DBUS_CONNECTION,
@@ -354,7 +396,7 @@ g_dbus_connection_class_init (GDBusConnectionClass *klass)
    * GDBusConnection::closed:
    * @connection: The #GDBusConnection emitting the signal.
    *
-   * Emitted when the connection is closed.
+   * Emitted when the connection is no longer open.
    **/
   signals[CLOSED_SIGNAL] = g_signal_new ("closed",
                                          G_TYPE_DBUS_CONNECTION,
@@ -365,14 +407,30 @@ g_dbus_connection_class_init (GDBusConnectionClass *klass)
                                          g_cclosure_marshal_VOID__VOID,
                                          G_TYPE_NONE,
                                          0);
+
+  /**
+   * GDBusConnection::initialized:
+   * @connection: The #GDBusConnection emitting the signal.
+   *
+   * Emitted when the connection is is initialized.
+   **/
+  signals[INITIALIZED_SIGNAL] = g_signal_new ("initialized",
+                                              G_TYPE_DBUS_CONNECTION,
+                                              G_SIGNAL_RUN_LAST,
+                                              G_STRUCT_OFFSET (GDBusConnectionClass, initialized),
+                                              NULL,
+                                              NULL,
+                                              g_cclosure_marshal_VOID__VOID,
+                                              G_TYPE_NONE,
+                                              0);
 }
 
 static void
 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 ();
+
+  connection->priv->is_initialized = FALSE;
 
   connection->priv->global_pending_call_id = 1;
   connection->priv->pending_call_id_to_simple = g_hash_table_new (g_direct_hash, g_direct_equal);
@@ -385,7 +443,7 @@ g_dbus_connection_init (GDBusConnection *connection)
  * Gets the type of message bus connection, if any.
  *
  * This will never return #G_BUS_TYPE_STARTER. If
- * #G_BUS_TYPE_STARTER was passed to g_dbus_connection_get()
+ * #G_BUS_TYPE_STARTER was passed to g_dbus_connection_bus_get()
  * then the return value will be either #G_BUS_TYPE_SESSION or
  * #G_BUS_TYPE_SYSTEM depending on what bus started the
  * process.
@@ -425,19 +483,39 @@ g_dbus_connection_get_is_open (GDBusConnection *connection)
 }
 
 /**
- * g_dbus_connection_get_is_opening:
+ * g_dbus_connection_get_is_initialized:
  * @connection: A #GDBusConnection.
  *
- * Gets whether a connection is currently opening.
+ * Gets whether @connection is initialized.
+ *
+ * To listen for changes connect to the #GDBusConnection::initialized
+ * signal or listen for notifications on the #GDBusConnection:is-initialized
+ * property.
  *
- * Returns: %TRUE if the connection is currently opening, %FALSE otherwise.
+ * Returns: %TRUE if the connection is initialized, %FALSE otherwise.
  **/
 gboolean
-g_dbus_connection_get_is_opening (GDBusConnection *connection)
+g_dbus_connection_get_is_initialized (GDBusConnection *connection)
 {
   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
 
-  return connection->priv->in_init_phase;
+  return connection->priv->is_initialized;
+}
+
+/**
+ * g_dbus_connection_get_is_private:
+ * @connection: A #GDBusConnection.
+ *
+ * Gets whether the connection is private.
+ *
+ * Returns: %TRUE if the connection is private, %FALSE otherwise.
+ **/
+gboolean
+g_dbus_connection_get_is_private (GDBusConnection *connection)
+{
+  g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
+
+  return connection->priv->is_private;
 }
 
 /**
@@ -502,6 +580,13 @@ attempt_connect (GDBusConnection  *connection,
       dbus_error_free (&dbus_error);
     }
 
+  if (!connection->priv->is_initialized)
+    {
+      connection->priv->is_initialized = TRUE;
+      g_signal_emit (connection, signals[INITIALIZED_SIGNAL], 0);
+      g_object_notify (G_OBJECT (connection), "is-initialized");
+    }
+
   return ret;
 }
 
@@ -653,368 +738,176 @@ g_dbus_connection_set_dbus_1_connection (GDBusConnection *connection,
 
 /* ---------------------------------------------------------------------------------------------------- */
 
-
 static gboolean
-open_bus_connection (gpointer user_data)
+attempt_to_connect_in_idle (gpointer user_data)
 {
   GDBusConnection *connection = G_DBUS_CONNECTION (user_data);
-  GError *error;
-  GSimpleAsyncResult *simple;
-  guint n;
-  gboolean did_connect;
-
-  error = NULL;
-  did_connect = attempt_connect (connection, &error);
-
-  G_LOCK (connection_lock);
-  if (!did_connect)
-    {
-      for (n = 0; n < connection->priv->init_phase_pending_simple_async_results->len; n++)
-        {
-          simple = G_SIMPLE_ASYNC_RESULT (connection->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);
-
-      /* set up timer for attempting to reconnect */
-      setup_reconnect_timer (connection);
-    }
-  else
-    {
-      for (n = 0; n < connection->priv->init_phase_pending_simple_async_results->len; n++)
-        {
-          simple = G_SIMPLE_ASYNC_RESULT (connection->priv->init_phase_pending_simple_async_results->pdata[n]);
-          g_simple_async_result_complete_in_idle (simple);
-          g_object_unref (simple);
-        }
-    }
-  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");
+  /* if our initial attempt to connect failed, set up timer for reconnection */
+  if (!attempt_connect (connection, NULL))
+    setup_reconnect_timer (connection);
 
+  g_object_unref (connection);
   return FALSE;
 }
 
-static GDBusConnection *
-g_dbus_connection_bus_get_internal (GBusType                bus_type,
-                                    gboolean                private,
-                                    GCancellable           *cancellable,
-                                    GAsyncReadyCallback     callback,
-                                    gpointer                user_data)
+static void
+g_dbus_connection_constructed (GObject *object)
 {
-  GDBusConnection *connection;
-  GSimpleAsyncResult *simple;
-
-  /* The fact we support singletons makes this complicated... since there's
-   * a window, the initialization phase, where we wait for the connection
-   * to be established.
-   *
-   * For example, suppose that two calls to g_dbus_connection_new() is
-   * made for the same bus when the program starts up. The we return
-   * two identical objects (since we support singletons) but the
-   * GAsyncReadyCallback are distinct. Hence, when returning a reffed
-   * instance of the singleton, we need to add the callback to the
-   * singleton so callbacks are fired at the right time.
-   */
+  GDBusConnection *connection = G_DBUS_CONNECTION (object);
 
-  g_return_val_if_fail (bus_type != G_BUS_TYPE_NONE, NULL);
+  /* attempt to open the connection in idle */
+  g_idle_add (attempt_to_connect_in_idle, g_object_ref (connection));
 
-  connection = NULL;
+  if (G_OBJECT_CLASS (g_dbus_connection_parent_class)->constructed != NULL)
+    G_OBJECT_CLASS (g_dbus_connection_parent_class)->constructed (object);
+}
 
-  /* TODO: use cancellable */
+/* ---------------------------------------------------------------------------------------------------- */
 
-  /* handle starter bus */
-  if (bus_type == G_BUS_TYPE_STARTER)
-    {
-      const gchar *starter_bus;
+static GObject *
+g_dbus_connection_constructor (GType                  type,
+                               guint                  n_construct_properties,
+                               GObjectConstructParam *construct_properties)
+{
+  GDBusConnection **singleton;
+  gboolean is_private;
+  GObject *object;
+  guint n;
 
-      starter_bus = g_getenv ("DBUS_STARTER_BUS_TYPE");
-      if (g_strcmp0 (starter_bus, "session") == 0)
-        {
-          bus_type = G_BUS_TYPE_SESSION;
-        }
-      else if (g_strcmp0 (starter_bus, "system") == 0)
-        {
-          bus_type = G_BUS_TYPE_SYSTEM;
-        }
-      else
-        {
-          g_critical ("Cannot construct a GDBusConnection object with bus_type G_BUS_TYPE_STARTER "
-                      "because the DBUS_STARTER_BUS_TYPE environment variable is not set. "
-                      "This is an error in the application.");
-          goto out;
-        }
-    }
+  object = NULL;
+  singleton = NULL;
+  is_private = FALSE;
 
-  /* singleton handling */
   G_LOCK (connection_lock);
-  if (!private)
+
+  for (n = 0; n < n_construct_properties; n++)
     {
-      if (bus_type == G_BUS_TYPE_SESSION && the_session_bus != NULL)
+      if (g_strcmp0 (construct_properties[n].pspec->name, "bus-type") == 0)
         {
-          connection = g_object_ref (the_session_bus);
-          simple = g_simple_async_result_new (G_OBJECT (connection),
-                                              callback,
-                                              user_data,
-                                              g_dbus_connection_bus_get_finish);
-          if (connection->priv->in_init_phase)
-            {
-              /* if still initializing, defer callback until we know what stuff looks like */
-              g_ptr_array_add (connection->priv->init_phase_pending_simple_async_results, simple);
-            }
-          else
+          GBusType bus_type;
+          const gchar *starter_bus;
+
+          bus_type = g_value_get_enum (construct_properties[n].value);
+          switch (bus_type)
             {
-              /* otherwise, return the result right away (e.g. in idle) */
-              g_simple_async_result_complete_in_idle (simple);
-              g_object_unref (simple);
+            case G_BUS_TYPE_NONE:
+              /* do nothing */
+              break;
+
+            case G_BUS_TYPE_SESSION:
+              singleton = &the_session_bus;
+              break;
+
+            case G_BUS_TYPE_SYSTEM:
+              singleton = &the_system_bus;
+              break;
+
+            case G_BUS_TYPE_STARTER:
+              starter_bus = g_getenv ("DBUS_STARTER_BUS_TYPE");
+              if (g_strcmp0 (starter_bus, "session") == 0)
+                {
+                  g_value_set_enum (construct_properties[n].value, G_BUS_TYPE_SESSION);
+                  singleton = &the_session_bus;
+                }
+              else if (g_strcmp0 (starter_bus, "system") == 0)
+                {
+                  g_value_set_enum (construct_properties[n].value, G_BUS_TYPE_SYSTEM);
+                  singleton = &the_system_bus;
+                }
+              else
+                {
+                  g_critical (_("Cannot construct a GDBusConnection object with bus_type G_BUS_TYPE_STARTER "
+                                "because the DBUS_STARTER_BUS_TYPE environment variable is not set. "
+                                "This is an error in the application or library using GDBus."));
+                  goto out;
+                }
+              break;
+
+            default:
+              g_assert_not_reached ();
+              break;
             }
-          G_UNLOCK (connection_lock);
-          goto out;
         }
-      else if (bus_type == G_BUS_TYPE_SYSTEM && the_system_bus != NULL)
+      else if (g_strcmp0 (construct_properties[n].pspec->name, "is-private") == 0)
         {
-          connection = g_object_ref (the_system_bus);
-          simple = g_simple_async_result_new (G_OBJECT (connection),
-                                              callback,
-                                              user_data,
-                                              g_dbus_connection_bus_get_finish);
-          if (connection->priv->in_init_phase)
-            {
-              /* if still initializing, defer callback until we know what stuff looks like */
-              g_ptr_array_add (connection->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_UNLOCK (connection_lock);
-          goto out;
+          is_private = g_value_get_boolean (construct_properties[n].value);
         }
     }
 
-  connection = G_DBUS_CONNECTION (g_object_new (G_TYPE_DBUS_CONNECTION,
-                                                "bus-type", bus_type,
-                                                NULL));
-  connection->priv->is_private = private;
+  if (is_private)
+    singleton = NULL;
 
-  if (!private)
+  if (singleton != NULL && *singleton != NULL)
     {
-      /* singleton handling, part 2 */
-      if (bus_type == G_BUS_TYPE_SESSION && the_session_bus == NULL)
-        {
-          the_session_bus = connection;
-        }
-      else if (bus_type == G_BUS_TYPE_SYSTEM && the_system_bus == NULL)
-        {
-          the_system_bus = connection;
-        }
-      G_UNLOCK (connection_lock);
+      object = g_object_ref (*singleton);
+      goto out;
     }
 
-  simple = g_simple_async_result_new (G_OBJECT (connection),
-                                      callback,
-                                      user_data,
-                                      private ? g_dbus_connection_bus_get_private_finish : g_dbus_connection_bus_get_finish);
-  g_ptr_array_add (connection->priv->init_phase_pending_simple_async_results, simple);
-  G_UNLOCK (connection_lock);
-
-  g_idle_add (open_bus_connection,
-              connection);
+  object = G_OBJECT_CLASS (g_dbus_connection_parent_class)->constructor (type,
+                                                                         n_construct_properties,
+                                                                         construct_properties);
 
+  if (singleton != NULL)
+    *singleton = G_DBUS_CONNECTION (object);
 
  out:
-  return connection;
+  G_UNLOCK (connection_lock);
+  return object;
 }
 
+/* ---------------------------------------------------------------------------------------------------- */
 
 /**
  * g_dbus_connection_bus_get:
- * @bus_type: The bus type (can't be #G_BUS_TYPE_NONE).
- * @cancellable: A #GCancellable or %NULL.
- * @callback: The callback function to invoke when finished attempting opening a connection.
- * @user_data: User data to pass to @callback.
- *
- * <note><para>This class is rarely used directly; if you are
- *             writing an API, it's often easier to use the
- *             g_bus_name_own() and g_bus_name_watch() APIs.
- * </para></note>
- *
- * Creates a new #GDBusConnection object and then attempts to open a
- * connection to the message bus specified by @bus_type. When the
- * attempt to connect to the message bus is finished, @callback will
- * be invoked (on the main thread) and you can use
- * g_dbus_connection_bus_get_finish() to see if the connection could be
- * opened.
- *
- * Note that the returned object is a singleton - i.e. it is shared
- * among all callers of g_dbus_connection_bus_get() for the same message
- * bus type. As such, the connection may already be open when using
- * g_dbus_connection_bus_get(). In this case @callback will still be
- * invoked and calls to g_dbus_connection_bus_get_finish() will not return
- * error. Another observation is that you cannot rely on the
- * #GDBusConnection::opened signal to fire if the connection is
- * already open. You can however use g_dbus_connection_get_is_open()
- * right after g_dbus_connection_bus_get() and just call the function you
- * would normally use for the #GDBusConnection::opened signal handler.
- *
- * If the message bus that @connection is connected to vanishes, the
- * #GDBusConnection::closed signal is emitted and the connection is
- * closed. When (and if) the message bus reappears the
- * #GDBusConnection::opened signal is emitted and the connection is
- * open.
+ * @bus_type: A #GBusType.
  *
- * Note that connections to message buses are created with the
- * #GDBusConnection:exit-on-close set to %TRUE so if you intend to
- * handle the case where the message bus is vanishing and appearing
- * you need to change this property via
- * e.g. g_dbus_connection_set_exit_on_close().
+ * Gets a connection to the message bus specified by @bus_type.
  *
- * An example of how this function typically is used can be seen in
- * the following example.
- * <example><title>Using g_dbus_connection_bus_get()</title><programlisting>
- * static void
- * on_connection_opened (GDBusConnection *connection,
- *                       gpointer         user_data)
- * {
- *   /<!-- -->* the connection to the bus is now open, do something with connection *<!-- -->/
- * }
+ * Since connecting to a message bus is an asynchronous operation, the returned object is
+ * not guaranteed to return correct information until it has been initialized.
+ * Use g_dbus_connection_get_is_initialized() to check whether the object is initialized
+ * and connect to the #GDBusConnection::initialized signal or listen for notifications
+ * on the #GDBusConnection:is-initialized property to get informed when it is.
  *
- * static void
- * on_connection_closed (GDBusConnection *connection,
- *                       gpointer         user_data)
- * {
- *   /<!-- -->* the connection to the message bus closed, clean up *<!-- -->/
- * }
+ * Note that the returned object may shared with other callers,
+ * e.g. if two separate parts of a process calls this function with
+ * the same @bus_type, they will share the same object. As such, the object
+ * may already have been initialized when it is returned.
  *
- * static void
- * get_bus_cb (GDBusConnection *connection,
- *             GAsyncResult    *result,
- *             gpointer         user_data)
- * {
- *   GError *error;
+ * #GDBusConnection deals gracefully with the underlying connection
+ * being closed. Once the remote process is back up, an attempt to
+ * reconnect will be made.
  *
- *   error = NULL;
- *   if (!g_dbus_connection_bus_get_finish (connection, result, &error))
- *     {
- *       /<!-- -->* failed to connect to the message bus - typically apps
- *        * want to complain on stderr and exit.
- *        *<!-- -->/
- *     }
- * }
- *
- * void
- * some_routine (SomeObject *data)
- * {
- *   data->priv->session_bus = g_dbus_connection_bus_get (G_BUS_TYPE_SESSION,
- *                                                        NULL,
- *                                                        (GAsyncReadyCallback) get_bus_cb,
- *                                                        data);
- *   g_signal_connect (data->priv->session_bus, "opened", G_CALLBACK (on_connection_opened), data);
- *   g_signal_connect (data->priv->session_bus, "closed", G_CALLBACK (on_connection_closed), data);
- *   /<!-- -->* handle the case where the connection is already open *<!-- -->/
- *   if (g_dbus_connection_get_is_open (data->priv->session_bus))
- *     on_connection_opened (data->priv->session_bus, data);
- * }
- * </programlisting></example>
- * If you need a private bus connection, use
- * g_dbus_connection_bus_get_private() instead.
- *
- * Returns: A #GDBusConnection object. Free with g_object_unref().
- */
+ * Returns: A #GDBusConnection. Free with g_object_unref().
+ **/
 GDBusConnection *
-g_dbus_connection_bus_get (GBusType                bus_type,
-                           GCancellable           *cancellable,
-                           GAsyncReadyCallback     callback,
-                           gpointer                user_data)
+g_dbus_connection_bus_get (GBusType bus_type)
 {
-  return g_dbus_connection_bus_get_internal (bus_type,
-                                             FALSE,
-                                             cancellable,
-                                             callback,
-                                             user_data);
+  return G_DBUS_CONNECTION (g_object_new (G_TYPE_DBUS_CONNECTION,
+                                          "bus-type", bus_type,
+                                          NULL));
 }
 
 /**
  * g_dbus_connection_bus_get_private:
- * @bus_type: The bus type (can't be #G_BUS_TYPE_NONE).
- * @cancellable: A #GCancellable or %NULL.
- * @callback: The callback function to invoke when finished attempting opening a connection.
- * @user_data: User data to pass to @callback.
- *
- * Like g_dbus_connection_bus_get() but opens a #GDBusConnection that
- * is not shared with anyone else.
- *
- * Returns: A #GDBusConnection object. Free with g_object_unref().
- */
-GDBusConnection *
-g_dbus_connection_bus_get_private (GBusType                bus_type,
-                                   GCancellable           *cancellable,
-                                   GAsyncReadyCallback     callback,
-                                   gpointer                user_data)
-{
-  return g_dbus_connection_bus_get_internal (bus_type,
-                                             TRUE,
-                                             cancellable,
-                                             callback,
-                                             user_data);
-}
-
-/**
- * g_dbus_connection_bus_get_finish:
- * @connection: A #GDBusConnection.
- * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to g_dbus_connection_bus_get().
- * @error: Return location for error or %NULL.
+ * @bus_type: A #GBusType.
  *
- * Finishes opening a connection to a message bus.
+ * Like g_dbus_connection_bus_get() but gets a connection that is not
+ * shared with other callers.
  *
- * Returns: %TRUE if the @connection is open, otherwise %FALSE with @error set.
+ * Returns: A #GDBusConnection. Free with g_object_unref().
  **/
-gboolean
-g_dbus_connection_bus_get_finish (GDBusConnection *connection,
-                                  GAsyncResult    *res,
-                                  GError         **error)
+GDBusConnection *
+g_dbus_connection_bus_get_private (GBusType bus_type)
 {
-  GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
-  g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
-  g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_dbus_connection_bus_get_finish);
-  if (g_simple_async_result_propagate_error (simple, error))
-    return FALSE;
-  else
-    return g_dbus_connection_get_is_open (connection);
+  return G_DBUS_CONNECTION (g_object_new (G_TYPE_DBUS_CONNECTION,
+                                          "bus-type", bus_type,
+                                          "is-private", TRUE,
+                                          NULL));
 }
 
-/**
- * g_dbus_connection_bus_get_private_finish:
- * @connection: A #GDBusConnection.
- * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to g_dbus_connection_bus_get_private().
- * @error: Return location for error or %NULL.
- *
- * Finishes opening a private connection to a message bus.
- *
- * Returns: %TRUE if the @connection is open, otherwise %FALSE with @error set.
- **/
-gboolean
-g_dbus_connection_bus_get_private_finish (GDBusConnection *connection,
-                                          GAsyncResult    *res,
-                                          GError         **error)
-{
-  GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
-  g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
-  g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_dbus_connection_bus_get_private_finish);
-  if (g_simple_async_result_propagate_error (simple, error))
-    return FALSE;
-  else
-    return g_dbus_connection_get_is_open (connection);
-}
+/* ---------------------------------------------------------------------------------------------------- */
 
 /**
  * g_dbus_connection_get_exit_on_close:
diff --git a/gdbus/gdbusconnection.h b/gdbus/gdbusconnection.h
index 75199cb..33bbc77 100644
--- a/gdbus/gdbusconnection.h
+++ b/gdbus/gdbusconnection.h
@@ -59,6 +59,7 @@ struct _GDBusConnection
  * GDBusConnectionClass:
  * @opened: Signal class handler for the #GDBusConnection::opened signal.
  * @closed: Signal class handler for the #GDBusConnection::closed signal.
+ * @initialized: Signal class handler for the #GDBusConnection::initialized signal.
  *
  * Class structure for #GDBusConnection.
  */
@@ -70,8 +71,9 @@ struct _GDBusConnectionClass
   /*< public >*/
 
   /* Signals */
-  void (*opened) (GDBusConnection *connection);
-  void (*closed) (GDBusConnection *connection);
+  void (*opened)      (GDBusConnection *connection);
+  void (*closed)      (GDBusConnection *connection);
+  void (*initialized) (GDBusConnection *connection);
 
   /*< private >*/
   /* Padding for future expansion */
@@ -86,23 +88,12 @@ struct _GDBusConnectionClass
 };
 
 GType            g_dbus_connection_get_type                   (void) G_GNUC_CONST;
-GDBusConnection *g_dbus_connection_bus_get                    (GBusType               bus_type,
-                                                               GCancellable          *cancellable,
-                                                               GAsyncReadyCallback    callback,
-                                                               gpointer               user_data);
-gboolean         g_dbus_connection_bus_get_finish             (GDBusConnection       *connection,
-                                                               GAsyncResult          *res,
-                                                               GError               **error);
-GDBusConnection *g_dbus_connection_bus_get_private            (GBusType               bus_type,
-                                                               GCancellable          *cancellable,
-                                                               GAsyncReadyCallback    callback,
-                                                               gpointer               user_data);
-gboolean         g_dbus_connection_bus_get_private_finish     (GDBusConnection       *connection,
-                                                               GAsyncResult          *res,
-                                                               GError               **error);
+GDBusConnection *g_dbus_connection_bus_get                    (GBusType            bus_type);
+GDBusConnection *g_dbus_connection_bus_get_private            (GBusType            bus_type);
 GBusType         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);
+gboolean         g_dbus_connection_get_is_initialized         (GDBusConnection    *connection);
+gboolean         g_dbus_connection_get_is_private             (GDBusConnection    *connection);
 const gchar     *g_dbus_connection_get_unique_name            (GDBusConnection    *connection);
 gboolean         g_dbus_connection_get_exit_on_close          (GDBusConnection    *connection);
 void             g_dbus_connection_set_exit_on_close          (GDBusConnection    *connection,
diff --git a/gdbus/gdbusnameowning.c b/gdbus/gdbusnameowning.c
index 51bdfa2..aef8f81 100644
--- a/gdbus/gdbusnameowning.c
+++ b/gdbus/gdbusnameowning.c
@@ -33,6 +33,8 @@
 
 #include "gdbusalias.h"
 
+/* TODO: don't hold lock when doing callbacks */
+
 /**
  * SECTION:gdbusnameowning
  * @title: Owning Bus Names
@@ -48,10 +50,15 @@ G_LOCK_DEFINE_STATIC (lock);
 
 /* ---------------------------------------------------------------------------------------------------- */
 
-typedef struct
+typedef enum
 {
-  volatile gint             ref_count;
+  PREVIOUS_CALL_NONE = 0,
+  PREVIOUS_CALL_ACQUIRED,
+  PREVIOUS_CALL_LOST,
+} PreviousCall;
 
+typedef struct
+{
   guint                     id;
   GBusNameAcquiredCallback  name_acquired_handler;
   GBusNameLostCallback      name_lost_handler;
@@ -61,31 +68,28 @@ typedef struct
   gulong                    name_acquired_signal_handler_id;
   gulong                    name_lost_signal_handler_id;
 
-  gboolean                  cancelled;
+  PreviousCall              previous_call;
+
+  gulong                    is_initialized_notify_id;
+  guint                     idle_id;
 } Client;
 
 static guint next_global_id = 1;
 static GHashTable *map_id_to_client = NULL;
 
-static Client *
-client_ref (Client *client)
-{
-  g_atomic_int_inc (&client->ref_count);
-  return client;
-}
-
 static void
-client_unref (Client *client)
+client_free (Client *client)
 {
-  if (g_atomic_int_dec_and_test (&client->ref_count))
-    {
-      if (client->name_acquired_signal_handler_id > 0)
-        g_signal_handler_disconnect (client->owner, client->name_acquired_signal_handler_id);
-      if (client->name_lost_signal_handler_id > 0)
-        g_signal_handler_disconnect (client->owner, client->name_lost_signal_handler_id);
-      g_object_unref (client->owner);
-      g_free (client);
-    }
+  if (client->name_acquired_signal_handler_id > 0)
+    g_signal_handler_disconnect (client->owner, client->name_acquired_signal_handler_id);
+  if (client->name_lost_signal_handler_id > 0)
+    g_signal_handler_disconnect (client->owner, client->name_lost_signal_handler_id);
+  if (client->is_initialized_notify_id > 0)
+    g_signal_handler_disconnect (client->owner, client->is_initialized_notify_id);
+  if (client->idle_id > 0)
+    g_source_remove (client->idle_id);
+  g_object_unref (client->owner);
+  g_free (client);
 }
 
 static void
@@ -93,6 +97,8 @@ on_name_acquired (GBusNameOwner *owner,
                   gpointer         user_data)
 {
   Client *client = user_data;
+  g_warn_if_fail (client->previous_call == PREVIOUS_CALL_NONE || client->previous_call == PREVIOUS_CALL_LOST);
+  client->previous_call = PREVIOUS_CALL_ACQUIRED;
   if (client->name_acquired_handler != NULL)
     {
       client->name_acquired_handler (g_bus_name_owner_get_connection (client->owner),
@@ -106,6 +112,8 @@ on_name_lost (GBusNameOwner *owner,
                   gpointer         user_data)
 {
   Client *client = user_data;
+  g_warn_if_fail (client->previous_call == PREVIOUS_CALL_NONE || client->previous_call == PREVIOUS_CALL_ACQUIRED);
+  client->previous_call = PREVIOUS_CALL_LOST;
   if (client->name_lost_handler != NULL)
     {
       client->name_lost_handler (g_bus_name_owner_get_connection (client->owner),
@@ -114,17 +122,11 @@ on_name_lost (GBusNameOwner *owner,
     }
 }
 
+/* must only be called with lock held */
 static void
-owner_async_ready_cb (GBusNameOwner *owner,
-                        GAsyncResult    *res,
-                        gpointer         user_data)
+client_is_determinate (Client *client)
 {
-  Client *client = user_data;
-
-  G_LOCK (lock);
-  if (client->cancelled)
-    goto out;
-  G_UNLOCK (lock);
+  gboolean owns_name;
 
   /* connect signals */
   client->name_acquired_signal_handler_id = g_signal_connect (client->owner,
@@ -136,9 +138,12 @@ owner_async_ready_cb (GBusNameOwner *owner,
                                                               G_CALLBACK (on_name_lost),
                                                               client);
 
-  /* and then report the name */
-  if (g_bus_name_owner_get_owns_name (client->owner))
+  /* and then report if the name is owned */
+  owns_name = g_bus_name_owner_get_owns_name (client->owner);
+  if (owns_name)
     {
+      g_warn_if_fail (client->previous_call == PREVIOUS_CALL_NONE);
+      client->previous_call = PREVIOUS_CALL_ACQUIRED;
       if (client->name_acquired_handler != NULL)
         {
           client->name_acquired_handler (g_bus_name_owner_get_connection (client->owner),
@@ -148,6 +153,8 @@ owner_async_ready_cb (GBusNameOwner *owner,
     }
   else
     {
+      g_warn_if_fail (client->previous_call == PREVIOUS_CALL_NONE);
+      client->previous_call = PREVIOUS_CALL_LOST;
       if (client->name_lost_handler != NULL)
         {
           client->name_lost_handler (g_bus_name_owner_get_connection (client->owner),
@@ -155,10 +162,31 @@ owner_async_ready_cb (GBusNameOwner *owner,
                                          client->user_data);
         }
     }
+}
 
+static void
+on_is_initialized_notify_cb (GBusNameOwner *owner,
+                             GParamSpec      *pspec,
+                             gpointer         user_data)
+{
+  Client *client = user_data;
+  G_LOCK (lock);
+  /* disconnect from signal */
+  g_signal_handler_disconnect (client->owner, client->is_initialized_notify_id);
+  client->is_initialized_notify_id = 0;
+  client_is_determinate (client);
+  G_UNLOCK (lock);
+}
 
- out:
-  client_unref (client);
+static gboolean
+do_callback_in_idle (gpointer user_data)
+{
+  Client *client = user_data;
+  G_LOCK (lock);
+  client->idle_id = 0;
+  client_is_determinate (client);
+  G_UNLOCK (lock);
+  return FALSE;
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -177,9 +205,9 @@ owner_async_ready_cb (GBusNameOwner *owner,
  * acquired respectively lost.
  *
  * You are guaranteed that one of the handlers will be invoked (on the
- * main thread) after calling this function. When you are done
- * owning the name, just call g_bus_unown() with the owner id
- * this function returns.
+ * main thread) after calling this function. When you are done owning
+ * the name, just call g_bus_unown_name() with the owner id this
+ * function returns.
  *
  * If the name is acquired or lost (for example another application
  * could acquire the name if you allow replacement), the handlers are
@@ -223,24 +251,32 @@ g_bus_own_name (GBusType                  bus_type,
   G_LOCK (lock);
 
   client = g_new0 (Client, 1);
-  client->ref_count = 1;
   client->id = next_global_id++; /* TODO: uh oh, handle overflow */
   client->name_acquired_handler = name_acquired_handler;
   client->name_lost_handler = name_lost_handler;
   client->user_data = user_data;
-  client->owner = g_bus_name_owner_new (bus_type,
-                                        name,
-                                        flags,
-                                        NULL,
-                                        (GAsyncReadyCallback) owner_async_ready_cb,
-                                        client_ref (client));
+  client->owner = g_bus_name_owner_new (bus_type, name, flags);
+  if (!g_bus_name_owner_get_is_initialized (client->owner))
+    {
+      /* wait for :is_initialized to change before reporting anything */
+      client->is_initialized_notify_id = g_signal_connect (client->owner,
+                                                           "notify::is-initialized",
+                                                           G_CALLBACK (on_is_initialized_notify_cb),
+                                                           client);
+    }
+  else
+    {
+      /* is initialized, do callback in idle */
+      client->idle_id = g_idle_add ((GSourceFunc) do_callback_in_idle,
+                                    client);
+    }
 
   if (map_id_to_client == NULL)
     {
       map_id_to_client = g_hash_table_new_full (g_direct_hash,
                                                 g_direct_equal,
                                                 NULL,
-                                                (GDestroyNotify) client_unref);
+                                                (GDestroyNotify) client_free);
     }
   g_hash_table_insert (map_id_to_client,
                        GUINT_TO_POINTER (client->id),
@@ -257,9 +293,9 @@ g_bus_own_name (GBusType                  bus_type,
  *
  * Stops owning a name.
  *
- * Note that no handlers are invoked when this happens so remember to
- * unregister exported objects and clean up state related to owning
- * the name.
+ * If currently owning the name (e.g. @name_acquired_handler was the
+ * last handler to be invoked), then @name_lost_handler will be invoked
+ * before this function returns.
  **/
 void
 g_bus_unown_name (guint owner_id)
@@ -276,7 +312,13 @@ g_bus_unown_name (guint owner_id)
       goto out;
     }
 
-  client->cancelled = TRUE;
+  if (client->previous_call == PREVIOUS_CALL_ACQUIRED)
+    {
+      if (client->name_lost_handler != NULL)
+        client->name_lost_handler (g_bus_name_owner_get_connection (client->owner),
+                                   g_bus_name_owner_get_name (client->owner),
+                                   client->user_data);
+    }
 
   g_warn_if_fail (g_hash_table_remove (map_id_to_client, GUINT_TO_POINTER (owner_id)) == 1);
 
diff --git a/gdbus/gdbusnamewatching.c b/gdbus/gdbusnamewatching.c
index b3b202d..a9c8733 100644
--- a/gdbus/gdbusnamewatching.c
+++ b/gdbus/gdbusnamewatching.c
@@ -33,6 +33,8 @@
 
 #include "gdbusalias.h"
 
+/* TODO: don't hold lock when doing callbacks */
+
 /**
  * SECTION:gdbusnamewatching
  * @title: Watching Bus Names
@@ -48,10 +50,15 @@ G_LOCK_DEFINE_STATIC (lock);
 
 /* ---------------------------------------------------------------------------------------------------- */
 
-typedef struct
+typedef enum
 {
-  volatile gint             ref_count;
+  PREVIOUS_CALL_NONE = 0,
+  PREVIOUS_CALL_APPEARED,
+  PREVIOUS_CALL_VANISHED,
+} PreviousCall;
 
+typedef struct
+{
   guint                     id;
   GBusNameAppearedCallback  name_appeared_handler;
   GBusNameVanishedCallback  name_vanished_handler;
@@ -61,31 +68,28 @@ typedef struct
   gulong                    name_appeared_signal_handler_id;
   gulong                    name_vanished_signal_handler_id;
 
-  gboolean                  cancelled;
+  PreviousCall              previous_call;
+
+  gulong                    is_initialized_notify_id;
+  guint                     idle_id;
 } Client;
 
 static guint next_global_id = 1;
 static GHashTable *map_id_to_client = NULL;
 
-static Client *
-client_ref (Client *client)
-{
-  g_atomic_int_inc (&client->ref_count);
-  return client;
-}
-
 static void
-client_unref (Client *client)
+client_free (Client *client)
 {
-  if (g_atomic_int_dec_and_test (&client->ref_count))
-    {
-      if (client->name_appeared_signal_handler_id > 0)
-        g_signal_handler_disconnect (client->watcher, client->name_appeared_signal_handler_id);
-      if (client->name_vanished_signal_handler_id > 0)
-        g_signal_handler_disconnect (client->watcher, client->name_vanished_signal_handler_id);
-      g_object_unref (client->watcher);
-      g_free (client);
-    }
+  if (client->name_appeared_signal_handler_id > 0)
+    g_signal_handler_disconnect (client->watcher, client->name_appeared_signal_handler_id);
+  if (client->name_vanished_signal_handler_id > 0)
+    g_signal_handler_disconnect (client->watcher, client->name_vanished_signal_handler_id);
+  if (client->is_initialized_notify_id > 0)
+    g_signal_handler_disconnect (client->watcher, client->is_initialized_notify_id);
+  if (client->idle_id > 0)
+    g_source_remove (client->idle_id);
+  g_object_unref (client->watcher);
+  g_free (client);
 }
 
 static void
@@ -93,6 +97,8 @@ on_name_appeared (GBusNameWatcher *watcher,
                   gpointer         user_data)
 {
   Client *client = user_data;
+  g_warn_if_fail (client->previous_call == PREVIOUS_CALL_NONE || client->previous_call == PREVIOUS_CALL_VANISHED);
+  client->previous_call = PREVIOUS_CALL_APPEARED;
   if (client->name_appeared_handler != NULL)
     {
       client->name_appeared_handler (g_bus_name_watcher_get_connection (client->watcher),
@@ -107,6 +113,8 @@ on_name_vanished (GBusNameWatcher *watcher,
                   gpointer         user_data)
 {
   Client *client = user_data;
+  g_warn_if_fail (client->previous_call == PREVIOUS_CALL_NONE || client->previous_call == PREVIOUS_CALL_APPEARED);
+  client->previous_call = PREVIOUS_CALL_VANISHED;
   if (client->name_vanished_handler != NULL)
     {
       client->name_vanished_handler (g_bus_name_watcher_get_connection (client->watcher),
@@ -115,19 +123,12 @@ on_name_vanished (GBusNameWatcher *watcher,
     }
 }
 
+/* must only be called with lock held */
 static void
-watcher_async_ready_cb (GBusNameWatcher *watcher,
-                        GAsyncResult    *res,
-                        gpointer         user_data)
+client_is_determinate (Client *client)
 {
-  Client *client = user_data;
   const gchar *name_owner;
 
-  G_LOCK (lock);
-  if (client->cancelled)
-    goto out;
-  G_UNLOCK (lock);
-
   /* connect signals */
   client->name_appeared_signal_handler_id = g_signal_connect (client->watcher,
                                                               "name-appeared",
@@ -139,9 +140,11 @@ watcher_async_ready_cb (GBusNameWatcher *watcher,
                                                               client);
 
   /* and then report the name */
-  name_owner = g_bus_name_watcher_get_name_owner (watcher);
+  name_owner = g_bus_name_watcher_get_name_owner (client->watcher);
   if (name_owner != NULL)
     {
+      g_warn_if_fail (client->previous_call == PREVIOUS_CALL_NONE);
+      client->previous_call = PREVIOUS_CALL_APPEARED;
       if (client->name_appeared_handler != NULL)
         {
           client->name_appeared_handler (g_bus_name_watcher_get_connection (client->watcher),
@@ -152,6 +155,8 @@ watcher_async_ready_cb (GBusNameWatcher *watcher,
     }
   else
     {
+      g_warn_if_fail (client->previous_call == PREVIOUS_CALL_NONE);
+      client->previous_call = PREVIOUS_CALL_VANISHED;
       if (client->name_vanished_handler != NULL)
         {
           client->name_vanished_handler (g_bus_name_watcher_get_connection (client->watcher),
@@ -159,10 +164,31 @@ watcher_async_ready_cb (GBusNameWatcher *watcher,
                                          client->user_data);
         }
     }
+}
 
+static void
+on_is_initialized_notify_cb (GBusNameWatcher *watcher,
+                             GParamSpec      *pspec,
+                             gpointer         user_data)
+{
+  Client *client = user_data;
+  G_LOCK (lock);
+  /* disconnect from signal */
+  g_signal_handler_disconnect (client->watcher, client->is_initialized_notify_id);
+  client->is_initialized_notify_id = 0;
+  client_is_determinate (client);
+  G_UNLOCK (lock);
+}
 
- out:
-  client_unref (client);
+static gboolean
+do_callback_in_idle (gpointer user_data)
+{
+  Client *client = user_data;
+  G_LOCK (lock);
+  client->idle_id = 0;
+  client_is_determinate (client);
+  G_UNLOCK (lock);
+  return FALSE;
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -181,8 +207,8 @@ watcher_async_ready_cb (GBusNameWatcher *watcher,
  *
  * You are guaranteed that one of the handlers will be invoked (on the
  * main thread) after calling this function. When you are done
- * watching the name, just call g_bus_unwatch() with the watcher id
- * this function returns.
+ * watching the name, just call g_bus_unwatch_name() with the watcher
+ * id this function returns.
  *
  * If the name vanishes or appears (for example the application owning
  * the name could restart), the handlers are also invoked. If the
@@ -224,23 +250,32 @@ g_bus_watch_name (GBusType                  bus_type,
   G_LOCK (lock);
 
   client = g_new0 (Client, 1);
-  client->ref_count = 1;
   client->id = next_global_id++; /* TODO: uh oh, handle overflow */
   client->name_appeared_handler = name_appeared_handler;
   client->name_vanished_handler = name_vanished_handler;
   client->user_data = user_data;
-  client->watcher = g_bus_name_watcher_new (bus_type,
-                                            name,
-                                            NULL,
-                                            (GAsyncReadyCallback) watcher_async_ready_cb,
-                                            client_ref (client));
+  client->watcher = g_bus_name_watcher_new (bus_type, name);
+  if (!g_bus_name_watcher_get_is_initialized (client->watcher))
+    {
+      /* wait for :is_initialized to change before reporting anything */
+      client->is_initialized_notify_id = g_signal_connect (client->watcher,
+                                                           "notify::is-initialized",
+                                                           G_CALLBACK (on_is_initialized_notify_cb),
+                                                           client);
+    }
+  else
+    {
+      /* is already initialized, do callback in idle */
+      client->idle_id = g_idle_add ((GSourceFunc) do_callback_in_idle,
+                                    client);
+    }
 
   if (map_id_to_client == NULL)
     {
       map_id_to_client = g_hash_table_new_full (g_direct_hash,
                                                 g_direct_equal,
                                                 NULL,
-                                                (GDestroyNotify) client_unref);
+                                                (GDestroyNotify) client_free);
     }
   g_hash_table_insert (map_id_to_client,
                        GUINT_TO_POINTER (client->id),
@@ -257,9 +292,9 @@ g_bus_watch_name (GBusType                  bus_type,
  *
  * Stops watching a name.
  *
- * Note that no handlers are invoked when this happens so remember to
- * destroy client side proxies and clean up state related to watching
- * the name.
+ * If the name being watched currently has an owner the name (e.g. @name_appeared_handler
+ * was the last handler to be invoked), then @name_vanished_handler will be invoked
+ * before this function returns.
  **/
 void
 g_bus_unwatch_name (guint watcher_id)
@@ -276,7 +311,13 @@ g_bus_unwatch_name (guint watcher_id)
       goto out;
     }
 
-  client->cancelled = TRUE;
+  if (client->previous_call == PREVIOUS_CALL_APPEARED)
+    {
+      if (client->name_vanished_handler != NULL)
+        client->name_vanished_handler (g_bus_name_watcher_get_connection (client->watcher),
+                                       g_bus_name_watcher_get_name (client->watcher),
+                                       client->user_data);
+    }
 
   g_warn_if_fail (g_hash_table_remove (map_id_to_client, GUINT_TO_POINTER (watcher_id)) == 1);
 
diff --git a/gdbus/tests/Makefile.am b/gdbus/tests/Makefile.am
index e17a07e..e9c1a3c 100644
--- a/gdbus/tests/Makefile.am
+++ b/gdbus/tests/Makefile.am
@@ -22,17 +22,15 @@ progs_ldadd     =                                       \
         $(top_builddir)/gdbus/libgdbus-2.0.la		\
 	$(NULL)
 
-TEST_PROGS +=				\
-        connection			\
-	names				\
-	proxy				\
-	$(NULL)
+TEST_PROGS += connection
+TEST_PROGS += names
+TEST_PROGS += proxy
 
-connection_SOURCES = connection.c sessionbus.c sessionbus.h tests.h
+connection_SOURCES = connection.c sessionbus.c sessionbus.h tests.h tests.c
 connection_LDADD = $(progs_ldadd)
 
-names_SOURCES = names.c sessionbus.c sessionbus.h tests.h
+names_SOURCES = names.c sessionbus.c sessionbus.h tests.h tests.c
 names_LDADD = $(progs_ldadd)
 
-proxy_SOURCES = proxy.c sessionbus.c sessionbus.h tests.h
+proxy_SOURCES = proxy.c sessionbus.c sessionbus.h tests.h tests.c
 proxy_LDADD = $(progs_ldadd)
diff --git a/gdbus/tests/connection.c b/gdbus/tests/connection.c
index 3997adc..087813d 100644
--- a/gdbus/tests/connection.c
+++ b/gdbus/tests/connection.c
@@ -29,265 +29,165 @@
 static GMainLoop *loop = NULL;
 
 /* ---------------------------------------------------------------------------------------------------- */
-/* Message Bus tests - check all aspects of connecting and reconnecting to bus instances                */
+/* Connection life-cycle testing */
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
-on_opened_no_bus_exists (GDBusConnection *connection,
-                         gpointer         user_data)
-{
-  g_assert_not_reached ();
-}
-
-static void
-on_closed_no_bus_exists (GDBusConnection *connection,
-                         gpointer         user_data)
-{
-  g_assert_not_reached ();
-}
-
-static void
-get_connection_callback_no_bus_exists (GDBusConnection *connection,
-                                       GAsyncResult    *result,
-                                       gpointer         user_data)
-{
-  GError *error;
-  gboolean ret;
-
-  error = NULL;
-  ret = g_dbus_connection_bus_get_finish (connection,
-                                          result,
-                                          &error);
-  _g_assert_error_domain (error, G_DBUS_ERROR);
-  g_error_free (error);
-  g_assert (!ret);
-  g_main_loop_quit (loop);
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static void
-on_opened_bus_exists (GDBusConnection *connection,
-                      gpointer         user_data)
-{
-  gboolean *val = user_data;
-  *val = TRUE;
-}
-
-static void
-on_opened_bus_exists_reconnect (GDBusConnection *connection,
-                                gpointer         user_data)
-{
-  gboolean *val = user_data;
-  *val = TRUE;
-  g_main_loop_quit (loop);
-}
-
-static void
-on_closed_bus_exists (GDBusConnection *connection,
-                      gpointer         user_data)
-{
-  gboolean *val = user_data;
-  *val = FALSE;
-
-  g_main_loop_quit (loop);
-}
-
-static void
-get_connection_callback_bus_exists (GDBusConnection *connection,
-                                    GAsyncResult    *result,
-                                    gpointer         user_data)
-{
-  GError *error;
-  gboolean ret;
-  gboolean *val = user_data;
-
-  /* check we get the ::opened signal before the callback */
-  g_assert (*val);
-
-  error = NULL;
-  ret = g_dbus_connection_bus_get_finish (connection,
-                                          result,
-                                          &error);
-  g_assert_no_error (error);
-  g_assert (ret);
-  g_main_loop_quit (loop);
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static void
-get_connection_callback_singleton (GDBusConnection *connection,
-                                   GAsyncResult    *result,
-                                   gpointer         user_data)
-{
-  GError *error;
-  gboolean ret;
-
-  error = NULL;
-  ret = g_dbus_connection_bus_get_finish (connection,
-                                          result,
-                                          &error);
-  g_assert_no_error (error);
-  g_assert (ret);
-  g_main_loop_quit (loop);
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static void
-get_connection_callback_private (GDBusConnection *connection,
-                                 GAsyncResult    *result,
-                                 gpointer         user_data)
-{
-  GError *error;
-  gboolean ret;
-
-  error = NULL;
-  ret = g_dbus_connection_bus_get_private_finish (connection,
-                                                  result,
-                                                  &error);
-  g_assert_no_error (error);
-  g_assert (ret);
-  g_main_loop_quit (loop);
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static void
-get_connection_callback_no_bus_exists_singleton (GDBusConnection *connection,
-                                                 GAsyncResult    *result,
-                                                 gpointer         user_data)
-{
-  guint *counter = user_data;
-  GError *error;
-  gboolean ret;
-
-  error = NULL;
-  ret = g_dbus_connection_bus_get_finish (connection,
-                                          result,
-                                          &error);
-  _g_assert_error_domain (error, G_DBUS_ERROR);
-  g_error_free (error);
-  g_assert (!ret);
-
-  *counter += 1;
-
-  if (*counter == 2)
-    g_main_loop_quit (loop);
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static void
-test_message_bus_connections (void)
+test_connection_life_cycle (void)
 {
   GDBusConnection *c;
   GDBusConnection *c2;
-  gboolean val;
-  guint counter;
-
-  /* Check for correct behavior when no bus is present */
-  c = g_dbus_connection_bus_get (G_BUS_TYPE_SESSION,
-                                 NULL,
-                                 (GAsyncReadyCallback) get_connection_callback_no_bus_exists,
-                                 NULL);
-  g_signal_connect (c, "opened", G_CALLBACK (on_opened_no_bus_exists), NULL);
-  g_signal_connect (c, "closed", G_CALLBACK (on_closed_no_bus_exists), NULL);
+
+  /**
+   * Check for correct behavior when no bus is present
+   *
+   */
+  c = g_dbus_connection_bus_get (G_BUS_TYPE_SESSION);
+  g_dbus_connection_set_exit_on_close (c, FALSE);
   g_assert (!g_dbus_connection_get_is_open (c));
-  g_main_loop_run (loop);
+  g_assert (!g_dbus_connection_get_is_initialized (c));
+  _g_assert_property_notify (c, "is-initialized");
   g_assert (!g_dbus_connection_get_is_open (c));
+  g_assert ( g_dbus_connection_get_is_initialized (c));
   g_object_unref (c);
 
-  /* Check for correct behavior if a bus is present and that we get the ::opened signal
+  /**
+   *  Check for correct behavior when a bus is present
    *
-   * Then check that get the ::closed signal when tearing down the bus.
+   *  1. Check #GObject::notify::is-initialized is emitted
+   *  2. Check #GObject::notify::is-open is emitted
+   *  3. Check #GDBusConnection::opened is emitted
    */
   session_bus_up ();
-  val = FALSE;
-  c = g_dbus_connection_bus_get (G_BUS_TYPE_SESSION,
-                                 NULL,                            /* cancellable */
-                                 (GAsyncReadyCallback) get_connection_callback_bus_exists,
-                                 &val);                           /* user_data */
-  g_signal_connect (c, "opened", G_CALLBACK (on_opened_bus_exists), &val);
-  g_signal_connect (c, "closed", G_CALLBACK (on_closed_bus_exists), &val);
+  /* case 1 */
+  c = g_dbus_connection_bus_get (G_BUS_TYPE_SESSION);
+  g_dbus_connection_set_exit_on_close (c, FALSE);
   g_assert (!g_dbus_connection_get_is_open (c));
-  g_main_loop_run (loop);
-  g_assert (g_dbus_connection_get_is_open (c));
-  g_assert (val);
+  g_assert (!g_dbus_connection_get_is_initialized (c));
+  _g_assert_property_notify (c, "is-initialized");
+  g_assert ( g_dbus_connection_get_is_open (c));
+  g_assert ( g_dbus_connection_get_is_initialized (c));
+  g_object_unref (c);
+  /* case 2 */
+  c = g_dbus_connection_bus_get (G_BUS_TYPE_SESSION);
+  g_dbus_connection_set_exit_on_close (c, FALSE);
+  g_assert (!g_dbus_connection_get_is_open (c));
+  g_assert (!g_dbus_connection_get_is_initialized (c));
+  _g_assert_property_notify (c, "is-open");
+  g_assert ( g_dbus_connection_get_is_open (c));
+  g_assert ( g_dbus_connection_get_is_initialized (c));
+  g_object_unref (c);
+  /* case 3 */
+  c = g_dbus_connection_bus_get (G_BUS_TYPE_SESSION);
   g_dbus_connection_set_exit_on_close (c, FALSE);
-  session_bus_down ();
-  g_main_loop_run (loop);
   g_assert (!g_dbus_connection_get_is_open (c));
-  g_assert (!val);
+  g_assert (!g_dbus_connection_get_is_initialized (c));
+  _g_assert_signal_received (c, "opened");
+  g_assert ( g_dbus_connection_get_is_open (c));
+  g_assert ( g_dbus_connection_get_is_initialized (c));
+  g_object_unref (c);
+
+  session_bus_down ();
 
-  /* Now check that we get the ::opened signal on the existing connection object when
-   * bringing up the bus.. this checks that the reconnect logic in GDBusConnection works.
+  /**
+   *  Check for correct behavior when the bus goes away
    *
-   * We replace the ::opened signal handler since we want to break out of the mainloop.
+   *  1. Check #GObject::notify::is-open is emitted
+   *  2. Check #GDBusConnection::closed is emitted
    */
-  g_signal_handlers_disconnect_by_func (c, on_opened_bus_exists, &val);
-  g_signal_connect (c, "opened", G_CALLBACK (on_opened_bus_exists_reconnect), &val);
+  /* case 1 */
   session_bus_up ();
-  g_main_loop_run (loop);
-  g_assert (g_dbus_connection_get_is_open (c));
+  c = g_dbus_connection_bus_get (G_BUS_TYPE_SESSION);
   g_dbus_connection_set_exit_on_close (c, FALSE);
-  g_assert (val);
-
-  /* Check that singleton handling works, e.g. we get the same object for the same bus type */
-  c2 = g_dbus_connection_bus_get (G_BUS_TYPE_SESSION,
-                                  NULL,                            /* cancellable */
-                                  (GAsyncReadyCallback) get_connection_callback_singleton,
-                                  NULL);                           /* user_data */
-  g_assert (c == c2);
-  g_main_loop_run (loop);
-  g_object_unref (c2);
-
-  /* Check that we get a distinct connection, with a distinct unique name, for private connections */
-  c2 = g_dbus_connection_bus_get_private (G_BUS_TYPE_SESSION,
-                                          NULL,                            /* cancellable */
-                                          (GAsyncReadyCallback) get_connection_callback_private,
-                                          NULL);                           /* user_data */
-  g_assert (c != c2);
-  g_main_loop_run (loop);
-  g_assert_cmpstr (g_dbus_connection_get_unique_name (c),
-                   !=,
-                   g_dbus_connection_get_unique_name (c2));
-  g_object_unref (c2);
+  g_assert (!g_dbus_connection_get_is_open (c));
+  g_assert (!g_dbus_connection_get_is_initialized (c));
+  _g_assert_property_notify (c, "is-initialized");
+  g_assert ( g_dbus_connection_get_is_open (c));
+  g_assert ( g_dbus_connection_get_is_initialized (c));
+  session_bus_down ();
+  _g_assert_property_notify (c, "is-open");
+  g_assert (!g_dbus_connection_get_is_open (c));
+  g_object_unref (c);
+  /* case 2 */
+  session_bus_up ();
+  c = g_dbus_connection_bus_get (G_BUS_TYPE_SESSION);
+  g_dbus_connection_set_exit_on_close (c, FALSE);
+  g_assert (!g_dbus_connection_get_is_open (c));
+  g_assert (!g_dbus_connection_get_is_initialized (c));
+  _g_assert_property_notify (c, "is-initialized");
+  g_assert ( g_dbus_connection_get_is_open (c));
+  g_assert ( g_dbus_connection_get_is_initialized (c));
+  session_bus_down ();
+  _g_assert_signal_received (c, "closed");
+  g_assert (!g_dbus_connection_get_is_open (c));
+  g_object_unref (c);
 
-  /* Try to bring the bus down and check we get the ::closed signal.
+  /**
+   * Check that reconnection logic works
    *
-   * The existing signal handler does the right thing here.
+   *  1. Check #GObject::notify::is-open is emitted
+   *  2. Check #GDBusConnection::closed and #GDBusConnection::opened signals are emitted
    */
+  /* case 1 */
+  session_bus_up ();
+  c = g_dbus_connection_bus_get (G_BUS_TYPE_SESSION);
+  g_dbus_connection_set_exit_on_close (c, FALSE);
+  g_assert (!g_dbus_connection_get_is_open (c));
+  g_assert (!g_dbus_connection_get_is_initialized (c));
+  _g_assert_property_notify (c, "is-initialized");
+  g_assert ( g_dbus_connection_get_is_open (c));
+  g_assert ( g_dbus_connection_get_is_initialized (c));
   session_bus_down ();
-  g_main_loop_run (loop);
+  _g_assert_property_notify (c, "is-open");
+  g_assert (!g_dbus_connection_get_is_open (c));
+  session_bus_up ();
+  _g_assert_property_notify (c, "is-open");
+  g_assert ( g_dbus_connection_get_is_open (c));
+  session_bus_down ();
+  _g_assert_property_notify (c, "is-open");
   g_assert (!g_dbus_connection_get_is_open (c));
-  g_assert (!val);
-
   g_object_unref (c);
-
-  /* Check that the error paths are correct when using singletons */
-  counter = 0;
-  c = g_dbus_connection_bus_get (G_BUS_TYPE_SESSION,
-                                 NULL,
-                                 (GAsyncReadyCallback) get_connection_callback_no_bus_exists_singleton,
-                                 &counter);
-  c2 = g_dbus_connection_bus_get (G_BUS_TYPE_SESSION,
-                                 NULL,
-                                 (GAsyncReadyCallback) get_connection_callback_no_bus_exists_singleton,
-                                 &counter);
+  /* case 2 */
+  session_bus_up ();
+  c = g_dbus_connection_bus_get (G_BUS_TYPE_SESSION);
+  g_dbus_connection_set_exit_on_close (c, FALSE);
   g_assert (!g_dbus_connection_get_is_open (c));
-  g_assert (!g_dbus_connection_get_is_open (c2));
-  g_main_loop_run (loop);
-  g_assert (counter == 2);
+  g_assert (!g_dbus_connection_get_is_initialized (c));
+  _g_assert_property_notify (c, "is-initialized");
+  g_assert ( g_dbus_connection_get_is_open (c));
+  g_assert ( g_dbus_connection_get_is_initialized (c));
+  session_bus_down ();
+  _g_assert_signal_received (c, "closed");
   g_assert (!g_dbus_connection_get_is_open (c));
-  g_assert (!g_dbus_connection_get_is_open (c2));
+  session_bus_up ();
+  _g_assert_signal_received (c, "opened");
+  g_assert ( g_dbus_connection_get_is_open (c));
+  session_bus_down ();
+  _g_assert_signal_received (c, "closed");
+  g_assert (!g_dbus_connection_get_is_open (c));
+  g_object_unref (c);
+
+  /**
+   * Check that singleton handling work
+   */
+  c = g_dbus_connection_bus_get (G_BUS_TYPE_SESSION);
+  c2 = g_dbus_connection_bus_get (G_BUS_TYPE_SESSION);
+  g_assert (c == c2);
+  g_object_unref (c);
+  g_object_unref (c2);
+
+  /**
+   * Check that private connections work
+   */
+  c = g_dbus_connection_bus_get (G_BUS_TYPE_SESSION);
+  c2 = g_dbus_connection_bus_get_private (G_BUS_TYPE_SESSION);
+  g_assert (c != c2);
   g_object_unref (c);
   g_object_unref (c2);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
-/* Test that g_dbus_connection_send() works */
+/* Test that sending and receiving messages work as expected */
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
@@ -310,13 +210,6 @@ msg_cb_expect_error (GDBusConnection *connection,
 }
 
 static void
-msg_on_connection_opened (GDBusConnection *connection,
-                          gpointer         user_data)
-{
-  g_main_loop_quit (loop);
-}
-
-static void
 msg_cb_expect_success (GDBusConnection *connection,
                        GAsyncResult    *res,
                        gpointer         user_data)
@@ -357,27 +250,28 @@ msg_cb_expect_error_cancelled (GDBusConnection *connection,
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
-test_dbus_connection_send (void)
+test_connection_send (void)
 {
   GDBusConnection *c;
   DBusMessage *m;
   GCancellable *ca;
 
-  /* get an unopened connection */
-  c = g_dbus_connection_bus_get (G_BUS_TYPE_SESSION,
-                                 NULL,
-                                 (GAsyncReadyCallback) get_connection_callback_no_bus_exists,
-                                 NULL);
+  /* First, get an unopened connection */
+  c = g_dbus_connection_bus_get (G_BUS_TYPE_SESSION);
   g_assert (!g_dbus_connection_get_is_open (c));
-  g_main_loop_run (loop);
+  _g_assert_property_notify (c, "is-initialized");
   g_assert (!g_dbus_connection_get_is_open (c));
+  g_assert ( g_dbus_connection_get_is_initialized (c));
 
+  /* Use the GetId() method on the message bus for testing */
   m = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
                                     DBUS_PATH_DBUS,
                                     DBUS_INTERFACE_DBUS,
                                     "GetId");
 
-  /* check we get an error when sending on an unopened connection */
+  /**
+   *  Check we get an error when sending messages on an unopened connection.
+   */
   g_dbus_connection_send_dbus_1_message_with_reply (c,
                                                     m,
                                                     -1,
@@ -386,8 +280,10 @@ test_dbus_connection_send (void)
                                                     NULL);
   g_main_loop_run (loop);
 
-  /* check that we never try an op if the GCancellable is already cancelled - i.e. we should
-   * get G_DBUS_ERROR_CANCELLED instead of G_DBUS_ERROR_FAILED
+  /**
+   * Check that we never actually send a message if the GCancellable is already cancelled - i.e.
+   * we should get #G_DBUS_ERROR_CANCELLED instead of #G_DBUS_ERROR_FAILED even when the actual
+   * connection is not up.
    */
   ca = g_cancellable_new ();
   g_cancellable_cancel (ca);
@@ -400,12 +296,14 @@ test_dbus_connection_send (void)
   g_main_loop_run (loop);
   g_object_unref (ca);
 
-  /* bring up the bus and try again */
-  g_signal_connect (c, "opened", G_CALLBACK (msg_on_connection_opened), NULL);
+  /* now bring up the bus and wait until the connection is open */
   session_bus_up ();
-  g_main_loop_run (loop);
+  _g_assert_signal_received (c, "opened");
   g_assert (g_dbus_connection_get_is_open (c));
-  g_signal_handlers_disconnect_by_func (c, G_CALLBACK (msg_on_connection_opened), NULL);
+
+  /**
+   * Check that we get a reply to the GetId() method call.
+   */
   g_dbus_connection_send_dbus_1_message_with_reply (c,
                                                     m,
                                                     -1,
@@ -414,7 +312,9 @@ test_dbus_connection_send (void)
                                                     NULL);
   g_main_loop_run (loop);
 
-  /* check that cancellation works (the message is already in flight when we cancel) */
+  /**
+   * Check that cancellation works when the message is already in flight.
+   */
   ca = g_cancellable_new ();
   g_dbus_connection_send_dbus_1_message_with_reply (c,
                                                     m,
@@ -430,7 +330,6 @@ test_dbus_connection_send (void)
   dbus_message_unref (m);
   g_object_unref (c);
   session_bus_down ();
-
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -451,7 +350,7 @@ main (int   argc,
   g_unsetenv ("DISPLAY");
   g_setenv ("DBUS_SESSION_BUS_ADDRESS", session_bus_get_temporary_address (), TRUE);
 
-  g_test_add_func ("/gdbus/message-bus-connections", test_message_bus_connections);
-  g_test_add_func ("/gdbus/dbus-connection-send", test_dbus_connection_send);
+  g_test_add_func ("/gdbus/connection-life-cycle", test_connection_life_cycle);
+  g_test_add_func ("/gdbus/connection-send", test_connection_send);
   return g_test_run();
 }
diff --git a/gdbus/tests/names.c b/gdbus/tests/names.c
index f446f1f..3476067 100644
--- a/gdbus/tests/names.c
+++ b/gdbus/tests/names.c
@@ -33,353 +33,141 @@ static GMainLoop *loop = NULL;
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
-on_name_acquired_expect_failure (GBusNameOwner *owner,
-                                 gpointer       user_data)
-{
-  g_assert_not_reached ();
-}
-
-static void
-on_name_lost_expect_failure (GBusNameOwner *owner,
-                             gpointer       user_data)
-{
-  g_assert_not_reached ();
-}
-
-static void
-on_owner_cb_expect_failure (GBusNameOwner *owner,
-                            GAsyncResult  *result,
-                            gpointer       user_data)
-{
-  gboolean *val = user_data;
-  gboolean ret;
-  GError *error;
-
-  error = NULL;
-  ret = g_bus_name_owner_new_finish (owner,
-                                     result,
-                                     &error);
-  _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);
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static void
-on_name_acquired_expect_success (GBusNameOwner *owner,
-                                 gpointer       user_data)
-{
-  gboolean *val2 = user_data;
-
-  *val2 = TRUE;
-}
-
-static void
-on_name_lost_expect_success (GBusNameOwner *owner,
-                             gpointer       user_data)
-{
-  g_assert_not_reached ();
-}
-
-static void
-on_owner_cb_expect_success (GBusNameOwner *owner,
-                            GAsyncResult  *result,
-                            gpointer       user_data)
-{
-  gboolean *val = user_data;
-  gboolean ret;
-  GError *error;
-
-  error = NULL;
-  ret = g_bus_name_owner_new_finish (owner,
-                                     result,
-                                     &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);
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static void
-on_name_lost_bringing_down_the_bus (GBusNameOwner *owner,
-                                    gpointer       user_data)
-{
-  gboolean *val = user_data;
-
-  *val = TRUE;
-
-  g_main_loop_quit (loop);
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static void
-on_name_acquired_bringing_up_the_bus (GBusNameOwner *owner,
-                                      gpointer       user_data)
-{
-  gboolean *val = user_data;
-
-  *val = TRUE;
-
-  g_main_loop_quit (loop);
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static void
-on_owner_cb_expect_failure2 (GBusNameOwner *owner,
-                             GAsyncResult  *result,
-                             gpointer       user_data)
-{
-  gboolean *val = user_data;
-  gboolean ret;
-  GError *error;
-
-  error = NULL;
-  ret = g_bus_name_owner_new_finish (owner,
-                                     result,
-                                     &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);
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-static void
-on_owner_for_connection_cb_expect_failure (GBusNameOwner *owner,
-                                           GAsyncResult  *result,
-                                           gpointer       user_data)
-{
-  gboolean *val = user_data;
-  gboolean ret;
-  GError *error;
-
-  error = NULL;
-  ret = g_bus_name_owner_new_for_connection_finish (owner,
-                                                    result,
-                                                    &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);
-}
-/* ---------------------------------------------------------------------------------------------------- */
-
-static void
-on_name_acquired_for_o2 (GBusNameOwner *owner,
-                         gpointer       user_data)
-{
-  gboolean *val = user_data;
-
-  *val = TRUE;
-
-  g_main_loop_quit (loop);
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static void
-on_name_lost_for_o2 (GBusNameOwner *owner,
-                     gpointer       user_data)
-{
-  gboolean *val = user_data;
-
-  *val = TRUE;
-
-  g_main_loop_quit (loop);
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static void
-get_connection_callback_private (GDBusConnection *connection,
-                                 GAsyncResult    *result,
-                                 gpointer         user_data)
-{
-  GError *error;
-  gboolean ret;
-
-  error = NULL;
-  ret = g_dbus_connection_bus_get_private_finish (connection,
-                                                  result,
-                                                  &error);
-  g_assert_no_error (error);
-  g_assert (ret);
-  g_main_loop_quit (loop);
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static void
 test_bus_name_owner (void)
 {
-  GDBusConnection *private_connection;
   GBusNameOwner *o;
   GBusNameOwner *o2;
-  gboolean val;
-  gboolean val2;
+  GDBusConnection *pc;
 
-  /* first try to own a name when there is no bus */
-  val = FALSE;
+  /**
+   *  Try to own a name when there is no bus.
+   *
+   *  The owner should not be initialized until we figure out there is no bus to connect to.
+   */
   o = g_bus_name_owner_new (G_BUS_TYPE_SESSION,
-                            "org.gtk.Test.Name1",
-                            G_BUS_NAME_OWNER_FLAGS_NONE,
-                            NULL,
-                            (GAsyncReadyCallback) on_owner_cb_expect_failure,
-                            &val);
-  g_signal_connect (o, "name-acquired", G_CALLBACK (on_name_acquired_expect_failure), NULL);
-  g_signal_connect (o, "name-lost", G_CALLBACK (on_name_lost_expect_failure), NULL);
-  g_main_loop_run (loop);
-  g_assert (val);
+                            "org.gtk.GDBus.Name1",
+                            G_BUS_NAME_OWNER_FLAGS_NONE);
+  g_assert (!g_bus_name_owner_get_is_initialized (o));
+  g_assert (!g_bus_name_owner_get_owns_name (o));
+  _g_assert_property_notify (o, "is-initialized");
+  g_assert ( g_bus_name_owner_get_is_initialized (o));
+  g_assert (!g_bus_name_owner_get_owns_name (o));
   g_object_unref (o);
 
-  /* try again, this time with a bus instance - the ::name-acquired signal should fire before the async reply */
+  /**
+   *  Try to own a name if we do have a bus instance.
+   *
+   *  The owner should not be initialized until we managed to acquire the name.
+   */
   session_bus_up ();
-  val = FALSE;
-  val2 = FALSE;
   o = g_bus_name_owner_new (G_BUS_TYPE_SESSION,
-                            "org.gtk.Test.Name1",
-                            G_BUS_NAME_OWNER_FLAGS_NONE,
-                            NULL,
-                            (GAsyncReadyCallback) on_owner_cb_expect_success,
-                            &val);
-  g_signal_connect (o, "name-acquired", G_CALLBACK (on_name_acquired_expect_success), &val2);
-  g_signal_connect (o, "name-lost", G_CALLBACK (on_name_lost_expect_success), NULL);
-  g_main_loop_run (loop);
-  g_assert (val);
-  g_assert (val2);
+                            "org.gtk.GDBus.Name1",
+                            G_BUS_NAME_OWNER_FLAGS_NONE);
+  g_assert (!g_bus_name_owner_get_is_initialized (o));
+  g_assert (!g_bus_name_owner_get_owns_name (o));
+  _g_assert_property_notify (o, "is-initialized");
+  g_assert ( g_bus_name_owner_get_is_initialized (o));
+  g_assert ( g_bus_name_owner_get_owns_name (o));
+  g_dbus_connection_set_exit_on_close (g_bus_name_owner_get_connection (o), FALSE);
 
-  /* try owning the same name again... this should not fail, we should get the same object
-   * as o because of singleton handling
+  /**
+   * try to own the same name again... this should not fail, we should get the same object
+   * because of singleton handling..
    */
   o2 = g_bus_name_owner_new (G_BUS_TYPE_SESSION,
-                             "org.gtk.Test.Name1",
-                             G_BUS_NAME_OWNER_FLAGS_NONE,
-                             NULL,
-                             (GAsyncReadyCallback) on_owner_cb_expect_success,
-                             &val);
-  g_main_loop_run (loop);
-  g_assert (val);
-  g_assert (o2 == o);
+                             "org.gtk.GDBus.Name1",
+                             G_BUS_NAME_OWNER_FLAGS_NONE);
+  g_assert (o == o2);
   g_object_unref (o2);
 
-  /* now kill o.. and then attempt to own the same name again.. */
-  g_object_unref (o);
-  val = FALSE;
-  val2 = FALSE;
-  o = g_bus_name_owner_new (G_BUS_TYPE_SESSION,
-                            "org.gtk.Test.Name1",
-                            G_BUS_NAME_OWNER_FLAGS_NONE,
-                            NULL,
-                            (GAsyncReadyCallback) on_owner_cb_expect_success,
-                            &val);
-  g_signal_connect (o, "name-acquired", G_CALLBACK (on_name_acquired_expect_success), &val2);
-  g_main_loop_run (loop);
-  g_assert (val);
-  g_assert (val2);
-
-  /* now bring down the bus.. this should trigger the ::name-lost signal */
-  val = FALSE;
-  g_signal_connect (o, "name-lost", G_CALLBACK (on_name_lost_bringing_down_the_bus), &val);
-  g_dbus_connection_set_exit_on_close (g_bus_name_owner_get_connection (o), FALSE);
+  /**
+   * Now bring the bus down and check that we lose the name.
+   */
   session_bus_down ();
-  g_main_loop_run (loop);
-  g_assert (val);
+  _g_assert_signal_received (o, "name-lost");
+  g_assert (!g_bus_name_owner_get_owns_name (o));
 
-  /* bring the bus back up... then we should get the ::name-acquired signal
-   *
-   * Can't use existing signal handler since it doesn't quit the main loop.
+
+  /**
+   * Bring the bus back up and check that we own the name - this checks that GBusNameOwner
+   * tries to reaquire the name on reconnects.
    */
-  val = FALSE;
-  g_signal_handlers_disconnect_by_func (o, on_name_acquired_expect_success, &val2);
-  g_signal_connect (o, "name-acquired", G_CALLBACK (on_name_acquired_bringing_up_the_bus), &val);
   session_bus_up ();
-  g_main_loop_run (loop);
-  g_assert (val);
+  _g_assert_signal_received (o, "name-acquired");
+  g_assert (g_bus_name_owner_get_owns_name (o));
 
-  /* Create a private connection and a bus name owner for that connection, o2, that tries to own
-   * the name with _REPLACE and _ALLOW_REPLACEMENT. This should fail because o already owns the name
-   * and didn't specify ALLOW_REPLACEMENT.
+  /**
+   * Create a private connection and use that to acquire the name.
+   *
+   * This should fail because o already owns the name and
+   * %G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT was not specified.
    */
-  private_connection = g_dbus_connection_bus_get_private (G_BUS_TYPE_SESSION,
-                                                          NULL,                            /* cancellable */
-                                                          (GAsyncReadyCallback) get_connection_callback_private,
-                                                          NULL);                           /* user_data */
-  g_main_loop_run (loop);
-  val = FALSE;
-  o2 = g_bus_name_owner_new_for_connection (private_connection,
-                                            "org.gtk.Test.Name1",
-                                            G_BUS_NAME_OWNER_FLAGS_REPLACE |
-                                            G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
-                                            NULL,
-                                            (GAsyncReadyCallback) on_owner_for_connection_cb_expect_failure,
-                                            &val);
-  g_object_unref (private_connection);
-  g_main_loop_run (loop);
+  pc = g_dbus_connection_bus_get_private (G_BUS_TYPE_SESSION);
+  g_assert (pc != g_bus_name_owner_get_connection (o));
+  g_dbus_connection_set_exit_on_close (pc, FALSE);
+  _g_assert_signal_received (pc, "opened");
+  o2 = g_bus_name_owner_new_for_connection (pc,
+                                            "org.gtk.GDBus.Name1",
+                                            G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT);
+  g_assert (!g_bus_name_owner_get_is_initialized (o2));
+  g_assert (!g_bus_name_owner_get_owns_name (o2));
+  _g_assert_property_notify (o2, "is-initialized");
+  g_assert ( g_bus_name_owner_get_is_initialized (o2));
   g_assert (!g_bus_name_owner_get_owns_name (o2));
-  g_assert (val);
 
-  /* OK, so o is owning the name and o2 is in queue. Kill o and check that o2 acquires the name. */
-  val = FALSE;
-  g_signal_connect (o2, "name-acquired", G_CALLBACK (on_name_acquired_for_o2), &val);
+  /**
+   * Now make o stop owning the name. This should result in o2 acquiring the name.
+   */
   g_object_unref (o);
-  g_main_loop_run (loop);
-  g_assert (g_bus_name_owner_get_owns_name (o2));
-  g_assert (val);
+  _g_assert_signal_received (o2, "name-acquired");
+  g_assert ( g_bus_name_owner_get_owns_name (o2));
 
-  /* Since o2 specified ALLOW_REPLACEMENT, check that o can claim the name only when using REPLACE */
-  val = FALSE;
+  /**
+   * Now try to acquire the name from a non-private connection without
+   * specifying %G_BUS_NAME_OWNER_FLAGS_REPLACE.
+   *
+   * This should fail because o2 already owns the name and we didn't
+   * want to replace it.
+   */
   o = g_bus_name_owner_new (G_BUS_TYPE_SESSION,
-                            "org.gtk.Test.Name1",
-                            G_BUS_NAME_OWNER_FLAGS_NONE,
-                            NULL,
-                            (GAsyncReadyCallback) on_owner_cb_expect_failure2,
-                            &val);
-  g_main_loop_run (loop);
-  g_assert (val);
+                            "org.gtk.GDBus.Name1",
+                            G_BUS_NAME_OWNER_FLAGS_NONE);
+  g_assert (!g_bus_name_owner_get_is_initialized (o));
+  g_assert (!g_bus_name_owner_get_owns_name (o));
+  _g_assert_property_notify (o, "is-initialized");
+  g_assert ( g_bus_name_owner_get_is_initialized (o));
   g_assert (!g_bus_name_owner_get_owns_name (o));
-  g_assert (g_bus_name_owner_get_owns_name (o2));
   g_object_unref (o);
-  /* and now with REPLACE */
-  val = FALSE;
+
+  /**
+   * Now try with specifying %G_BUS_NAME_OWNER_FLAGS_REPLACE.
+   *
+   * This will make o2 lose the name since we specified replacement
+   * and o2 allows replacement.
+   */
   o = g_bus_name_owner_new (G_BUS_TYPE_SESSION,
-                            "org.gtk.Test.Name1",
-                            G_BUS_NAME_OWNER_FLAGS_REPLACE,
-                            NULL,
-                            (GAsyncReadyCallback) on_owner_cb_expect_success,
-                            &val);
-  g_main_loop_run (loop);
-  g_assert (val);
-  g_assert (g_bus_name_owner_get_owns_name (o));
-  /* we might not have gotten the signal for o2 yet */
+                            "org.gtk.GDBus.Name1",
+                            G_BUS_NAME_OWNER_FLAGS_REPLACE);
+  g_assert (!g_bus_name_owner_get_is_initialized (o));
+  g_assert (!g_bus_name_owner_get_owns_name (o));
+  _g_assert_property_notify (o, "is-initialized");
+  g_assert ( g_bus_name_owner_get_is_initialized (o));
+  g_assert ( g_bus_name_owner_get_owns_name (o));
+  /* unfortunately it varies whether o2 gets NameLost before o gets NameAcquired... */
   if (g_bus_name_owner_get_owns_name (o2))
-    {
-      val = FALSE;
-      g_signal_connect (o2, "name-lost", G_CALLBACK (on_name_lost_for_o2), &val);
-      g_main_loop_run (loop);
-      g_assert (val);
-      g_assert (!g_bus_name_owner_get_owns_name (o2));
-    }
-  /* make sure we don't exit when bringing down the bus */
-  g_dbus_connection_set_exit_on_close (g_bus_name_owner_get_connection (o), FALSE);
-  g_dbus_connection_set_exit_on_close (g_bus_name_owner_get_connection (o2), FALSE);
-  g_object_unref (o2);
+    _g_assert_signal_received (o2, "name-lost");
+  g_assert (!g_bus_name_owner_get_owns_name (o2));
+
+  /**
+   * Now, give up the name again.. o2 should get it back.
+   */
   g_object_unref (o);
+  _g_assert_signal_received (o2, "name-acquired");
+  g_assert ( g_bus_name_owner_get_owns_name (o2));
 
+  /* Clean up */
+  g_object_unref (o2);
+  g_object_unref (pc);
   session_bus_down ();
 }
 
@@ -388,245 +176,396 @@ test_bus_name_owner (void)
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
-bnw_cb_expect_error (GBusNameWatcher *watcher,
-                     GAsyncResult    *res,
-                     gpointer         user_data)
+test_bus_name_watcher (void)
 {
-  GError *error;
-  gboolean ret;
-
-  error = NULL;
-  ret = g_bus_name_watcher_new_finish (watcher,
-                                       res,
-                                       &error);
-  _g_assert_error_domain (error, G_DBUS_ERROR);
-  g_error_free (error);
-  g_assert (!ret);
-  g_assert_cmpstr (g_bus_name_watcher_get_name_owner (watcher), ==, NULL);
+  GBusNameWatcher *w;
+  GBusNameOwner *o;
 
-  g_main_loop_quit (loop);
-}
+  /**
+   *  Try to watch a name when there is no bus.
+   *
+   *  The watcher should not be initialized until we figure out there is no bus to connect to.
+   */
+  w = g_bus_name_watcher_new (G_BUS_TYPE_SESSION,
+                              "org.gtk.GDBus.Name1");
+  g_assert (!g_bus_name_watcher_get_is_initialized (w));
+  g_assert (g_bus_name_watcher_get_name_owner (w) == NULL);
+  _g_assert_property_notify (w, "is-initialized");
+  g_assert ( g_bus_name_watcher_get_is_initialized (w));
+  g_assert (g_bus_name_watcher_get_name_owner (w) == NULL);
+  g_object_unref (w);
 
-/* ---------------------------------------------------------------------------------------------------- */
+  /**
+   *  Try to watch a name if we do have a bus instance.
+   *
+   *  The watcher should not be initialized until connected.
+   */
+  session_bus_up ();
+  w = g_bus_name_watcher_new (G_BUS_TYPE_SESSION,
+                              "org.gtk.GDBus.Name1");
+  g_assert (!g_bus_name_watcher_get_is_initialized (w));
+  g_assert (g_bus_name_watcher_get_name_owner (w) == NULL);
+  _g_assert_property_notify (w, "is-initialized");
+  g_assert ( g_bus_name_watcher_get_is_initialized (w));
+  g_assert (g_bus_name_watcher_get_name_owner (w) == NULL);
+  g_assert (g_dbus_connection_get_is_open (g_bus_name_watcher_get_connection (w)));
+  g_object_unref (w);
 
-static void
-bnw_cb_expect_null_owner (GBusNameWatcher *watcher,
-                          GAsyncResult    *res,
-                          gpointer         user_data)
-{
-  GError *error;
-  gboolean ret;
+  /**
+   * Now own a name and then create a new watcher.
+   */
+  /* own the name */
+  o = g_bus_name_owner_new (G_BUS_TYPE_SESSION,
+                            "org.gtk.GDBus.Name1",
+                            G_BUS_NAME_OWNER_FLAGS_NONE);
+  g_assert (!g_bus_name_owner_get_is_initialized (o));
+  g_assert (!g_bus_name_owner_get_owns_name (o));
+  _g_assert_property_notify (o, "is-initialized");
+  g_assert ( g_bus_name_owner_get_is_initialized (o));
+  g_assert ( g_bus_name_owner_get_owns_name (o));
+  g_dbus_connection_set_exit_on_close (g_bus_name_owner_get_connection (o), FALSE);
+  /* create watcher */
+  w = g_bus_name_watcher_new (G_BUS_TYPE_SESSION,
+                              "org.gtk.GDBus.Name1");
+  g_assert (!g_bus_name_watcher_get_is_initialized (w));
+  g_assert (g_bus_name_watcher_get_name_owner (w) == NULL);
+  _g_assert_property_notify (w, "is-initialized");
+  g_assert ( g_bus_name_watcher_get_is_initialized (w));
+  g_assert (g_bus_name_watcher_get_name_owner (w) != NULL);
+  g_object_unref (w);
+  g_object_unref (o);
 
-  error = NULL;
-  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);
+  /**
+   * Now create the watcher and then own the name.
+   *
+   * The watcher should emit #GBusNameWatcher::name-appeared.
+   */
+  /* create watcher */
+  w = g_bus_name_watcher_new (G_BUS_TYPE_SESSION,
+                              "org.gtk.GDBus.Name1");
+  g_assert (!g_bus_name_watcher_get_is_initialized (w));
+  g_assert (g_bus_name_watcher_get_name_owner (w) == NULL);
+  _g_assert_property_notify (w, "is-initialized");
+  g_assert ( g_bus_name_watcher_get_is_initialized (w));
+  g_assert (g_bus_name_watcher_get_name_owner (w) == NULL);
+  /* own the name */
+  o = g_bus_name_owner_new (G_BUS_TYPE_SESSION,
+                            "org.gtk.GDBus.Name1",
+                            G_BUS_NAME_OWNER_FLAGS_NONE);
+  g_dbus_connection_set_exit_on_close (g_bus_name_owner_get_connection (o), FALSE);
+  g_assert (!g_bus_name_owner_get_is_initialized (o));
+  g_assert (!g_bus_name_owner_get_owns_name (o));
+  /* wait until watcher has noticed */
+  _g_assert_signal_received (w, "name-appeared");
+  g_assert (g_bus_name_watcher_get_name_owner (w) != NULL);
 
-  g_main_loop_quit (loop);
+  /**
+   * Now destroy the owner.
+   *
+   * The watcher should emit #GBusNameWatcher::name-vanished.
+   */
+  g_object_unref (o);
+  _g_assert_signal_received (w, "name-vanished");
+  g_assert (g_bus_name_watcher_get_name_owner (w) == NULL);
+
+  /* cleanup */
+  g_object_unref (w);
+  session_bus_down ();
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
+/* Test that g_bus_own_name() works correctly */
+/* ---------------------------------------------------------------------------------------------------- */
 
-static void
-bnw_on_owner_cb_expect_success (GBusNameOwner *owner,
-                                GAsyncResult  *result,
-                                gpointer       user_data)
+typedef struct
 {
-  gboolean ret;
-  GError *error;
-
-  error = NULL;
-  ret = g_bus_name_owner_new_finish (owner,
-                                     result,
-                                     &error);
-  g_assert_no_error (error);
-  g_assert (ret);
-  g_assert (g_bus_name_owner_get_owns_name (owner));
+  guint num_acquired;
+  guint num_lost;
+} OwnNameData;
 
+static void
+name_acquired_handler (GDBusConnection *connection,
+                       const gchar     *name,
+                       gpointer         user_data)
+{
+  OwnNameData *data = user_data;
+  g_dbus_connection_set_exit_on_close (connection, FALSE);
+  data->num_acquired += 1;
   g_main_loop_quit (loop);
 }
 
-/* ---------------------------------------------------------------------------------------------------- */
-
 static void
-bnw_cb_expect_owner (GBusNameWatcher *watcher,
-                     GAsyncResult    *res,
-                     gpointer         user_data)
+name_lost_handler (GDBusConnection *connection,
+                   const gchar     *name,
+                   gpointer         user_data)
 {
-  GError *error;
-  gboolean ret;
-
-  error = NULL;
-  ret = g_bus_name_watcher_new_finish (watcher,
-                                       res,
-                                       &error);
-  g_assert_no_error (error);
-  g_assert (ret);
-  g_assert_cmpstr (g_bus_name_watcher_get_name_owner (watcher), !=, NULL);
-
+  OwnNameData *data = user_data;
+  g_dbus_connection_set_exit_on_close (connection, FALSE);
+  data->num_lost += 1;
   g_main_loop_quit (loop);
 }
 
-/* ---------------------------------------------------------------------------------------------------- */
-
 static void
-bnw_on_name_vanished (GBusNameWatcher *watcher,
-                      gpointer         user_data)
+test_bus_own_name (void)
 {
-  g_main_loop_quit (loop);
+  guint id;
+  OwnNameData data;
+
+  /**
+   * First check that name_lost_handler() is invoked if there is no bus.
+   *
+   * Also make sure name_lost_handler() isn't invoked when unowning the name.
+   */
+  data.num_acquired = 0;
+  data.num_lost = 0;
+  id = g_bus_own_name (G_BUS_TYPE_SESSION,
+                       "org.gtk.GDBus.Name1",
+                       G_BUS_NAME_OWNER_FLAGS_NONE,
+                       name_acquired_handler,
+                       name_lost_handler,
+                       &data);
+  g_assert_cmpint (data.num_acquired, ==, 0);
+  g_assert_cmpint (data.num_lost,     ==, 0);
+  g_main_loop_run (loop);
+  g_assert_cmpint (data.num_acquired, ==, 0);
+  g_assert_cmpint (data.num_lost,     ==, 1);
+  g_bus_unown_name (id);
+  g_assert_cmpint (data.num_acquired, ==, 0);
+  g_assert_cmpint (data.num_lost,     ==, 1);
+
+  /**
+   * Bring up a bus, then own a name and check name_acquired_handler() is invoked.
+   */
+  session_bus_up ();
+  data.num_acquired = 0;
+  data.num_lost = 0;
+  id = g_bus_own_name (G_BUS_TYPE_SESSION,
+                       "org.gtk.GDBus.Name1",
+                       G_BUS_NAME_OWNER_FLAGS_NONE,
+                       name_acquired_handler,
+                       name_lost_handler,
+                       &data);
+  g_assert_cmpint (data.num_acquired, ==, 0);
+  g_assert_cmpint (data.num_lost,     ==, 0);
+  g_main_loop_run (loop);
+  g_assert_cmpint (data.num_acquired, ==, 1);
+  g_assert_cmpint (data.num_lost,     ==, 0);
+
+  /**
+   * Stop owning the name - this should trigger name_lost_handler() because of this
+   * guarantee
+   *
+   *   If currently owning the name (e.g. @name_acquired_handler was the
+   *   last handler to be invoked), then @name_lost_handler will be invoked
+   *   before this function returns.
+   *
+   * in g_bus_unown_name().
+   */
+  g_bus_unown_name (id);
+  g_assert_cmpint (data.num_acquired, ==, 1);
+  g_assert_cmpint (data.num_lost,     ==, 1);
+
+  /**
+   * Own the name again. Then nuke the bus and bring it back up, checking
+   * that the name_lost_handler() and name_acquired() handlers are invoked
+   * as appropriate.
+   */
+  data.num_acquired = 0;
+  data.num_lost = 0;
+  id = g_bus_own_name (G_BUS_TYPE_SESSION,
+                       "org.gtk.GDBus.Name1",
+                       G_BUS_NAME_OWNER_FLAGS_NONE,
+                       name_acquired_handler,
+                       name_lost_handler,
+                       &data);
+  g_assert_cmpint (data.num_acquired, ==, 0);
+  g_assert_cmpint (data.num_lost,     ==, 0);
+  g_main_loop_run (loop);
+  g_assert_cmpint (data.num_acquired, ==, 1);
+  g_assert_cmpint (data.num_lost,     ==, 0);
+  /* nuke the bus */
+  session_bus_down ();
+  g_main_loop_run (loop);
+  g_assert_cmpint (data.num_acquired, ==, 1);
+  g_assert_cmpint (data.num_lost,     ==, 1);
+  /* bring the bus back up */
+  session_bus_up ();
+  g_main_loop_run (loop);
+  g_assert_cmpint (data.num_acquired, ==, 2);
+  g_assert_cmpint (data.num_lost,     ==, 1);
+  /* nuke the bus */
+  session_bus_down ();
+  g_main_loop_run (loop);
+  g_assert_cmpint (data.num_acquired, ==, 2);
+  g_assert_cmpint (data.num_lost,     ==, 2);
+
+  /* cleanup */
+  g_bus_unown_name (id);
+  g_assert_cmpint (data.num_acquired, ==, 2);
+  g_assert_cmpint (data.num_lost,     ==, 2);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
+/* Test that g_bus_watch_name() works correctly */
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef struct
+{
+  guint num_appeared;
+  guint num_vanished;
+} WatchNameData;
 
 static void
-bnw_on_name_appeared (GBusNameWatcher *watcher,
-                      gpointer         user_data)
+name_appeared_handler (GDBusConnection *connection,
+                       const gchar     *name,
+                       const gchar     *name_owner,
+                       gpointer         user_data)
 {
+  WatchNameData *data = user_data;
+  g_dbus_connection_set_exit_on_close (connection, FALSE);
+  data->num_appeared += 1;
   g_main_loop_quit (loop);
 }
 
-/* ---------------------------------------------------------------------------------------------------- */
-
 static void
-bnw_cb_singleton (GBusNameWatcher *watcher,
-                  GAsyncResult    *res,
-                  gpointer         user_data)
+name_vanished_handler (GDBusConnection *connection,
+                       const gchar     *name,
+                       gpointer         user_data)
 {
-  gboolean *val = user_data;
-  GError *error;
-  gboolean ret;
-
-  error = NULL;
-  ret = g_bus_name_watcher_new_finish (watcher,
-                                       res,
-                                       &error);
-  g_assert_no_error (error);
-  g_assert (ret);
-  g_assert_cmpstr (g_bus_name_watcher_get_name_owner (watcher), !=, NULL);
-
-  *val = TRUE;
-
+  WatchNameData *data = user_data;
+  g_dbus_connection_set_exit_on_close (connection, FALSE);
+  data->num_vanished += 1;
   g_main_loop_quit (loop);
 }
 
-/* ---------------------------------------------------------------------------------------------------- */
-
 static void
-test_bus_name_watcher (void)
+test_bus_watch_name (void)
 {
-  GBusNameWatcher *w;
-  GBusNameWatcher *w2;
+  WatchNameData data;
   GBusNameOwner *o;
-  gboolean val;
+  guint id;
 
-  /* if no session bus is available, expect the callback to expect an error */
-  w = g_bus_name_watcher_new (G_BUS_TYPE_SESSION,
-                              "org.gtk.Test.Name1",
-                              NULL,
-                              (GAsyncReadyCallback) bnw_cb_expect_error,
-                              NULL);
+  /**
+   * First check that name_vanished_handler() is invoked if there is no bus.
+   *
+   * Also make sure name_vanished_handler() isn't invoked when unwatching the name.
+   */
+  data.num_appeared = 0;
+  data.num_vanished = 0;
+  id = g_bus_watch_name (G_BUS_TYPE_SESSION,
+                         "org.gtk.GDBus.Name1",
+                         name_appeared_handler,
+                         name_vanished_handler,
+                         &data);
+  g_assert_cmpint (data.num_appeared, ==, 0);
+  g_assert_cmpint (data.num_vanished, ==, 0);
   g_main_loop_run (loop);
-  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 fail */
+  g_assert_cmpint (data.num_appeared, ==, 0);
+  g_assert_cmpint (data.num_vanished, ==, 1);
+  g_bus_unwatch_name (id);
+  g_assert_cmpint (data.num_appeared, ==, 0);
+  g_assert_cmpint (data.num_vanished, ==, 1);
+
+  /**
+   * Now bring up a bus, own a name, and then start watching it.
+   */
   session_bus_up ();
-  w = g_bus_name_watcher_new (G_BUS_TYPE_SESSION,
-                              "org.gtk.Test.Name1",
-                              NULL,
-                              (GAsyncReadyCallback) bnw_cb_expect_null_owner,
-                              NULL);
-  g_main_loop_run (loop);
-  g_dbus_connection_set_exit_on_close (g_bus_name_watcher_get_connection (w), FALSE);
-  g_object_unref (w);
-
-  /* now start owning a name */
+  /* own the name */
   o = g_bus_name_owner_new (G_BUS_TYPE_SESSION,
-                            "org.gtk.Test.Name1",
-                            G_BUS_NAME_OWNER_FLAGS_NONE,
-                            NULL,
-                            (GAsyncReadyCallback) bnw_on_owner_cb_expect_success,
-                            NULL);
-  g_main_loop_run (loop);
-
-  /* now we should expect to get the name owner in the callback when constructing the watcher */
-  w = g_bus_name_watcher_new (G_BUS_TYPE_SESSION,
-                              "org.gtk.Test.Name1",
-                              NULL,
-                              (GAsyncReadyCallback) bnw_cb_expect_owner,
-                              NULL);
+                            "org.gtk.GDBus.Name1",
+                            G_BUS_NAME_OWNER_FLAGS_NONE);
+  g_dbus_connection_set_exit_on_close (g_bus_name_owner_get_connection (o), FALSE);
+  g_assert (!g_bus_name_owner_get_owns_name (o));
+  _g_assert_signal_received (o, "name-acquired");
+  g_assert ( g_bus_name_owner_get_owns_name (o));
+  /* watch the name */
+  data.num_appeared = 0;
+  data.num_vanished = 0;
+  id = g_bus_watch_name (G_BUS_TYPE_SESSION,
+                         "org.gtk.GDBus.Name1",
+                         name_appeared_handler,
+                         name_vanished_handler,
+                         &data);
+  g_assert_cmpint (data.num_appeared, ==, 0);
+  g_assert_cmpint (data.num_vanished, ==, 0);
   g_main_loop_run (loop);
-  g_assert_cmpstr (g_bus_name_watcher_get_name_owner (w), !=, NULL);
+  g_assert_cmpint (data.num_appeared, ==, 1);
+  g_assert_cmpint (data.num_vanished, ==, 0);
 
-  /* now stop owning the name and check that the watcher emits the ::name-vanished signal */
-  g_signal_connect (w, "name-vanished", G_CALLBACK (bnw_on_name_vanished), NULL);
+  /**
+   * Unwatch the name - this should trigger name_vanished_handler() because of this
+   * guarantee
+   *
+   *   If the name being watched currently has an owner the name (e.g. @name_appeared_handler
+   *   was the last handler to be invoked), then @name_vanished_handler will be invoked
+   *   before this function returns.
+   *
+   * in g_bus_unwatch_name().
+   */
+  g_bus_unwatch_name (id);
+  g_assert_cmpint (data.num_appeared, ==, 1);
+  g_assert_cmpint (data.num_vanished, ==, 1);
   g_object_unref (o);
-  g_main_loop_run (loop);
-  g_assert_cmpstr (g_bus_name_watcher_get_name_owner (w), ==, NULL);
-  g_signal_handlers_disconnect_by_func (w, bnw_on_name_vanished, NULL);
 
-  /* start owning the name and check that the watcher emits the ::name-appeared signal */
-  g_signal_connect (w, "name-appeared", G_CALLBACK (bnw_on_name_appeared), NULL);
+  /**
+   * Create a watcher and then make a name be owned.
+   *
+   * This should trigger name_appeared_handler() ...
+   */
+  /* watch the name */
+  data.num_appeared = 0;
+  data.num_vanished = 0;
+  id = g_bus_watch_name (G_BUS_TYPE_SESSION,
+                         "org.gtk.GDBus.Name1",
+                         name_appeared_handler,
+                         name_vanished_handler,
+                         &data);
+  g_assert_cmpint (data.num_appeared, ==, 0);
+  g_assert_cmpint (data.num_vanished, ==, 0);
+  g_main_loop_run (loop);
+  g_assert_cmpint (data.num_appeared, ==, 0);
+  g_assert_cmpint (data.num_vanished, ==, 1);
+  /* own the name */
   o = g_bus_name_owner_new (G_BUS_TYPE_SESSION,
-                            "org.gtk.Test.Name1",
-                            G_BUS_NAME_OWNER_FLAGS_NONE,
-                            NULL,
-                            NULL,
-                            NULL);
+                            "org.gtk.GDBus.Name1",
+                            G_BUS_NAME_OWNER_FLAGS_NONE);
+  g_dbus_connection_set_exit_on_close (g_bus_name_owner_get_connection (o), FALSE);
+  g_assert (!g_bus_name_owner_get_owns_name (o));
   g_main_loop_run (loop);
-  g_assert_cmpstr (g_bus_name_watcher_get_name_owner (w), !=, NULL);
-  g_signal_handlers_disconnect_by_func (w, bnw_on_name_appeared, NULL);
-
-  /* now check that we get ::name-vanished when the bus goes away */
-  g_signal_connect (w, "name-vanished", G_CALLBACK (bnw_on_name_vanished), NULL);
-  g_dbus_connection_set_exit_on_close (g_bus_name_watcher_get_connection (w), FALSE);
+  g_assert_cmpint (data.num_appeared, ==, 1);
+  g_assert_cmpint (data.num_vanished, ==, 1);
+  /* there's a race here, owner might not know that it has owned the name yet.. so.. */
+  if (!g_bus_name_owner_get_owns_name (o))
+    _g_assert_signal_received (o, "name-acquired");
+  g_assert ( g_bus_name_owner_get_owns_name (o));
+
+  /**
+   * Nuke the bus and check that the name vanishes. Then bring the bus back up
+   * and check that the name appears.
+   */
   session_bus_down ();
   g_main_loop_run (loop);
-  g_assert_cmpstr (g_bus_name_watcher_get_name_owner (w), ==, NULL);
-  g_signal_handlers_disconnect_by_func (w, bnw_on_name_vanished, NULL);
-
-  /* and ::name-appeared when the bus comes back up (this works because
-   * GBusNameOwner will claim the name on reconnection)
-   */
-  g_signal_connect (w, "name-appeared", G_CALLBACK (bnw_on_name_appeared), NULL);
+  g_assert_cmpint (data.num_appeared, ==, 1);
+  g_assert_cmpint (data.num_vanished, ==, 2);
+  /* again, work around possible races */
+  if (g_bus_name_owner_get_owns_name (o))
+    _g_assert_signal_received (o, "name-lost");
+  g_assert (!g_bus_name_owner_get_owns_name (o));
   session_bus_up ();
   g_main_loop_run (loop);
-  g_assert_cmpstr (g_bus_name_watcher_get_name_owner (w), !=, NULL);
-  g_signal_handlers_disconnect_by_func (w, bnw_on_name_appeared, NULL);
-
-  /* check that singleton handling works, e.g. a new watcher for the _same_
-   * connection and name gives the same object
-   */
-  val = FALSE;
-  w2 = g_bus_name_watcher_new (G_BUS_TYPE_SESSION,
-                               "org.gtk.Test.Name1",
-                               NULL,
-                               (GAsyncReadyCallback) bnw_cb_singleton,
-                               &val);
-  g_assert (w == w2);
-  g_assert (!val);
-  g_main_loop_run (loop);
-  g_assert (val);
-  g_object_unref (w2);
-  w2 = g_bus_name_watcher_new (G_BUS_TYPE_SESSION,
-                               "org.gtk.Test.Name2",
-                               NULL,
-                               NULL,
-                               NULL);
-  g_assert (w != w2);
-  g_object_unref (w2);
-
-  /* stop watching */
-  g_object_unref (w);
-
-  /* kill owner */
+  g_assert_cmpint (data.num_appeared, ==, 2);
+  g_assert_cmpint (data.num_vanished, ==, 2);
+  /* again, work around possible races */
+  if (!g_bus_name_owner_get_owns_name (o))
+    _g_assert_signal_received (o, "name-acquired");
+  g_assert ( g_bus_name_owner_get_owns_name (o));
+  g_bus_unwatch_name (id);
+  g_assert_cmpint (data.num_appeared, ==, 2);
+  g_assert_cmpint (data.num_vanished, ==, 3);
   g_object_unref (o);
 
-  /* tear down bus */
   session_bus_down ();
+
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -649,5 +588,7 @@ main (int   argc,
 
   g_test_add_func ("/gdbus/bus-name-owner", test_bus_name_owner);
   g_test_add_func ("/gdbus/bus-name-watcher", test_bus_name_watcher);
+  g_test_add_func ("/gdbus/bus-own-name", test_bus_own_name);
+  g_test_add_func ("/gdbus/bus-watch-name", test_bus_watch_name);
   return g_test_run();
 }
diff --git a/gdbus/tests/tests.c b/gdbus/tests/tests.c
new file mode 100644
index 0000000..57e4822
--- /dev/null
+++ b/gdbus/tests/tests.c
@@ -0,0 +1,131 @@
+/* GLib testing framework examples and tests
+ *
+ * Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#include <gdbus/gdbus.h>
+#include <unistd.h>
+
+#include "tests.h"
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef struct
+{
+  GMainLoop *loop;
+  gboolean   timed_out;
+} PropertyNotifyData;
+
+static void
+on_property_notify (GObject    *object,
+                    GParamSpec *pspec,
+                    gpointer    user_data)
+{
+  PropertyNotifyData *data = user_data;
+  g_main_loop_quit (data->loop);
+}
+
+static gboolean
+on_property_notify_timeout (gpointer user_data)
+{
+  PropertyNotifyData *data = user_data;
+  data->timed_out = TRUE;
+  g_main_loop_quit (data->loop);
+  return TRUE;
+}
+
+gboolean
+_g_assert_property_notify_run (gpointer     object,
+                               const gchar *property_name)
+{
+  gchar *s;
+  gulong handler_id;
+  guint timeout_id;
+  PropertyNotifyData data;
+
+  data.loop = g_main_loop_new (NULL, FALSE);
+  data.timed_out = FALSE;
+  s = g_strdup_printf ("notify::%s", property_name);
+  handler_id = g_signal_connect (object,
+                                 s,
+                                 G_CALLBACK (on_property_notify),
+                                 &data);
+  g_free (s);
+  timeout_id = g_timeout_add (5 * 1000,
+                              on_property_notify_timeout,
+                              &data);
+  g_main_loop_run (data.loop);
+  g_signal_handler_disconnect (object, handler_id);
+  g_source_remove (timeout_id);
+  g_main_loop_unref (data.loop);
+
+  return data.timed_out;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef struct
+{
+  GMainLoop *loop;
+  gboolean   timed_out;
+} SignalReceivedData;
+
+static void
+on_signal_received (gpointer user_data)
+{
+  SignalReceivedData *data = user_data;
+  g_main_loop_quit (data->loop);
+}
+
+static gboolean
+on_signal_received_timeout (gpointer user_data)
+{
+  SignalReceivedData *data = user_data;
+  data->timed_out = TRUE;
+  g_main_loop_quit (data->loop);
+  return TRUE;
+}
+
+gboolean
+_g_assert_signal_received_run (gpointer     object,
+                               const gchar *signal_name)
+{
+  gulong handler_id;
+  guint timeout_id;
+  SignalReceivedData data;
+
+  data.loop = g_main_loop_new (NULL, FALSE);
+  data.timed_out = FALSE;
+  handler_id = g_signal_connect_swapped (object,
+                                         signal_name,
+                                         G_CALLBACK (on_signal_received),
+                                         &data);
+  timeout_id = g_timeout_add (5 * 1000,
+                              on_signal_received_timeout,
+                              &data);
+  g_main_loop_run (data.loop);
+  g_signal_handler_disconnect (object, handler_id);
+  g_source_remove (timeout_id);
+  g_main_loop_unref (data.loop);
+
+  return data.timed_out;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
diff --git a/gdbus/tests/tests.h b/gdbus/tests/tests.h
index d533240..b768ca5 100644
--- a/gdbus/tests/tests.h
+++ b/gdbus/tests/tests.h
@@ -34,10 +34,84 @@ G_BEGIN_DECLS
  * get a different error message on connecting to a bus if the socket file is there vs
  * if the socket file is missing.
  */
+
 #define _g_assert_error_domain(err, dom)	do { if (!err || (err)->domain != dom) \
       g_assertion_message_error (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
                                  #err, err, dom, -1); } while (0)
 
+#define _g_assert_property_notify(object, property_name)                \
+  do                                                                    \
+    {                                                                   \
+      if (!G_IS_OBJECT (object))                                        \
+        {                                                               \
+          g_assertion_message (G_LOG_DOMAIN,                            \
+                               __FILE__,                                \
+                               __LINE__,                                \
+                               G_STRFUNC,                               \
+                               "Not a GObject instance");               \
+        }                                                               \
+      if (g_object_class_find_property (G_OBJECT_GET_CLASS (object),    \
+                                        property_name) == NULL)         \
+        {                                                               \
+          g_assertion_message (G_LOG_DOMAIN,                            \
+                               __FILE__,                                \
+                               __LINE__,                                \
+                               G_STRFUNC,                               \
+                               "Property " property_name " does not "   \
+                               "exist on object");                      \
+        }                                                               \
+      if (_g_assert_property_notify_run (object, property_name))        \
+        {                                                               \
+          g_assertion_message (G_LOG_DOMAIN,                            \
+                               __FILE__,                                \
+                               __LINE__,                                \
+                               G_STRFUNC,                               \
+                               "Timed out waiting for notification "    \
+                               "on property " property_name);           \
+        }                                                               \
+    }                                                                   \
+  while (FALSE)
+
+#define _g_assert_signal_received(object, signal_name)                  \
+  do                                                                    \
+    {                                                                   \
+      if (!G_IS_OBJECT (object))                                        \
+        {                                                               \
+          g_assertion_message (G_LOG_DOMAIN,                            \
+                               __FILE__,                                \
+                               __LINE__,                                \
+                               G_STRFUNC,                               \
+                               "Not a GObject instance");               \
+        }                                                               \
+      if (g_signal_lookup (signal_name,                                 \
+                           G_TYPE_FROM_INSTANCE (object)) == 0)         \
+        {                                                               \
+          g_assertion_message (G_LOG_DOMAIN,                            \
+                               __FILE__,                                \
+                               __LINE__,                                \
+                               G_STRFUNC,                               \
+                               "Signal " signal_name " does not "       \
+                               "exist on object");                      \
+        }                                                               \
+      if (_g_assert_signal_received_run (object, signal_name))          \
+        {                                                               \
+          g_assertion_message (G_LOG_DOMAIN,                            \
+                               __FILE__,                                \
+                               __LINE__,                                \
+                               G_STRFUNC,                               \
+                               "Timed out waiting for signal "          \
+                               signal_name);                            \
+        }                                                               \
+    }                                                                   \
+  while (FALSE)
+
+gboolean _g_assert_property_notify_run (gpointer     object,
+                                        const gchar *property_name);
+
+
+gboolean _g_assert_signal_received_run (gpointer     object,
+                                        const gchar *signal_name);
+
 G_END_DECLS
 
 #endif /* __TESTS_H__ */



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