[kdbus] Integrate acquiring and releasing names on kdbus with GLib core
[platform/upstream/glib.git] / gio / gdbusnameowning.c
index 3090165..d39faea 100644 (file)
@@ -1,6 +1,6 @@
 /* GDBus - GLib D-Bus Library
  *
- * Copyright (C) 2008-2009 Red Hat, Inc.
+ * 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
@@ -13,9 +13,7 @@
  * 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.
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
  *
  * Author: David Zeuthen <davidz@redhat.com>
  */
 
 #include <stdlib.h>
 
-#include <glib/gi18n.h>
-
 #include "gdbusutils.h"
 #include "gdbusnameowning.h"
 #include "gdbuserror.h"
 #include "gdbusprivate.h"
 #include "gdbusconnection.h"
 
+#ifdef G_OS_UNIX
+#include "gkdbusconnection.h"
+#endif
+
+#include "glibintl.h"
+
 /**
  * SECTION:gdbusnameowning
  * @title: Owning Bus Names
  * @short_description: Simple API for owning bus names
- * @include: gdbus/gdbus.h
+ * @include: gio/gio.h
  *
  * Convenience API for owning bus names.
  *
- * <example id="gdbus-owning-names"><title>Simple application owning a name</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../../gio/tests/gdbus-example-own-name.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting></example>
+ * A simple example for owning a name can be found in
+ * [gdbus-example-own-name.c](https://git.gnome.org/browse/glib/tree/gio/tests/gdbus-example-own-name.c) 
  */
 
 G_LOCK_DEFINE_STATIC (lock);
@@ -74,7 +77,7 @@ typedef struct
   guint                     name_acquired_subscription_id;
   guint                     name_lost_subscription_id;
 
-  gboolean                  cancelled;
+  volatile gboolean         cancelled; /* must hold lock when reading or modifying */
 
   gboolean                  needs_release;
 } Client;
@@ -105,8 +108,7 @@ client_unref (Client *client)
             g_dbus_connection_signal_unsubscribe (client->connection, client->name_lost_subscription_id);
           g_object_unref (client->connection);
         }
-      if (client->main_context != NULL)
-        g_main_context_unref (client->main_context);
+      g_main_context_unref (client->main_context);
       g_free (client->name);
       if (client->user_data_free_func != NULL)
         client->user_data_free_func (client->user_data);
@@ -199,6 +201,7 @@ schedule_call_in_idle (Client *client, CallType  call_type)
                          call_in_idle_cb,
                          data,
                          (GDestroyNotify) call_handler_data_free);
+  g_source_set_name (idle_source, "[gio] call_in_idle_cb");
   g_source_attach (idle_source, client->main_context);
   g_source_unref (idle_source);
 }
