* 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>
*/
*
* 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);
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;
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);
}
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:
+ ;
}
/* ---------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------- */
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_call_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)
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,
- G_DBUS_SIGNAL_FLAGS_NONE,
- 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,
- G_DBUS_SIGNAL_FLAGS_NONE,
- 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);
}
"closed",
G_CALLBACK (on_connection_disconnected),
client);
-
/* attempt to acquire the name */
- 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));
+ if (1)
+ {
+ GError *error = NULL;
+ guint32 request_name_reply;
+
+ request_name_reply = 0;
+
+ request_name_reply = g_dbus_request_name (client->connection, client->name, client->flags, &error);
+ g_assert_no_error (error);
+
+ 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));
+ }
}
{
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)
{
/**
* g_bus_own_name_on_connection:
- * @connection: A #GDBusConnection.
- * @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
*/
/**
* 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 for the same name (unless
* interleaved with calls to g_bus_unown_name()) - only the first call
* 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"/>.
+ * 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
*/
/**
* 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_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.
+ * the bus of type @bus_type or %NULL
* @name_acquired_closure: (allow-none): #GClosure to invoke when @name is
- * acquired or %NULL.
+ * acquired or %NULL
* @name_lost_closure: (allow-none): #GClosure to invoke when @name is lost or
- * %NULL.
+ * %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.
+ * 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)
+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,
/**
* 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.
+ * @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.
+ * 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.
+ * 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.
+ * 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)
+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,
/**
* 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.
*
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;
* I believe this is a bug in the bus daemon.
*/
error = NULL;
- 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 (1)
+ {
+ g_dbus_release_name (client->connection, client->name, &error);
+ g_assert_no_error (error);
+
+ result = g_variant_ref_sink (g_variant_new_uint32 (1));
+ }
+ 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);