[glib] Bug 621213 – GDBusProxy and well-known names



commit 32f2e9a85beedeea36ac7623f68f6eb878465d44
Author: David Zeuthen <davidz redhat com>
Date:   Fri Jun 11 15:45:18 2010 -0400

    Bug 621213 â?? GDBusProxy and well-known names
    
    Allow constructing a GDBusProxy for well-known names as discussed here
    http://mail.gnome.org/archives/gtk-devel-list/2009-October/msg00075.html
    including test cases.
    
    Make it possible to create a GDBusProxy for a GBusType instead of a
    GDBusConnection. This requires G_BUS_TYPE_NONE so add that too.
    
    Nuke g_bus_watch_proxy() since one can now more or less use GDBusProxy
    for this.
    
    Port gdbus-example-watch-proxy to this new API and include this
    example in the GDBusProxy doc page.
    
    Also nuke the GType parameter from the GDBusProxy constructors as
    requested here: https://bugzilla.gnome.org/show_bug.cgi?id=621229
    
    Also update the porting guide and other API docs for this change.
    
    Also fix a bug in the signal dispatching code so each subscriber only
    get notified once, not N times, for the same signal. Also add a test
    case for this.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=621213
    
    Signed-off-by: David Zeuthen <davidz redhat com>

 docs/reference/gio/gio-docs.xml          |    1 -
 docs/reference/gio/gio-sections.txt      |   17 +-
 docs/reference/gio/migrating-gdbus.xml   |   62 +--
 gio/Makefile.am                          |    2 -
 gio/gdbusconnection.c                    |  152 +++--
 gio/gdbusproxy.c                         | 1071 ++++++++++++++++++++++++------
 gio/gdbusproxy.h                         |   28 +-
 gio/gdbusproxywatching.c                 |  666 -------------------
 gio/gdbusproxywatching.h                 |  115 ----
 gio/gio.h                                |    1 -
 gio/gio.symbols                          |   16 +-
 gio/gioenums.h                           |   14 +-
 gio/tests/Makefile.am                    |    4 +
 gio/tests/gdbus-connection.c             |   22 +-
 gio/tests/gdbus-example-proxy-subclass.c |   83 ---
 gio/tests/gdbus-example-watch-proxy.c    |  149 +++--
 gio/tests/gdbus-export.c                 |    5 -
 gio/tests/gdbus-introspection.c          |   55 +-
 gio/tests/gdbus-peer.c                   |    1 -
 gio/tests/gdbus-proxy-well-known-name.c  |  283 ++++++++
 gio/tests/gdbus-proxy.c                  |   84 +--
 gio/tests/gdbus-threading.c              |   55 +-
 22 files changed, 1508 insertions(+), 1378 deletions(-)
---
diff --git a/docs/reference/gio/gio-docs.xml b/docs/reference/gio/gio-docs.xml
index 0e092d1..9d4f03f 100644
--- a/docs/reference/gio/gio-docs.xml
+++ b/docs/reference/gio/gio-docs.xml
@@ -143,7 +143,6 @@
       <title>Highlevel D-Bus Support</title>
       <xi:include href="xml/gdbusnameowning.xml"/>
       <xi:include href="xml/gdbusnamewatching.xml"/>
-      <xi:include href="xml/gdbusproxywatching.xml"/>
       <xi:include href="xml/gdbusproxy.xml"/>
     </chapter>
     <chapter id="utils">
diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index b09f267..9c820a3 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -2483,17 +2483,6 @@ g_bus_watch_name_on_connection_with_closures
 </SECTION>
 
 <SECTION>
-<FILE>gdbusproxywatching</FILE>
-GBusProxyAppearedCallback
-GBusProxyVanishedCallback
-g_bus_watch_proxy
-g_bus_watch_proxy_on_connection
-g_bus_unwatch_proxy
-g_bus_watch_proxy_with_closures
-g_bus_watch_proxy_on_connection_with_closures
-</SECTION>
-
-<SECTION>
 <FILE>gdbuserror</FILE>
 GDBusError
 G_DBUS_ERROR
@@ -2521,9 +2510,13 @@ GDBusProxyClass
 g_dbus_proxy_new
 g_dbus_proxy_new_finish
 g_dbus_proxy_new_sync
+g_dbus_proxy_new_for_bus
+g_dbus_proxy_new_for_bus_finish
+g_dbus_proxy_new_for_bus_sync
 g_dbus_proxy_get_flags
 g_dbus_proxy_get_connection
-g_dbus_proxy_get_unique_bus_name
+g_dbus_proxy_get_name
+g_dbus_proxy_get_name_owner
 g_dbus_proxy_get_object_path
 g_dbus_proxy_get_interface_name
 g_dbus_proxy_get_default_timeout
diff --git a/docs/reference/gio/migrating-gdbus.xml b/docs/reference/gio/migrating-gdbus.xml
index 14e70b7..bd7b8c5 100644
--- a/docs/reference/gio/migrating-gdbus.xml
+++ b/docs/reference/gio/migrating-gdbus.xml
@@ -1,5 +1,5 @@
 <chapter>
-  <title>Migrating from dbus-glib to GDBus</title>
+  <title>Migrating to GDBus</title>
 
   <section>
     <title>Conceptual differences</title>
@@ -47,8 +47,8 @@
           <row><entry>#DBusGMethodInvocation</entry><entry>#GDBusMethodInvocation</entry></row>
           <row><entry>dbus_g_bus_get()</entry><entry>g_bus_get_sync(), also see
                g_bus_get()</entry></row>
-          <row><entry>dbus_g_proxy_new_for_name()</entry><entry>g_dbus_proxy_new_sync(), also see
-               g_dbus_proxy_new()</entry></row>
+          <row><entry>dbus_g_proxy_new_for_name()</entry><entry>g_dbus_proxy_new_sync() and
+               g_dbus_proxy_new_for_bus_sync(), also see g_dbus_proxy_new()</entry></row>
           <row><entry>dbus_g_proxy_add_signal()</entry><entry>not needed, use the generic #GDBusProxy::g-signal</entry></row>
           <row><entry>dbus_g_proxy_connect_signal()</entry><entry>use g_signal_connect() with #GDBusProxy::g-signal</entry></row>
           <row><entry>dbus_g_connection_register_g_object()</entry><entry>g_dbus_connection_register_object()</entry></row>
@@ -177,46 +177,28 @@ on_name_acquired (GDBusConnection *connection,
       the current owner of the name, and that owner can change over time.
     </para>
     <para>
-      In contrast, #GDBusProxy instances are always bound to a unique name.
-      To get a proxy for a well-known name, you either have to call
-      GetNameOwner yourself and construct a proxy for the unique name
-      of the current name owner, or use the high-level API. The latter
-      option is highly recommended:
+      The same can be achieved with #GDBusProxy:
       <informalexample><programlisting><![CDATA[
-static void
-on_proxy_appeared (GDBusConnection *connection,
-                   const gchar     *name,
-                   const gchar     *name_owner,
-                   GDBusProxy      *proxy,
-                   gpointer         user_data)
-{
-  /* start to use proxy */
-}
-
-  /* ... */
-
-  watcher_id = g_bus_watch_proxy (G_BUS_TYPE_SYSTEM,
-                                  "org.freedesktop.Accounts",
-                                  G_BUS_NAME_WATCHER_FLAGS_NONE,
-                                  "/org/freedesktop/Accounts",
-                                  "org.freedesktop.Accounts",
-                                  G_TYPE_DBUS_PROXY,
-                                  G_BUS_PROXY_FLAGS_NONE,
-                                  on_proxy_appeared,
-                                  on_proxy_vanished,
-                                  NULL,
-                                  NULL);
-
-  g_main_loop_run (loop);
-
-  g_bus_unwatch_proxy (watcher_id);
+  error = NULL;
+  proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
+                                         G_DBUS_PROXY_FLAGS_NONE,
+                                         NULL, /* GDBusInterfaceInfo */
+                                         "org.freedesktop.Accounts",
+                                         "/org/freedesktop/Accounts",
+                                         "org.freedesktop.Accounts",
+                                         NULL, /* GCancellable */
+                                         &error);
       ]]>
       </programlisting></informalexample>
-      Like g_bus_own_name(), g_bus_watch_proxy() is asynchronous and
-      you are expected to enter your mainloop to await the on_proxy_appeared()
-      callback. Note that GDBus also does all the setup operations for the
-      proxy asynchronously, and only calls your callback when the proxy
-      is ready for use.
+      For an added layer of safety, you can specify what D-Bus
+      interface the proxy is expected to conform to by using the
+      #GDBusInterfaceInfo type.
+    </para>
+    <para>
+      Additionally, #GDBusProxy loads, caches and tracks changes to
+      the D-Bus properties on the remote object. It also sets up match
+      rules so D-Bus signals from the remote object are delivered
+      locally.
     </para>
   </section>
   <section>
diff --git a/gio/Makefile.am b/gio/Makefile.am
index fe4053e..a94bde0 100644
--- a/gio/Makefile.am
+++ b/gio/Makefile.am
@@ -89,7 +89,6 @@ gdbus_headers = 			\
 	gdbusmessage.h			\
 	gdbusnameowning.h		\
 	gdbusnamewatching.h		\
-	gdbusproxywatching.h		\
 	gdbusproxy.h			\
 	gdbusintrospection.h		\
 	gdbusmethodinvocation.h		\
@@ -110,7 +109,6 @@ gdbus_sources = 							\
 	gdbusmessage.h			gdbusmessage.c			\
 	gdbusnameowning.h		gdbusnameowning.c		\
 	gdbusnamewatching.h		gdbusnamewatching.c		\
-	gdbusproxywatching.h		gdbusproxywatching.c		\
 	gdbusproxy.h			gdbusproxy.c			\
 	gdbusprivate.h			gdbusprivate.c			\
 	gdbusintrospection.h		gdbusintrospection.c		\
diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c
index c6b34d1..a41ee85 100644
--- a/gio/gdbusconnection.c
+++ b/gio/gdbusconnection.c
@@ -144,7 +144,7 @@
  *
  * This class is rarely used directly in D-Bus clients. If you are writing
  * an D-Bus client, it is often easier to use the g_bus_own_name(),
- * g_bus_watch_name() or g_bus_watch_proxy() APIs.
+ * g_bus_watch_name() or g_dbus_proxy_new_for_bus() APIs.
  *
  * <example id="gdbus-server"><title>D-Bus server example</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude"; parse="text" href="../../../../gio/tests/gdbus-example-server.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting></example>
  *
@@ -265,9 +265,9 @@ struct _GDBusConnectionPrivate
   GHashTable *map_method_serial_to_send_message_data;  /* guint32 -> SendMessageData* */
 
   /* Maps used for managing signal subscription */
-  GHashTable *map_rule_to_signal_data;          /* gchar* -> SignalData */
-  GHashTable *map_id_to_signal_data;            /* guint  -> SignalData */
-  GHashTable *map_sender_to_signal_data_array;  /* gchar* -> GPtrArray* of SignalData */
+  GHashTable *map_rule_to_signal_data;                      /* match rule (gchar*)    -> SignalData */
+  GHashTable *map_id_to_signal_data;                        /* id (guint)             -> SignalData */
+  GHashTable *map_sender_unique_name_to_signal_data_array;  /* unique sender (gchar*) -> GPtrArray* of SignalData */
 
   /* Maps used for managing exported objects and subtrees */
   GHashTable *map_object_path_to_eo;  /* gchar* -> ExportedObject* */
@@ -408,7 +408,7 @@ g_dbus_connection_finalize (GObject *object)
   purge_all_signal_subscriptions (connection);
   g_hash_table_unref (connection->priv->map_rule_to_signal_data);
   g_hash_table_unref (connection->priv->map_id_to_signal_data);
-  g_hash_table_unref (connection->priv->map_sender_to_signal_data_array);
+  g_hash_table_unref (connection->priv->map_sender_unique_name_to_signal_data_array);
 
   g_hash_table_unref (connection->priv->map_id_to_ei);
   g_hash_table_unref (connection->priv->map_object_path_to_eo);
@@ -785,10 +785,10 @@ g_dbus_connection_init (GDBusConnection *connection)
                                                                 g_str_equal);
   connection->priv->map_id_to_signal_data = g_hash_table_new (g_direct_hash,
                                                               g_direct_equal);