@@ -206,37 +209,53 @@ schedule_call_in_idle (Client *client, CallType  call_type)
 static void
 do_call (Client *client, CallType call_type)
 {
+  GMainContext *current_context;
+
   /* only schedule in idle if we're not in the right thread */
-  if (g_main_context_get_thread_default () != client->main_context)
+  current_context = g_main_context_ref_thread_default ();
+  if (current_context != client->main_context)
     schedule_call_in_idle (client, call_type);
   else
     actually_do_call (client, client->connection, call_type);
+  g_main_context_unref (current_context);
 }
 
 static void
 call_acquired_handler (Client *client)
 {
+  G_LOCK (lock);
   if (client->previous_call != PREVIOUS_CALL_ACQUIRED)
     {
       client->previous_call = PREVIOUS_CALL_ACQUIRED;
       if (!client->cancelled)
         {
+          G_UNLOCK (lock);
           do_call (client, CALL_TYPE_NAME_ACQUIRED);
+          goto out;
         }
     }
+  G_UNLOCK (lock);
+ out:
+  ;
 }
 
 static void
 call_lost_handler (Client  *client)
 {
+  G_LOCK (lock);
   if (client->previous_call != PREVIOUS_CALL_LOST)
     {
       client->previous_call = PREVIOUS_CALL_LOST;
       if (!client->cancelled)
         {
+          G_UNLOCK (lock);
           do_call (client, CALL_TYPE_NAME_LOST);
+          goto out;
         }
     }
+  G_UNLOCK (lock);
+ out:
+  ;
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -260,7 +279,7 @@ on_name_lost_or_acquired (GDBusConnection  *connection,
 
   if (g_strcmp0 (signal_name, "NameLost") == 0)
     {
-      g_variant_get (parameters, "(s)", &name);
+      g_variant_get (parameters, "(&s)", &name);
       if (g_strcmp0 (name, client->name) == 0)
         {
           call_lost_handler (client);
@@ -268,7 +287,7 @@ on_name_lost_or_acquired (GDBusConnection  *connection,
     }
   else if (g_strcmp0 (signal_name, "NameAcquired") == 0)
     {
-      g_variant_get (parameters, "(s)", &name);
+      g_variant_get (parameters, "(&s)", &name);
       if (g_strcmp0 (name, client->name) == 0)
         {
           call_acquired_handler (client);
@@ -281,27 +300,11 @@ on_name_lost_or_acquired (GDBusConnection  *connection,
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
-request_name_cb (GObject      *source_object,
-                 GAsyncResult *res,
-                 gpointer      user_data)
+process_request_name_reply (Client  *client,
+                            guint32  request_name_reply)
 {
-  Client *client = user_data;
-  GVariant *result;
-  guint32 request_name_reply;
   gboolean subscribe;
 
-  request_name_reply = 0;
-  result = NULL;
-
-  result = g_dbus_connection_invoke_method_finish (client->connection,
-                                                   res,
-                                                   NULL);
-  if (result != NULL)
-    {
-      g_variant_get (result, "(u)", &request_name_reply);
-      g_variant_unref (result);
-    }
-
   subscribe = FALSE;
 
   switch (request_name_reply)
@@ -329,30 +332,75 @@ request_name_cb (GObject      *source_object,
       break;
     }
 
+
   if (subscribe)
     {
+      GDBusConnection *connection = NULL;
+
+      /* if cancelled, there is no point in subscribing to signals - if not, make sure
+       * we use a known good Connection object since it may be set to NULL at any point
+       * after being cancelled
+       */
+      G_LOCK (lock);
+      if (!client->cancelled)
+        connection = g_object_ref (client->connection);
+      G_UNLOCK (lock);
+
       /* start listening to NameLost and NameAcquired messages */
-      client->name_lost_subscription_id =
-        g_dbus_connection_signal_subscribe (client->connection,
-                                            "org.freedesktop.DBus",
-                                            "org.freedesktop.DBus",
-                                            "NameLost",
-                                            "/org/freedesktop/DBus",
-                                            client->name,
-                                            on_name_lost_or_acquired,
-                                            client,
-                                            NULL);
-      client->name_acquired_subscription_id =
-        g_dbus_connection_signal_subscribe (client->connection,
-                                            "org.freedesktop.DBus",
-                                            "org.freedesktop.DBus",
-                                            "NameAcquired",
-                                            "/org/freedesktop/DBus",
-                                            client->name,
-                                            on_name_lost_or_acquired,
-                                            client,
-                                            NULL);
+      if (connection != NULL)
+        {
+          client->name_lost_subscription_id =
+            g_dbus_connection_signal_subscribe (connection,
+                                                "org.freedesktop.DBus",
+                                                "org.freedesktop.DBus",
+                                                "NameLost",
+                                                "/org/freedesktop/DBus",
+                                                client->name,
+                                                G_DBUS_SIGNAL_FLAGS_NONE,
+                                                on_name_lost_or_acquired,
+                                                client,
+                                                NULL);
+          client->name_acquired_subscription_id =
+            g_dbus_connection_signal_subscribe (connection,
+                                                "org.freedesktop.DBus",
+                                                "org.freedesktop.DBus",
+                                                "NameAcquired",
+                                                "/org/freedesktop/DBus",
+                                                client->name,
+                                                G_DBUS_SIGNAL_FLAGS_NONE,
+                                                on_name_lost_or_acquired,
+                                                client,
+                                                NULL);
+          g_object_unref (connection);
+        }
     }
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+request_name_cb (GObject      *source_object,
+                 GAsyncResult *res,
+                 gpointer      user_data)
+{
+  Client *client = user_data;
+  GVariant *result;
+  guint32 request_name_reply;
+
+  request_name_reply = 0;
+  result = NULL;
+
+  /* don't use client->connection - it may be NULL already */
+  result = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
+                                          res,
+                                          NULL);
+  if (result != NULL)
+    {
+      g_variant_get (result, "(u)", &request_name_reply);
+      g_variant_unref (result);
+    }
+
+  process_request_name_reply (client, request_name_reply);
 
   client_unref (client);
 }
@@ -394,19 +442,41 @@ has_connection (Client *client)
                                                              client);
 
   /* attempt to acquire the name */
-  g_dbus_connection_invoke_method (client->connection,
-                                   "org.freedesktop.DBus",  /* bus name */
-                                   "/org/freedesktop/DBus", /* object path */
-                                   "org.freedesktop.DBus",  /* interface name */
-                                   "RequestName",           /* method name */
-                                   g_variant_new ("(su)",
-                                                  client->name,
-                                                  client->flags),
-                                   G_DBUS_INVOKE_METHOD_FLAGS_NONE,
-                                   -1,
-                                   NULL,
-                                   (GAsyncReadyCallback) request_name_cb,
-                                   client_ref (client));
+  if (G_IS_KDBUS_CONNECTION (g_dbus_connection_get_stream (client->connection)))
+    {
+      GVariant *result;
+      guint32 request_name_reply;
+
+      request_name_reply = 0;
+      result = NULL;
+
+      result = _g_kdbus_RequestName (client->connection, client->name, client->flags, NULL);
+
+      if (result != NULL)
+        {
+          g_variant_get (result, "(u)", &request_name_reply);
+          g_variant_unref (result);
+        }
+
+      process_request_name_reply (client, request_name_reply);
+    }
+  else
+    {
+      g_dbus_connection_call (client->connection,
+                              "org.freedesktop.DBus",  /* bus name */
+                              "/org/freedesktop/DBus", /* object path */
+                              "org.freedesktop.DBus",  /* interface name */
+                              "RequestName",           /* method name */
+                              g_variant_new ("(su)",
+                                             client->name,
+                                             client->flags),
+                              G_VARIANT_TYPE ("(u)"),
+                              G_DBUS_CALL_FLAGS_NONE,
+                              -1,
+                              NULL,
+                              (GAsyncReadyCallback) request_name_cb,
+                              client_ref (client));
+    }
 }
 
 
@@ -417,6 +487,15 @@ connection_get_cb (GObject      *source_object,
 {
   Client *client = user_data;
 
+  /* must not do anything if already cancelled */
+  G_LOCK (lock);
+  if (client->cancelled)
+    {
+      G_UNLOCK (lock);
+      goto out;
+    }
+  G_UNLOCK (lock);
+
   client->connection = g_bus_get_finish (res, NULL);
   if (client->connection == NULL)
     {
@@ -448,20 +527,22 @@ connection_get_cb (GObject      *source_object,
 
 /**
  * g_bus_own_name_on_connection:
- * @connection: A #GDBusConnection that is not closed.
- * @name: The well-known name to own.
- * @flags: A set of flags from the #GBusNameOwnerFlags enumeration.
- * @name_acquired_handler: Handler to invoke when @name is acquired or %NULL.
- * @name_lost_handler: Handler to invoke when @name is lost or %NULL.
- * @user_data: User data to pass to handlers.
- * @user_data_free_func: Function for freeing @user_data or %NULL.
+ * @connection: a #GDBusConnection
+ * @name: the well-known name to own
+ * @flags: a set of flags from the #GBusNameOwnerFlags enumeration
+ * @name_acquired_handler: (allow-none): handler to invoke when @name is acquired or %NULL
+ * @name_lost_handler: (allow-none): handler to invoke when @name is lost or %NULL
+ * @user_data: user data to pass to handlers
+ * @user_data_free_func: (allow-none): function for freeing @user_data or %NULL
  *
  * Like g_bus_own_name() but takes a #GDBusConnection instead of a
  * #GBusType.
  *
- * Returns: An identifier (never 0) that an be used with
- * g_bus_unown_name() to stop owning the name.
- **/
+ * Returns: an identifier (never 0) that an be used with
+ *     g_bus_unown_name() to stop owning the name
+ *
+ * Since: 2.26
+ */
 guint
 g_bus_own_name_on_connection (GDBusConnection          *connection,
                               const gchar              *name,
@@ -474,7 +555,6 @@ g_bus_own_name_on_connection (GDBusConnection          *connection,
   Client *client;
 
   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 (g_dbus_is_name (name) && !g_dbus_is_unique_name (name), 0);
 
   G_LOCK (lock);
@@ -488,9 +568,7 @@ g_bus_own_name_on_connection (GDBusConnection          *connection,
   client->name_lost_handler = name_lost_handler;
   client->user_data = user_data;
   client->user_data_free_func = user_data_free_func;
-  client->main_context = g_main_context_get_thread_default ();
-  if (client->main_context != NULL)
-    g_main_context_ref (client->main_context);
+  client->main_context = g_main_context_ref_thread_default ();
 
   client->connection = g_object_ref (connection);
 
@@ -511,47 +589,47 @@ g_bus_own_name_on_connection (GDBusConnection          *connection,
 
 /**
  * g_bus_own_name:
- * @bus_type: The type of bus to own a name on.
- * @name: The well-known name to own.
- * @flags: A set of flags from the #GBusNameOwnerFlags enumeration.
- * @bus_acquired_handler: Handler to invoke when connected to the bus of type @bus_type or %NULL.
- * @name_acquired_handler: Handler to invoke when @name is acquired or %NULL.
- * @name_lost_handler: Handler to invoke when @name is lost or %NULL.
- * @user_data: User data to pass to handlers.
- * @user_data_free_func: Function for freeing @user_data or %NULL.
+ * @bus_type: the type of bus to own a name on
+ * @name: the well-known name to own
+ * @flags: a set of flags from the #GBusNameOwnerFlags enumeration
+ * @bus_acquired_handler: (allow-none): handler to invoke when connected to the bus of type @bus_type or %NULL
+ * @name_acquired_handler: (allow-none): handler to invoke when @name is acquired or %NULL
+ * @name_lost_handler: (allow-none): handler to invoke when @name is lost or %NULL
+ * @user_data: user data to pass to handlers
+ * @user_data_free_func: (allow-none): function for freeing @user_data or %NULL
  *
  * Starts acquiring @name on the bus specified by @bus_type and calls
  * @name_acquired_handler and @name_lost_handler when the name is
- * acquired respectively lost. Callbacks will be invoked in the <link
- * linkend="g-main-context-push-thread-default">thread-default main
- * loop</link> of the thread you are calling this function from.
+ * acquired respectively lost. Callbacks will be invoked in the 
+ * [thread-default main context][g-main-context-push-thread-default]
+ * of the thread you are calling this function from.
  *
  * You are guaranteed that one of the @name_acquired_handler and @name_lost_handler
  * callbacks will be invoked after calling this function - there are three
  * possible cases:
- * <itemizedlist>
- *   <listitem><para>
- *     @name_lost_handler with a %NULL connection (if a connection to the bus can't be made).
- *   </para></listitem>
- *   <listitem><para>
- *     @bus_acquired_handler then @name_lost_handler (if the name can't be obtained)
- *   </para></listitem>
- *   <listitem><para>
- *     @bus_acquired_handler then @name_acquired_handler (if the name was obtained).
- *   </para></listitem>
- * </itemizedlist>
+ * 
+ * - @name_lost_handler with a %NULL connection (if a connection to the bus
+ *   can't be made).
+ *
+ * - @bus_acquired_handler then @name_lost_handler (if the name can't be
+ *   obtained)
+ *
+ * - @bus_acquired_handler then @name_acquired_handler (if the name was
+ *   obtained).
+ *
  * When you are done owning the name, just call g_bus_unown_name()
  * with the owner id this function returns.
  *
  * If the name is acquired or lost (for example another application
  * could acquire the name if you allow replacement or the application
- * currently owning the name exits), the handlers are also invoked. If the
- * #GDBusConnection that is used for attempting to own the name
- * closes, then @name_lost_handler is invoked since it is no
- * longer possible for other processes to access the process.
+ * currently owning the name exits), the handlers are also invoked.
+ * If the #GDBusConnection that is used for attempting to own the name
+ * closes, then @name_lost_handler is invoked since it is no longer
+ * possible for other processes to access the process.
  *
- * You cannot use g_bus_own_name() several times (unless interleaved
- * with calls to g_bus_unown_name()) - only the first call will work.
+ * You cannot use g_bus_own_name() several times for the same name (unless
+ * interleaved with calls to g_bus_unown_name()) - only the first call
+ * will work.
  *
  * Another guarantee is that invocations of @name_acquired_handler
  * and @name_lost_handler are guaranteed to alternate; that
@@ -559,19 +637,22 @@ g_bus_own_name_on_connection (GDBusConnection          *connection,
  * guaranteed that the next time one of the handlers is invoked, it
  * will be @name_lost_handler. The reverse is also true.
  *
- * If you plan on exporting objects (using e.g. g_dbus_connection_register_object()), note
- * that it is generally too late to export the objects in @name_acquired_handler. Instead,
- * you can do this in @bus_acquired_handler since you are guaranteed that this will
- * run before @name is requested from the bus.
+ * If you plan on exporting objects (using e.g.
+ * g_dbus_connection_register_object()), note that it is generally too late
+ * to export the objects in @name_acquired_handler. Instead, you can do this
+ * in @bus_acquired_handler since you are guaranteed that this will run
+ * before @name is requested from the bus.
  *
  * This behavior makes it very simple to write applications that wants
- * to own names and export objects, see <xref linkend="gdbus-owning-names"/>. Simply
- * register objects to be exported in @bus_acquired_handler and
+ * to [own names][gdbus-owning-names] and export objects.
+ * Simply register objects to be exported in @bus_acquired_handler and
  * unregister the objects (if any) in @name_lost_handler.
  *
- * Returns: An identifier (never 0) that an be used with
- * g_bus_unown_name() to stop owning the name.
- **/
+ * Returns: an identifier (never 0) that an be used with
+ *     g_bus_unown_name() to stop owning the name.
+ *
+ * Since: 2.26
+ */
 guint
 g_bus_own_name (GBusType                  bus_type,
                 const gchar              *name,
@@ -584,7 +665,6 @@ g_bus_own_name (GBusType                  bus_type,
 {
   Client *client;
 
-  g_return_val_if_fail (bus_type != G_BUS_TYPE_NONE, 0);
   g_return_val_if_fail (g_dbus_is_name (name) && !g_dbus_is_unique_name (name), 0);
 
   G_LOCK (lock);
@@ -599,9 +679,7 @@ g_bus_own_name (GBusType                  bus_type,
   client->name_lost_handler = name_lost_handler;
   client->user_data = user_data;
   client->user_data_free_func = user_data_free_func;
-  client->main_context = g_main_context_get_thread_default ();
-  if (client->main_context != NULL)
-    g_main_context_ref (client->main_context);
+  client->main_context = g_main_context_ref_thread_default ();
 
   if (map_id_to_client == NULL)
     {
@@ -621,11 +699,212 @@ g_bus_own_name (GBusType                  bus_type,
   return client->id;
 }
 
+typedef struct {
+  GClosure *bus_acquired_closure;
+  GClosure *name_acquired_closure;
+  GClosure *name_lost_closure;
+} OwnNameData;
+
+static OwnNameData *
+own_name_data_new (GClosure *bus_acquired_closure,
+                   GClosure *name_acquired_closure,
+                   GClosure *name_lost_closure)
+{
+  OwnNameData *data;
+
+  data = g_new0 (OwnNameData, 1);
+
+  if (bus_acquired_closure != NULL)
+    {
+      data->bus_acquired_closure = g_closure_ref (bus_acquired_closure);
+      g_closure_sink (bus_acquired_closure);
+      if (G_CLOSURE_NEEDS_MARSHAL (bus_acquired_closure))
+        g_closure_set_marshal (bus_acquired_closure, g_cclosure_marshal_generic);
+    }
+
+  if (name_acquired_closure != NULL)
+    {
+      data->name_acquired_closure = g_closure_ref (name_acquired_closure);
+      g_closure_sink (name_acquired_closure);
+      if (G_CLOSURE_NEEDS_MARSHAL (name_acquired_closure))
+        g_closure_set_marshal (name_acquired_closure, g_cclosure_marshal_generic);
+    }
+
+  if (name_lost_closure != NULL)
+    {
+      data->name_lost_closure = g_closure_ref (name_lost_closure);
+      g_closure_sink (name_lost_closure);
+      if (G_CLOSURE_NEEDS_MARSHAL (name_lost_closure))
+        g_closure_set_marshal (name_lost_closure, g_cclosure_marshal_generic);
+    }
+
+  return data;
+}
+
+static void
+own_with_closures_on_bus_acquired (GDBusConnection *connection,
+                                   const gchar     *name,
+                                   gpointer         user_data)
+{
+  OwnNameData *data = user_data;
+  GValue params[2] = { G_VALUE_INIT, G_VALUE_INIT };
+
+  g_value_init (&params[0], G_TYPE_DBUS_CONNECTION);
+  g_value_set_object (&params[0], connection);
+
+  g_value_init (&params[1], G_TYPE_STRING);
+  g_value_set_string (&params[1], name);
+
+  g_closure_invoke (data->bus_acquired_closure, NULL, 2, params, NULL);
+
+  g_value_unset (params + 0);
+  g_value_unset (params + 1);
+}
+
+static void
+own_with_closures_on_name_acquired (GDBusConnection *connection,
+                                    const gchar     *name,
+                                    gpointer         user_data)
+{
+  OwnNameData *data = user_data;
+  GValue params[2] = { G_VALUE_INIT, G_VALUE_INIT };
+
+  g_value_init (&params[0], G_TYPE_DBUS_CONNECTION);
+  g_value_set_object (&params[0], connection);
+
+  g_value_init (&params[1], G_TYPE_STRING);
+  g_value_set_string (&params[1], name);
+
+  g_closure_invoke (data->name_acquired_closure, NULL, 2, params, NULL);
+
+  g_value_unset (params + 0);
+  g_value_unset (params + 1);
+}
+
+static void
+own_with_closures_on_name_lost (GDBusConnection *connection,
+                                const gchar     *name,
+                                gpointer         user_data)
+{
+  OwnNameData *data = user_data;
+  GValue params[2] = { G_VALUE_INIT, G_VALUE_INIT };
+
+  g_value_init (&params[0], G_TYPE_DBUS_CONNECTION);
+  g_value_set_object (&params[0], connection);
+
+  g_value_init (&params[1], G_TYPE_STRING);
+  g_value_set_string (&params[1], name);
+
+  g_closure_invoke (data->name_lost_closure, NULL, 2, params, NULL);
+
+  g_value_unset (params + 0);
+  g_value_unset (params + 1);
+}
+
+static void
+bus_own_name_free_func (gpointer user_data)
+{
+  OwnNameData *data = user_data;
+
+  if (data->bus_acquired_closure != NULL)
+    g_closure_unref (data->bus_acquired_closure);
+
+  if (data->name_acquired_closure != NULL)
+    g_closure_unref (data->name_acquired_closure);
+
+  if (data->name_lost_closure != NULL)
+    g_closure_unref (data->name_lost_closure);
+
+  g_free (data);
+}
+
+/**
+ * g_bus_own_name_with_closures:
+ * @bus_type: the type of bus to own a name on
+ * @name: the well-known name to own
+ * @flags: a set of flags from the #GBusNameOwnerFlags enumeration
+ * @bus_acquired_closure: (allow-none): #GClosure to invoke when connected to
+ *     the bus of type @bus_type or %NULL
+ * @name_acquired_closure: (allow-none): #GClosure to invoke when @name is
+ *     acquired or %NULL
+ * @name_lost_closure: (allow-none): #GClosure to invoke when @name is lost or
+ *     %NULL
+ *
+ * Version of g_bus_own_name() using closures instead of callbacks for
+ * easier binding in other languages.
+ *
+ * Returns: an identifier (never 0) that an be used with
+ *     g_bus_unown_name() to stop owning the name.
+ *
+ * Rename to: g_bus_own_name
+ *
+ * Since: 2.26
+ */
+guint
+g_bus_own_name_with_closures (GBusType            bus_type,
+                              const gchar        *name,
+                              GBusNameOwnerFlags  flags,
+                              GClosure           *bus_acquired_closure,
+                              GClosure           *name_acquired_closure,
+                              GClosure           *name_lost_closure)
+{
+  return g_bus_own_name (bus_type,
+          name,
+          flags,
+          bus_acquired_closure != NULL ? own_with_closures_on_bus_acquired : NULL,
+          name_acquired_closure != NULL ? own_with_closures_on_name_acquired : NULL,
+          name_lost_closure != NULL ? own_with_closures_on_name_lost : NULL,
+          own_name_data_new (bus_acquired_closure,
+                             name_acquired_closure,
+                             name_lost_closure),
+          bus_own_name_free_func);
+}
+
+/**
+ * g_bus_own_name_on_connection_with_closures:
+ * @connection: a #GDBusConnection
+ * @name: the well-known name to own
+ * @flags: a set of flags from the #GBusNameOwnerFlags enumeration
+ * @name_acquired_closure: (allow-none): #GClosure to invoke when @name is
+ *     acquired or %NULL
+ * @name_lost_closure: (allow-none): #GClosure to invoke when @name is lost
+ *     or %NULL
+ *
+ * Version of g_bus_own_name_on_connection() using closures instead of
+ * callbacks for easier binding in other languages.
+ *
+ * Returns: an identifier (never 0) that an be used with
+ *     g_bus_unown_name() to stop owning the name.
+ *
+ * Rename to: g_bus_own_name_on_connection
+ *
+ * Since: 2.26
+ */
+guint
+g_bus_own_name_on_connection_with_closures (GDBusConnection    *connection,
+                                            const gchar        *name,
+                                            GBusNameOwnerFlags  flags,
+                                            GClosure           *name_acquired_closure,
+                                            GClosure           *name_lost_closure)
+{
+  return g_bus_own_name_on_connection (connection,
+          name,
+          flags,
+          name_acquired_closure != NULL ? own_with_closures_on_name_acquired : NULL,
+          name_lost_closure != NULL ? own_with_closures_on_name_lost : NULL,
+          own_name_data_new (NULL,
+                             name_acquired_closure,
+                             name_lost_closure),
+          bus_own_name_free_func);
+}
+
 /**
  * g_bus_unown_name:
- * @owner_id: An identifier obtained from g_bus_own_name()
+ * @owner_id: an identifier obtained from g_bus_own_name()
  *
  * Stops owning a name.
+ *
+ * Since: 2.26
  */
 void
 g_bus_unown_name (guint owner_id)
@@ -654,7 +933,9 @@ g_bus_unown_name (guint owner_id)
   if (client != NULL)
     {
       /* Release the name if needed */
-      if (client->needs_release && client->connection != NULL)
+      if (client->needs_release &&
+          client->connection != NULL &&
+          !g_dbus_connection_is_closed (client->connection))
         {
           GVariant *result;
           GError *error;
@@ -667,16 +948,20 @@ g_bus_unown_name (guint owner_id)
            * I believe this is a bug in the bus daemon.
            */
           error = NULL;
-          result = g_dbus_connection_invoke_method_sync (client->connection,
-                                                         "org.freedesktop.DBus",  /* bus name */
-                                                         "/org/freedesktop/DBus", /* object path */
-                                                         "org.freedesktop.DBus",  /* interface name */
-                                                         "ReleaseName",           /* method name */
-                                                         g_variant_new ("(s)", client->name),
-                                                         G_DBUS_INVOKE_METHOD_FLAGS_NONE,
-                                                         -1,
-                                                         NULL,
-                                                         &error);
+          if (G_IS_KDBUS_CONNECTION (g_dbus_connection_get_stream (client->connection)))
+            result = _g_kdbus_ReleaseName (client->connection, client->name, &error);
+          else
+            result = g_dbus_connection_call_sync (client->connection,
+                                                  "org.freedesktop.DBus",  /* bus name */
+                                                  "/org/freedesktop/DBus", /* object path */
+                                                  "org.freedesktop.DBus",  /* interface name */
+                                                  "ReleaseName",           /* method name */
+                                                  g_variant_new ("(s)", client->name),
+                                                  G_VARIANT_TYPE ("(u)"),
+                                                  G_DBUS_CALL_FLAGS_NONE,
+                                                  -1,
+                                                  NULL,
+                                                  &error);
           if (result == NULL)
             {
               g_warning ("Error releasing name %s: %s", client->name, error->message);