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