* 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
* 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.
(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);
}
}
* @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),
/**
* 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
* @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;
/* 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;
/* 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;
}
/**
* 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
*
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
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,
* 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:
* message. Similary, 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: #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.)
+ *
* 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 */
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);
* @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
*
{
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, 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
/**
* 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
/**
* 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.
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 ();
/**
* 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
*
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)