-  connection->priv->map_sender_to_signal_data_array = g_hash_table_new_full (g_str_hash,
-                                                                             g_str_equal,
-                                                                             g_free,
-                                                                             NULL);
+  connection->priv->map_sender_unique_name_to_signal_data_array = g_hash_table_new_full (g_str_hash,
+                                                                                         g_str_equal,
+                                                                                         g_free,
+                                                                                         NULL);
 
   connection->priv->map_object_path_to_eo = g_hash_table_new_full (g_str_hash,
                                                                    g_str_equal,
@@ -2372,6 +2372,7 @@ typedef struct
 {
   gchar *rule;
   gchar *sender;
+  gchar *sender_unique_name; /* if sender is unique or org.freedesktop.DBus, then that name... otherwise blank */
   gchar *interface_name;
   gchar *member;
   gchar *object_path;
@@ -2389,16 +2390,17 @@ typedef struct
 } SignalSubscriber;
 
 static void
-signal_data_free (SignalData *data)
-{
-  g_free (data->rule);
-  g_free (data->sender);
-  g_free (data->interface_name);
-  g_free (data->member);
-  g_free (data->object_path);
-  g_free (data->arg0);
-  g_array_free (data->subscribers, TRUE);
-  g_free (data);
+signal_data_free (SignalData *signal_data)
+{
+  g_free (signal_data->rule);
+  g_free (signal_data->sender);
+  g_free (signal_data->sender_unique_name);
+  g_free (signal_data->interface_name);
+  g_free (signal_data->member);
+  g_free (signal_data->object_path);
+  g_free (signal_data->arg0);
+  g_array_free (signal_data->subscribers, TRUE);
+  g_free (signal_data);
 }
 
 static gchar *
@@ -2444,7 +2446,6 @@ add_match_rule (GDBusConnection *connection,
                                             "org.freedesktop.DBus", /* interface */
                                             "AddMatch");
   g_dbus_message_set_body (message, g_variant_new ("(s)", match_rule));
-
   error = NULL;
   if (!g_dbus_connection_send_message_unlocked (connection,
                                                 message,
@@ -2490,7 +2491,7 @@ remove_match_rule (GDBusConnection *connection,
 static gboolean
 is_signal_data_for_name_lost_or_acquired (SignalData *signal_data)
 {
-  return g_strcmp0 (signal_data->sender, "org.freedesktop.DBus") == 0 &&
+  return g_strcmp0 (signal_data->sender_unique_name, "org.freedesktop.DBus") == 0 &&
          g_strcmp0 (signal_data->interface_name, "org.freedesktop.DBus") == 0 &&
          g_strcmp0 (signal_data->object_path, "/org/freedesktop/DBus") == 0 &&
          (g_strcmp0 (signal_data->member, "NameLost") == 0 ||
@@ -2502,7 +2503,7 @@ is_signal_data_for_name_lost_or_acquired (SignalData *signal_data)
 /**
  * g_dbus_connection_signal_subscribe:
  * @connection: A #GDBusConnection.
- * @sender: Sender name to match on. Must be either <literal>org.freedesktop.DBus</literal> (for listening to signals from the message bus daemon) or a unique name or %NULL to listen from all senders.
+ * @sender: Sender name to match on (unique or well-known name) or %NULL to listen from all senders.
  * @interface_name: D-Bus interface name to match on or %NULL to match on all interfaces.
  * @member: D-Bus signal name to match on or %NULL to match on all signals.
  * @object_path: Object path to match on or %NULL to match on all object paths.
@@ -2517,14 +2518,18 @@ is_signal_data_for_name_lost_or_acquired (SignalData *signal_data)
  * linkend="g-main-context-push-thread-default">thread-default main
  * loop</link> of the thread you are calling this method from.
  *
- * It is considered a programming error to use this function if @connection is closed.
+ * It is considered a programming error to use this function if
+ * @connection is closed.
+ *
+ * If @connection is not a message bus connection, @sender must be
+ * %NULL.
  *
- * Note that if @sender is not <literal>org.freedesktop.DBus</literal> (for listening to signals from the
- * message bus daemon), then it needs to be a unique bus name or %NULL (for listening to signals from any
- * name) - you cannot pass a name like <literal>com.example.MyApp</literal>.
- * Use e.g. g_bus_watch_name() to find the unique name for the owner of the name you are interested in. Also note
- * that this function does not remove a subscription if @sender vanishes from the bus. You have to manually
- * call g_dbus_connection_signal_unsubscribe() to remove a subscription.
+ * If @sender is a well-known name note that @callback is invoked with
+ * the unique name for the owner of @sender, not the well-known name
+ * as one would expect. This is because the message bus rewrites the
+ * name. As such, to avoid certain race conditions, users should be
+ * tracking the name owner of the well-known name and use that when
+ * processing the received signal.
  *
  * Returns: A subscription identifier that can be used with g_dbus_connection_signal_unsubscribe().
  *
@@ -2545,6 +2550,7 @@ g_dbus_connection_signal_subscribe (GDBusConnection     *connection,
   SignalData *signal_data;
   SignalSubscriber subscriber;
   GPtrArray *signal_data_array;
+  const gchar *sender_unique_name;
 
   /* Right now we abort if AddMatch() fails since it can only fail with the bus being in
    * an OOM condition. We might want to change that but that would involve making
@@ -2558,8 +2564,7 @@ g_dbus_connection_signal_subscribe (GDBusConnection     *connection,
 
   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
   g_return_val_if_fail (!g_dbus_connection_is_closed (connection), 0);
-  g_return_val_if_fail (sender == NULL || ((strcmp (sender, "org.freedesktop.DBus") == 0 || sender[0] == ':') &&
-                                           (connection->priv->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION)), 0);
+  g_return_val_if_fail (sender == NULL || (g_dbus_is_name (sender) && (connection->priv->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION)), 0);
   g_return_val_if_fail (interface_name == NULL || g_dbus_is_interface_name (interface_name), 0);
   g_return_val_if_fail (member == NULL || g_dbus_is_member_name (member), 0);
   g_return_val_if_fail (object_path == NULL || g_variant_is_object_path (object_path), 0);
@@ -2569,8 +2574,10 @@ g_dbus_connection_signal_subscribe (GDBusConnection     *connection,
 
   rule = args_to_rule (sender, interface_name, member, object_path, arg0);
 
-  if (sender == NULL)
-    sender = "";
+  if (sender != NULL && (g_dbus_is_unique_name (sender) || g_strcmp0 (sender, "org.freedesktop.DBus") == 0))
+    sender_unique_name = sender;
+  else
+    sender_unique_name = "";
 
   subscriber.callback = callback;
   subscriber.user_data = user_data;
@@ -2590,13 +2597,14 @@ g_dbus_connection_signal_subscribe (GDBusConnection     *connection,
     }
 
   signal_data = g_new0 (SignalData, 1);
-  signal_data->rule           = rule;
-  signal_data->sender         = g_strdup (sender);
-  signal_data->interface_name = g_strdup (interface_name);
-  signal_data->member         = g_strdup (member);
-  signal_data->object_path    = g_strdup (object_path);
-  signal_data->arg0           = g_strdup (arg0);
-  signal_data->subscribers    = g_array_new (FALSE, FALSE, sizeof (SignalSubscriber));
+  signal_data->rule                  = rule;
+  signal_data->sender                = g_strdup (sender);
+  signal_data->sender_unique_name    = g_strdup (sender_unique_name);
+  signal_data->interface_name        = g_strdup (interface_name);
+  signal_data->member                = g_strdup (member);
+  signal_data->object_path           = g_strdup (object_path);
+  signal_data->arg0                  = g_strdup (arg0);
+  signal_data->subscribers           = g_array_new (FALSE, FALSE, sizeof (SignalSubscriber));
   g_array_append_val (signal_data->subscribers, subscriber);
 
   g_hash_table_insert (connection->priv->map_rule_to_signal_data,
@@ -2614,22 +2622,22 @@ g_dbus_connection_signal_subscribe (GDBusConnection     *connection,
         add_match_rule (connection, signal_data->rule);
     }
 
- out:
-  g_hash_table_insert (connection->priv->map_id_to_signal_data,
-                       GUINT_TO_POINTER (subscriber.id),
-                       signal_data);
-
-  signal_data_array = g_hash_table_lookup (connection->priv->map_sender_to_signal_data_array,
-                                           signal_data->sender);
+  signal_data_array = g_hash_table_lookup (connection->priv->map_sender_unique_name_to_signal_data_array,
+                                           signal_data->sender_unique_name);
   if (signal_data_array == NULL)
     {
       signal_data_array = g_ptr_array_new ();
-      g_hash_table_insert (connection->priv->map_sender_to_signal_data_array,
-                           g_strdup (signal_data->sender),
+      g_hash_table_insert (connection->priv->map_sender_unique_name_to_signal_data_array,
+                           g_strdup (signal_data->sender_unique_name),
                            signal_data_array);
     }
   g_ptr_array_add (signal_data_array, signal_data);
 
+ out:
+  g_hash_table_insert (connection->priv->map_id_to_signal_data,
+                       GUINT_TO_POINTER (subscriber.id),
+                       signal_data);
+
   CONNECTION_UNLOCK (connection);
 
   return subscriber.id;
@@ -2669,24 +2677,27 @@ unsubscribe_id_internal (GDBusConnection *connection,
       g_array_remove_index (signal_data->subscribers, n);
 
       if (signal_data->subscribers->len == 0)
-        g_warn_if_fail (g_hash_table_remove (connection->priv->map_rule_to_signal_data, signal_data->rule));
+        {
+          g_warn_if_fail (g_hash_table_remove (connection->priv->map_rule_to_signal_data, signal_data->rule));
 
-      signal_data_array = g_hash_table_lookup (connection->priv->map_sender_to_signal_data_array,
-                                               signal_data->sender);
-      g_warn_if_fail (signal_data_array != NULL);
-      g_warn_if_fail (g_ptr_array_remove (signal_data_array, signal_data));
+          signal_data_array = g_hash_table_lookup (connection->priv->map_sender_unique_name_to_signal_data_array,
+                                                   signal_data->sender_unique_name);
+          g_warn_if_fail (signal_data_array != NULL);
+          g_warn_if_fail (g_ptr_array_remove (signal_data_array, signal_data));
 
-      if (signal_data_array->len == 0)
-        {
-          g_warn_if_fail (g_hash_table_remove (connection->priv->map_sender_to_signal_data_array, signal_data->sender));
+          if (signal_data_array->len == 0)
+            {
+              g_warn_if_fail (g_hash_table_remove (connection->priv->map_sender_unique_name_to_signal_data_array,
+                                                   signal_data->sender_unique_name));
+            }
 
           /* remove the match rule from the bus unless NameLost or NameAcquired (see subscribe()) */
           if (connection->priv->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION)
             {
               if (!is_signal_data_for_name_lost_or_acquired (signal_data))
-                remove_match_rule (connection, signal_data->rule);
+                if (!connection->priv->closed)
+                  remove_match_rule (connection, signal_data->rule);
             }
-
           signal_data_free (signal_data);
         }
 
@@ -2779,7 +2790,8 @@ emit_signal_instance_in_idle_cb (gpointer data)
     }
 
 #if 0
-  g_debug ("in emit_signal_instance_in_idle_cb (sender=%s path=%s interface=%s member=%s params=%s)",
+  g_print ("in emit_signal_instance_in_idle_cb (id=%d sender=%s path=%s interface=%s member=%s params=%s)\n",
+           signal_instance->subscription_id,
            signal_instance->sender,
            signal_instance->path,
            signal_instance->interface,
@@ -2842,11 +2854,17 @@ schedule_callbacks (GDBusConnection *connection,
   arg0 = g_dbus_message_get_arg0 (message);
 
 #if 0
-  g_debug ("sender    = `%s'", sender);
-  g_debug ("interface = `%s'", interface);
-  g_debug ("member    = `%s'", member);
-  g_debug ("path      = `%s'", path);
-  g_debug ("arg0      = `%s'", arg0);
+  g_print ("In schedule_callbacks:\n"
+           "  sender    = `%s'\n"
+           "  interface = `%s'\n"
+           "  member    = `%s'\n"
+           "  path      = `%s'\n"
+           "  arg0      = `%s'\n",
+           sender,
+           interface,
+           member,
+           path,
+           arg0);
 #endif
 
   /* TODO: if this is slow, then we can change signal_data_array into
@@ -2912,13 +2930,13 @@ distribute_signals (GDBusConnection *connection,
   /* collect subscribers that match on sender */
   if (sender != NULL)
     {
-      signal_data_array = g_hash_table_lookup (connection->priv->map_sender_to_signal_data_array, sender);
+      signal_data_array = g_hash_table_lookup (connection->priv->map_sender_unique_name_to_signal_data_array, sender);
       if (signal_data_array != NULL)
         schedule_callbacks (connection, signal_data_array, message, sender);
     }
 
   /* collect subscribers not matching on sender */
-  signal_data_array = g_hash_table_lookup (connection->priv->map_sender_to_signal_data_array, "");
+  signal_data_array = g_hash_table_lookup (connection->priv->map_sender_unique_name_to_signal_data_array, "");
   if (signal_data_array != NULL)
     schedule_callbacks (connection, signal_data_array, message, sender);
 }
diff --git a/gio/gdbusproxy.c b/gio/gdbusproxy.c
index fe5c97d..1344b7c 100644
--- a/gio/gdbusproxy.c
+++ b/gio/gdbusproxy.c
@@ -25,8 +25,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <gobject/gvaluecollector.h>
-
 #include "gdbusutils.h"
 #include "gdbusproxy.h"
 #include "gioenumtypes.h"
@@ -39,45 +37,61 @@
 #include "gioerror.h"
 #include "gasyncresult.h"
 #include "gsimpleasyncresult.h"
+#include "gcancellable.h"
 
 #include "glibintl.h"
 #include "gioalias.h"
 
 /**
  * SECTION:gdbusproxy
- * @short_description: Base class for proxies
+ * @short_description: Client-side proxies
  * @include: gio/gio.h
  *
  * #GDBusProxy is a base class used for proxies to access a D-Bus
- * interface on a remote object. A #GDBusProxy can only be constructed
- * for unique name bus and does not track whether the name
- * vanishes. Use g_bus_watch_proxy() to construct #GDBusProxy proxies
- * for owners of a well-known names.
+ * interface on a remote object. A #GDBusProxy can be constructed for
+ * both well-known and unique names.
  *
- * By default, #GDBusProxy will cache all properties (and listen for
- * their changes) of the remote object, and proxy all signals that gets
+ * By default, #GDBusProxy will cache all properties (and listen to
+ * changes) of the remote object, and proxy all signals that gets
  * emitted. This behaviour can be changed by passing suitable
- * #GDBusProxyFlags when the proxy is created.
+ * #GDBusProxyFlags when the proxy is created. If the proxy is for a
+ * well-known name, the property cache is flushed when the name owner
+ * vanishes and reloaded when a name owner appears.
+ *
+ * If a #GDBusProxy is used for a well-known name, the owner of the
+ * name is tracked and can be read from
+ * #GDBusProxy:g-name-owner. Connect to the #GObject::notify signal to
+ * get notified of changes. Additionally, only signals and property
+ * changes emitted from the current name owner are considered. This
+ * avoids a number of race conditions when the name is lost by one
+ * owner and claimed by another.
  *
  * The generic #GDBusProxy::g-properties-changed and #GDBusProxy::g-signal
  * signals are not very convenient to work with. Therefore, the recommended
  * way of working with proxies is to subclass #GDBusProxy, and have
- * more natural properties and signals in your derived class. The
- * @interface_type argument of g_bus_watch_proxy() lets you obtain
- * instances of your derived class when using the high-level API.
+ * more natural properties and signals in your derived class.
  *
  * See <xref linkend="gdbus-example-proxy-subclass"/> for an example.
+ *
+ * <example id="gdbus-wellknown-proxy"><title>GDBusProxy for a well-known-name</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude"; parse="text" href="../../../../gio/tests/gdbus-example-watch-proxy.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting></example>
  */
 
 struct _GDBusProxyPrivate
 {
+  GBusType bus_type;
   GDBusConnection *connection;
+
   GDBusProxyFlags flags;
-  gchar *unique_bus_name;
+  gchar *name;
+  gchar *name_owner;
   gchar *object_path;
   gchar *interface_name;
   gint timeout_msec;
 
+  guint name_owner_changed_subscription_id;
+
+  GCancellable *get_all_cancellable;
+
   /* gchar* -> GVariant* */
   GHashTable *properties;
 
@@ -93,7 +107,9 @@ enum
 {
   PROP_0,
   PROP_G_CONNECTION,
-  PROP_G_UNIQUE_BUS_NAME,
+  PROP_G_BUS_TYPE,
+  PROP_G_NAME,
+  PROP_G_NAME_OWNER,
   PROP_G_FLAGS,
   PROP_G_OBJECT_PATH,
   PROP_G_INTERFACE_NAME,
@@ -108,8 +124,6 @@ enum
   LAST_SIGNAL,
 };
 
-static void g_dbus_proxy_constructed (GObject *object);
-
 guint signals[LAST_SIGNAL] = {0};
 
 static void initable_iface_init       (GInitableIface *initable_iface);
@@ -125,6 +139,12 @@ g_dbus_proxy_finalize (GObject *object)
 {
   GDBusProxy *proxy = G_DBUS_PROXY (object);
 
+  g_warn_if_fail (proxy->priv->get_all_cancellable == NULL);
+
+  if (proxy->priv->name_owner_changed_subscription_id > 0)
+    g_dbus_connection_signal_unsubscribe (proxy->priv->connection,
+                                          proxy->priv->name_owner_changed_subscription_id);
+
   if (proxy->priv->properties_changed_subscriber_id > 0)
     g_dbus_connection_signal_unsubscribe (proxy->priv->connection,
                                           proxy->priv->properties_changed_subscriber_id);
@@ -134,7 +154,8 @@ g_dbus_proxy_finalize (GObject *object)
                                           proxy->priv->signals_subscriber_id);
 
   g_object_unref (proxy->priv->connection);
-  g_free (proxy->priv->unique_bus_name);
+  g_free (proxy->priv->name);
+  g_free (proxy->priv->name_owner);
   g_free (proxy->priv->object_path);
   g_free (proxy->priv->interface_name);
   if (proxy->priv->properties != NULL)
@@ -164,8 +185,12 @@ g_dbus_proxy_get_property (GObject    *object,
       g_value_set_flags (value, proxy->priv->flags);
       break;
 
-    case PROP_G_UNIQUE_BUS_NAME:
-      g_value_set_string (value, proxy->priv->unique_bus_name);
+    case PROP_G_NAME:
+      g_value_set_string (value, proxy->priv->name);
+      break;
+
+    case PROP_G_NAME_OWNER:
+      g_value_set_string (value, proxy->priv->name_owner);
       break;
 
     case PROP_G_OBJECT_PATH:
@@ -208,8 +233,8 @@ g_dbus_proxy_set_property (GObject      *object,
       proxy->priv->flags = g_value_get_flags (value);
       break;
 
-    case PROP_G_UNIQUE_BUS_NAME:
-      proxy->priv->unique_bus_name = g_value_dup_string (value);
+    case PROP_G_NAME:
+      proxy->priv->name = g_value_dup_string (value);
       break;
 
     case PROP_G_OBJECT_PATH:
@@ -228,6 +253,10 @@ g_dbus_proxy_set_property (GObject      *object,
       g_dbus_proxy_set_interface_info (proxy, g_value_get_boxed (value));
       break;
 
+    case PROP_G_BUS_TYPE:
+      proxy->priv->bus_type = g_value_get_enum (value);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -242,7 +271,6 @@ g_dbus_proxy_class_init (GDBusProxyClass *klass)
   gobject_class->finalize     = g_dbus_proxy_finalize;
   gobject_class->set_property = g_dbus_proxy_set_property;
   gobject_class->get_property = g_dbus_proxy_get_property;
-  gobject_class->constructed  = g_dbus_proxy_constructed;
 
   /* Note that all property names are prefixed to avoid collisions with D-Bus property names
    * in derived classes */
@@ -291,6 +319,29 @@ g_dbus_proxy_class_init (GDBusProxyClass *klass)
                                                         G_PARAM_STATIC_NICK));
 
   /**
+   * GDBusProxy:g-bus-type:
+   *
+   * If this property is not %G_BUS_TYPE_NONE, then
+   * #GDBusProxy:g-connection must be %NULL and will be set to the
+   * #GDBusConnection obtained by calling g_bus_get() with the value
+   * of this property.
+   *
+   * Since: 2.26
+   */
+  g_object_class_install_property (gobject_class,
+                                   PROP_G_BUS_TYPE,
+                                   g_param_spec_enum ("g-bus-type",
+                                                      P_("Bus Type"),
+                                                      P_("The bus to connect to, if any"),
+                                                      G_TYPE_BUS_TYPE,
+                                                      G_BUS_TYPE_NONE,
+                                                      G_PARAM_WRITABLE |
+                                                      G_PARAM_CONSTRUCT_ONLY |
+                                                      G_PARAM_STATIC_NAME |
+                                                      G_PARAM_STATIC_BLURB |
+                                                      G_PARAM_STATIC_NICK));
+
+  /**
    * GDBusProxy:g-flags:
    *
    * Flags from the #GDBusProxyFlags enumeration.
@@ -312,17 +363,17 @@ g_dbus_proxy_class_init (GDBusProxyClass *klass)
                                                        G_PARAM_STATIC_NICK));
 
   /**
-   * GDBusProxy:g-unique-bus-name:
+   * GDBusProxy:g-name:
    *
-   * The unique bus name the proxy is for.
+   * The well-known or unique name that the proxy is for.
    *
    * Since: 2.26
    */
   g_object_class_install_property (gobject_class,
-                                   PROP_G_UNIQUE_BUS_NAME,
-                                   g_param_spec_string ("g-unique-bus-name",
-                                                        P_("g-unique-bus-name"),
-                                                        P_("The unique bus name the proxy is for"),
+                                   PROP_G_NAME,
+                                   g_param_spec_string ("g-name",
+                                                        P_("g-name"),
+                                                        P_("The well-known or unique name that the proxy is for"),
                                                         NULL,
                                                         G_PARAM_READABLE |
                                                         G_PARAM_WRITABLE |
@@ -332,6 +383,26 @@ g_dbus_proxy_class_init (GDBusProxyClass *klass)
                                                         G_PARAM_STATIC_NICK));
 
   /**
+   * GDBusProxy:g-name-owner:
+   *
+   * The unique name that owns #GDBusProxy:name or %NULL if no-one
+   * currently owns that name. You may connect to #GObject::notify signal to
+   * track changes to this property.
+   *
+   * Since: 2.26
+   */
+  g_object_class_install_property (gobject_class,
+                                   PROP_G_NAME_OWNER,
+                                   g_param_spec_string ("g-name-owner",
+                                                        P_("g-name-owner"),
+                                                        P_("The unique name for the owner"),
+                                                        NULL,
+                                                        G_PARAM_READABLE |
+                                                        G_PARAM_STATIC_NAME |
+                                                        G_PARAM_STATIC_BLURB |
+                                                        G_PARAM_STATIC_NICK));
+
+  /**
    * GDBusProxy:g-object-path:
    *
    * The object path the proxy is for.
@@ -667,6 +738,9 @@ on_signal_received (GDBusConnection *connection,
   if (!proxy->priv->initialized)
     goto out;
 
+  if (g_strcmp0 (sender_name, proxy->priv->name_owner) != 0)
+    goto out;
+
   g_signal_emit (proxy,
                  signals[SIGNAL_SIGNAL],
                  0,
@@ -705,6 +779,9 @@ on_properties_changed (GDBusConnection *connection,
   if (!proxy->priv->initialized)
     goto out;
 
+  if (g_strcmp0 (sender_name, proxy->priv->name_owner) != 0)
+    goto out;
+
   if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sa{sv}as)")))
     {
       g_warning ("Value for PropertiesChanged signal with type `%s' does not match `(sa{sv}as)'",
@@ -749,51 +826,6 @@ on_properties_changed (GDBusConnection *connection,
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
-g_dbus_proxy_constructed (GObject *object)
-{
-  if (G_OBJECT_CLASS (g_dbus_proxy_parent_class)->constructed != NULL)
-    G_OBJECT_CLASS (g_dbus_proxy_parent_class)->constructed (object);
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static void
-subscribe_to_signals (GDBusProxy *proxy)
-{
-  if (!(proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES))
-    {
-      /* subscribe to PropertiesChanged() */
-      proxy->priv->properties_changed_subscriber_id =
-        g_dbus_connection_signal_subscribe (proxy->priv->connection,
-                                            proxy->priv->unique_bus_name,
-                                            "org.freedesktop.DBus.Properties",
-                                            "PropertiesChanged",
-                                            proxy->priv->object_path,
-                                            proxy->priv->interface_name,
-                                            on_properties_changed,
-                                            proxy,
-                                            NULL);
-    }
-
-  if (!(proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS))
-    {
-      /* subscribe to all signals for the object */
-      proxy->priv->signals_subscriber_id =
-        g_dbus_connection_signal_subscribe (proxy->priv->connection,
-                                            proxy->priv->unique_bus_name,
-                                            proxy->priv->interface_name,
-                                            NULL,                        /* member */
-                                            proxy->priv->object_path,
-                                            NULL,                        /* arg0 */
-                                            on_signal_received,
-                                            proxy,
-                                            NULL);
-    }
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static void
 process_get_all_reply (GDBusProxy *proxy,
                        GVariant   *result)
 {
@@ -811,7 +843,7 @@ process_get_all_reply (GDBusProxy *proxy,
   g_variant_get (result, "(a{sv})", &iter);
   while (g_variant_iter_next (iter, "{sv}", &key, &value))
     {
-      //g_print ("got %s -> %s\n", key, g_variant_markup_print (value, FALSE, 0, 0));
+      /*g_print ("got %s -> %s\n", key, g_variant_print (value, FALSE));*/
 
       g_hash_table_insert (proxy->priv->properties,
                            key, /* adopts string */
@@ -823,81 +855,183 @@ process_get_all_reply (GDBusProxy *proxy,
   ;
 }
 
-static gboolean
-initable_init (GInitable     *initable,
-               GCancellable  *cancellable,
-               GError       **error)
+typedef struct
 {
-  GDBusProxy *proxy = G_DBUS_PROXY (initable);
+  GDBusProxy *proxy;
+  GCancellable *cancellable;
+  gchar *name_owner;
+} LoadPropertiesOnNameOwnerChangedData;
+
+static void
+on_name_owner_changed_get_all_cb (GDBusConnection *connection,
+                                  GAsyncResult    *res,
+                                  gpointer         user_data)
+{
+  LoadPropertiesOnNameOwnerChangedData *data = user_data;
   GVariant *result;
-  gboolean ret;
+  GError *error;
+  gboolean cancelled;
 
-  ret = FALSE;
+  cancelled = FALSE;
 
-  subscribe_to_signals (proxy);
+  error = NULL;
+  result = g_dbus_connection_call_finish (connection,
+                                          res,
+                                          &error);
+  if (result == NULL)
+    {
+      if (error->domain == G_IO_ERROR && error->code == G_IO_ERROR_CANCELLED)
+        cancelled = TRUE;
+      /* We just ignore if GetAll() is failing. Because this might happen
+       * if the object has no properties at all. Or if the caller is
+       * not authorized to see the properties.
+       *
+       * Either way, apps can know about this by using
+       * get_cached_property_names() or get_cached_property().
+       *
+       * TODO: handle G_DBUS_DEBUG flag 'proxy' and, if enabled, log the
+       * fact that GetAll() failed
+       */
+      //g_debug ("error: %d %d %s", error->domain, error->code, error->message);
+      g_error_free (error);
+    }
 
-  if (!(proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES))
+  /* and finally we can notify */
+  if (!cancelled)
     {
-      /* load all properties synchronously */
-      result = g_dbus_connection_call_sync (proxy->priv->connection,
-                                            proxy->priv->unique_bus_name,
-                                            proxy->priv->object_path,
-                                            "org.freedesktop.DBus.Properties",
-                                            "GetAll",
-                                            g_variant_new ("(s)", proxy->priv->interface_name),
-                                            G_VARIANT_TYPE ("(a{sv})"),
-                                            G_DBUS_CALL_FLAGS_NONE,
-                                            -1,           /* timeout */
-                                            cancellable,
-                                            error);
-      if (result == NULL)
+      g_free (data->proxy->priv->name_owner);
+      data->proxy->priv->name_owner = data->name_owner;
+      data->name_owner = NULL; /* to avoid an extra copy, we steal the string */
+
+      g_hash_table_remove_all (data->proxy->priv->properties);
+      if (result != NULL)
         {
-          /* We just ignore if GetAll() is failing. Because this might happen
-           * if the object has no properties at all. Or if the caller is
-           * not authorized to see the properties.
-           *
-           * Either way, apps can know about this by using
-           * get_cached_property_names() or get_cached_property().
-           *
-           * TODO: handle G_DBUS_DEBUG flag 'proxy' and, if enabled, log the
-           * fact that GetAll() failed
-           */
-          //g_debug ("error: %d %d %s", error->domain, error->code, error->message);
-          if (error != NULL)
-            {
-              g_error_free (*error);
-              *error = NULL;
-            }
-          ret = TRUE;
-          goto out;
+          process_get_all_reply (data->proxy, result);
+          g_variant_unref (result);
         }
 
-      process_get_all_reply (proxy, result);
-
-      g_variant_unref (result);
+      g_object_notify (G_OBJECT (data->proxy), "g-name-owner");
     }
 
-  ret = TRUE;
+  if (data->cancellable == data->proxy->priv->get_all_cancellable)
+    data->proxy->priv->get_all_cancellable = NULL;
 
- out:
-  proxy->priv->initialized = TRUE;
-  return ret;
+  g_object_unref (data->proxy);
+  g_object_unref (data->cancellable);
+  g_free (data->name_owner);
+  g_free (data);
 }
 
 static void
-initable_iface_init (GInitableIface *initable_iface)
+on_name_owner_changed (GDBusConnection *connection,
+                       const gchar      *sender_name,
+                       const gchar      *object_path,
+                       const gchar      *interface_name,
+                       const gchar      *signal_name,
+                       GVariant         *parameters,
+                       gpointer          user_data)
 {
-  initable_iface->init = initable_init;
+  GDBusProxy *proxy = G_DBUS_PROXY (user_data);
+  const gchar *name;
+  const gchar *old_owner;
+  const gchar *new_owner;
+
+  /* if we are already trying to load properties, cancel that */
+  if (proxy->priv->get_all_cancellable != NULL)
+    {
+      g_cancellable_cancel (proxy->priv->get_all_cancellable);
+      proxy->priv->get_all_cancellable = NULL;
+    }
+
+  g_variant_get (parameters,
+                 "(&s&s&s)",
+                 &name,
+                 &old_owner,
+                 &new_owner);
+
+  /* we only care about a specific name */
+  if (g_strcmp0 (name, proxy->priv->name) != 0)
+    goto out;
+
+  if (strlen (new_owner) == 0)
+    {
+      g_free (proxy->priv->name_owner);
+      proxy->priv->name_owner = NULL;
+      g_hash_table_remove_all (proxy->priv->properties);
+      g_object_notify (G_OBJECT (proxy), "g-name-owner");
+    }
+  else
+    {
+      /* ignore duplicates - this can happen when activating the service */
+      if (g_strcmp0 (new_owner, proxy->priv->name_owner) == 0)
+        goto out;
+
+      if (proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES)
+        {
+          g_free (proxy->priv->name_owner);
+          proxy->priv->name_owner = g_strdup (new_owner);
+          g_hash_table_remove_all (proxy->priv->properties);
+          g_object_notify (G_OBJECT (proxy), "g-name-owner");
+        }
+      else
+        {
+          LoadPropertiesOnNameOwnerChangedData *data;
+
+          /* start loading properties.. only then emit notify::g-name-owner .. we
+           * need to be able to cancel this in the event another NameOwnerChanged
+           * signal suddenly happens
+           */
+
+          g_assert (proxy->priv->get_all_cancellable == NULL);
+          proxy->priv->get_all_cancellable = g_cancellable_new ();
+          data = g_new0 (LoadPropertiesOnNameOwnerChangedData, 1);
+          data->proxy = g_object_ref (proxy);
+          data->cancellable = proxy->priv->get_all_cancellable;
+          data->name_owner = g_strdup (new_owner);
+          g_dbus_connection_call (proxy->priv->connection,
+                                  data->name_owner,
+                                  proxy->priv->object_path,
+                                  "org.freedesktop.DBus.Properties",
+                                  "GetAll",
+                                  g_variant_new ("(s)", proxy->priv->interface_name),
+                                  G_VARIANT_TYPE ("(a{sv})"),
+                                  G_DBUS_CALL_FLAGS_NONE,
+                                  -1,           /* timeout */
+                                  proxy->priv->get_all_cancellable,
+                                  (GAsyncReadyCallback) on_name_owner_changed_get_all_cb,
+                                  data);
+        }
+    }
+
+ out:
+  ;
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+typedef struct
+{
+  GDBusProxy *proxy;
+  GCancellable *cancellable;
+  GSimpleAsyncResult *simple;
+} AsyncInitData;
+
 static void
-get_all_cb (GDBusConnection *connection,
-            GAsyncResult    *res,
-            gpointer         user_data)
+async_init_data_free (AsyncInitData *data)
 {
-  GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+  g_object_unref (data->proxy);
+  if (data->cancellable != NULL)
+    g_object_unref (data->cancellable);
+  g_object_unref (data->simple);
+  g_free (data);
+}
+
+static void
+async_init_get_all_cb (GDBusConnection *connection,
+                       GAsyncResult    *res,
+                       gpointer         user_data)
+{
+  AsyncInitData *data = user_data;
   GVariant *result;
   GError *error;
 
@@ -922,59 +1056,237 @@ get_all_cb (GDBusConnection *connection,
     }
   else
     {
-      g_simple_async_result_set_op_res_gpointer (simple,
+      g_simple_async_result_set_op_res_gpointer (data->simple,
                                                  result,
                                                  (GDestroyNotify) g_variant_unref);
     }
 
-  g_simple_async_result_complete_in_idle (simple);
-  g_object_unref (simple);
+  g_simple_async_result_complete_in_idle (data->simple);
+  async_init_data_free (data);
 }
 
+
 static void
-async_initable_init_async (GAsyncInitable      *initable,
-                           gint                 io_priority,
-                           GCancellable        *cancellable,
-                           GAsyncReadyCallback  callback,
-                           gpointer             user_data)
+async_init_get_name_owner_cb (GDBusConnection *connection,
+                              GAsyncResult    *res,
+                              gpointer         user_data)
 {
-  GDBusProxy *proxy = G_DBUS_PROXY (initable);
-  GSimpleAsyncResult *simple;
+  AsyncInitData *data = user_data;
 
-  simple = g_simple_async_result_new (G_OBJECT (proxy),
-                                      callback,
-                                      user_data,
-                                      NULL);
+  if (res != NULL)
+    {
+      GError *error;
+      GVariant *result;
 
-  subscribe_to_signals (proxy);
+      error = NULL;
+      result = g_dbus_connection_call_finish (connection,
+                                              res,
+                                              &error);
+      if (result == NULL)
+        {
+          if (error->domain == G_DBUS_ERROR &&
+              error->code == G_DBUS_ERROR_NAME_HAS_NO_OWNER)
+            {
+              g_error_free (error);
+            }
+          else
+            {
+              g_simple_async_result_set_from_error (data->simple, error);
+              g_error_free (error);
+              g_simple_async_result_complete_in_idle (data->simple);
+              async_init_data_free (data);
+              goto out;
+            }
+        }
+      else
+        {
+          g_variant_get (result,
+                         "(s)",
+                         &data->proxy->priv->name_owner);
+          g_variant_unref (result);
+        }
+    }
 
-  if (!(proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES))
+  if (!(data->proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES))
     {
       /* load all properties asynchronously */
-      g_dbus_connection_call (proxy->priv->connection,
-                              proxy->priv->unique_bus_name,
-                              proxy->priv->object_path,
+      g_dbus_connection_call (data->proxy->priv->connection,
+                              data->proxy->priv->name_owner,
+                              data->proxy->priv->object_path,
                               "org.freedesktop.DBus.Properties",
                               "GetAll",
-                              g_variant_new ("(s)", proxy->priv->interface_name),
+                              g_variant_new ("(s)", data->proxy->priv->interface_name),
                               G_VARIANT_TYPE ("(a{sv})"),
                               G_DBUS_CALL_FLAGS_NONE,
                               -1,           /* timeout */
-                              cancellable,
-                              (GAsyncReadyCallback) get_all_cb,
-                              simple);
+                              data->cancellable,
+                              (GAsyncReadyCallback) async_init_get_all_cb,
+                              data);
     }
   else
     {
-      g_simple_async_result_complete_in_idle (simple);
-      g_object_unref (simple);
+      g_simple_async_result_complete_in_idle (data->simple);
+      async_init_data_free (data);
+    }
+
+ out:
+  ;
+}
+
+static void
+async_init_call_get_name_owner (AsyncInitData *data)
+{
+  g_dbus_connection_call (data->proxy->priv->connection,
+                          "org.freedesktop.DBus",  /* name */
+                          "/org/freedesktop/DBus", /* object path */
+                          "org.freedesktop.DBus",  /* interface */
+                          "GetNameOwner",
+                          g_variant_new ("(s)",
+                                         data->proxy->priv->name),
+                          G_VARIANT_TYPE ("(s)"),
+                          G_DBUS_CALL_FLAGS_NONE,
+                          -1,           /* timeout */
+                          data->cancellable,
+                          (GAsyncReadyCallback) async_init_get_name_owner_cb,
+                          data);
+}
+
+static void
+async_init_start_service_by_name_cb (GDBusConnection *connection,
+                                     GAsyncResult    *res,
+                                     gpointer         user_data)
+{
+  AsyncInitData *data = user_data;
+  GError *error;
+  GVariant *result;
+
+  error = NULL;
+  result = g_dbus_connection_call_finish (connection,
+                                          res,
+                                          &error);
+  if (result == NULL)
+    {
+      /* Errors are not unexpected; the bus will reply e.g.
+       *
+       *   org.freedesktop.DBus.Error.ServiceUnknown: The name org.gnome.Epiphany2
+       *   was not provided by any .service files
+       *
+       * This doesn't mean that the name doesn't have an owner, just
+       * that it's not provided by a .service file. So just proceed to
+       * invoke GetNameOwner() if dealing with that error.
+       */
+      if (error->domain == G_DBUS_ERROR &&
+          error->code == G_DBUS_ERROR_SERVICE_UNKNOWN)
+        {
+          g_error_free (error);
+        }
+      else
+        {
+          g_prefix_error (&error,
+                          _("Error calling StartServiceByName for %s: "),
+                          data->proxy->priv->name);
+          goto failed;
+        }
+    }
+  else
+    {
+      guint32 start_service_result;
+      g_variant_get (result,
+                     "(u)",
+                     &start_service_result);
+      g_variant_unref (result);
+      if (start_service_result == 1 ||  /* DBUS_START_REPLY_SUCCESS */
+          start_service_result == 2)    /* DBUS_START_REPLY_ALREADY_RUNNING */
+        {
+          /* continue to invoke GetNameOwner() */
+        }
+      else
+        {
+          error = g_error_new (G_IO_ERROR,
+                               G_IO_ERROR_FAILED,
+                               _("Unexpected reply %d from StartServiceByName(\"%s\") method"),
+                               start_service_result,
+                               data->proxy->priv->name);
+          goto failed;
+        }
+    }
+
+  async_init_call_get_name_owner (data);
+  return;
+
+ failed:
+  g_warn_if_fail (error != NULL);
+  g_simple_async_result_set_from_error (data->simple, error);
+  g_error_free (error);
+  g_simple_async_result_complete_in_idle (data->simple);
+  async_init_data_free (data);
+}
+
+static void
+async_init_call_start_service_by_name (AsyncInitData *data)
+{
+  g_dbus_connection_call (data->proxy->priv->connection,
+                          "org.freedesktop.DBus",  /* name */
+                          "/org/freedesktop/DBus", /* object path */
+                          "org.freedesktop.DBus",  /* interface */
+                          "StartServiceByName",
+                          g_variant_new ("(su)",
+                                         data->proxy->priv->name,
+                                         0),
+                          G_VARIANT_TYPE ("(u)"),
+                          G_DBUS_CALL_FLAGS_NONE,
+                          -1,           /* timeout */
+                          data->cancellable,
+                          (GAsyncReadyCallback) async_init_start_service_by_name_cb,
+                          data);
+}
+
+static void
+async_initable_init_second_async (GAsyncInitable      *initable,
+                                  gint                 io_priority,
+                                  GCancellable        *cancellable,
+                                  GAsyncReadyCallback  callback,
+                                  gpointer             user_data)
+{
+  GDBusProxy *proxy = G_DBUS_PROXY (initable);
+  AsyncInitData *data;
+
+  data = g_new0 (AsyncInitData, 1);
+  data->proxy = g_object_ref (proxy);
+  data->cancellable = cancellable != NULL ? g_object_ref (cancellable) : NULL;
+  data->simple = g_simple_async_result_new (G_OBJECT (proxy),
+                                            callback,
+                                            user_data,
+                                            NULL);
+
+  /* Check name ownership asynchronously - possibly also start the service */
+  if (proxy->priv->name == NULL)
+    {
+      /* Do nothing */
+      async_init_get_name_owner_cb (proxy->priv->connection, NULL, data);
+    }
+  else if (g_dbus_is_unique_name (proxy->priv->name))
+    {
+      proxy->priv->name_owner = g_strdup (proxy->priv->name);
+      async_init_get_name_owner_cb (proxy->priv->connection, NULL, data);
+    }
+  else
+    {
+      if (proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START)
+        {
+          async_init_call_get_name_owner (data);
+        }
+      else
+        {
+          async_init_call_start_service_by_name (data);
+        }
     }
 }
 
 static gboolean
-async_initable_init_finish (GAsyncInitable  *initable,
-                            GAsyncResult    *res,
-                            GError         **error)
+async_initable_init_second_finish (GAsyncInitable  *initable,
+                                   GAsyncResult    *res,
+                                   GError         **error)
 {
   GDBusProxy *proxy = G_DBUS_PROXY (initable);
   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
@@ -999,6 +1311,156 @@ async_initable_init_finish (GAsyncInitable  *initable,
   return ret;
 }
 
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+async_initable_init_first (GAsyncInitable *initable)
+{
+  GDBusProxy *proxy = G_DBUS_PROXY (initable);
+
+  if (!(proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES))
+    {
+      /* subscribe to PropertiesChanged() */
+      proxy->priv->properties_changed_subscriber_id =
+        g_dbus_connection_signal_subscribe (proxy->priv->connection,
+                                            proxy->priv->name,
+                                            "org.freedesktop.DBus.Properties",
+                                            "PropertiesChanged",
+                                            proxy->priv->object_path,
+                                            proxy->priv->interface_name,
+                                            on_properties_changed,
+                                            proxy,
+                                            NULL);
+    }
+
+  if (!(proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS))
+    {
+      /* subscribe to all signals for the object */
+      proxy->priv->signals_subscriber_id =
+        g_dbus_connection_signal_subscribe (proxy->priv->connection,
+                                            proxy->priv->name,
+                                            proxy->priv->interface_name,
+                                            NULL,                        /* member */
+                                            proxy->priv->object_path,
+                                            NULL,                        /* arg0 */
+                                            on_signal_received,
+                                            proxy,
+                                            NULL);
+    }
+
+  if (proxy->priv->name != NULL && !g_dbus_is_unique_name (proxy->priv->name))
+    {
+      proxy->priv->name_owner_changed_subscription_id =
+        g_dbus_connection_signal_subscribe (proxy->priv->connection,
+                                            "org.freedesktop.DBus",  /* name */
+                                            "org.freedesktop.DBus",  /* interface */
+                                            "NameOwnerChanged",      /* signal name */
+                                            "/org/freedesktop/DBus", /* path */
+                                            proxy->priv->name,       /* arg0 */
+                                            on_name_owner_changed,
+                                            proxy,
+                                            NULL);
+    }
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/* initialization is split into two parts - the first is the
+ * non-blocing part that requires the callers GMainContext - the
+ * second is a blocking part async part that doesn't require the
+ * callers GMainContext.. we do this split so the code can be reused
+ * in the GInitable implementation below.
+ *
+ * Note that obtaining a GDBusConnection is not shared between the two
+ * paths.
+ */
+
+typedef struct
+{
+  GDBusProxy          *proxy;
+  gint                 io_priority;
+  GCancellable        *cancellable;
+  GAsyncReadyCallback  callback;
+  gpointer             user_data;
+} GetConnectionData;
+
+static void
+get_connection_cb (GObject       *source_object,
+                   GAsyncResult  *res,
+                   gpointer       user_data)
+{
+  GetConnectionData *data = user_data;
+  GError *error;
+
+  data->proxy->priv->connection = g_bus_get_finish (res, &error);
+  if (data->proxy->priv->connection == NULL)
+    {
+      GSimpleAsyncResult *simple;
+      simple = g_simple_async_result_new (G_OBJECT (data->proxy),
+                                          data->callback,
+                                          data->user_data,
+                                          NULL);
+      g_simple_async_result_set_from_error (simple, error);
+      g_error_free (error);
+      g_simple_async_result_complete_in_idle (simple);
+      g_object_unref (simple);
+    }
+  else
+    {
+      async_initable_init_first (G_ASYNC_INITABLE (data->proxy));
+      async_initable_init_second_async (G_ASYNC_INITABLE (data->proxy),
+                                        data->io_priority,
+                                        data->cancellable,
+                                        data->callback,
+                                        data->user_data);
+    }
+
+  if (data->cancellable != NULL)
+    g_object_unref (data->cancellable);
+  g_free (data);
+}
+
+static void
+async_initable_init_async (GAsyncInitable      *initable,
+                           gint                 io_priority,
+                           GCancellable        *cancellable,
+                           GAsyncReadyCallback  callback,
+                           gpointer             user_data)
+{
+  GDBusProxy *proxy = G_DBUS_PROXY (initable);
+
+  if (proxy->priv->bus_type != G_BUS_TYPE_NONE)
+    {
+      GetConnectionData *data;
+
+      g_assert (proxy->priv->connection == NULL);
+
+      data = g_new0 (GetConnectionData, 1);
+      data->proxy = proxy;
+      data->io_priority = io_priority;
+      data->cancellable = cancellable != NULL ? g_object_ref (cancellable) : NULL;
+      data->callback = callback;
+      data->user_data = user_data;
+      g_bus_get (proxy->priv->bus_type,
+                 cancellable,
+                 get_connection_cb,
+                 data);
+    }
+  else
+    {
+      async_initable_init_first (initable);
+      async_initable_init_second_async (initable, io_priority, cancellable, callback, user_data);
+    }
+}
+
+static gboolean
+async_initable_init_finish (GAsyncInitable  *initable,
+                            GAsyncResult    *res,
+                            GError         **error)
+{
+  return async_initable_init_second_finish (initable, res, error);
+}
+
 static void
 async_initable_iface_init (GAsyncInitableIface *async_initable_iface)
 {
@@ -1008,42 +1470,135 @@ async_initable_iface_init (GAsyncInitableIface *async_initable_iface)
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+typedef struct
+{
+  GMainContext *context;
+  GMainLoop *loop;
+  GAsyncResult *res;
+} InitableAsyncInitableData;
+
+static void
+async_initable_init_async_cb (GObject      *source_object,
+                              GAsyncResult *res,
+                              gpointer      user_data)
+{
+  InitableAsyncInitableData *data = user_data;
+  data->res = g_object_ref (res);
+  g_main_loop_quit (data->loop);
+}
+
+/* Simply reuse the GAsyncInitable implementation but run the first
+ * part (that is non-blocking and requires the callers GMainContext)
+ * with the callers GMainContext.. and the second with a private
+ * GMainContext (bug 621310 is slightly related).
+ *
+ * Note that obtaining a GDBusConnection is not shared between the two
+ * paths.
+ */
+static gboolean
+initable_init (GInitable     *initable,
+               GCancellable  *cancellable,
+               GError       **error)
+{
+  GDBusProxy *proxy = G_DBUS_PROXY (initable);
+  InitableAsyncInitableData *data;
+  gboolean ret;
+
+  ret = FALSE;
+
+  if (proxy->priv->bus_type != G_BUS_TYPE_NONE)
+    {
+      g_assert (proxy->priv->connection == NULL);
+      proxy->priv->connection = g_bus_get_sync (proxy->priv->bus_type,
+                                                cancellable,
+                                                error);
+      if (proxy->priv->connection == NULL)
+        goto out;
+    }
+
+  async_initable_init_first (G_ASYNC_INITABLE (initable));
+
+  data = g_new0 (InitableAsyncInitableData, 1);
+  data->context = g_main_context_new ();
+  data->loop = g_main_loop_new (data->context, FALSE);
+
+  g_main_context_push_thread_default (data->context);
+
+  async_initable_init_second_async (G_ASYNC_INITABLE (initable),
+                                    G_PRIORITY_DEFAULT,
+                                    cancellable,
+                                    async_initable_init_async_cb,
+                                    data);
+
+  g_main_loop_run (data->loop);
+
+  ret = async_initable_init_second_finish (G_ASYNC_INITABLE (initable),
+                                           data->res,
+                                           error);
+
+  g_main_context_pop_thread_default (data->context);
+
+  g_main_context_unref (data->context);
+  g_main_loop_unref (data->loop);
+  g_object_unref (data->res);
+  g_free (data);
+
+ out:
+
+  return ret;
+}
+
+static void
+initable_iface_init (GInitableIface *initable_iface)
+{
+  initable_iface->init = initable_init;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 /**
  * g_dbus_proxy_new:
  * @connection: A #GDBusConnection.
- * @object_type: Either #G_TYPE_DBUS_PROXY or the #GType for the #GDBusProxy<!-- -->-derived type of proxy to create.
  * @flags: Flags used when constructing the proxy.
  * @info: A #GDBusInterfaceInfo specifying the minimal interface that @proxy conforms to or %NULL.
- * @unique_bus_name: A unique bus name or %NULL if @connection is not a message bus connection.
+ * @name: A bus name (well-known or unique) or %NULL if @connection is not a message bus connection.
  * @object_path: An object path.
  * @interface_name: A D-Bus interface name.
  * @cancellable: A #GCancellable or %NULL.
  * @callback: Callback function to invoke when the proxy is ready.
  * @user_data: User data to pass to @callback.
  *
- * Creates a proxy for accessing @interface_name on the remote object at @object_path
- * owned by @unique_bus_name at @connection and asynchronously loads D-Bus properties unless the
- * #G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES flag is used. Connect to the
- * #GDBusProxy::g-properties-changed signal to get notified about property changes.
+ * Creates a proxy for accessing @interface_name on the remote object
+ * at @object_path owned by @name at @connection and asynchronously
+ * loads D-Bus properties unless the
+ * #G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES flag is used. Connect to
+ * the #GDBusProxy::g-properties-changed signal to get notified about
+ * property changes.
  *
  * If the #G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS flag is not set, also sets up
  * match rules for signals. Connect to the #GDBusProxy::g-signal signal
  * to handle signals from the remote object.
  *
+ * If @name is a well-known name and the
+ * #G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START flag isn't set and no name
+ * owner currently exists, the message bus will be requested to launch
+ * a name owner for the name.
+ *
  * This is a failable asynchronous constructor - when the proxy is
  * ready, @callback will be invoked and you can use
  * g_dbus_proxy_new_finish() to get the result.
  *
  * See g_dbus_proxy_new_sync() and for a synchronous version of this constructor.
  *
+ * See <xref linkend="gdbus-wellknown-proxy"/> for an example of how #GDBusProxy can be used.
+ *
  * Since: 2.26
  */
 void
 g_dbus_proxy_new (GDBusConnection     *connection,
-                  GType                object_type,
                   GDBusProxyFlags      flags,
                   GDBusInterfaceInfo  *info,
-                  const gchar         *unique_bus_name,
+                  const gchar         *name,
                   const gchar         *object_path,
                   const gchar         *interface_name,
                   GCancellable        *cancellable,
@@ -1051,20 +1606,18 @@ g_dbus_proxy_new (GDBusConnection     *connection,
                   gpointer             user_data)
 {
   g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
-  g_return_if_fail (g_type_is_a (object_type, G_TYPE_DBUS_PROXY));
-  g_return_if_fail ((unique_bus_name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) ||
-                    g_dbus_is_unique_name (unique_bus_name));
+  g_return_if_fail ((name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) || g_dbus_is_name (name));
   g_return_if_fail (g_variant_is_object_path (object_path));
   g_return_if_fail (g_dbus_is_interface_name (interface_name));
 
-  g_async_initable_new_async (object_type,
+  g_async_initable_new_async (G_TYPE_DBUS_PROXY,
                               G_PRIORITY_DEFAULT,
                               cancellable,
                               callback,
                               user_data,
                               "g-flags", flags,
                               "g-interface-info", info,
-                              "g-unique-bus-name", unique_bus_name,
+                              "g-name", name,
                               "g-connection", connection,
                               "g-object-path", object_path,
                               "g-interface-name", interface_name,
@@ -1103,42 +1656,45 @@ g_dbus_proxy_new_finish (GAsyncResult  *res,
     return NULL;
 }
 
-
-/* ---------------------------------------------------------------------------------------------------- */
-
 /**
  * g_dbus_proxy_new_sync:
  * @connection: A #GDBusConnection.
- * @object_type: Either #G_TYPE_DBUS_PROXY or the #GType for the #GDBusProxy<!-- -->-derived type of proxy to create.
  * @flags: Flags used when constructing the proxy.
  * @info: A #GDBusInterfaceInfo specifying the minimal interface that @proxy conforms to or %NULL.
- * @unique_bus_name: A unique bus name or %NULL if @connection is not a message bus connection.
+ * @name: A bus name (well-known or unique) or %NULL if @connection is not a message bus connection.
  * @object_path: An object path.
  * @interface_name: A D-Bus interface name.
  * @cancellable: A #GCancellable or %NULL.
  * @error: Return location for error or %NULL.
  *
- * Creates a proxy for accessing @interface_name on the remote object at @object_path
- * owned by @unique_bus_name at @connection and synchronously loads D-Bus properties unless the
+ * Creates a proxy for accessing @interface_name on the remote object
+ * at @object_path owned by @name at @connection and synchronously
+ * loads D-Bus properties unless the
  * #G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES flag is used.
  *
  * If the #G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS flag is not set, also sets up
  * match rules for signals. Connect to the #GDBusProxy::g-signal signal
  * to handle signals from the remote object.
  *
+ * If @name is a well-known name and the
+ * #G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START flag isn't set and no name
+ * owner currently exists, the message bus will be requested to launch
+ * a name owner for the name.
+ *
  * This is a synchronous failable constructor. See g_dbus_proxy_new()
  * and g_dbus_proxy_new_finish() for the asynchronous version.
  *
+ * See <xref linkend="gdbus-wellknown-proxy"/> for an example of how #GDBusProxy can be used.
+ *
  * Returns: A #GDBusProxy or %NULL if error is set. Free with g_object_unref().
  *
  * Since: 2.26
  */
 GDBusProxy *
 g_dbus_proxy_new_sync (GDBusConnection     *connection,
-                       GType                object_type,
                        GDBusProxyFlags      flags,
                        GDBusInterfaceInfo  *info,
-                       const gchar         *unique_bus_name,
+                       const gchar         *name,
                        const gchar         *object_path,
                        const gchar         *interface_name,
                        GCancellable        *cancellable,
@@ -1147,18 +1703,17 @@ g_dbus_proxy_new_sync (GDBusConnection     *connection,
   GInitable *initable;
 
   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
-  g_return_val_if_fail (g_type_is_a (object_type, G_TYPE_DBUS_PROXY), NULL);
-  g_return_val_if_fail ((unique_bus_name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) ||
-                        g_dbus_is_unique_name (unique_bus_name), NULL);
+  g_return_val_if_fail ((name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) ||
+                        g_dbus_is_name (name), NULL);
   g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
   g_return_val_if_fail (g_dbus_is_interface_name (interface_name), NULL);
 
-  initable = g_initable_new (object_type,
+  initable = g_initable_new (G_TYPE_DBUS_PROXY,
                              cancellable,
                              error,
                              "g-flags", flags,
                              "g-interface-info", info,
-                             "g-unique-bus-name", unique_bus_name,
+                             "g-name", name,
                              "g-connection", connection,
                              "g-object-path", object_path,
                              "g-interface-name", interface_name,
@@ -1172,6 +1727,124 @@ g_dbus_proxy_new_sync (GDBusConnection     *connection,
 /* ---------------------------------------------------------------------------------------------------- */
 
 /**
+ * g_dbus_proxy_new_for_bus:
+ * @bus_type: A #GBusType.
+ * @flags: Flags used when constructing the proxy.
+ * @info: A #GDBusInterfaceInfo specifying the minimal interface that @proxy conforms to or %NULL.
+ * @name: A bus name (well-known or unique).
+ * @object_path: An object path.
+ * @interface_name: A D-Bus interface name.
+ * @cancellable: A #GCancellable or %NULL.
+ * @callback: Callback function to invoke when the proxy is ready.
+ * @user_data: User data to pass to @callback.
+ *
+ * Like g_dbus_proxy_new() but takes a #GBusType instead of a #GDBusConnection.
+ *
+ * See <xref linkend="gdbus-wellknown-proxy"/> for an example of how #GDBusProxy can be used.
+ *
+ * Since: 2.26
+ */
+void
+g_dbus_proxy_new_for_bus (GBusType             bus_type,
+                          GDBusProxyFlags      flags,
+                          GDBusInterfaceInfo  *info,
+                          const gchar         *name,
+                          const gchar         *object_path,
+                          const gchar         *interface_name,
+                          GCancellable        *cancellable,
+                          GAsyncReadyCallback  callback,
+                          gpointer             user_data)
+{
+  g_return_if_fail (g_dbus_is_name (name));
+  g_return_if_fail (g_variant_is_object_path (object_path));
+  g_return_if_fail (g_dbus_is_interface_name (interface_name));
+
+  g_async_initable_new_async (G_TYPE_DBUS_PROXY,
+                              G_PRIORITY_DEFAULT,
+                              cancellable,
+                              callback,
+                              user_data,
+                              "g-flags", flags,
+                              "g-interface-info", info,
+                              "g-name", name,
+                              "g-bus-type", bus_type,
+                              "g-object-path", object_path,
+                              "g-interface-name", interface_name,
+                              NULL);
+}
+
+/**
+ * g_dbus_proxy_new_for_bus_finish:
+ * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to g_dbus_proxy_new_for_bus().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes creating a #GDBusProxy.
+ *
+ * Returns: A #GDBusProxy or %NULL if @error is set. Free with g_object_unref().
+ *
+ * Since: 2.26
+ */
+GDBusProxy *
+g_dbus_proxy_new_for_bus_finish (GAsyncResult  *res,
+                                 GError       **error)
+{
+  return g_dbus_proxy_new_finish (res, error);
+}
+
+/**
+ * g_dbus_proxy_new_for_bus_sync:
+ * @bus_type: A #GBusType.
+ * @flags: Flags used when constructing the proxy.
+ * @info: A #GDBusInterfaceInfo specifying the minimal interface that @proxy conforms to or %NULL.
+ * @name: A bus name (well-known or unique).
+ * @object_path: An object path.
+ * @interface_name: A D-Bus interface name.
+ * @cancellable: A #GCancellable or %NULL.
+ * @error: Return location for error or %NULL.
+ *
+ * Like g_dbus_proxy_new_sync() but takes a #GBusType instead of a #GDBusConnection.
+ *
+ * See <xref linkend="gdbus-wellknown-proxy"/> for an example of how #GDBusProxy can be used.
+ *
+ * Returns: A #GDBusProxy or %NULL if error is set. Free with g_object_unref().
+ *
+ * Since: 2.26
+ */
+GDBusProxy *
+g_dbus_proxy_new_for_bus_sync (GBusType             bus_type,
+                               GDBusProxyFlags      flags,
+                               GDBusInterfaceInfo  *info,
+                               const gchar         *name,
+                               const gchar         *object_path,
+                               const gchar         *interface_name,
+                               GCancellable        *cancellable,
+                               GError             **error)
+{
+  GInitable *initable;
+
+  g_return_val_if_fail (g_dbus_is_name (name), NULL);
+  g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
+  g_return_val_if_fail (g_dbus_is_interface_name (interface_name), NULL);
+
+  initable = g_initable_new (G_TYPE_DBUS_PROXY,
+                             cancellable,
+                             error,
+                             "g-flags", flags,
+                             "g-interface-info", info,
+                             "g-name", name,
+                             "g-bus-type", bus_type,
+                             "g-object-path", object_path,
+                             "g-interface-name", interface_name,
+                             NULL);
+  if (initable != NULL)
+    return G_DBUS_PROXY (initable);
+  else
+    return NULL;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
  * g_dbus_proxy_get_connection:
  * @proxy: A #GDBusProxy.
  *
@@ -1206,20 +1879,40 @@ g_dbus_proxy_get_flags (GDBusProxy *proxy)
 }
 
 /**
- * g_dbus_proxy_get_unique_bus_name:
+ * g_dbus_proxy_get_name:
  * @proxy: A #GDBusProxy.
  *
- * Gets the unique bus name @proxy is for.
+ * Gets the name that @proxy was constructed for.
  *
  * Returns: A string owned by @proxy. Do not free.
  *
  * Since: 2.26
  */
 const gchar *
-g_dbus_proxy_get_unique_bus_name (GDBusProxy *proxy)
+g_dbus_proxy_get_name (GDBusProxy *proxy)
+{
+  g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
+  return proxy->priv->name;
+}
+
+/**
+ * g_dbus_proxy_get_name_owner:
+ * @proxy: A #GDBusProxy.
+ *
+ * The unique name that owns the name that @proxy is for or %NULL if
+ * no-one currently owns that name. You may connect to the
+ * #GObject::notify signal to track changes to the
+ * #GDBusProxy:g-name-owner property.
+ *
+ * Returns: The name owner or %NULL if no name owner exists. Free with g_free().
+ *
+ * Since: 2.26
+ */
+gchar *
+g_dbus_proxy_get_name_owner (GDBusProxy *proxy)
 {
   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
-  return proxy->priv->unique_bus_name;
+  return g_strdup (proxy->priv->name_owner);
 }
 
 /**
@@ -1528,7 +2221,7 @@ g_dbus_proxy_call (GDBusProxy          *proxy,
     reply_type = NULL;
 
   g_dbus_connection_call (proxy->priv->connection,
-                          proxy->priv->unique_bus_name,
+                          proxy->priv->name_owner,
                           proxy->priv->object_path,
                           target_interface_name,
                           target_method_name,
@@ -1681,7 +2374,7 @@ g_dbus_proxy_call_sync (GDBusProxy      *proxy,
     reply_type = NULL;
 
   ret = g_dbus_connection_call_sync (proxy->priv->connection,
-                                     proxy->priv->unique_bus_name,
+                                     proxy->priv->name_owner,
                                      proxy->priv->object_path,
                                      target_interface_name,
                                      target_method_name,
diff --git a/gio/gdbusproxy.h b/gio/gdbusproxy.h
index 9279353..5294229 100644
--- a/gio/gdbusproxy.h
+++ b/gio/gdbusproxy.h
@@ -95,10 +95,9 @@ struct _GDBusProxyClass
 
 GType            g_dbus_proxy_get_type                  (void) G_GNUC_CONST;
 void             g_dbus_proxy_new                       (GDBusConnection     *connection,
-                                                         GType                object_type,
                                                          GDBusProxyFlags      flags,
                                                          GDBusInterfaceInfo *info,
-                                                         const gchar         *unique_bus_name,
+                                                         const gchar         *name,
                                                          const gchar         *object_path,
                                                          const gchar         *interface_name,
                                                          GCancellable        *cancellable,
@@ -107,17 +106,36 @@ void             g_dbus_proxy_new                       (GDBusConnection     *co
 GDBusProxy      *g_dbus_proxy_new_finish                (GAsyncResult        *res,
                                                          GError             **error);
 GDBusProxy      *g_dbus_proxy_new_sync                  (GDBusConnection     *connection,
-                                                         GType                object_type,
                                                          GDBusProxyFlags      flags,
                                                          GDBusInterfaceInfo *info,
-                                                         const gchar         *unique_bus_name,
+                                                         const gchar         *name,
+                                                         const gchar         *object_path,
+                                                         const gchar         *interface_name,
+                                                         GCancellable        *cancellable,
+                                                         GError             **error);
+void             g_dbus_proxy_new_for_bus               (GBusType             bus_type,
+                                                         GDBusProxyFlags      flags,
+                                                         GDBusInterfaceInfo *info,
+                                                         const gchar         *name,
+                                                         const gchar         *object_path,
+                                                         const gchar         *interface_name,
+                                                         GCancellable        *cancellable,
+                                                         GAsyncReadyCallback  callback,
+                                                         gpointer             user_data);
+GDBusProxy      *g_dbus_proxy_new_for_bus_finish        (GAsyncResult        *res,
+                                                         GError             **error);
+GDBusProxy      *g_dbus_proxy_new_for_bus_sync          (GBusType             bus_type,
+                                                         GDBusProxyFlags      flags,
+                                                         GDBusInterfaceInfo *info,
+                                                         const gchar         *name,
                                                          const gchar         *object_path,
                                                          const gchar         *interface_name,
                                                          GCancellable        *cancellable,
                                                          GError             **error);
 GDBusConnection *g_dbus_proxy_get_connection            (GDBusProxy          *proxy);
 GDBusProxyFlags  g_dbus_proxy_get_flags                 (GDBusProxy          *proxy);
-const gchar     *g_dbus_proxy_get_unique_bus_name       (GDBusProxy          *proxy);
+const gchar     *g_dbus_proxy_get_name                  (GDBusProxy          *proxy);
+gchar           *g_dbus_proxy_get_name_owner            (GDBusProxy          *proxy);
 const gchar     *g_dbus_proxy_get_object_path           (GDBusProxy          *proxy);
 const gchar     *g_dbus_proxy_get_interface_name        (GDBusProxy          *proxy);
 gint             g_dbus_proxy_get_default_timeout       (GDBusProxy          *proxy);
diff --git a/gio/gio.h b/gio/gio.h
index 11cb725..a80ed84 100644
--- a/gio/gio.h
+++ b/gio/gio.h
@@ -52,7 +52,6 @@
 #include <gio/gdbusnameowning.h>
 #include <gio/gdbusnamewatching.h>
 #include <gio/gdbusproxy.h>
-#include <gio/gdbusproxywatching.h>
 #include <gio/gdbusserver.h>
 #include <gio/gdbusutils.h>
 #include <gio/gdrive.h>
diff --git a/gio/gio.symbols b/gio/gio.symbols
index 3f61cff..689f96e 100644
--- a/gio/gio.symbols
+++ b/gio/gio.symbols
@@ -1695,6 +1695,9 @@ g_dbus_proxy_get_type G_GNUC_CONST
 g_dbus_proxy_new
 g_dbus_proxy_new_finish
 g_dbus_proxy_new_sync
+g_dbus_proxy_new_for_bus
+g_dbus_proxy_new_for_bus_finish
+g_dbus_proxy_new_for_bus_sync
 g_dbus_proxy_get_cached_property
 g_dbus_proxy_set_cached_property
 g_dbus_proxy_get_cached_property_names
@@ -1704,7 +1707,8 @@ g_dbus_proxy_get_flags
 g_dbus_proxy_get_interface_info
 g_dbus_proxy_get_interface_name
 g_dbus_proxy_get_object_path
-g_dbus_proxy_get_unique_bus_name
+g_dbus_proxy_get_name
+g_dbus_proxy_get_name_owner
 g_dbus_proxy_set_default_timeout
 g_dbus_proxy_set_interface_info
 g_dbus_proxy_call
@@ -1713,16 +1717,6 @@ g_dbus_proxy_call_sync
 #endif
 #endif
 
-#if IN_HEADER(__G_DBUS_PROXY_WATCHING_H__)
-#if IN_FILE(__G_DBUS_PROXY_WATCHING_C__)
-g_bus_watch_proxy
-g_bus_watch_proxy_on_connection
-g_bus_unwatch_proxy
-g_bus_watch_proxy_with_closures
-g_bus_watch_proxy_on_connection_with_closures
-#endif
-#endif
-
 #if IN_HEADER(__G_DBUS_SERVER_H__)
 #if IN_FILE(__G_DBUS_SERVER_C__)
 g_dbus_server_get_type G_GNUC_CONST
diff --git a/gio/gioenums.h b/gio/gioenums.h
index efd08d5..9d1e126 100644
--- a/gio/gioenums.h
+++ b/gio/gioenums.h
@@ -741,6 +741,7 @@ typedef enum {
 /**
  * GBusType:
  * @G_BUS_TYPE_STARTER: An alias for the message bus that activated the process, if any.
+ * @G_BUS_TYPE_NONE: Not a message bus.
  * @G_BUS_TYPE_SYSTEM: The system-wide message bus.
  * @G_BUS_TYPE_SESSION: The login session message bus.
  *
@@ -750,7 +751,8 @@ typedef enum {
  */
 typedef enum
 {
-  G_BUS_TYPE_STARTER = 0,
+  G_BUS_TYPE_STARTER = -1,
+  G_BUS_TYPE_NONE = 0,
   G_BUS_TYPE_SYSTEM  = 1,
   G_BUS_TYPE_SESSION = 2
 } GBusType;
@@ -795,6 +797,9 @@ typedef enum
  * @G_DBUS_PROXY_FLAGS_NONE: No flags set.
  * @G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES: Don't load properties.
  * @G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS: Don't connect to signals on the remote object.
+ * @G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START: If not set and the proxy if for a well-known name,
+ * then request the bus to launch an owner for the name if no-one owns the name. This flag can
+ * only be used in proxies for well-known names.
  *
  * Flags used when constructing an instance of a #GDBusProxy derived class.
  *
@@ -802,9 +807,10 @@ typedef enum
  */
 typedef enum
 {
-  G_DBUS_PROXY_FLAGS_NONE = 0,                        /*< nick=none >*/
-  G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES = (1<<0), /*< nick=do-not-load-properties >*/
-  G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS = (1<<1) /*< nick=do-not-connect-signals >*/
+  G_DBUS_PROXY_FLAGS_NONE = 0,
+  G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES = (1<<0),
+  G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS = (1<<1),
+  G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START = (1<<2)
 } GDBusProxyFlags;
 
 /**
diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am
index 99d2db5..0abfa5a 100644
--- a/gio/tests/Makefile.am
+++ b/gio/tests/Makefile.am
@@ -48,6 +48,7 @@ TEST_PROGS +=			\
 	gdbus-connection	\
 	gdbus-names		\
 	gdbus-proxy		\
+	gdbus-proxy-well-known-name \
 	gdbus-introspection	\
 	gdbus-threading		\
 	gdbus-export		\
@@ -208,6 +209,9 @@ gdbus_names_LDADD = $(progs_ldadd)
 gdbus_proxy_SOURCES = gdbus-proxy.c gdbus-sessionbus.c gdbus-sessionbus.h gdbus-tests.h gdbus-tests.c
 gdbus_proxy_LDADD = $(progs_ldadd)
 
+gdbus_proxy_well_known_name_SOURCES = gdbus-proxy-well-known-name.c gdbus-sessionbus.c gdbus-sessionbus.h gdbus-tests.h gdbus-tests.c
+gdbus_proxy_well_known_name_LDADD = $(progs_ldadd)
+
 gdbus_introspection_SOURCES = gdbus-introspection.c gdbus-sessionbus.c gdbus-sessionbus.h gdbus-tests.h gdbus-tests.c
 gdbus_introspection_LDADD = $(progs_ldadd)
 
diff --git a/gio/tests/gdbus-connection.c b/gio/tests/gdbus-connection.c
index 2a48126..15fca70 100644
--- a/gio/tests/gdbus-connection.c
+++ b/gio/tests/gdbus-connection.c
@@ -360,9 +360,11 @@ test_connection_signals (void)
   GDBusConnection *c2;
   GDBusConnection *c3;
   guint s1;
+  guint s1b;
   guint s2;
   guint s3;
   gint count_s1;
+  gint count_s1b;
   gint count_s2;
   gint count_name_owner_changed;
   GError *error;
@@ -425,11 +427,26 @@ test_connection_signals (void)
                                            test_connection_signal_handler,
                                            &count_name_owner_changed,
                                            NULL);
+  /* Note that s1b is *just like* s1 - this is to catch a bug where N
+   * subscriptions of the same rule causes N calls to each of the N
+   * subscriptions instead of just 1 call to each of the N subscriptions.
+   */
+  s1b = g_dbus_connection_signal_subscribe (c1,
+                                           ":1.2",
+                                           "org.gtk.GDBus.ExampleInterface",
+                                           "Foo",
+                                           "/org/gtk/GDBus/ExampleInterface",
+                                           NULL,
+                                           test_connection_signal_handler,
+                                           &count_s1b,
+                                           NULL);
   g_assert (s1 != 0);
+  g_assert (s1b != 0);
   g_assert (s2 != 0);
   g_assert (s3 != 0);
 
   count_s1 = 0;
+  count_s1b = 0;
   count_s2 = 0;
   count_name_owner_changed = 0;
 
@@ -480,7 +497,7 @@ test_connection_signals (void)
                                        &error);
   g_assert_no_error (error);
   g_assert (ret);
-  while (!(count_s1 == 1 && count_s2 == 1))
+  while (!(count_s1 >= 1 && count_s2 >= 1))
     g_main_loop_run (loop);
   g_assert_cmpint (count_s1, ==, 1);
   g_assert_cmpint (count_s2, ==, 1);
@@ -510,7 +527,7 @@ test_connection_signals (void)
   guint quit_mainloop_id;
   quit_mainloop_fired = FALSE;
   quit_mainloop_id = g_timeout_add (5000, test_connection_signal_quit_mainloop, &quit_mainloop_fired);
-  while (count_name_owner_changed != 2 && !quit_mainloop_fired)
+  while (count_name_owner_changed < 2 && !quit_mainloop_fired)
     g_main_loop_run (loop);
   g_source_remove (quit_mainloop_id);
   g_assert_cmpint (count_s1, ==, 1);
@@ -520,6 +537,7 @@ test_connection_signals (void)
   g_dbus_connection_signal_unsubscribe (c1, s1);
   g_dbus_connection_signal_unsubscribe (c1, s2);
   g_dbus_connection_signal_unsubscribe (c1, s3);
+  g_dbus_connection_signal_unsubscribe (c1, s1b);
 
   _g_object_wait_for_single_ref (c1);
   _g_object_wait_for_single_ref (c2);
diff --git a/gio/tests/gdbus-example-proxy-subclass.c b/gio/tests/gdbus-example-proxy-subclass.c
index b5ee9f8..fb1a528 100644
--- a/gio/tests/gdbus-example-proxy-subclass.c
+++ b/gio/tests/gdbus-example-proxy-subclass.c
@@ -350,92 +350,9 @@ accounts_user_frobnicate_finish (AccountsUser        *user,
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
-/* Example usage of the AccountsUser type */
-/* ---------------------------------------------------------------------------------------------------- */
-
-static void
-print_user (AccountsUser *user)
-{
-  g_print ("  user-name       = `%s'\n", accounts_user_get_user_name (user));
-  g_print ("  real-name       = `%s'\n", accounts_user_get_real_name (user));
-  g_print ("  automatic-login = %s\n", accounts_user_get_automatic_login (user) ? "true" : "false");
-}
-
-static void
-on_changed (AccountsUser *user,
-            gpointer      user_data)
-{
-  g_print ("+++ Received the AccountsUser::changed signal\n");
-  print_user (user);
-}
-
-static void
-on_notify (GObject    *object,
-           GParamSpec *pspec,
-           gpointer    user_data)
-{
-  AccountsUser *user = ACCOUNTS_USER (object);
-  g_print ("+++ Received the GObject::notify signal for property `%s'\n",
-           pspec->name);
-  print_user (user);
-}
-
-static void
-on_proxy_appeared (GDBusConnection *connection,
-                   const gchar     *name,
-                   const gchar     *name_owner,
-                   GDBusProxy      *proxy,
-                   gpointer         user_data)
-{
-  AccountsUser *user = ACCOUNTS_USER (proxy);
-
-  g_print ("+++ Acquired proxy for user\n");
-  print_user (user);
-
-  g_signal_connect (proxy,
-                    "notify",
-                    G_CALLBACK (on_notify),
-                    NULL);
-  g_signal_connect (user,
-                    "changed",
-                    G_CALLBACK (on_changed),
-                    NULL);
-}
-
-static void
-on_proxy_vanished (GDBusConnection *connection,
-                   const gchar     *name,
-                   gpointer         user_data)
-{
-  g_print ("--- Cannot create proxy for user: no remote object\n");
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
 
 gint
 main (gint argc, gchar *argv[])
 {
-  guint watcher_id;
-  GMainLoop *loop;
-
-  g_type_init ();
-
-  watcher_id = g_bus_watch_proxy (G_BUS_TYPE_SYSTEM,
-                                  "org.freedesktop.Accounts",
-                                  G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
-                                  "/org/freedesktop/Accounts/User500",
-                                  "org.freedesktop.Accounts.User",
-                                  ACCOUNTS_TYPE_USER,
-                                  G_DBUS_PROXY_FLAGS_NONE,
-                                  on_proxy_appeared,
-                                  on_proxy_vanished,
-                                  NULL,
-                                  NULL);
-
-  loop = g_main_loop_new (NULL, FALSE);
-  g_main_loop_run (loop);
-  g_main_loop_unref (loop);
-  g_bus_unwatch_proxy (watcher_id);
-
   return 0;
 }
diff --git a/gio/tests/gdbus-example-watch-proxy.c b/gio/tests/gdbus-example-watch-proxy.c
index e5b844d..c66826d 100644
--- a/gio/tests/gdbus-example-watch-proxy.c
+++ b/gio/tests/gdbus-example-watch-proxy.c
@@ -4,7 +4,7 @@ static gchar *opt_name         = NULL;
 static gchar *opt_object_path  = NULL;
 static gchar *opt_interface    = NULL;
 static gboolean opt_system_bus = FALSE;
-static gboolean opt_auto_start = FALSE;
+static gboolean opt_no_auto_start = FALSE;
 static gboolean opt_no_properties = FALSE;
 
 static GOptionEntry opt_entries[] =
@@ -13,11 +13,13 @@ static GOptionEntry opt_entries[] =
   { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_object_path, "Object path of the remote object", NULL },
   { "interface", 'i', 0, G_OPTION_ARG_STRING, &opt_interface, "D-Bus interface of remote object", NULL },
   { "system-bus", 's', 0, G_OPTION_ARG_NONE, &opt_system_bus, "Use the system-bus instead of the session-bus", NULL },
-  { "auto-start", 'a', 0, G_OPTION_ARG_NONE, &opt_auto_start, "Instruct the bus to launch an owner for the name", NULL},
+  { "no-auto-start", 'a', 0, G_OPTION_ARG_NONE, &opt_no_auto_start, "Don't instruct the bus to launch an owner for the name", NULL},
   { "no-properties", 'p', 0, G_OPTION_ARG_NONE, &opt_no_properties, "Do not load properties", NULL},
   { NULL}
 };
 
+static GMainLoop *loop = NULL;
+
 static void
 print_properties (GDBusProxy *proxy)
 {
@@ -100,64 +102,62 @@ on_signal (GDBusProxy *proxy,
 }
 
 static void
-on_proxy_appeared (GDBusConnection *connection,
-                   const gchar     *name,
-                   const gchar     *name_owner,
-                   GDBusProxy      *proxy,
-                   gpointer         user_data)
+print_proxy (GDBusProxy *proxy)
 {
-  g_print ("+++ Acquired proxy object for remote object owned by %s\n"
-           "    bus:          %s\n"
-           "    name:         %s\n"
-           "    object path:  %s\n"
-           "    interface:    %s\n",
-           name_owner,
-           opt_system_bus ? "System Bus" : "Session Bus",
-           opt_name,
-           opt_object_path,
-           opt_interface);
-
-  print_properties (proxy);
+  gchar *name_owner;
 
-  g_signal_connect (proxy,
-                    "g-properties-changed",
-                    G_CALLBACK (on_properties_changed),
-                    NULL);
-
-  g_signal_connect (proxy,
-                    "g-signal",
-                    G_CALLBACK (on_signal),
-                    NULL);
+  name_owner = g_dbus_proxy_get_name_owner (proxy);
+  if (name_owner != NULL)
+    {
+      g_print ("+++ Proxy object points to remote object owned by %s\n"
+               "    bus:          %s\n"
+               "    name:         %s\n"
+               "    object path:  %s\n"
+               "    interface:    %s\n",
+               name_owner,
+               opt_system_bus ? "System Bus" : "Session Bus",
+               opt_name,
+               opt_object_path,
+               opt_interface);
+      print_properties (proxy);
+    }
+  else
+    {
+      g_print ("--- Proxy object is inert - there is no name owner for the name\n"
+               "    bus:          %s\n"
+               "    name:         %s\n"
+               "    object path:  %s\n"
+               "    interface:    %s\n",
+               opt_system_bus ? "System Bus" : "Session Bus",
+               opt_name,
+               opt_object_path,
+               opt_interface);
+    }
+  g_free (name_owner);
 }
 
 static void
-on_proxy_vanished (GDBusConnection *connection,
-                   const gchar     *name,
-                   gpointer         user_data)
+on_name_owner_notify (GObject    *object,
+                      GParamSpec *pspec,
+                      gpointer    user_data)
 {
-  g_print ("--- Cannot create proxy object for\n"
-           "    bus:          %s\n"
-           "    name:         %s\n"
-           "    object path:  %s\n"
-           "    interface:    %s\n",
-           opt_system_bus ? "System Bus" : "Session Bus",
-           opt_name,
-           opt_object_path,
-           opt_interface);
+  GDBusProxy *proxy = G_DBUS_PROXY (object);
+  print_proxy (proxy);
 }
 
 int
 main (int argc, char *argv[])
 {
-  guint watcher_id;
-  GMainLoop *loop;
   GOptionContext *opt_context;
   GError *error;
-  GBusNameWatcherFlags flags;
-  GDBusProxyFlags proxy_flags;
+  GDBusProxyFlags flags;
+  GDBusProxy *proxy;
 
   g_type_init ();
 
+  loop = NULL;
+  proxy = NULL;
+
   opt_context = g_option_context_new ("g_bus_watch_proxy() example");
   g_option_context_set_summary (opt_context,
                                 "Example: to watch the object of gdbus-example-server, use:\n"
@@ -169,7 +169,7 @@ main (int argc, char *argv[])
   error = NULL;
   if (!g_option_context_parse (opt_context, &argc, &argv, &error))
     {
-      g_printerr ("Error parsing options: %s", error->message);
+      g_printerr ("Error parsing options: %s\n", error->message);
       goto out;
     }
   if (opt_name == NULL || opt_object_path == NULL || opt_interface == NULL)
@@ -178,32 +178,51 @@ main (int argc, char *argv[])
       goto out;
     }
 
-  flags = G_BUS_NAME_WATCHER_FLAGS_NONE;
-  if (opt_auto_start)
-    flags |= G_BUS_NAME_WATCHER_FLAGS_AUTO_START;
-
-  proxy_flags = G_DBUS_PROXY_FLAGS_NONE;
+  flags = G_DBUS_PROXY_FLAGS_NONE;
   if (opt_no_properties)
-    proxy_flags |= G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES;
-
-  watcher_id = g_bus_watch_proxy (opt_system_bus ? G_BUS_TYPE_SYSTEM : G_BUS_TYPE_SESSION,
-                                  opt_name,
-                                  flags,
-                                  opt_object_path,
-                                  opt_interface,
-                                  G_TYPE_DBUS_PROXY,
-                                  proxy_flags,
-                                  on_proxy_appeared,
-                                  on_proxy_vanished,
-                                  NULL,
-                                  NULL);
+    flags |= G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES;
+  if (opt_no_auto_start)
+    flags |= G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START;
 
   loop = g_main_loop_new (NULL, FALSE);
-  g_main_loop_run (loop);
 
-  g_bus_unwatch_proxy (watcher_id);
+  error = NULL;
+  proxy = g_dbus_proxy_new_for_bus_sync (opt_system_bus ? G_BUS_TYPE_SYSTEM : G_BUS_TYPE_SESSION,
+                                         flags,
+                                         NULL, /* GDBusInterfaceInfo */
+                                         opt_name,
+                                         opt_object_path,
+                                         opt_interface,
+                                         NULL, /* GCancellable */
+                                         &error);
+  if (proxy == NULL)
+    {
+      g_printerr ("Error creating proxy: %s\n", error->message);
+      g_error_free (error);
+      goto out;
+    }
+
+  g_signal_connect (proxy,
+                    "g-properties-changed",
+                    G_CALLBACK (on_properties_changed),
+                    NULL);
+  g_signal_connect (proxy,
+                    "g-signal",
+                    G_CALLBACK (on_signal),
+                    NULL);
+  g_signal_connect (proxy,
+                    "notify::g-name-owner",
+                    G_CALLBACK (on_name_owner_notify),
+                    NULL);
+  print_proxy (proxy);
+
+  g_main_loop_run (loop);
 
  out:
+  if (proxy != NULL)
+    g_object_unref (proxy);
+  if (loop != NULL)
+    g_main_loop_unref (loop);
   g_option_context_free (opt_context);
   g_free (opt_name);
   g_free (opt_object_path);
diff --git a/gio/tests/gdbus-export.c b/gio/tests/gdbus-export.c
index 297fb23..d1f3eed 100644
--- a/gio/tests/gdbus-export.c
+++ b/gio/tests/gdbus-export.c
@@ -343,7 +343,6 @@ get_nodes_at (GDBusConnection  *c,
 
   error = NULL;
   proxy = g_dbus_proxy_new_sync (c,
-                                 G_TYPE_DBUS_PROXY,
                                  G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
                                  G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
                                  NULL,
@@ -400,7 +399,6 @@ has_interface (GDBusConnection *c,
 
   error = NULL;
   proxy = g_dbus_proxy_new_sync (c,
-                                 G_TYPE_DBUS_PROXY,
                                  G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
                                  G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
                                  NULL,
@@ -450,7 +448,6 @@ count_interfaces (GDBusConnection *c,
 
   error = NULL;
   proxy = g_dbus_proxy_new_sync (c,
-                                 G_TYPE_DBUS_PROXY,
                                  G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
                                  G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
                                  NULL,
@@ -522,7 +519,6 @@ dyna_create (GDBusConnection *c,
 
   error = NULL;
   proxy = g_dbus_proxy_new_sync (c,
-                                 G_TYPE_DBUS_PROXY,
                                  G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
                                  G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
                                  NULL,
@@ -745,7 +741,6 @@ test_dispatch_thread_func (gpointer user_data)
   const gchar *value_str;
 
   foo_proxy = g_dbus_proxy_new_sync (c,
-                                     G_TYPE_DBUS_PROXY,
                                      G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS |
                                      G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
                                      NULL,
diff --git a/gio/tests/gdbus-introspection.c b/gio/tests/gdbus-introspection.c
index 6209c5d..1ec3844 100644
--- a/gio/tests/gdbus-introspection.c
+++ b/gio/tests/gdbus-introspection.c
@@ -34,11 +34,7 @@ static GMainLoop *loop = NULL;
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
-introspection_on_proxy_appeared (GDBusConnection *connection,
-                                 const gchar     *name,
-                                 const gchar     *name_owner,
-                                 GDBusProxy      *proxy,
-                                 gpointer         user_data)
+test_introspection (GDBusProxy *proxy)
 {
   GError *error;
   const gchar *xml_data;
@@ -105,47 +101,46 @@ introspection_on_proxy_appeared (GDBusConnection *connection,
 }
 
 static void
-introspection_on_proxy_vanished (GDBusConnection *connection,
-                                 const gchar     *name,
-                                 gpointer         user_data)
-{
-}
-
-static void
 test_introspection_parser (void)
 {
-  guint watcher_id;
+  GDBusProxy *proxy;
+  GDBusConnection *connection;
+  GError *error;
 
   session_bus_up ();
 
-  watcher_id = g_bus_watch_proxy (G_BUS_TYPE_SESSION,
-                                  "com.example.TestService",
-                                  G_BUS_NAME_WATCHER_FLAGS_NONE,
-                                  "/com/example/TestObject",
-                                  "com.example.Frob",
-                                  G_TYPE_DBUS_PROXY,
-                                  G_DBUS_PROXY_FLAGS_NONE,
-                                  introspection_on_proxy_appeared,
-                                  introspection_on_proxy_vanished,
-                                  NULL,
-                                  NULL);
-
   /* TODO: wait a bit for the bus to come up.. ideally session_bus_up() won't return
    * until one can connect to the bus but that's not how things work right now
    */
   usleep (500 * 1000);
+
+  error = NULL;
+  connection = g_bus_get_sync (G_BUS_TYPE_SESSION,
+                               NULL,
+                               &error);
+  g_assert_no_error (error);
+  error = NULL;
+  proxy = g_dbus_proxy_new_sync (connection,
+                                 G_DBUS_PROXY_FLAGS_NONE,
+                                 NULL,                      /* GDBusInterfaceInfo */
+                                 "com.example.TestService", /* name */
+                                 "/com/example/TestObject", /* object path */
+                                 "com.example.Frob",        /* interface */
+                                 NULL, /* GCancellable */
+                                 &error);
+  g_assert_no_error (error);
+
   /* this is safe; testserver will exit once the bus goes away */
   g_assert (g_spawn_command_line_async (SRCDIR "/gdbus-testserver.py", NULL));
 
-  g_main_loop_run (loop);
+  _g_assert_property_notify (proxy, "g-name-owner");
 
-  g_bus_unwatch_proxy (watcher_id);
+  test_introspection (proxy);
 
-  /* tear down bus */
-  session_bus_down ();
+  g_object_unref (proxy);
+  g_object_unref (connection);
 }
 
-
 /* ---------------------------------------------------------------------------------------------------- */
 
 int
diff --git a/gio/tests/gdbus-peer.c b/gio/tests/gdbus-peer.c
index 97f0308..7d81372 100644
--- a/gio/tests/gdbus-peer.c
+++ b/gio/tests/gdbus-peer.c
@@ -526,7 +526,6 @@ test_peer (void)
    */
   error = NULL;
   proxy = g_dbus_proxy_new_sync (c,
-                                 G_TYPE_DBUS_PROXY,
                                  G_DBUS_PROXY_FLAGS_NONE,
                                  NULL,
                                  NULL, /* bus_name */
diff --git a/gio/tests/gdbus-proxy-well-known-name.c b/gio/tests/gdbus-proxy-well-known-name.c
new file mode 100644
index 0000000..a599ef6
--- /dev/null
+++ b/gio/tests/gdbus-proxy-well-known-name.c
@@ -0,0 +1,283 @@
+/* GLib testing framework examples and tests
+ *
+ * Copyright (C) 2008-2010 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 <gio/gio.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "gdbus-tests.h"
+
+/* all tests rely on a shared mainloop */
+static GMainLoop *loop = NULL;
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+proxy_new_cb (GObject       *source_object,
+              GAsyncResult  *res,
+              gpointer       user_data)
+{
+  GDBusProxy **ret = user_data;
+  GError *error;
+
+  error = NULL;
+  *ret = g_dbus_proxy_new_finish (res, &error);
+  g_assert_no_error (error);
+  g_assert (ret != NULL);
+
+  g_main_loop_quit (loop);
+}
+
+static void
+test_proxy_well_known_name (void)
+{
+  GDBusProxy *p;
+  GDBusProxy *p2;
+  GDBusProxy *ap;
+  GDBusProxy *ap2;
+  GDBusConnection *c;
+  GError *error;
+  gchar *name_owner;
+  gchar **property_names;
+  GVariant *variant;
+  GVariant *result;
+
+  session_bus_up ();
+
+  /* TODO: wait a bit for the bus to come up.. ideally session_bus_up() won't return
+   * until one can connect to the bus but that's not how things work right now
+   */
+  usleep (500 * 1000);
+
+  error = NULL;
+  c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
+  g_assert_no_error (error);
+  g_assert (c != NULL);
+
+  error = NULL;
+  p = g_dbus_proxy_new_sync (c,
+                             G_DBUS_PROXY_FLAGS_NONE,
+                             NULL,                      /* GDBusInterfaceInfo* */
+                             "com.example.TestService", /* name */
+                             "/com/example/TestObject", /* object path */
+                             "com.example.Frob",        /* interface name */
+                             NULL,                      /* GCancellable */
+                             &error);
+  g_assert_no_error (error);
+
+  /* we shouldn't have a name owner nor any cached properties */
+  g_assert_cmpstr (g_dbus_proxy_get_name_owner (p), ==, NULL);
+  g_assert (g_dbus_proxy_get_cached_property_names (p) == NULL);
+
+  /* also for async: we shouldn't have a name owner nor any cached properties */
+  g_dbus_proxy_new (c,
+                    G_DBUS_PROXY_FLAGS_NONE,
+                    NULL,                      /* GDBusInterfaceInfo* */
+                    "com.example.TestService", /* name */
+                    "/com/example/TestObject", /* object path */
+                    "com.example.Frob",        /* interface name */
+                    NULL,                      /* GCancellable */
+                    (GAsyncReadyCallback) proxy_new_cb,
+                    &ap);
+  g_main_loop_run (loop);
+  g_assert_cmpstr (g_dbus_proxy_get_name_owner (ap), ==, NULL);
+  g_assert (g_dbus_proxy_get_cached_property_names (ap) == NULL);
+
+  /* this is safe; testserver will exit once the bus goes away */
+  g_assert (g_spawn_command_line_async (SRCDIR "/gdbus-testserver.py", NULL));
+
+  /* check that we get the notify::g-name-owner signal */
+  _g_assert_property_notify (p, "g-name-owner");
+
+  /* Now we should have a name owner as well as properties */
+  name_owner = g_dbus_proxy_get_name_owner (p);
+  property_names = g_dbus_proxy_get_cached_property_names (p);
+  g_assert (g_dbus_is_unique_name (name_owner));
+  g_assert (property_names != NULL && g_strv_length (property_names) > 0);
+  g_free (name_owner);
+  g_strfreev (property_names);
+
+  /* if we create another proxy with the service being available, check that
+   * it has a name owner and properties
+   */
+  error = NULL;
+  p2 = g_dbus_proxy_new_sync (c,
+                              G_DBUS_PROXY_FLAGS_NONE,
+                              NULL,                      /* GDBusInterfaceInfo* */
+                              "com.example.TestService", /* name */
+                              "/com/example/TestObject", /* object path */
+                              "com.example.Frob",        /* interface name */
+                              NULL,                      /* GCancellable */
+                              &error);
+  g_assert_no_error (error);
+  name_owner = g_dbus_proxy_get_name_owner (p2);
+  property_names = g_dbus_proxy_get_cached_property_names (p2);
+  g_assert (g_dbus_is_unique_name (name_owner));
+  g_assert (property_names != NULL && g_strv_length (property_names) > 0);
+  g_free (name_owner);
+  g_strfreev (property_names);
+
+  /* also for async: we should have a name owner and cached properties */
+  g_dbus_proxy_new (c,
+                    G_DBUS_PROXY_FLAGS_NONE,
+                    NULL,                      /* GDBusInterfaceInfo* */
+                    "com.example.TestService", /* name */
+                    "/com/example/TestObject", /* object path */
+                    "com.example.Frob",        /* interface name */
+                    NULL,                      /* GCancellable */
+                    (GAsyncReadyCallback) proxy_new_cb,
+                    &ap2);
+  g_main_loop_run (loop);
+  name_owner = g_dbus_proxy_get_name_owner (ap2);
+  property_names = g_dbus_proxy_get_cached_property_names (ap2);
+  g_assert (g_dbus_is_unique_name (name_owner));
+  g_assert (property_names != NULL && g_strv_length (property_names) > 0);
+  g_free (name_owner);
+  g_strfreev (property_names);
+
+  /* Check property value is the initial value */
+  variant = g_dbus_proxy_get_cached_property (p, "y");
+  g_assert (variant != NULL);
+  g_assert_cmpint (g_variant_get_byte (variant), ==, 1);
+  g_variant_unref (variant);
+  variant = g_dbus_proxy_get_cached_property (p2, "y");
+  g_assert (variant != NULL);
+  g_assert_cmpint (g_variant_get_byte (variant), ==, 1);
+  g_variant_unref (variant);
+  variant = g_dbus_proxy_get_cached_property (ap, "y");
+  g_assert (variant != NULL);
+  g_assert_cmpint (g_variant_get_byte (variant), ==, 1);
+  g_variant_unref (variant);
+  variant = g_dbus_proxy_get_cached_property (ap2, "y");
+  g_assert (variant != NULL);
+  g_assert_cmpint (g_variant_get_byte (variant), ==, 1);
+  g_variant_unref (variant);
+
+  /* Check that properties are updated on both p and p2 */
+  result = g_dbus_proxy_call_sync (p,
+                                   "FrobSetProperty",
+                                   g_variant_new ("(sv)",
+                                                  "y",
+                                                  g_variant_new_byte (42)),
+                                   G_DBUS_CALL_FLAGS_NONE,
+                                   -1,
+                                   NULL,
+                                   &error);
+  g_assert_no_error (error);
+  g_assert (result != NULL);
+  g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
+  g_variant_unref (result);
+  _g_assert_signal_received (p, "g-properties-changed");
+  variant = g_dbus_proxy_get_cached_property (p, "y");
+  g_assert (variant != NULL);
+  g_assert_cmpint (g_variant_get_byte (variant), ==, 42);
+  g_variant_unref (variant);
+  variant = g_dbus_proxy_get_cached_property (p2, "y");
+  g_assert (variant != NULL);
+  g_assert_cmpint (g_variant_get_byte (variant), ==, 42);
+  g_variant_unref (variant);
+  variant = g_dbus_proxy_get_cached_property (ap, "y");
+  g_assert (variant != NULL);
+  g_assert_cmpint (g_variant_get_byte (variant), ==, 42);
+  g_variant_unref (variant);
+  variant = g_dbus_proxy_get_cached_property (ap2, "y");
+  g_assert (variant != NULL);
+  g_assert_cmpint (g_variant_get_byte (variant), ==, 42);
+  g_variant_unref (variant);
+
+  /* Nuke the service and check that we get the signal and then don't
+   * have a name owner nor any cached properties
+   */
+  result = g_dbus_proxy_call_sync (p,
+                                   "Quit",
+                                   NULL,
+                                   G_DBUS_CALL_FLAGS_NONE,
+                                   -1,
+                                   NULL,
+                                   &error);
+  g_assert_no_error (error);
+  g_assert (result != NULL);
+  g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
+  g_variant_unref (result);
+  /* and wait... */
+  _g_assert_property_notify (p, "g-name-owner");
+  /* now we shouldn't have a name owner nor any cached properties */
+  g_assert_cmpstr (g_dbus_proxy_get_name_owner (p), ==, NULL);
+  g_assert (g_dbus_proxy_get_cached_property_names (p) == NULL);
+  g_assert (g_dbus_proxy_get_cached_property (p, "y") == NULL);
+
+  /* now bring back the server and wait for the proxy to be updated.. now
+   * the 'y' property should be back at 1...
+   */
+  /* this is safe; testserver will exit once the bus goes away */
+  g_assert (g_spawn_command_line_async (SRCDIR "/gdbus-testserver.py", NULL));
+  /* check that we get the notify::g-name-owner signal */
+  _g_assert_property_notify (p, "g-name-owner");
+  /* Now we should have a name owner as well as properties */
+  name_owner = g_dbus_proxy_get_name_owner (p);
+  property_names = g_dbus_proxy_get_cached_property_names (p);
+  g_assert (g_dbus_is_unique_name (name_owner));
+  g_assert (property_names != NULL && g_strv_length (property_names) > 0);
+  g_free (name_owner);
+  g_strfreev (property_names);
+  /* and finally check the 'y' property */
+  variant = g_dbus_proxy_get_cached_property (p, "y");
+  g_assert (variant != NULL);
+  g_assert_cmpint (g_variant_get_byte (variant), ==, 1);
+  g_variant_unref (variant);
+
+  g_object_unref (p2);
+  g_object_unref (p);
+  g_object_unref (ap2);
+  g_object_unref (ap);
+
+  g_object_unref (c);
+
+  /* tear down bus */
+  session_bus_down ();
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+int
+main (int   argc,
+      char *argv[])
+{
+  gint ret;
+
+  g_type_init ();
+  g_test_init (&argc, &argv, NULL);
+
+  /* all the tests rely on a shared main loop */
+  loop = g_main_loop_new (NULL, FALSE);
+
+  /* all the tests use a session bus with a well-known address that we can bring up and down
+   * using session_bus_up() and session_bus_down().
+   */
+  g_unsetenv ("DISPLAY");
+  g_setenv ("DBUS_SESSION_BUS_ADDRESS", session_bus_get_temporary_address (), TRUE);
+
+  g_test_add_func ("/gdbus/proxy-well-known-name", test_proxy_well_known_name);
+
+  ret = g_test_run();
+  return ret;
+}
diff --git a/gio/tests/gdbus-proxy.c b/gio/tests/gdbus-proxy.c
index 970bf47..782bf77 100644
--- a/gio/tests/gdbus-proxy.c
+++ b/gio/tests/gdbus-proxy.c
@@ -34,10 +34,7 @@ static GMainLoop *loop = NULL;
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
-test_methods (GDBusConnection *connection,
-              const gchar     *name,
-              const gchar     *name_owner,
-              GDBusProxy      *proxy)
+test_methods (GDBusProxy *proxy)
 {
   GVariant *result;
   GError *error;
@@ -133,10 +130,7 @@ test_methods (GDBusConnection *connection,
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
-test_properties (GDBusConnection *connection,
-                 const gchar     *name,
-                 const gchar     *name_owner,
-                 GDBusProxy      *proxy)
+test_properties (GDBusProxy *proxy)
 {
   GError *error;
   GVariant *variant;
@@ -281,10 +275,7 @@ test_proxy_signals_on_emit_signal_cb (GDBusProxy   *proxy,
 }
 
 static void
-test_signals (GDBusConnection *connection,
-              const gchar     *name,
-              const gchar     *name_owner,
-              GDBusProxy      *proxy)
+test_signals (GDBusProxy *proxy)
 {
   GError *error;
   GString *s;
@@ -359,10 +350,7 @@ test_signals (GDBusConnection *connection,
 }
 
 static void
-test_bogus_method_return (GDBusConnection *connection,
-                          const gchar     *name,
-                          const gchar     *name_owner,
-                          GDBusProxy      *proxy)
+test_bogus_method_return (GDBusProxy *proxy)
 {
   GError *error = NULL;
   GVariant *result;
@@ -401,16 +389,8 @@ static const gchar *frob_dbus_interface_xml =
 static GDBusInterfaceInfo *frob_dbus_interface_info;
 
 static void
-on_proxy_appeared (GDBusConnection *connection,
-                   const gchar     *name,
-                   const gchar     *name_owner,
-                   GDBusProxy      *proxy,
-                   gpointer         user_data)
+test_expected_interface (GDBusProxy *proxy)
 {
-  test_methods (connection, name, name_owner, proxy);
-  test_properties (connection, name, name_owner, proxy);
-  test_signals (connection, name, name_owner, proxy);
-
   /* This is obviously wrong but expected interface is not set so we don't fail... */
   g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_string ("error_me_out!"));
   g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_byte (42));
@@ -419,12 +399,12 @@ on_proxy_appeared (GDBusConnection *connection,
 
   /* Now repeat the method tests, with an expected interface set */
   g_dbus_proxy_set_interface_info (proxy, frob_dbus_interface_info);
-  test_methods (connection, name, name_owner, proxy);
+  test_methods (proxy);
 
   /* And now one more test where we deliberately set the expected
    * interface definition incorrectly
    */
-  test_bogus_method_return (connection, name, name_owner, proxy);
+  test_bogus_method_return (proxy);
 
   /* Also check that we complain if setting a cached property of the wrong type */
   if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR))
@@ -443,21 +423,14 @@ on_proxy_appeared (GDBusConnection *connection,
 
   /* this should work, however (since the type is correct) */
   g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_byte (42));
-
-  g_main_loop_quit (loop);
-}
-
-static void
-on_proxy_vanished (GDBusConnection *connection,
-                   const gchar     *name,
-                   gpointer         user_data)
-{
 }
 
 static void
 test_proxy (void)
 {
-  guint watcher_id;
+  GDBusProxy *proxy;
+  GDBusConnection *connection;
+  GError *error;
 
   session_bus_up ();
 
@@ -466,27 +439,34 @@ test_proxy (void)
    */
   usleep (500 * 1000);
 
-  watcher_id = g_bus_watch_proxy (G_BUS_TYPE_SESSION,
-                                  "com.example.TestService",
-                                  G_BUS_NAME_WATCHER_FLAGS_NONE,
-                                  "/com/example/TestObject",
-                                  "com.example.Frob",
-                                  G_TYPE_DBUS_PROXY,
-                                  G_DBUS_PROXY_FLAGS_NONE,
-                                  on_proxy_appeared,
-                                  on_proxy_vanished,
-                                  NULL,
-                                  NULL);
+  error = NULL;
+  connection = g_bus_get_sync (G_BUS_TYPE_SESSION,
+                               NULL,
+                               &error);
+  g_assert_no_error (error);
+  error = NULL;
+  proxy = g_dbus_proxy_new_sync (connection,
+                                 G_DBUS_PROXY_FLAGS_NONE,
+                                 NULL,                      /* GDBusInterfaceInfo */
+                                 "com.example.TestService", /* name */
+                                 "/com/example/TestObject", /* object path */
+                                 "com.example.Frob",        /* interface */
+                                 NULL, /* GCancellable */
+                                 &error);
+  g_assert_no_error (error);
 
   /* this is safe; testserver will exit once the bus goes away */
   g_assert (g_spawn_command_line_async (SRCDIR "/gdbus-testserver.py", NULL));
 
-  g_main_loop_run (loop);
+  _g_assert_property_notify (proxy, "g-name-owner");
 
-  g_bus_unwatch_proxy (watcher_id);
+  test_methods (proxy);
+  test_properties (proxy);
+  test_signals (proxy);
+  test_expected_interface (proxy);
 
-  /* tear down bus */
-  session_bus_down ();
+  g_object_unref (proxy);
+  g_object_unref (connection);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
diff --git a/gio/tests/gdbus-threading.c b/gio/tests/gdbus-threading.c
index 24e0704..05c7c86 100644
--- a/gio/tests/gdbus-threading.c
+++ b/gio/tests/gdbus-threading.c
@@ -348,11 +348,7 @@ test_sleep_in_thread_func (gpointer _data)
 }
 
 static void
-on_proxy_appeared (GDBusConnection *connection,
-                   const gchar     *name,
-                   const gchar     *name_owner,
-                   GDBusProxy      *proxy,
-                   gpointer         user_data)
+test_method_calls_on_proxy (GDBusProxy *proxy)
 {
   guint n;
 
@@ -454,32 +450,37 @@ on_proxy_appeared (GDBusConnection *connection,
 }
 
 static void
-on_proxy_vanished (GDBusConnection *connection,
-                   const gchar     *name,
-                   gpointer         user_data)
-{
-}
-
-static void
 test_method_calls_in_thread (void)
 {
-  guint watcher_id;
-
-  watcher_id = g_bus_watch_proxy (G_BUS_TYPE_SESSION,
-                                  "com.example.TestService",
-                                  G_BUS_NAME_WATCHER_FLAGS_NONE,
-                                  "/com/example/TestObject",
-                                  "com.example.Frob",
-                                  G_TYPE_DBUS_PROXY,
-                                  G_DBUS_PROXY_FLAGS_NONE,
-                                  on_proxy_appeared,
-                                  on_proxy_vanished,
-                                  NULL,
-                                  NULL);
+  GDBusProxy *proxy;
+  GDBusConnection *connection;
+  GError *error;
+  gchar *name_owner;
 
-  g_main_loop_run (loop);
+  error = NULL;
+  connection = g_bus_get_sync (G_BUS_TYPE_SESSION,
+                               NULL,
+                               &error);
+  g_assert_no_error (error);
+  error = NULL;
+  proxy = g_dbus_proxy_new_sync (connection,
+                                 G_DBUS_PROXY_FLAGS_NONE,
+                                 NULL,                      /* GDBusInterfaceInfo */
+                                 "com.example.TestService", /* name */
+                                 "/com/example/TestObject", /* object path */
+                                 "com.example.Frob",        /* interface */
+                                 NULL, /* GCancellable */
+                                 &error);
+  g_assert_no_error (error);
+
+  name_owner = g_dbus_proxy_get_name_owner (proxy);
+  g_assert_cmpstr (name_owner, !=, NULL);
+  g_free (name_owner);
+
+  test_method_calls_on_proxy (proxy);
 
-  g_bus_unwatch_proxy (watcher_id);
+  g_object_unref (proxy);
+  g_object_unref (connection);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */



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