* 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.
+ * version 2.1 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
* kind of pitfalls it avoids
* - Export objects before claiming names
* - Talk about auto-starting services (cf. GBusNameWatcherFlags)
- *
- * - use abstract sockets in test code
- * - right now it doesn't work, dbus-daemon(1) fails with
- *
- * /gdbus/connection/filter: Failed to start message bus: Failed to bind
- * socket "/tmp/g-dbus-tests-pid-28531": Address already in use
- * ** WARNING **: Error reading address from dbus daemon, 0 bytes read
- *
- * or similar.
*/
#include "config.h"
#include "giostream.h"
#include "gasyncresult.h"
#include "gtask.h"
+#include "gmarshal-internal.h"
#ifdef G_OS_UNIX
#include "gunixconnection.h"
* The #GDBusConnection type is used for D-Bus connections to remote
* peers such as a message buses. It is a low-level API that offers a
* lot of flexibility. For instance, it lets you establish a connection
- * over any transport that can by represented as an #GIOStream.
+ * over any transport that can by represented as a #GIOStream.
*
* This class is rarely used directly in D-Bus clients. If you are writing
* a D-Bus client, it is often easier to use the g_bus_own_name(),
* ## An example for file descriptor passing # {#gdbus-unix-fd-client}
*
* Here is an example for passing UNIX file descriptors:
- * [gdbus-unix-fd-client.c](https://git.gnome.org/browse/glib/tree/gio/tests/gdbus-unix-fd-client.c)
+ * [gdbus-unix-fd-client.c](https://git.gnome.org/browse/glib/tree/gio/tests/gdbus-example-unix-fd-client.c)
*
* ## An example for exporting a GObject # {#gdbus-export}
*
* message, and we're being called from its thread, so no memory barrier is
* required before accessing them.
*/
-#define SEND_MESSAGE_FLAGS_INITIALIZING (1<<31)
+#define SEND_MESSAGE_FLAGS_INITIALIZING (1u << 31)
/* Same as SEND_MESSAGE_FLAGS_INITIALIZING, but in GDBusCallFlags */
-#define CALL_FLAGS_INITIALIZING (1<<31)
+#define CALL_FLAGS_INITIALIZING (1u << 31)
/* ---------------------------------------------------------------------------------------------------- */
/*
* call_destroy_notify: <internal>
- * @context: (allow-none): A #GMainContext or %NULL.
- * @callback: (allow-none): A #GDestroyNotify or %NULL.
+ * @context: (nullable): A #GMainContext or %NULL.
+ * @callback: (nullable): A #GDestroyNotify or %NULL.
* @user_data: Data to pass to @callback.
*
* Schedules @callback to run in @context.
else
{
if (alive_connections != NULL)
- g_warn_if_fail (g_hash_table_lookup (alive_connections, connection) == NULL);
+ g_warn_if_fail (!g_hash_table_contains (alive_connections, connection));
}
CONNECTION_UNLOCK (connection);
G_UNLOCK (message_bus_lock);
g_value_set_flags (value, g_dbus_connection_get_capabilities (connection));
break;
+ case PROP_FLAGS:
+ g_value_set_flags (value, g_dbus_connection_get_flags (connection));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
(flags & FLAG_INITIALIZED) != 0 &&
connection->initialization_error == NULL)
{
- if (error != NULL)
- {
- g_printerr ("%s: Remote peer vanished with error: %s (%s, %d). Exiting.\n",
- G_STRFUNC,
- error->message,
- g_quark_to_string (error->domain), error->code);
- }
- else
- {
- g_printerr ("%s: Remote peer vanished. Exiting.\n", G_STRFUNC);
- }
raise (SIGTERM);
}
}
P_("Flags"),
G_TYPE_DBUS_CONNECTION_FLAGS,
G_DBUS_CONNECTION_FLAGS_NONE,
+ G_PARAM_READABLE |
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_NAME |
* @connection: the #GDBusConnection emitting the signal
* @remote_peer_vanished: %TRUE if @connection is closed because the
* remote peer closed its end of the connection
- * @error: (allow-none): a #GError with more details about the event or %NULL
+ * @error: (nullable): a #GError with more details about the event or %NULL
*
* Emitted when the connection is closed.
*
*
* Since: 2.26
*/
- signals[CLOSED_SIGNAL] = g_signal_new ("closed",
+ signals[CLOSED_SIGNAL] = g_signal_new (I_("closed"),
G_TYPE_DBUS_CONNECTION,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GDBusConnectionClass, closed),
NULL,
NULL,
- NULL,
+ _g_cclosure_marshal_VOID__BOOLEAN_BOXED,
G_TYPE_NONE,
2,
G_TYPE_BOOLEAN,
G_TYPE_ERROR);
+ g_signal_set_va_marshaller (signals[CLOSED_SIGNAL],
+ G_TYPE_FROM_CLASS (klass),
+ _g_cclosure_marshal_VOID__BOOLEAN_BOXEDv);
}
static void
return connection->capabilities;
}
+/**
+ * g_dbus_connection_get_flags:
+ * @connection: a #GDBusConnection
+ *
+ * Gets the flags used to construct this connection
+ *
+ * Returns: zero or more flags from the #GDBusConnectionFlags enumeration
+ *
+ * Since: 2.60
+ */
+GDBusConnectionFlags
+g_dbus_connection_get_flags (GDBusConnection *connection)
+{
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), G_DBUS_CONNECTION_FLAGS_NONE);
+
+ /* do not use g_return_val_if_fail(), we want the memory barrier */
+ if (!check_initialized (connection))
+ return G_DBUS_CONNECTION_FLAGS_NONE;
+
+ return connection->flags;
+}
+
/* ---------------------------------------------------------------------------------------------------- */
/* Called in a temporary thread without holding locks. */
/**
* g_dbus_connection_flush:
* @connection: a #GDBusConnection
- * @cancellable: (allow-none): a #GCancellable or %NULL
- * @callback: (allow-none): a #GAsyncReadyCallback to call when the
+ * @cancellable: (nullable): a #GCancellable or %NULL
+ * @callback: (nullable): a #GAsyncReadyCallback to call when the
* request is satisfied or %NULL if you don't care about the result
* @user_data: The data to pass to @callback
*
g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
task = g_task_new (connection, cancellable, callback, user_data);
+ g_task_set_source_tag (task, g_dbus_connection_flush);
g_task_run_in_thread (task, flush_in_thread_func);
g_object_unref (task);
}
/**
* g_dbus_connection_flush_sync:
* @connection: a #GDBusConnection
- * @cancellable: (allow-none): a #GCancellable or %NULL
+ * @cancellable: (nullable): a #GCancellable or %NULL
* @error: return location for error or %NULL
*
* Synchronously flushes @connection. The calling thread is blocked
/**
* g_dbus_connection_close:
* @connection: a #GDBusConnection
- * @cancellable: (allow-none): a #GCancellable or %NULL
- * @callback: (allow-none): a #GAsyncReadyCallback to call when the request is
+ * @cancellable: (nullable): a #GCancellable or %NULL
+ * @callback: (nullable): a #GAsyncReadyCallback to call when the request is
* satisfied or %NULL if you don't care about the result
* @user_data: The data to pass to @callback
*
g_assert (connection->worker != NULL);
task = g_task_new (connection, cancellable, callback, user_data);
+ g_task_set_source_tag (task, g_dbus_connection_close);
_g_dbus_worker_close (connection->worker, task);
g_object_unref (task);
}
/**
* g_dbus_connection_close_sync:
* @connection: a #GDBusConnection
- * @cancellable: (allow-none): a #GCancellable or %NULL
+ * @cancellable: (nullable): a #GCancellable or %NULL
* @error: return location for error or %NULL
*
- * Synchronously closees @connection. The calling thread is blocked
+ * Synchronously closes @connection. The calling thread is blocked
* until this is done. See g_dbus_connection_close() for the
* asynchronous version of this method and more details about what it
* does.
* @connection: a #GDBusConnection
* @message: a #GDBusMessage
* @flags: flags affecting how the message is sent
- * @out_serial: (out) (allow-none): return location for serial number assigned
+ * @out_serial: (out) (optional): return location for serial number assigned
* to @message when sending it or %NULL
* @error: Return location for error or %NULL
*
/* ---------------------------------------------------------------------------------------------------- */
-/* can be called from any thread with lock held */
+/* can be called from any thread with lock held; @task is (transfer full) */
static void
send_message_with_reply_cleanup (GTask *task, gboolean remove)
{
/* ---------------------------------------------------------------------------------------------------- */
-/* Called from GDBus worker thread with lock held */
+/* Called from GDBus worker thread with lock held; @task is (transfer full). */
static void
send_message_data_deliver_reply_unlocked (GTask *task,
GDBusMessage *reply)
/* ---------------------------------------------------------------------------------------------------- */
-/* Called from a user thread, lock is not held */
+/* Called from a user thread, lock is not held; @task is (transfer full) */
static gboolean
send_message_with_reply_cancelled_idle_cb (gpointer user_data)
{
/* ---------------------------------------------------------------------------------------------------- */
-/* Called from a user thread, lock is not held */
+/* Called from a user thread, lock is not held; @task is (transfer full) */
static gboolean
send_message_with_reply_timeout_cb (gpointer user_data)
{
data = g_slice_new0 (SendMessageData);
task = g_task_new (connection, cancellable, callback, user_data);
+ g_task_set_source_tag (task,
+ g_dbus_connection_send_message_with_reply_unlocked);
g_task_set_task_data (task, data, (GDestroyNotify) send_message_data_free);
if (g_task_return_error_if_cancelled (task))
g_hash_table_insert (connection->map_method_serial_to_task,
GUINT_TO_POINTER (*out_serial),
- task);
+ g_steal_pointer (&task));
}
/**
* @flags: flags affecting how the message is sent
* @timeout_msec: the timeout in milliseconds, -1 to use the default
* timeout or %G_MAXINT for no timeout
- * @out_serial: (out) (allow-none): return location for serial number assigned
+ * @out_serial: (out) (optional): return location for serial number assigned
* to @message when sending it or %NULL
- * @cancellable: (allow-none): a #GCancellable or %NULL
- * @callback: (allow-none): a #GAsyncReadyCallback to call when the request
+ * @cancellable: (nullable): a #GCancellable or %NULL
+ * @callback: (nullable): a #GAsyncReadyCallback to call when the request
* is satisfied or %NULL if you don't care about the result
* @user_data: The data to pass to @callback
*
* @flags: flags affecting how the message is sent.
* @timeout_msec: the timeout in milliseconds, -1 to use the default
* timeout or %G_MAXINT for no timeout
- * @out_serial: (out) (allow-none): return location for serial number
+ * @out_serial: (out) (optional): return location for serial number
* assigned to @message when sending it or %NULL
- * @cancellable: (allow-none): a #GCancellable or %NULL
+ * @cancellable: (nullable): a #GCancellable or %NULL
* @error: return location for error or %NULL
*
* Synchronously sends @message to the peer represented by @connection
typedef struct
{
- GDBusMessageFilterFunction func;
- gpointer user_data;
-} FilterCallback;
-
-typedef struct
-{
guint id;
+ guint ref_count;
GDBusMessageFilterFunction filter_function;
gpointer user_data;
GDestroyNotify user_data_free_func;
+ GMainContext *context;
} FilterData;
+/* requires CONNECTION_LOCK */
+static FilterData **
+copy_filter_list (GPtrArray *filters)
+{
+ FilterData **copy;
+ guint n;
+
+ copy = g_new (FilterData *, filters->len + 1);
+ for (n = 0; n < filters->len; n++)
+ {
+ copy[n] = filters->pdata[n];
+ copy[n]->ref_count++;
+ }
+ copy[n] = NULL;
+
+ return copy;
+}
+
+/* requires CONNECTION_LOCK */
+static void
+free_filter_list (FilterData **filters)
+{
+ guint n;
+
+ for (n = 0; filters[n]; n++)
+ {
+ filters[n]->ref_count--;
+ if (filters[n]->ref_count == 0)
+ {
+ call_destroy_notify (filters[n]->context,
+ filters[n]->user_data_free_func,
+ filters[n]->user_data);
+ g_main_context_unref (filters[n]->context);
+ g_free (filters[n]);
+ }
+ }
+ g_free (filters);
+}
+
/* Called in GDBusWorker's thread - we must not block - with no lock held */
static void
on_worker_message_received (GDBusWorker *worker,
gpointer user_data)
{
GDBusConnection *connection;
- FilterCallback *filters;
- guint num_filters;
+ FilterData **filters;
guint n;
gboolean alive;
G_LOCK (message_bus_lock);
- alive = (g_hash_table_lookup (alive_connections, user_data) != NULL);
+ alive = g_hash_table_contains (alive_connections, user_data);
if (!alive)
{
G_UNLOCK (message_bus_lock);
/* First collect the set of callback functions */
CONNECTION_LOCK (connection);
- num_filters = connection->filters->len;
- filters = g_new0 (FilterCallback, num_filters);
- for (n = 0; n < num_filters; n++)
- {
- FilterData *data = connection->filters->pdata[n];
- filters[n].func = data->filter_function;
- filters[n].user_data = data->user_data;
- }
+ filters = copy_filter_list (connection->filters);
CONNECTION_UNLOCK (connection);
/* then call the filters in order (without holding the lock) */
- for (n = 0; n < num_filters; n++)
+ for (n = 0; filters[n]; n++)
{
- message = filters[n].func (connection,
- message,
- TRUE,
- filters[n].user_data);
+ message = filters[n]->filter_function (connection,
+ message,
+ TRUE,
+ filters[n]->user_data);
if (message == NULL)
break;
g_dbus_message_lock (message);
}
+ CONNECTION_LOCK (connection);
+ free_filter_list (filters);
+ CONNECTION_UNLOCK (connection);
+
/* Standard dispatch unless the filter ate the message - no need to
* do anything if the message was altered
*/
GUINT_TO_POINTER (reply_serial));
if (task != NULL)
{
+ /* This removes @task from @map_method_serial_to_task. */
//g_debug ("delivering reply/error for serial %d for %p", reply_serial, connection);
send_message_data_deliver_reply_unlocked (task, message);
}
if (message != NULL)
g_object_unref (message);
g_object_unref (connection);
- g_free (filters);
}
/* Called in GDBusWorker's thread, lock is not held */
gpointer user_data)
{
GDBusConnection *connection;
- FilterCallback *filters;
- guint num_filters;
+ FilterData **filters;
guint n;
gboolean alive;
G_LOCK (message_bus_lock);
- alive = (g_hash_table_lookup (alive_connections, user_data) != NULL);
+ alive = g_hash_table_contains (alive_connections, user_data);
if (!alive)
{
G_UNLOCK (message_bus_lock);
/* First collect the set of callback functions */
CONNECTION_LOCK (connection);
- num_filters = connection->filters->len;
- filters = g_new0 (FilterCallback, num_filters);
- for (n = 0; n < num_filters; n++)
- {
- FilterData *data = connection->filters->pdata[n];
- filters[n].func = data->filter_function;
- filters[n].user_data = data->user_data;
- }
+ filters = copy_filter_list (connection->filters);
CONNECTION_UNLOCK (connection);
/* then call the filters in order (without holding the lock) */
- for (n = 0; n < num_filters; n++)
+ for (n = 0; filters[n]; n++)
{
g_dbus_message_lock (message);
- message = filters[n].func (connection,
- message,
- FALSE,
- filters[n].user_data);
+ message = filters[n]->filter_function (connection,
+ message,
+ FALSE,
+ filters[n]->user_data);
if (message == NULL)
break;
}
+ CONNECTION_LOCK (connection);
+ free_filter_list (filters);
+ CONNECTION_UNLOCK (connection);
+
g_object_unref (connection);
- g_free (filters);
return message;
}
guint old_atomic_flags;
G_LOCK (message_bus_lock);
- alive = (g_hash_table_lookup (alive_connections, user_data) != NULL);
+ alive = g_hash_table_contains (alive_connections, user_data);
if (!alive)
{
G_UNLOCK (message_bus_lock);
G_LOCK (message_bus_lock);
if (alive_connections == NULL)
alive_connections = g_hash_table_new (g_direct_hash, g_direct_equal);
- g_hash_table_insert (alive_connections, connection, connection);
+ g_hash_table_add (alive_connections, connection);
G_UNLOCK (message_bus_lock);
connection->worker = _g_dbus_worker_new (connection->stream,
/**
* g_dbus_connection_new:
* @stream: a #GIOStream
- * @guid: (allow-none): the GUID to use if a authenticating as a server or %NULL
+ * @guid: (nullable): the GUID to use if a authenticating as a server or %NULL
* @flags: flags describing how to make the connection
- * @observer: (allow-none): a #GDBusAuthObserver or %NULL
- * @cancellable: (allow-none): a #GCancellable or %NULL
+ * @observer: (nullable): a #GDBusAuthObserver or %NULL
+ * @cancellable: (nullable): a #GCancellable or %NULL
* @callback: a #GAsyncReadyCallback to call when the request is satisfied
* @user_data: the data to pass to @callback
*
* then call g_dbus_connection_new_finish() to get the result of the
* operation.
*
- * This is a asynchronous failable constructor. See
+ * This is an asynchronous failable constructor. See
* g_dbus_connection_new_sync() for the synchronous
* version.
*
GAsyncReadyCallback callback,
gpointer user_data)
{
+ _g_dbus_initialize ();
+
g_return_if_fail (G_IS_IO_STREAM (stream));
+
g_async_initable_new_async (G_TYPE_DBUS_CONNECTION,
G_PRIORITY_DEFAULT,
cancellable,
/**
* g_dbus_connection_new_sync:
* @stream: a #GIOStream
- * @guid: (allow-none): the GUID to use if a authenticating as a server or %NULL
+ * @guid: (nullable): the GUID to use if a authenticating as a server or %NULL
* @flags: flags describing how to make the connection
- * @observer: (allow-none): a #GDBusAuthObserver or %NULL
- * @cancellable: (allow-none): a #GCancellable or %NULL
+ * @observer: (nullable): a #GDBusAuthObserver or %NULL
+ * @cancellable: (nullable): a #GCancellable or %NULL
* @error: return location for error or %NULL
*
* Synchronously sets up a D-Bus connection for exchanging D-Bus messages
GCancellable *cancellable,
GError **error)
{
+ _g_dbus_initialize ();
g_return_val_if_fail (G_IS_IO_STREAM (stream), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
return g_initable_new (G_TYPE_DBUS_CONNECTION,
* g_dbus_connection_new_for_address:
* @address: a D-Bus address
* @flags: flags describing how to make the connection
- * @observer: (allow-none): a #GDBusAuthObserver or %NULL
- * @cancellable: (allow-none): a #GCancellable or %NULL
+ * @observer: (nullable): a #GDBusAuthObserver or %NULL
+ * @cancellable: (nullable): a #GCancellable or %NULL
* @callback: a #GAsyncReadyCallback to call when the request is satisfied
* @user_data: the data to pass to @callback
*
* Asynchronously connects and sets up a D-Bus client connection for
* exchanging D-Bus messages with an endpoint specified by @address
- * which must be in the D-Bus address format.
+ * which must be in the
+ * [D-Bus address format](https://dbus.freedesktop.org/doc/dbus-specification.html#addresses).
*
* This constructor can only be used to initiate client-side
* connections - use g_dbus_connection_new() if you need to act as the
* %G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS flags.
*
* When the operation is finished, @callback will be invoked. You can
- * then call g_dbus_connection_new_finish() to get the result of the
- * operation.
+ * then call g_dbus_connection_new_for_address_finish() to get the result of
+ * the operation.
*
* If @observer is not %NULL it may be used to control the
* authentication process.
*
- * This is a asynchronous failable constructor. See
+ * This is an asynchronous failable constructor. See
* g_dbus_connection_new_for_address_sync() for the synchronous
* version.
*
GAsyncReadyCallback callback,
gpointer user_data)
{
+ _g_dbus_initialize ();
+
g_return_if_fail (address != NULL);
+
g_async_initable_new_async (G_TYPE_DBUS_CONNECTION,
G_PRIORITY_DEFAULT,
cancellable,
* g_dbus_connection_new_for_address_sync:
* @address: a D-Bus address
* @flags: flags describing how to make the connection
- * @observer: (allow-none): a #GDBusAuthObserver or %NULL
- * @cancellable: (allow-none): a #GCancellable or %NULL
+ * @observer: (nullable): a #GDBusAuthObserver or %NULL
+ * @cancellable: (nullable): a #GCancellable or %NULL
* @error: return location for error or %NULL
*
* Synchronously connects and sets up a D-Bus client connection for
* exchanging D-Bus messages with an endpoint specified by @address
- * which must be in the D-Bus address format.
+ * which must be in the
+ * [D-Bus address format](https://dbus.freedesktop.org/doc/dbus-specification.html#addresses).
*
* This constructor can only be used to initiate client-side
* connections - use g_dbus_connection_new_sync() if you need to act
GCancellable *cancellable,
GError **error)
{
+ _g_dbus_initialize ();
+
g_return_val_if_fail (address != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
return g_initable_new (G_TYPE_DBUS_CONNECTION,
* more details.
*
* Note that this function should be used with care. Most modern UNIX
- * desktops tie the notion of a user session the session bus, and expect
- * all of a users applications to quit when their bus connection goes away.
+ * desktops tie the notion of a user session with the session bus, and expect
+ * all of a user's applications to quit when their bus connection goes away.
* If you are setting @exit_on_close to %FALSE for the shared session
* bus connection, you should make sure that your application exits
* when the user session ends.
* bus. This can also be used to figure out if @connection is a
* message bus connection.
*
- * Returns: the unique name or %NULL if @connection is not a message
+ * Returns: (nullable): the unique name or %NULL if @connection is not a message
* bus connection. Do not free this string, it is owned by
* @connection.
*
* each application is a client. So this method will always return
* %NULL for message bus clients.
*
- * Returns: (transfer none): a #GCredentials or %NULL if not available.
- * Do not free this object, it is owned by @connection.
+ * Returns: (transfer none) (nullable): a #GCredentials or %NULL if not
+ * available. Do not free this object, it is owned by @connection.
*
* Since: 2.26
*/
/* ---------------------------------------------------------------------------------------------------- */
-static guint _global_filter_id = 1;
+static volatile guint _global_filter_id = 1;
/**
* g_dbus_connection_add_filter:
* dispatched anywhere else - not even the standard dispatch machinery
* (that API such as g_dbus_connection_signal_subscribe() and
* g_dbus_connection_send_message_with_reply() relies on) will see the
- * message. Similary, if a filter consumes an outgoing message, the
+ * message. Similarly, if a filter consumes an outgoing message, the
* message will not be sent to the other peer.
*
+ * If @user_data_free_func is non-%NULL, it will be called (in the
+ * thread-default main context of the thread you are calling this
+ * method from) at some point after @user_data is no longer
+ * needed. (It is not guaranteed to be called synchronously when the
+ * filter is removed, and may be called after @connection has been
+ * destroyed.)
+ *
* Returns: a filter identifier that can be used with
* g_dbus_connection_remove_filter()
*
CONNECTION_LOCK (connection);
data = g_new0 (FilterData, 1);
- data->id = _global_filter_id++; /* TODO: overflow etc. */
+ data->id = g_atomic_int_add (&_global_filter_id, 1); /* TODO: overflow etc. */
+ data->ref_count = 1;
data->filter_function = filter_function;
data->user_data = user_data;
data->user_data_free_func = user_data_free_func;
+ data->context = g_main_context_ref_thread_default ();
g_ptr_array_add (connection->filters, data);
CONNECTION_UNLOCK (connection);
for (n = 0; n < connection->filters->len; n++)
{
FilterData *data = connection->filters->pdata[n];
- if (data->user_data_free_func != NULL)
- data->user_data_free_func (data->user_data);
+
+ call_destroy_notify (data->context,
+ data->user_data_free_func,
+ data->user_data);
+ g_main_context_unref (data->context);
g_free (data);
}
}
*
* Removes a filter.
*
+ * Note that since filters run in a different thread, there is a race
+ * condition where it is possible that the filter will be running even
+ * after calling g_dbus_connection_remove_filter(), so you cannot just
+ * free data that the filter might be using. Instead, you should pass
+ * a #GDestroyNotify to g_dbus_connection_add_filter(), which will be
+ * called when it is guaranteed that the data is no longer needed.
+ *
* Since: 2.26
*/
void
guint filter_id)
{
guint n;
+ gboolean found;
FilterData *to_destroy;
g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
g_return_if_fail (check_initialized (connection));
CONNECTION_LOCK (connection);
+ found = FALSE;
to_destroy = NULL;
for (n = 0; n < connection->filters->len; n++)
{
FilterData *data = connection->filters->pdata[n];
if (data->id == filter_id)
{
+ found = TRUE;
g_ptr_array_remove_index (connection->filters, n);
- to_destroy = data;
+ data->ref_count--;
+ if (data->ref_count == 0)
+ to_destroy = data;
break;
}
}
{
if (to_destroy->user_data_free_func != NULL)
to_destroy->user_data_free_func (to_destroy->user_data);
+ g_main_context_unref (to_destroy->context);
g_free (to_destroy);
}
- else
+ else if (!found)
{
g_warning ("g_dbus_connection_remove_filter: No filter found for filter_id %d", filter_id);
}
return g_string_free (rule, FALSE);
}
-static guint _global_subscriber_id = 1;
-static guint _global_registration_id = 1;
-static guint _global_subtree_registration_id = 1;
+static volatile guint _global_subscriber_id = 1;
+static volatile guint _global_registration_id = 1;
+static volatile guint _global_subtree_registration_id = 1;
/* ---------------------------------------------------------------------------------------------------- */
/**
* g_dbus_connection_signal_subscribe:
* @connection: a #GDBusConnection
- * @sender: (allow-none): sender name to match on (unique or well-known name)
+ * @sender: (nullable): sender name to match on (unique or well-known name)
* or %NULL to listen from all senders
- * @interface_name: (allow-none): D-Bus interface name to match on or %NULL to
+ * @interface_name: (nullable): D-Bus interface name to match on or %NULL to
* match on all interfaces
- * @member: (allow-none): D-Bus signal name to match on or %NULL to match on
+ * @member: (nullable): D-Bus signal name to match on or %NULL to match on
* all signals
- * @object_path: (allow-none): object path to match on or %NULL to match on
+ * @object_path: (nullable): object path to match on or %NULL to match on
* all object paths
- * @arg0: (allow-none): contents of first string argument to match on or %NULL
+ * @arg0: (nullable): contents of first string argument to match on or %NULL
* to match on all kinds of arguments
- * @flags: flags describing how to subscribe to the signal (currently unused)
+ * @flags: #GDBusSignalFlags describing how arg0 is used in subscribing to the
+ * signal
* @callback: callback to invoke when there is a signal matching the requested data
* @user_data: user data to pass to @callback
- * @user_data_free_func: (allow-none): function to free @user_data with when
+ * @user_data_free_func: (nullable): function to free @user_data with when
* subscription is removed or %NULL
*
* Subscribes to signals on @connection and invokes @callback with a whenever
* interpreted as part of a namespace or path. The first argument
* of a signal is matched against that part as specified by D-Bus.
*
+ * If @user_data_free_func is non-%NULL, it will be called (in the
+ * thread-default main context of the thread you are calling this
+ * method from) at some point after @user_data is no longer
+ * needed. (It is not guaranteed to be called synchronously when the
+ * signal is unsubscribed from, and may be called after @connection
+ * has been destroyed.)
+ *
+ * The returned subscription identifier is an opaque value which is guaranteed
+ * to never be zero.
+ *
+ * This function can never fail.
+ *
* Returns: a subscription identifier that can be used with g_dbus_connection_signal_unsubscribe()
*
* Since: 2.26
subscriber.callback = callback;
subscriber.user_data = user_data;
subscriber.user_data_free_func = user_data_free_func;
- subscriber.id = _global_subscriber_id++; /* TODO: overflow etc. */
+ subscriber.id = g_atomic_int_add (&_global_subscriber_id, 1); /* TODO: overflow etc. */
subscriber.context = g_main_context_ref_thread_default ();
/* see if we've already have this rule */
len_a = strlen (path_a);
len_b = strlen (path_b);
- if (len_a < len_b && path_a[len_a - 1] != '/')
+ if (len_a < len_b && (len_a == 0 || path_a[len_a - 1] != '/'))
return FALSE;
- if (len_b < len_a && path_b[len_b - 1] != '/')
+ if (len_b < len_a && (len_b == 0 || path_b[len_b - 1] != '/'))
return FALSE;
return memcmp (path_a, path_b, MIN (len_a, len_b)) == 0;
{
reply = g_dbus_message_new_method_error (data->message,
"org.freedesktop.DBus.Error.UnknownMethod",
- _("No such interface 'org.freedesktop.DBus.Properties' on object at path %s"),
+ _("No such interface “org.freedesktop.DBus.Properties” on object at path %s"),
g_dbus_message_get_path (data->message));
g_dbus_connection_send_message (data->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
g_object_unref (reply);
{
reply = g_dbus_message_new_method_error (message,
"org.freedesktop.DBus.Error.InvalidArgs",
- _("No such property '%s'"),
+ _("No such property “%s”"),
property_name);
g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
g_object_unref (reply);
{
reply = g_dbus_message_new_method_error (message,
"org.freedesktop.DBus.Error.InvalidArgs",
- _("Property '%s' is not readable"),
+ _("Property “%s” is not readable"),
property_name);
g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
g_object_unref (reply);
{
reply = g_dbus_message_new_method_error (message,
"org.freedesktop.DBus.Error.InvalidArgs",
- _("Property '%s' is not writable"),
+ _("Property “%s” is not writable"),
property_name);
g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
g_object_unref (reply);
{
reply = g_dbus_message_new_method_error (message,
"org.freedesktop.DBus.Error.InvalidArgs",
- _("Error setting property '%s': Expected type '%s' but got '%s'"),
+ _("Error setting property “%s”: Expected type “%s” but got “%s”"),
property_name, property_info->signature,
g_variant_get_type_string (value));
g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
GDBusMessage *reply;
reply = g_dbus_message_new_method_error (message,
"org.freedesktop.DBus.Error.InvalidArgs",
- _("No such interface '%s'"),
+ _("No such interface “%s”"),
interface_name);
g_dbus_connection_send_message_unlocked (eo->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
g_object_unref (reply);
{
reply = g_dbus_message_new_method_error (data->message,
"org.freedesktop.DBus.Error.UnknownMethod",
- _("No such interface 'org.freedesktop.DBus.Properties' on object at path %s"),
+ _("No such interface “org.freedesktop.DBus.Properties” on object at path %s"),
g_dbus_message_get_path (data->message));
g_dbus_connection_send_message (data->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
g_object_unref (reply);
GDBusMessage *reply;
reply = g_dbus_message_new_method_error (message,
"org.freedesktop.DBus.Error.InvalidArgs",
- _("No such interface"),
+ _("No such interface “%s”"),
interface_name);
g_dbus_connection_send_message_unlocked (eo->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
g_object_unref (reply);
else
s = g_strdup (begin);
- if (g_hash_table_lookup (set, s) == NULL)
- g_hash_table_insert (set, s, GUINT_TO_POINTER (1));
+ if (!g_hash_table_contains (set, s))
+ g_hash_table_add (set, s);
else
g_free (s);
}
GDBusMessage *reply;
reply = g_dbus_message_new_method_error (g_dbus_method_invocation_get_message (invocation),
"org.freedesktop.DBus.Error.UnknownMethod",
- _("No such interface '%s' on object at path %s"),
+ _("No such interface “%s” on object at path %s"),
g_dbus_method_invocation_get_interface_name (invocation),
g_dbus_method_invocation_get_object_path (invocation));
g_dbus_connection_send_message (g_dbus_method_invocation_get_connection (invocation), reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
call_in_idle_cb,
invocation,
g_object_unref);
- g_source_set_name (idle_source, "[gio] call_in_idle_cb");
+ g_source_set_name (idle_source, "[gio, " __FILE__ "] call_in_idle_cb");
g_source_attach (idle_source, main_context);
g_source_unref (idle_source);
}
{
reply = g_dbus_message_new_method_error (message,
"org.freedesktop.DBus.Error.UnknownMethod",
- _("No such method '%s'"),
+ _("No such method “%s”"),
g_dbus_message_get_member (message));
g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
g_object_unref (reply);
reply = g_dbus_message_new_method_error (message,
"org.freedesktop.DBus.Error.InvalidArgs",
- _("Type of message, '%s', does not match expected type '%s'"),
+ _("Type of message, “%s”, does not match expected type “%s”"),
g_variant_get_type_string (parameters),
type_string);
g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
* @connection: a #GDBusConnection
* @object_path: the object path to register at
* @interface_info: introspection data for the interface
- * @vtable: (allow-none): a #GDBusInterfaceVTable to call into or %NULL
- * @user_data: (allow-none): data to pass to functions in @vtable
+ * @vtable: (nullable): a #GDBusInterfaceVTable to call into or %NULL
+ * @user_data: (nullable): data to pass to functions in @vtable
* @user_data_free_func: function to call when the object path is unregistered
* @error: return location for error or %NULL
*
}
ei = g_new0 (ExportedInterface, 1);
- ei->id = _global_registration_id++; /* TODO: overflow etc. */
+ ei->id = g_atomic_int_add (&_global_registration_id, 1); /* TODO: overflow etc. */
ei->eo = eo;
ei->user_data = user_data;
ei->user_data_free_func = user_data_free_func;
return ret;
}
+typedef struct {
+ GClosure *method_call_closure;
+ GClosure *get_property_closure;
+ GClosure *set_property_closure;
+} RegisterObjectData;
+
+static RegisterObjectData *
+register_object_data_new (GClosure *method_call_closure,
+ GClosure *get_property_closure,
+ GClosure *set_property_closure)
+{
+ RegisterObjectData *data;
+
+ data = g_new0 (RegisterObjectData, 1);
+
+ if (method_call_closure != NULL)
+ {
+ data->method_call_closure = g_closure_ref (method_call_closure);
+ g_closure_sink (method_call_closure);
+ if (G_CLOSURE_NEEDS_MARSHAL (method_call_closure))
+ g_closure_set_marshal (method_call_closure, g_cclosure_marshal_generic);
+ }
+
+ if (get_property_closure != NULL)
+ {
+ data->get_property_closure = g_closure_ref (get_property_closure);
+ g_closure_sink (get_property_closure);
+ if (G_CLOSURE_NEEDS_MARSHAL (get_property_closure))
+ g_closure_set_marshal (get_property_closure, g_cclosure_marshal_generic);
+ }
+
+ if (set_property_closure != NULL)
+ {
+ data->set_property_closure = g_closure_ref (set_property_closure);
+ g_closure_sink (set_property_closure);
+ if (G_CLOSURE_NEEDS_MARSHAL (set_property_closure))
+ g_closure_set_marshal (set_property_closure, g_cclosure_marshal_generic);
+ }
+
+ return data;
+}
+
+static void
+register_object_free_func (gpointer user_data)
+{
+ RegisterObjectData *data = user_data;
+
+ g_clear_pointer (&data->method_call_closure, g_closure_unref);
+ g_clear_pointer (&data->get_property_closure, g_closure_unref);
+ g_clear_pointer (&data->set_property_closure, g_closure_unref);
+
+ g_free (data);
+}
+
+static void
+register_with_closures_on_method_call (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ RegisterObjectData *data = user_data;
+ GValue params[] = { G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT };
+
+ g_value_init (¶ms[0], G_TYPE_DBUS_CONNECTION);
+ g_value_set_object (¶ms[0], connection);
+
+ g_value_init (¶ms[1], G_TYPE_STRING);
+ g_value_set_string (¶ms[1], sender);
+
+ g_value_init (¶ms[2], G_TYPE_STRING);
+ g_value_set_string (¶ms[2], object_path);
+
+ g_value_init (¶ms[3], G_TYPE_STRING);
+ g_value_set_string (¶ms[3], interface_name);
+
+ g_value_init (¶ms[4], G_TYPE_STRING);
+ g_value_set_string (¶ms[4], method_name);
+
+ g_value_init (¶ms[5], G_TYPE_VARIANT);
+ g_value_set_variant (¶ms[5], parameters);
+
+ g_value_init (¶ms[6], G_TYPE_DBUS_METHOD_INVOCATION);
+ g_value_set_object (¶ms[6], invocation);
+
+ g_closure_invoke (data->method_call_closure, NULL, G_N_ELEMENTS (params), params, NULL);
+
+ g_value_unset (params + 0);
+ g_value_unset (params + 1);
+ g_value_unset (params + 2);
+ g_value_unset (params + 3);
+ g_value_unset (params + 4);
+ g_value_unset (params + 5);
+ g_value_unset (params + 6);
+}
+
+static GVariant *
+register_with_closures_on_get_property (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *property_name,
+ GError **error,
+ gpointer user_data)
+{
+ RegisterObjectData *data = user_data;
+ GValue params[] = { G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT };
+ GValue result_value = G_VALUE_INIT;
+ GVariant *result;
+
+ g_value_init (¶ms[0], G_TYPE_DBUS_CONNECTION);
+ g_value_set_object (¶ms[0], connection);
+
+ g_value_init (¶ms[1], G_TYPE_STRING);
+ g_value_set_string (¶ms[1], sender);
+
+ g_value_init (¶ms[2], G_TYPE_STRING);
+ g_value_set_string (¶ms[2], object_path);
+
+ g_value_init (¶ms[3], G_TYPE_STRING);
+ g_value_set_string (¶ms[3], interface_name);
+
+ g_value_init (¶ms[4], G_TYPE_STRING);
+ g_value_set_string (¶ms[4], property_name);
+
+ g_value_init (&result_value, G_TYPE_VARIANT);
+
+ g_closure_invoke (data->get_property_closure, &result_value, G_N_ELEMENTS (params), params, NULL);
+
+ result = g_value_get_variant (&result_value);
+ if (result)
+ g_variant_ref (result);
+
+ g_value_unset (params + 0);
+ g_value_unset (params + 1);
+ g_value_unset (params + 2);
+ g_value_unset (params + 3);
+ g_value_unset (params + 4);
+ g_value_unset (&result_value);
+
+ if (!result)
+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+ _("Unable to retrieve property %s.%s"),
+ interface_name, property_name);
+
+ return result;
+}
+
+static gboolean
+register_with_closures_on_set_property (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *property_name,
+ GVariant *value,
+ GError **error,
+ gpointer user_data)
+{
+ RegisterObjectData *data = user_data;
+ GValue params[] = { G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT };
+ GValue result_value = G_VALUE_INIT;
+ gboolean result;
+
+ g_value_init (¶ms[0], G_TYPE_DBUS_CONNECTION);
+ g_value_set_object (¶ms[0], connection);
+
+ g_value_init (¶ms[1], G_TYPE_STRING);
+ g_value_set_string (¶ms[1], sender);
+
+ g_value_init (¶ms[2], G_TYPE_STRING);
+ g_value_set_string (¶ms[2], object_path);
+
+ g_value_init (¶ms[3], G_TYPE_STRING);
+ g_value_set_string (¶ms[3], interface_name);
+
+ g_value_init (¶ms[4], G_TYPE_STRING);
+ g_value_set_string (¶ms[4], property_name);
+
+ g_value_init (¶ms[5], G_TYPE_VARIANT);
+ g_value_set_variant (¶ms[5], value);
+
+ g_value_init (&result_value, G_TYPE_BOOLEAN);
+
+ g_closure_invoke (data->set_property_closure, &result_value, G_N_ELEMENTS (params), params, NULL);
+
+ result = g_value_get_boolean (&result_value);
+
+ g_value_unset (params + 0);
+ g_value_unset (params + 1);
+ g_value_unset (params + 2);
+ g_value_unset (params + 3);
+ g_value_unset (params + 4);
+ g_value_unset (params + 5);
+ g_value_unset (&result_value);
+
+ if (!result)
+ g_set_error (error,
+ G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+ _("Unable to set property %s.%s"),
+ interface_name, property_name);
+
+ return result;
+}
+
+/**
+ * g_dbus_connection_register_object_with_closures: (rename-to g_dbus_connection_register_object)
+ * @connection: A #GDBusConnection.
+ * @object_path: The object path to register at.
+ * @interface_info: Introspection data for the interface.
+ * @method_call_closure: (nullable): #GClosure for handling incoming method calls.
+ * @get_property_closure: (nullable): #GClosure for getting a property.
+ * @set_property_closure: (nullable): #GClosure for setting a property.
+ * @error: Return location for error or %NULL.
+ *
+ * Version of g_dbus_connection_register_object() using closures instead of a
+ * #GDBusInterfaceVTable for easier binding in other languages.
+ *
+ * Returns: 0 if @error is set, otherwise a registration id (never 0)
+ * that can be used with g_dbus_connection_unregister_object() .
+ *
+ * Since: 2.46
+ */
+guint
+g_dbus_connection_register_object_with_closures (GDBusConnection *connection,
+ const gchar *object_path,
+ GDBusInterfaceInfo *interface_info,
+ GClosure *method_call_closure,
+ GClosure *get_property_closure,
+ GClosure *set_property_closure,
+ GError **error)
+{
+ RegisterObjectData *data;
+ GDBusInterfaceVTable vtable =
+ {
+ method_call_closure != NULL ? register_with_closures_on_method_call : NULL,
+ get_property_closure != NULL ? register_with_closures_on_get_property : NULL,
+ set_property_closure != NULL ? register_with_closures_on_set_property : NULL
+ };
+
+ data = register_object_data_new (method_call_closure, get_property_closure, set_property_closure);
+
+ return g_dbus_connection_register_object (connection,
+ object_path,
+ interface_info,
+ &vtable,
+ data,
+ register_object_free_func,
+ error);
+}
+
/* ---------------------------------------------------------------------------------------------------- */
/**
* g_dbus_connection_emit_signal:
* @connection: a #GDBusConnection
- * @destination_bus_name: (allow-none): the unique bus name for the destination
+ * @destination_bus_name: (nullable): the unique bus name for the destination
* for the signal or %NULL to emit to all listeners
* @object_path: path of remote object
* @interface_name: D-Bus interface to emit a signal on
* @signal_name: the name of the signal to emit
- * @parameters: (allow-none): a #GVariant tuple with parameters for the signal
+ * @parameters: (nullable): a #GVariant tuple with parameters for the signal
* or %NULL if not passing parameters
* @error: Return location for error or %NULL
*
*
* If the parameters GVariant is floating, it is consumed.
*
- * This can only fail if @parameters is not compatible with the D-Bus protocol.
+ * This can only fail if @parameters is not compatible with the D-Bus protocol
+ * (%G_IO_ERROR_INVALID_ARGUMENT), or if @connection has been closed
+ * (%G_IO_ERROR_CLOSED).
*
* Returns: %TRUE unless @error is set
*
add_call_flags (GDBusMessage *message,
GDBusCallFlags flags)
{
+ GDBusMessageFlags msg_flags = 0;
+
if (flags & G_DBUS_CALL_FLAGS_NO_AUTO_START)
- g_dbus_message_set_flags (message, G_DBUS_MESSAGE_FLAGS_NO_AUTO_START);
+ msg_flags |= G_DBUS_MESSAGE_FLAGS_NO_AUTO_START;
+ if (flags & G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION)
+ msg_flags |= G_DBUS_MESSAGE_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION;
+ if (msg_flags)
+ g_dbus_message_set_flags (message, msg_flags);
}
static GVariant *
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_INVALID_ARGUMENT,
- _("Method '%s' returned type '%s', but expected '%s'"),
+ _("Method “%s” returned type “%s”, but expected “%s”"),
method_name, g_variant_get_type_string (result), type_string);
g_variant_unref (result);
{
GVariantType *reply_type;
gchar *method_name; /* for error message */
- guint32 serial;
GUnixFDList *fd_list;
} CallState;
" <<<< ASYNC COMPLETE %s() (serial %d)\n"
" ",
state->method_name,
- state->serial);
+ g_dbus_message_get_reply_serial (reply));
if (reply != NULL)
{
g_print ("SUCCESS\n");
state->reply_type = g_variant_type_copy (reply_type);
task = g_task_new (connection, cancellable, callback, user_data);
+ g_task_set_source_tag (task, g_dbus_connection_call_internal);
g_task_set_task_data (task, state, (GDestroyNotify) call_state_free);
g_dbus_connection_send_message_with_reply (connection,
message,
G_DBUS_SEND_MESSAGE_FLAGS_NONE,
timeout_msec,
- &state->serial,
+ &serial,
cancellable,
g_dbus_connection_call_done,
task);
- serial = state->serial;
}
else
{
/**
* g_dbus_connection_call:
* @connection: a #GDBusConnection
- * @bus_name: (allow-none): a unique or well-known bus name or %NULL if
+ * @bus_name: (nullable): a unique or well-known bus name or %NULL if
* @connection is not a message bus connection
* @object_path: path of remote object
* @interface_name: D-Bus interface to invoke method on
* @method_name: the name of the method to invoke
- * @parameters: (allow-none): a #GVariant tuple with parameters for the method
+ * @parameters: (nullable): a #GVariant tuple with parameters for the method
* or %NULL if not passing parameters
- * @reply_type: (allow-none): the expected type of the reply, or %NULL
+ * @reply_type: (nullable): the expected type of the reply (which will be a
+ * tuple), or %NULL
* @flags: flags from the #GDBusCallFlags enumeration
* @timeout_msec: the timeout in milliseconds, -1 to use the default
* timeout or %G_MAXINT for no timeout
- * @cancellable: (allow-none): a #GCancellable or %NULL
- * @callback: (allow-none): a #GAsyncReadyCallback to call when the request
+ * @cancellable: (nullable): a #GCancellable or %NULL
+ * @callback: (nullable): a #GAsyncReadyCallback to call when the request
* is satisfied or %NULL if you don't care about the result of the
* method invocation
* @user_data: the data to pass to @callback
*
* If @reply_type is non-%NULL then the reply will be checked for having this type and an
* error will be raised if it does not match. Said another way, if you give a @reply_type
- * then any non-%NULL return value will be of this type.
+ * then any non-%NULL return value will be of this type. Unless it’s
+ * %G_VARIANT_TYPE_UNIT, the @reply_type will be a tuple containing one or more
+ * values.
*
* If the @parameters #GVariant is floating, it is consumed. This allows
* convenient 'inline' use of g_variant_new(), e.g.:
/**
* g_dbus_connection_call_sync:
* @connection: a #GDBusConnection
- * @bus_name: (allow-none): a unique or well-known bus name or %NULL if
+ * @bus_name: (nullable): a unique or well-known bus name or %NULL if
* @connection is not a message bus connection
* @object_path: path of remote object
* @interface_name: D-Bus interface to invoke method on
* @method_name: the name of the method to invoke
- * @parameters: (allow-none): a #GVariant tuple with parameters for the method
+ * @parameters: (nullable): a #GVariant tuple with parameters for the method
* or %NULL if not passing parameters
- * @reply_type: (allow-none): the expected type of the reply, or %NULL
+ * @reply_type: (nullable): the expected type of the reply, or %NULL
* @flags: flags from the #GDBusCallFlags enumeration
* @timeout_msec: the timeout in milliseconds, -1 to use the default
* timeout or %G_MAXINT for no timeout
- * @cancellable: (allow-none): a #GCancellable or %NULL
+ * @cancellable: (nullable): a #GCancellable or %NULL
* @error: return location for error or %NULL
*
* Synchronously invokes the @method_name method on the
* operation will fail with %G_IO_ERROR_CANCELLED. If @parameters
* contains a value not compatible with the D-Bus protocol, the operation
* fails with %G_IO_ERROR_INVALID_ARGUMENT.
-
+ *
* If @reply_type is non-%NULL then the reply will be checked for having
* this type and an error will be raised if it does not match. Said
* another way, if you give a @reply_type then any non-%NULL return
/**
* g_dbus_connection_call_with_unix_fd_list:
* @connection: a #GDBusConnection
- * @bus_name: (allow-none): a unique or well-known bus name or %NULL if
+ * @bus_name: (nullable): a unique or well-known bus name or %NULL if
* @connection is not a message bus connection
* @object_path: path of remote object
* @interface_name: D-Bus interface to invoke method on
* @method_name: the name of the method to invoke
- * @parameters: (allow-none): a #GVariant tuple with parameters for the method
+ * @parameters: (nullable): a #GVariant tuple with parameters for the method
* or %NULL if not passing parameters
- * @reply_type: (allow-none): the expected type of the reply, or %NULL
+ * @reply_type: (nullable): the expected type of the reply, or %NULL
* @flags: flags from the #GDBusCallFlags enumeration
* @timeout_msec: the timeout in milliseconds, -1 to use the default
* timeout or %G_MAXINT for no timeout
- * @fd_list: (allow-none): a #GUnixFDList or %NULL
- * @cancellable: (allow-none): a #GCancellable or %NULL
- * @callback: (allow-none): a #GAsyncReadyCallback to call when the request is
+ * @fd_list: (nullable): a #GUnixFDList or %NULL
+ * @cancellable: (nullable): a #GCancellable or %NULL
+ * @callback: (nullable): a #GAsyncReadyCallback to call when the request is
* satisfied or %NULL if you don't * care about the result of the
* method invocation
* @user_data: The data to pass to @callback.
/**
* g_dbus_connection_call_with_unix_fd_list_finish:
* @connection: a #GDBusConnection
- * @out_fd_list: (out) (allow-none): return location for a #GUnixFDList or %NULL
+ * @out_fd_list: (out) (optional): return location for a #GUnixFDList or %NULL
* @res: a #GAsyncResult obtained from the #GAsyncReadyCallback passed to
* g_dbus_connection_call_with_unix_fd_list()
* @error: return location for error or %NULL
/**
* g_dbus_connection_call_with_unix_fd_list_sync:
* @connection: a #GDBusConnection
- * @bus_name: (allow-none): a unique or well-known bus name or %NULL
+ * @bus_name: (nullable): a unique or well-known bus name or %NULL
* if @connection is not a message bus connection
* @object_path: path of remote object
* @interface_name: D-Bus interface to invoke method on
* @method_name: the name of the method to invoke
- * @parameters: (allow-none): a #GVariant tuple with parameters for
+ * @parameters: (nullable): a #GVariant tuple with parameters for
* the method or %NULL if not passing parameters
- * @reply_type: (allow-none): the expected type of the reply, or %NULL
+ * @reply_type: (nullable): the expected type of the reply, or %NULL
* @flags: flags from the #GDBusCallFlags enumeration
* @timeout_msec: the timeout in milliseconds, -1 to use the default
* timeout or %G_MAXINT for no timeout
- * @fd_list: (allow-none): a #GUnixFDList or %NULL
- * @out_fd_list: (out) (allow-none): return location for a #GUnixFDList or %NULL
- * @cancellable: (allow-none): a #GCancellable or %NULL
+ * @fd_list: (nullable): a #GUnixFDList or %NULL
+ * @out_fd_list: (out) (optional): return location for a #GUnixFDList or %NULL
+ * @cancellable: (nullable): a #GCancellable or %NULL
* @error: return location for error or %NULL
*
* Like g_dbus_connection_call_sync() but also takes and returns #GUnixFDList objects.
GDBusMessage *reply;
reply = g_dbus_message_new_method_error (message,
"org.freedesktop.DBus.Error.InvalidArgs",
- _("No such interface '%s'"),
+ _("No such interface “%s”"),
interface_name);
g_dbus_connection_send_message (es->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
g_object_unref (reply);
GDBusMessage *reply;
reply = g_dbus_message_new_method_error (data->message,
"org.freedesktop.DBus.Error.UnknownMethod",
- _("Method '%s' on interface '%s' with signature '%s' does not exist"),
+ _("Method “%s” on interface “%s” with signature “%s” does not exist"),
g_dbus_message_get_member (data->message),
g_dbus_message_get_interface (data->message),
g_dbus_message_get_signature (data->message));
es->vtable = _g_dbus_subtree_vtable_copy (vtable);
es->flags = flags;
- es->id = _global_subtree_registration_id++; /* TODO: overflow etc. */
+ es->id = g_atomic_int_add (&_global_subtree_registration_id, 1); /* TODO: overflow etc. */
es->user_data = user_data;
es->user_data_free_func = user_data_free_func;
es->context = g_main_context_ref_thread_default ();
/* if we end up here, the message has not been not handled - so return an error saying this */
reply = g_dbus_message_new_method_error (message,
"org.freedesktop.DBus.Error.UnknownMethod",
- _("No such interface '%s' on object at path %s"),
+ _("No such interface “%s” on object at path %s"),
interface_name,
object_path);
g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
G_IO_ERROR,
G_IO_ERROR_INVALID_ARGUMENT,
_("Cannot determine bus address from DBUS_STARTER_BUS_TYPE environment variable"
- " - unknown value '%s'"),
+ " — unknown value “%s”"),
starter_bus);
}
else
return ret;
}
+/* May be called from any thread. Must not hold message_bus_lock. */
+void
+_g_bus_forget_singleton (GBusType bus_type)
+{
+ GWeakRef *singleton;
+
+ G_LOCK (message_bus_lock);
+
+ singleton = message_bus_get_singleton (bus_type, NULL);
+
+ if (singleton != NULL)
+ g_weak_ref_set (singleton, NULL);
+
+ G_UNLOCK (message_bus_lock);
+}
+
/**
* g_bus_get_sync:
* @bus_type: a #GBusType
- * @cancellable: (allow-none): a #GCancellable or %NULL
+ * @cancellable: (nullable): a #GCancellable or %NULL
* @error: return location for error or %NULL
*
* Synchronously connects to the message bus specified by @bus_type.
{
GDBusConnection *connection;
+ _g_dbus_initialize ();
+
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
connection = get_uninitialized_connection (bus_type, cancellable, error);
/**
* g_bus_get:
* @bus_type: a #GBusType
- * @cancellable: (allow-none): a #GCancellable or %NULL
+ * @cancellable: (nullable): a #GCancellable or %NULL
* @callback: a #GAsyncReadyCallback to call when the request is satisfied
* @user_data: the data to pass to @callback
*
* When the operation is finished, @callback will be invoked. You can
* then call g_bus_get_finish() to get the result of the operation.
*
- * This is a asynchronous failable function. See g_bus_get_sync() for
+ * This is an asynchronous failable function. See g_bus_get_sync() for
* the synchronous version.
*
* Since: 2.26
GTask *task;
GError *error = NULL;
+ _g_dbus_initialize ();
+
task = g_task_new (NULL, cancellable, callback, user_data);
+ g_task_set_source_tag (task, g_bus_get);
connection = get_uninitialized_connection (bus_type, cancellable, &error);
if (connection == NULL)