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>
This commit is contained in:
David Zeuthen 2010-06-11 15:45:18 -04:00
parent e0f8d30dea
commit 32f2e9a85b
22 changed files with 1514 additions and 1384 deletions

View File

@ -143,7 +143,6 @@
<title>Highlevel D-Bus Support</title> <title>Highlevel D-Bus Support</title>
<xi:include href="xml/gdbusnameowning.xml"/> <xi:include href="xml/gdbusnameowning.xml"/>
<xi:include href="xml/gdbusnamewatching.xml"/> <xi:include href="xml/gdbusnamewatching.xml"/>
<xi:include href="xml/gdbusproxywatching.xml"/>
<xi:include href="xml/gdbusproxy.xml"/> <xi:include href="xml/gdbusproxy.xml"/>
</chapter> </chapter>
<chapter id="utils"> <chapter id="utils">

View File

@ -2482,17 +2482,6 @@ g_bus_watch_name_with_closures
g_bus_watch_name_on_connection_with_closures g_bus_watch_name_on_connection_with_closures
</SECTION> </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> <SECTION>
<FILE>gdbuserror</FILE> <FILE>gdbuserror</FILE>
GDBusError GDBusError
@ -2521,9 +2510,13 @@ GDBusProxyClass
g_dbus_proxy_new g_dbus_proxy_new
g_dbus_proxy_new_finish g_dbus_proxy_new_finish
g_dbus_proxy_new_sync 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_flags
g_dbus_proxy_get_connection 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_object_path
g_dbus_proxy_get_interface_name g_dbus_proxy_get_interface_name
g_dbus_proxy_get_default_timeout g_dbus_proxy_get_default_timeout

View File

@ -1,5 +1,5 @@
<chapter> <chapter>
<title>Migrating from dbus-glib to GDBus</title> <title>Migrating to GDBus</title>
<section> <section>
<title>Conceptual differences</title> <title>Conceptual differences</title>
@ -47,8 +47,8 @@
<row><entry>#DBusGMethodInvocation</entry><entry>#GDBusMethodInvocation</entry></row> <row><entry>#DBusGMethodInvocation</entry><entry>#GDBusMethodInvocation</entry></row>
<row><entry>dbus_g_bus_get()</entry><entry>g_bus_get_sync(), also see <row><entry>dbus_g_bus_get()</entry><entry>g_bus_get_sync(), also see
g_bus_get()</entry></row> g_bus_get()</entry></row>
<row><entry>dbus_g_proxy_new_for_name()</entry><entry>g_dbus_proxy_new_sync(), also see <row><entry>dbus_g_proxy_new_for_name()</entry><entry>g_dbus_proxy_new_sync() and
g_dbus_proxy_new()</entry></row> 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_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_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> <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. the current owner of the name, and that owner can change over time.
</para> </para>
<para> <para>
In contrast, #GDBusProxy instances are always bound to a unique name. The same can be achieved with #GDBusProxy:
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:
<informalexample><programlisting><![CDATA[ <informalexample><programlisting><![CDATA[
static void error = NULL;
on_proxy_appeared (GDBusConnection *connection, proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
const gchar *name, G_DBUS_PROXY_FLAGS_NONE,
const gchar *name_owner, NULL, /* GDBusInterfaceInfo */
GDBusProxy *proxy, "org.freedesktop.Accounts",
gpointer user_data) "/org/freedesktop/Accounts",
{ "org.freedesktop.Accounts",
/* start to use proxy */ NULL, /* GCancellable */
} &error);
/* ... */
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);
]]> ]]>
</programlisting></informalexample> </programlisting></informalexample>
Like g_bus_own_name(), g_bus_watch_proxy() is asynchronous and For an added layer of safety, you can specify what D-Bus
you are expected to enter your mainloop to await the on_proxy_appeared() interface the proxy is expected to conform to by using the
callback. Note that GDBus also does all the setup operations for the #GDBusInterfaceInfo type.
proxy asynchronously, and only calls your callback when the proxy </para>
is ready for use. <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> </para>
</section> </section>
<section> <section>

View File

@ -89,7 +89,6 @@ gdbus_headers = \
gdbusmessage.h \ gdbusmessage.h \
gdbusnameowning.h \ gdbusnameowning.h \
gdbusnamewatching.h \ gdbusnamewatching.h \
gdbusproxywatching.h \
gdbusproxy.h \ gdbusproxy.h \
gdbusintrospection.h \ gdbusintrospection.h \
gdbusmethodinvocation.h \ gdbusmethodinvocation.h \
@ -110,7 +109,6 @@ gdbus_sources = \
gdbusmessage.h gdbusmessage.c \ gdbusmessage.h gdbusmessage.c \
gdbusnameowning.h gdbusnameowning.c \ gdbusnameowning.h gdbusnameowning.c \
gdbusnamewatching.h gdbusnamewatching.c \ gdbusnamewatching.h gdbusnamewatching.c \
gdbusproxywatching.h gdbusproxywatching.c \
gdbusproxy.h gdbusproxy.c \ gdbusproxy.h gdbusproxy.c \
gdbusprivate.h gdbusprivate.c \ gdbusprivate.h gdbusprivate.c \
gdbusintrospection.h gdbusintrospection.c \ gdbusintrospection.h gdbusintrospection.c \

View File

@ -144,7 +144,7 @@
* *
* This class is rarely used directly in D-Bus clients. If you are writing * 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(), * 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> * <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* */ GHashTable *map_method_serial_to_send_message_data; /* guint32 -> SendMessageData* */
/* Maps used for managing signal subscription */ /* Maps used for managing signal subscription */
GHashTable *map_rule_to_signal_data; /* gchar* -> SignalData */ GHashTable *map_rule_to_signal_data; /* match rule (gchar*) -> SignalData */
GHashTable *map_id_to_signal_data; /* guint -> SignalData */ GHashTable *map_id_to_signal_data; /* id (guint) -> SignalData */
GHashTable *map_sender_to_signal_data_array; /* gchar* -> GPtrArray* of SignalData */ GHashTable *map_sender_unique_name_to_signal_data_array; /* unique sender (gchar*) -> GPtrArray* of SignalData */
/* Maps used for managing exported objects and subtrees */ /* Maps used for managing exported objects and subtrees */
GHashTable *map_object_path_to_eo; /* gchar* -> ExportedObject* */ GHashTable *map_object_path_to_eo; /* gchar* -> ExportedObject* */
@ -408,7 +408,7 @@ g_dbus_connection_finalize (GObject *object)
purge_all_signal_subscriptions (connection); purge_all_signal_subscriptions (connection);
g_hash_table_unref (connection->priv->map_rule_to_signal_data); 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_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_id_to_ei);
g_hash_table_unref (connection->priv->map_object_path_to_eo); g_hash_table_unref (connection->priv->map_object_path_to_eo);
@ -785,10 +785,10 @@ g_dbus_connection_init (GDBusConnection *connection)
g_str_equal); g_str_equal);
connection->priv->map_id_to_signal_data = g_hash_table_new (g_direct_hash, connection->priv->map_id_to_signal_data = g_hash_table_new (g_direct_hash,
g_direct_equal); g_direct_equal);
connection->priv->map_sender_to_signal_data_array = g_hash_table_new_full (g_str_hash, connection->priv->map_sender_unique_name_to_signal_data_array = g_hash_table_new_full (g_str_hash,
g_str_equal, g_str_equal,
g_free, g_free,
NULL); NULL);
connection->priv->map_object_path_to_eo = g_hash_table_new_full (g_str_hash, connection->priv->map_object_path_to_eo = g_hash_table_new_full (g_str_hash,
g_str_equal, g_str_equal,
@ -2372,6 +2372,7 @@ typedef struct
{ {
gchar *rule; gchar *rule;
gchar *sender; gchar *sender;
gchar *sender_unique_name; /* if sender is unique or org.freedesktop.DBus, then that name... otherwise blank */
gchar *interface_name; gchar *interface_name;
gchar *member; gchar *member;
gchar *object_path; gchar *object_path;
@ -2389,16 +2390,17 @@ typedef struct
} SignalSubscriber; } SignalSubscriber;
static void static void
signal_data_free (SignalData *data) signal_data_free (SignalData *signal_data)
{ {
g_free (data->rule); g_free (signal_data->rule);
g_free (data->sender); g_free (signal_data->sender);
g_free (data->interface_name); g_free (signal_data->sender_unique_name);
g_free (data->member); g_free (signal_data->interface_name);
g_free (data->object_path); g_free (signal_data->member);
g_free (data->arg0); g_free (signal_data->object_path);
g_array_free (data->subscribers, TRUE); g_free (signal_data->arg0);
g_free (data); g_array_free (signal_data->subscribers, TRUE);
g_free (signal_data);
} }
static gchar * static gchar *
@ -2444,7 +2446,6 @@ add_match_rule (GDBusConnection *connection,
"org.freedesktop.DBus", /* interface */ "org.freedesktop.DBus", /* interface */
"AddMatch"); "AddMatch");
g_dbus_message_set_body (message, g_variant_new ("(s)", match_rule)); g_dbus_message_set_body (message, g_variant_new ("(s)", match_rule));
error = NULL; error = NULL;
if (!g_dbus_connection_send_message_unlocked (connection, if (!g_dbus_connection_send_message_unlocked (connection,
message, message,
@ -2490,7 +2491,7 @@ remove_match_rule (GDBusConnection *connection,
static gboolean static gboolean
is_signal_data_for_name_lost_or_acquired (SignalData *signal_data) 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->interface_name, "org.freedesktop.DBus") == 0 &&
g_strcmp0 (signal_data->object_path, "/org/freedesktop/DBus") == 0 && g_strcmp0 (signal_data->object_path, "/org/freedesktop/DBus") == 0 &&
(g_strcmp0 (signal_data->member, "NameLost") == 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: * g_dbus_connection_signal_subscribe:
* @connection: A #GDBusConnection. * @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. * @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. * @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. * @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 * linkend="g-main-context-push-thread-default">thread-default main
* loop</link> of the thread you are calling this method from. * 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.
* *
* Note that if @sender is not <literal>org.freedesktop.DBus</literal> (for listening to signals from the * If @connection is not a message bus connection, @sender must be
* message bus daemon), then it needs to be a unique bus name or %NULL (for listening to signals from any * %NULL.
* 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 * If @sender is a well-known name note that @callback is invoked with
* that this function does not remove a subscription if @sender vanishes from the bus. You have to manually * the unique name for the owner of @sender, not the well-known name
* call g_dbus_connection_signal_unsubscribe() to remove a subscription. * 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(). * 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; SignalData *signal_data;
SignalSubscriber subscriber; SignalSubscriber subscriber;
GPtrArray *signal_data_array; 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 /* 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 * 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_IS_DBUS_CONNECTION (connection), 0);
g_return_val_if_fail (!g_dbus_connection_is_closed (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] == ':') && g_return_val_if_fail (sender == NULL || (g_dbus_is_name (sender) && (connection->priv->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION)), 0);
(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 (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 (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); 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); rule = args_to_rule (sender, interface_name, member, object_path, arg0);
if (sender == NULL) if (sender != NULL && (g_dbus_is_unique_name (sender) || g_strcmp0 (sender, "org.freedesktop.DBus") == 0))
sender = ""; sender_unique_name = sender;
else
sender_unique_name = "";
subscriber.callback = callback; subscriber.callback = callback;
subscriber.user_data = user_data; subscriber.user_data = user_data;
@ -2590,13 +2597,14 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection,
} }
signal_data = g_new0 (SignalData, 1); signal_data = g_new0 (SignalData, 1);
signal_data->rule = rule; signal_data->rule = rule;
signal_data->sender = g_strdup (sender); signal_data->sender = g_strdup (sender);
signal_data->interface_name = g_strdup (interface_name); signal_data->sender_unique_name = g_strdup (sender_unique_name);
signal_data->member = g_strdup (member); signal_data->interface_name = g_strdup (interface_name);
signal_data->object_path = g_strdup (object_path); signal_data->member = g_strdup (member);
signal_data->arg0 = g_strdup (arg0); signal_data->object_path = g_strdup (object_path);
signal_data->subscribers = g_array_new (FALSE, FALSE, sizeof (SignalSubscriber)); 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_array_append_val (signal_data->subscribers, subscriber);
g_hash_table_insert (connection->priv->map_rule_to_signal_data, 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); add_match_rule (connection, signal_data->rule);
} }
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_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: out:
g_hash_table_insert (connection->priv->map_id_to_signal_data, g_hash_table_insert (connection->priv->map_id_to_signal_data,
GUINT_TO_POINTER (subscriber.id), GUINT_TO_POINTER (subscriber.id),
signal_data); signal_data);
signal_data_array = g_hash_table_lookup (connection->priv->map_sender_to_signal_data_array,
signal_data->sender);
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),
signal_data_array);
}
g_ptr_array_add (signal_data_array, signal_data);
CONNECTION_UNLOCK (connection); CONNECTION_UNLOCK (connection);
return subscriber.id; return subscriber.id;
@ -2669,24 +2677,27 @@ unsubscribe_id_internal (GDBusConnection *connection,
g_array_remove_index (signal_data->subscribers, n); g_array_remove_index (signal_data->subscribers, n);
if (signal_data->subscribers->len == 0) if (signal_data->subscribers->len == 0)
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));
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)); 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_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_unique_name_to_signal_data_array,
signal_data->sender_unique_name));
}
/* remove the match rule from the bus unless NameLost or NameAcquired (see subscribe()) */ /* 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 (connection->priv->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION)
{ {
if (!is_signal_data_for_name_lost_or_acquired (signal_data)) 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); signal_data_free (signal_data);
} }
@ -2779,7 +2790,8 @@ emit_signal_instance_in_idle_cb (gpointer data)
} }
#if 0 #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->sender,
signal_instance->path, signal_instance->path,
signal_instance->interface, signal_instance->interface,
@ -2842,11 +2854,17 @@ schedule_callbacks (GDBusConnection *connection,
arg0 = g_dbus_message_get_arg0 (message); arg0 = g_dbus_message_get_arg0 (message);
#if 0 #if 0
g_debug ("sender = `%s'", sender); g_print ("In schedule_callbacks:\n"
g_debug ("interface = `%s'", interface); " sender = `%s'\n"
g_debug ("member = `%s'", member); " interface = `%s'\n"
g_debug ("path = `%s'", path); " member = `%s'\n"
g_debug ("arg0 = `%s'", arg0); " path = `%s'\n"
" arg0 = `%s'\n",
sender,
interface,
member,
path,
arg0);
#endif #endif
/* TODO: if this is slow, then we can change signal_data_array into /* 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 */ /* collect subscribers that match on sender */
if (sender != NULL) 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) if (signal_data_array != NULL)
schedule_callbacks (connection, signal_data_array, message, sender); schedule_callbacks (connection, signal_data_array, message, sender);
} }
/* collect subscribers not matching on 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) if (signal_data_array != NULL)
schedule_callbacks (connection, signal_data_array, message, sender); schedule_callbacks (connection, signal_data_array, message, sender);
} }

File diff suppressed because it is too large Load Diff

View File

@ -95,10 +95,9 @@ struct _GDBusProxyClass
GType g_dbus_proxy_get_type (void) G_GNUC_CONST; GType g_dbus_proxy_get_type (void) G_GNUC_CONST;
void g_dbus_proxy_new (GDBusConnection *connection, void g_dbus_proxy_new (GDBusConnection *connection,
GType object_type,
GDBusProxyFlags flags, GDBusProxyFlags flags,
GDBusInterfaceInfo *info, GDBusInterfaceInfo *info,
const gchar *unique_bus_name, const gchar *name,
const gchar *object_path, const gchar *object_path,
const gchar *interface_name, const gchar *interface_name,
GCancellable *cancellable, GCancellable *cancellable,
@ -107,17 +106,36 @@ void g_dbus_proxy_new (GDBusConnection *co
GDBusProxy *g_dbus_proxy_new_finish (GAsyncResult *res, GDBusProxy *g_dbus_proxy_new_finish (GAsyncResult *res,
GError **error); GError **error);
GDBusProxy *g_dbus_proxy_new_sync (GDBusConnection *connection, GDBusProxy *g_dbus_proxy_new_sync (GDBusConnection *connection,
GType object_type,
GDBusProxyFlags flags, GDBusProxyFlags flags,
GDBusInterfaceInfo *info, 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 *object_path,
const gchar *interface_name, const gchar *interface_name,
GCancellable *cancellable, GCancellable *cancellable,
GError **error); GError **error);
GDBusConnection *g_dbus_proxy_get_connection (GDBusProxy *proxy); GDBusConnection *g_dbus_proxy_get_connection (GDBusProxy *proxy);
GDBusProxyFlags g_dbus_proxy_get_flags (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_object_path (GDBusProxy *proxy);
const gchar *g_dbus_proxy_get_interface_name (GDBusProxy *proxy); const gchar *g_dbus_proxy_get_interface_name (GDBusProxy *proxy);
gint g_dbus_proxy_get_default_timeout (GDBusProxy *proxy); gint g_dbus_proxy_get_default_timeout (GDBusProxy *proxy);

View File

@ -1,666 +0,0 @@
/* GDBus - GLib D-Bus Library
*
* 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 "config.h"
#include <stdlib.h>
#include "gdbusutils.h"
#include "gdbusconnection.h"
#include "gdbusnamewatching.h"
#include "gdbusproxywatching.h"
#include "gdbuserror.h"
#include "gdbusprivate.h"
#include "gdbusproxy.h"
#include "gcancellable.h"
#include "glibintl.h"
#include "gioalias.h"
/**
* SECTION:gdbusproxywatching
* @title: Watching Proxies
* @short_description: Simple API for watching proxies
* @include: gio/gio.h
*
* Convenience API for watching bus proxies.
*
* <example id="gdbus-watching-proxy"><title>Simple application watching a proxy</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>
*/
/* ---------------------------------------------------------------------------------------------------- */
G_LOCK_DEFINE_STATIC (lock);
static guint next_global_id = 1;
static GHashTable *map_id_to_client = NULL;
/* ---------------------------------------------------------------------------------------------------- */
typedef struct
{
guint id;
GBusProxyAppearedCallback proxy_appeared_handler;
GBusProxyVanishedCallback proxy_vanished_handler;
gpointer user_data;
GDestroyNotify user_data_free_func;
GMainContext *main_context;
gchar *name;
gchar *name_owner;
GDBusConnection *connection;
guint name_watcher_id;
GCancellable *cancellable;
gchar *object_path;
gchar *interface_name;
GType interface_type;
GDBusProxyFlags proxy_flags;
GDBusProxy *proxy;
gboolean initial_construction;
} Client;
static void
client_unref (Client *client)
{
/* ensure we're only called from g_bus_unwatch_proxy */
g_assert (client->name_watcher_id == 0);
g_free (client->name_owner);
if (client->connection != NULL)
g_object_unref (client->connection);
if (client->proxy != NULL)
g_object_unref (client->proxy);
g_free (client->name);
g_free (client->object_path);
g_free (client->interface_name);
if (client->main_context != NULL)
g_main_context_unref (client->main_context);
if (client->user_data_free_func != NULL)
client->user_data_free_func (client->user_data);
g_free (client);
}
/* ---------------------------------------------------------------------------------------------------- */
static void
proxy_constructed_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
Client *client = user_data;
GDBusProxy *proxy;
GError *error;
error = NULL;
proxy = g_dbus_proxy_new_finish (res, &error);
if (proxy == NULL)
{
/* g_warning ("error while constructing proxy: %s", error->message); */
g_error_free (error);
/* handle initial construction, send out vanished if the name
* is there but we constructing a proxy fails
*/
if (client->initial_construction)
{
if (client->proxy_vanished_handler != NULL)
{
client->proxy_vanished_handler (client->connection,
client->name,
client->user_data);
}
client->initial_construction = FALSE;
}
}
else
{
g_assert (client->proxy == NULL);
g_assert (client->cancellable != NULL);
client->proxy = G_DBUS_PROXY (proxy);
g_object_unref (client->cancellable);
client->cancellable = NULL;
/* perform callback */
if (client->proxy_appeared_handler != NULL)
{
client->proxy_appeared_handler (client->connection,
client->name,
client->name_owner,
client->proxy,
client->user_data);
}
client->initial_construction = FALSE;
}
}
static void
on_name_appeared (GDBusConnection *connection,
const gchar *name,
const gchar *name_owner,
gpointer user_data)
{
Client *client = user_data;
//g_debug ("\n\nname appeared (owner `%s')", name_owner);
/* invariants */
g_assert (client->name_owner == NULL);
g_assert (client->connection == NULL);
g_assert (client->cancellable == NULL);
client->name_owner = g_strdup (name_owner);
client->connection = g_object_ref (connection);
client->cancellable = g_cancellable_new ();
g_dbus_proxy_new (client->connection,
client->interface_type,
client->proxy_flags,
NULL, /* GDBusInterfaceInfo */
client->name_owner,
client->object_path,
client->interface_name,
client->cancellable,
proxy_constructed_cb,
client);
}
static void
on_name_vanished (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
Client *client = user_data;
/*g_debug ("\n\nname vanished");*/
g_free (client->name_owner);
if (client->connection != NULL)
g_object_unref (client->connection);
client->name_owner = NULL;
client->connection = NULL;
/* free the proxy if we have it */
if (client->proxy != NULL)
{
g_assert (client->cancellable == NULL);
g_object_unref (client->proxy);
client->proxy = NULL;
/* if we have the proxy, it means we last sent out a 'appeared'
* callback - so send out a 'vanished' callback
*/
if (client->proxy_vanished_handler != NULL)
{
client->proxy_vanished_handler (client->connection,
client->name,
client->user_data);
}
client->initial_construction = FALSE;
}
else
{
/* otherwise cancel construction of the proxy if applicable */
if (client->cancellable != NULL)
{
g_cancellable_cancel (client->cancellable);
g_object_unref (client->cancellable);
client->cancellable = NULL;
}
else
{
/* handle initial construction, send out vanished if
* the name isn't there
*/
if (client->initial_construction)
{
if (client->proxy_vanished_handler != NULL)
{
client->proxy_vanished_handler (client->connection,
client->name,
client->user_data);
}
client->initial_construction = FALSE;
}
}
}
}
/**
* g_bus_watch_proxy:
* @bus_type: The type of bus to watch a name on.
* @name: The name (well-known or unique) to watch.
* @flags: Flags from the #GBusNameWatcherFlags enumeration.
* @object_path: The object path of the remote object to watch.
* @interface_name: The D-Bus interface name for the proxy.
* @interface_type: The #GType for the kind of proxy to create. This must be a #GDBusProxy derived type.
* @proxy_flags: Flags from #GDBusProxyFlags to use when constructing the proxy.
* @proxy_appeared_handler: Handler to invoke when @name is known to exist and the
* requested proxy is available.
* @proxy_vanished_handler: Handler to invoke when @name is known to not exist
* and the previously created proxy is no longer available.
* @user_data: User data to pass to handlers.
* @user_data_free_func: Function for freeing @user_data or %NULL.
*
* Starts watching a remote object at @object_path owned by @name on
* the bus specified by @bus_type. When the object is available, a
* #GDBusProxy (or derived class cf. @interface_type) instance is
* constructed for the @interface_name D-Bus interface and then
* @proxy_appeared_handler will be called when the proxy is ready and
* all properties have been loaded. When @name vanishes,
* @proxy_vanished_handler is called.
*
* This function makes it very simple to write applications that wants
* to watch a well-known remote object on a well-known name, see <xref
* linkend="gdbus-watching-proxy"/>. Basically, the application simply
* starts using the proxy when @proxy_appeared_handler is called and
* stops using it when @proxy_vanished_handler is called. Callbacks
* will be invoked in the <link
* linkend="g-main-context-push-thread-default">thread-default main
* loop</link> of the thread you are calling this function from.
*
* Applications typically use this function to watch the
* <quote>manager</quote> object of a well-known name. Upon acquiring
* a proxy for the manager object, applications typically construct
* additional proxies in response to the result of enumeration methods
* on the manager object.
*
* Many of the comments that apply to g_bus_watch_name() also apply
* here. For example, you are guaranteed that one of the handlers will
* be invoked (on the main thread) after calling this function and
* also that the two handlers alternate. When you are done watching the
* proxy, just call g_bus_unwatch_proxy().
*
* Returns: An identifier (never 0) that can be used with
* g_bus_unwatch_proxy() to stop watching the remote object.
*
* Since: 2.26
*/
guint
g_bus_watch_proxy (GBusType bus_type,
const gchar *name,
GBusNameWatcherFlags flags,
const gchar *object_path,
const gchar *interface_name,
GType interface_type,
GDBusProxyFlags proxy_flags,
GBusProxyAppearedCallback proxy_appeared_handler,
GBusProxyVanishedCallback proxy_vanished_handler,
gpointer user_data,
GDestroyNotify user_data_free_func)
{
Client *client;
g_return_val_if_fail (g_dbus_is_name (name), 0);
g_return_val_if_fail (g_variant_is_object_path (object_path), 0);
g_return_val_if_fail (g_dbus_is_interface_name (interface_name), 0);
g_return_val_if_fail (g_type_is_a (interface_type, G_TYPE_DBUS_PROXY), 0);
G_LOCK (lock);
client = g_new0 (Client, 1);
client->id = next_global_id++; /* TODO: uh oh, handle overflow */
client->name = g_strdup (name);
client->proxy_appeared_handler = proxy_appeared_handler;
client->proxy_vanished_handler = proxy_vanished_handler;
client->user_data = user_data;
client->user_data_free_func = user_data_free_func;
client->main_context = g_main_context_get_thread_default ();
if (client->main_context != NULL)
g_main_context_ref (client->main_context);
client->name_watcher_id = g_bus_watch_name (bus_type,
name,
flags,
on_name_appeared,
on_name_vanished,
client,
NULL);
client->object_path = g_strdup (object_path);
client->interface_name = g_strdup (interface_name);
client->interface_type = interface_type;
client->proxy_flags = proxy_flags;
client->initial_construction = TRUE;
if (map_id_to_client == NULL)
{
map_id_to_client = g_hash_table_new (g_direct_hash, g_direct_equal);
}
g_hash_table_insert (map_id_to_client,
GUINT_TO_POINTER (client->id),
client);
G_UNLOCK (lock);
return client->id;
}
/**
* g_bus_watch_proxy_on_connection:
* @connection: A #GDBusConnection that is not closed.
* @name: The name (well-known or unique) to watch.
* @flags: Flags from the #GBusNameWatcherFlags enumeration.
* @object_path: The object path of the remote object to watch.
* @interface_name: The D-Bus interface name for the proxy.
* @interface_type: The #GType for the kind of proxy to create. This must be a #GDBusProxy derived type.
* @proxy_flags: Flags from #GDBusProxyFlags to use when constructing the proxy.
* @proxy_appeared_handler: Handler to invoke when @name is known to exist and the
* requested proxy is available.
* @proxy_vanished_handler: Handler to invoke when @name is known to not exist
* and the previously created proxy is no longer available.
* @user_data: User data to pass to handlers.
* @user_data_free_func: Function for freeing @user_data or %NULL.
*
* Like g_bus_watch_proxy() but takes a #GDBusConnection instead of a
* #GBusType.
*
* Returns: An identifier (never 0) that can be used with
* g_bus_unwatch_proxy() to stop watching the remote object.
*
* Since: 2.26
*/
guint
g_bus_watch_proxy_on_connection (GDBusConnection *connection,
const gchar *name,
GBusNameWatcherFlags flags,
const gchar *object_path,
const gchar *interface_name,
GType interface_type,
GDBusProxyFlags proxy_flags,
GBusProxyAppearedCallback proxy_appeared_handler,
GBusProxyVanishedCallback proxy_vanished_handler,
gpointer user_data,
GDestroyNotify user_data_free_func)
{
Client *client;
g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
g_return_val_if_fail (g_dbus_is_name (name), 0);
g_return_val_if_fail (g_variant_is_object_path (object_path), 0);
g_return_val_if_fail (g_dbus_is_interface_name (interface_name), 0);
g_return_val_if_fail (g_type_is_a (interface_type, G_TYPE_DBUS_PROXY), 0);
G_LOCK (lock);
client = g_new0 (Client, 1);
client->id = next_global_id++; /* TODO: uh oh, handle overflow */
client->name = g_strdup (name);
client->proxy_appeared_handler = proxy_appeared_handler;
client->proxy_vanished_handler = proxy_vanished_handler;
client->user_data = user_data;
client->user_data_free_func = user_data_free_func;
client->main_context = g_main_context_get_thread_default ();
if (client->main_context != NULL)
g_main_context_ref (client->main_context);
client->name_watcher_id = g_bus_watch_name_on_connection (connection,
name,
flags,
on_name_appeared,
on_name_vanished,
client,
NULL);
client->object_path = g_strdup (object_path);
client->interface_name = g_strdup (interface_name);
client->interface_type = interface_type;
client->proxy_flags = proxy_flags;
client->initial_construction = TRUE;
if (map_id_to_client == NULL)
{
map_id_to_client = g_hash_table_new (g_direct_hash, g_direct_equal);
}
g_hash_table_insert (map_id_to_client,
GUINT_TO_POINTER (client->id),
client);
G_UNLOCK (lock);
return client->id;
}
typedef struct {
GClosure *proxy_appeared_closure;
GClosure *proxy_vanished_closure;
} WatchProxyData;
static void
watch_with_closures_on_proxy_appeared (GDBusConnection *connection,
const gchar *name,
const gchar *name_owner,
GDBusProxy *proxy,
gpointer user_data)
{
WatchProxyData *data = user_data;
GValue params[4] = { { 0, }, { 0, }, { 0, }, { 0, } };
g_value_init (&params[0], G_TYPE_DBUS_CONNECTION);
g_value_set_object (&params[0], connection);
g_value_init (&params[1], G_TYPE_STRING);
g_value_set_string (&params[1], name);
g_value_init (&params[2], G_TYPE_STRING);
g_value_set_string (&params[2], name_owner);
g_value_init (&params[3], G_TYPE_DBUS_PROXY);
g_value_set_object (&params[3], proxy);
g_closure_invoke (data->proxy_appeared_closure, NULL, 4, params, NULL);
}
static void
watch_with_closures_on_proxy_vanished (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
WatchProxyData *data = user_data;
GValue params[2] = { { 0, }, { 0, } };
g_value_init (&params[0], G_TYPE_DBUS_CONNECTION);
g_value_set_object (&params[0], connection);
g_value_init (&params[1], G_TYPE_STRING);
g_value_set_string (&params[1], name);
g_closure_invoke (data->proxy_vanished_closure, NULL, 2, params, NULL);
}
static void
bus_watch_proxy_free_func (gpointer user_data)
{
WatchProxyData *data = user_data;
if (data->proxy_appeared_closure != NULL)
g_closure_unref (data->proxy_appeared_closure);
if (data->proxy_vanished_closure != NULL)
g_closure_unref (data->proxy_vanished_closure);
g_free (data);
}
/**
* g_bus_watch_proxy_with_closures:
* @bus_type: The type of bus to watch a name on.
* @name: The name (well-known or unique) to watch.
* @flags: Flags from the #GBusNameWatcherFlags enumeration.
* @object_path: The object path of the remote object to watch.
* @interface_name: The D-Bus interface name for the proxy.
* @interface_type: The #GType for the kind of proxy to create. This must be a #GDBusProxy derived type.
* @proxy_flags: Flags from #GDBusProxyFlags to use when constructing the proxy.
* @proxy_appeared_closure: (allow-none): #GClosure to invoke when @name is
* known to exist and the requested proxy is available.
* @proxy_vanished_closure: (allow-none): #GClosure to invoke when @name is
* known to not exist and the previously created proxy is no longer available.
*
* Version of g_bus_watch_proxy() using closures instead of callbacks for
* easier binding in other languages.
*
* Returns: An identifier (never 0) that can be used with
* g_bus_unwatch_proxy() to stop watching the remote object.
*
* Rename to: g_bus_watch_proxy
*
* Since: 2.26
*/
guint
g_bus_watch_proxy_with_closures (GBusType bus_type,
const gchar *name,
GBusNameWatcherFlags flags,
const gchar *object_path,
const gchar *interface_name,
GType interface_type,
GDBusProxyFlags proxy_flags,
GClosure *proxy_appeared_closure,
GClosure *proxy_vanished_closure)
{
WatchProxyData *data;
data = g_new0 (WatchProxyData, 1);
if (proxy_appeared_closure != NULL)
data->proxy_appeared_closure = g_closure_ref (proxy_appeared_closure);
if (proxy_vanished_closure != NULL)
data->proxy_vanished_closure = g_closure_ref (proxy_vanished_closure);
return g_bus_watch_proxy (bus_type,
name,
flags,
object_path,
interface_name,
interface_type,
proxy_flags,
proxy_appeared_closure != NULL ? watch_with_closures_on_proxy_appeared : NULL,
proxy_vanished_closure != NULL ? watch_with_closures_on_proxy_vanished : NULL,
data,
bus_watch_proxy_free_func);
}
/**
* g_bus_watch_proxy_on_connection_with_closures:
* @connection: A #GDBusConnection that is not closed.
* @name: The name (well-known or unique) to watch.
* @flags: Flags from the #GBusNameWatcherFlags enumeration.
* @object_path: The object path of the remote object to watch.
* @interface_name: The D-Bus interface name for the proxy.
* @interface_type: The #GType for the kind of proxy to create. This must be a #GDBusProxy derived type.
* @proxy_flags: Flags from #GDBusProxyFlags to use when constructing the proxy.
* @proxy_appeared_closure: (allow-none): #GClosure to invoke when @name is
* known to exist and the requested proxy is available.
* @proxy_vanished_closure: (allow-none): #GClosure to invoke when @name is
* known to not exist and the previously created proxy is no longer available.
*
* Version of g_bus_watch_proxy_on_connection() using closures instead of
* callbacks for easier binding in other languages.
*
* Returns: An identifier (never 0) that can be used with
* g_bus_unwatch_proxy() to stop watching the remote object.
*
* Rename to: g_bus_watch_proxy_on_connection
*
* Since: 2.26
*/
guint
g_bus_watch_proxy_on_connection_with_closures (
GDBusConnection *connection,
const gchar *name,
GBusNameWatcherFlags flags,
const gchar *object_path,
const gchar *interface_name,
GType interface_type,
GDBusProxyFlags proxy_flags,
GClosure *proxy_appeared_closure,
GClosure *proxy_vanished_closure)
{
WatchProxyData *data;
data = g_new0 (WatchProxyData, 1);
if (proxy_appeared_closure != NULL)
data->proxy_appeared_closure = g_closure_ref (proxy_appeared_closure);
if (proxy_vanished_closure != NULL)
data->proxy_vanished_closure = g_closure_ref (proxy_vanished_closure);
return g_bus_watch_proxy_on_connection (connection,
name,
flags,
object_path,
interface_name,
interface_type,
proxy_flags,
proxy_appeared_closure != NULL ? watch_with_closures_on_proxy_appeared : NULL,
proxy_vanished_closure != NULL ? watch_with_closures_on_proxy_vanished : NULL,
data,
bus_watch_proxy_free_func);
}
/**
* g_bus_unwatch_proxy:
* @watcher_id: An identifier obtained from g_bus_watch_proxy()
*
* Stops watching proxy.
*
* Since: 2.26
*/
void
g_bus_unwatch_proxy (guint watcher_id)
{
Client *client;
g_return_if_fail (watcher_id > 0);
client = NULL;
G_LOCK (lock);
if (watcher_id == 0 ||
map_id_to_client == NULL ||
(client = g_hash_table_lookup (map_id_to_client, GUINT_TO_POINTER (watcher_id))) == NULL)
{
g_warning ("Invalid id %d passed to g_bus_unwatch_proxy()", watcher_id);
goto out;
}
g_warn_if_fail (g_hash_table_remove (map_id_to_client, GUINT_TO_POINTER (watcher_id)));
out:
G_UNLOCK (lock);
if (client != NULL)
{
g_bus_unwatch_name (client->name_watcher_id);
client->name_watcher_id = 0;
client_unref (client);
}
}
#define __G_DBUS_PROXY_WATCHING_C__
#include "gioaliasdef.c"

View File

@ -1,115 +0,0 @@
/* GDBus - GLib D-Bus Library
*
* 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>
*/
#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
#error "Only <gio/gio.h> can be included directly."
#endif
#ifndef __G_DBUS_PROXY_WATCHING_H__
#define __G_DBUS_PROXY_WATCHING_H__
#include <gio/giotypes.h>
G_BEGIN_DECLS
/**
* GBusProxyAppearedCallback:
* @connection: The #GDBusConnection the proxy is being watched on.
* @name: The name being watched.
* @name_owner: Unique name of the owner of the name being watched.
* @proxy: A #GDBusProxy (or derived) instance with all properties loaded.
* @user_data: User data passed to g_bus_watch_proxy().
*
* Invoked when the proxy being watched is ready for use - the passed
* @proxy object is valid until the #GBusProxyVanishedCallback
* callback is invoked.
*
* Since: 2.26
*/
typedef void (*GBusProxyAppearedCallback) (GDBusConnection *connection,
const gchar *name,
const gchar *name_owner,
GDBusProxy *proxy,
gpointer user_data);
/**
* GBusProxyVanishedCallback:
* @connection: The #GDBusConnection the proxy is being watched on.
* @name: The name being watched.
* @user_data: User data passed to g_bus_watch_proxy().
*
* Invoked when the proxy being watched has vanished. The #GDBusProxy
* object passed in the #GBusProxyAppearedCallback callback is no
* longer valid.
*
* Since: 2.26
*/
typedef void (*GBusProxyVanishedCallback) (GDBusConnection *connection,
const gchar *name,
gpointer user_data);
guint g_bus_watch_proxy (GBusType bus_type,
const gchar *name,
GBusNameWatcherFlags flags,
const gchar *object_path,
const gchar *interface_name,
GType interface_type,
GDBusProxyFlags proxy_flags,
GBusProxyAppearedCallback proxy_appeared_handler,
GBusProxyVanishedCallback proxy_vanished_handler,
gpointer user_data,
GDestroyNotify user_data_free_func);
guint g_bus_watch_proxy_on_connection (GDBusConnection *connection,
const gchar *name,
GBusNameWatcherFlags flags,
const gchar *object_path,
const gchar *interface_name,
GType interface_type,
GDBusProxyFlags proxy_flags,
GBusProxyAppearedCallback proxy_appeared_handler,
GBusProxyVanishedCallback proxy_vanished_handler,
gpointer user_data,
GDestroyNotify user_data_free_func);
guint g_bus_watch_proxy_with_closures (GBusType bus_type,
const gchar *name,
GBusNameWatcherFlags flags,
const gchar *object_path,
const gchar *interface_name,
GType interface_type,
GDBusProxyFlags proxy_flags,
GClosure *proxy_appeared_closure,
GClosure *proxy_vanished_closure);
guint g_bus_watch_proxy_on_connection_with_closures (
GDBusConnection *connection,
const gchar *name,
GBusNameWatcherFlags flags,
const gchar *object_path,
const gchar *interface_name,
GType interface_type,
GDBusProxyFlags proxy_flags,
GClosure *proxy_appeared_closure,
GClosure *proxy_vanished_closure);
void g_bus_unwatch_proxy (guint watcher_id);
G_END_DECLS
#endif /* __G_DBUS_PROXY_WATCHING_H__ */

View File

@ -52,7 +52,6 @@
#include <gio/gdbusnameowning.h> #include <gio/gdbusnameowning.h>
#include <gio/gdbusnamewatching.h> #include <gio/gdbusnamewatching.h>
#include <gio/gdbusproxy.h> #include <gio/gdbusproxy.h>
#include <gio/gdbusproxywatching.h>
#include <gio/gdbusserver.h> #include <gio/gdbusserver.h>
#include <gio/gdbusutils.h> #include <gio/gdbusutils.h>
#include <gio/gdrive.h> #include <gio/gdrive.h>

View File

@ -1695,6 +1695,9 @@ g_dbus_proxy_get_type G_GNUC_CONST
g_dbus_proxy_new g_dbus_proxy_new
g_dbus_proxy_new_finish g_dbus_proxy_new_finish
g_dbus_proxy_new_sync 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_get_cached_property
g_dbus_proxy_set_cached_property g_dbus_proxy_set_cached_property
g_dbus_proxy_get_cached_property_names 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_info
g_dbus_proxy_get_interface_name g_dbus_proxy_get_interface_name
g_dbus_proxy_get_object_path 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_default_timeout
g_dbus_proxy_set_interface_info g_dbus_proxy_set_interface_info
g_dbus_proxy_call g_dbus_proxy_call
@ -1713,16 +1717,6 @@ g_dbus_proxy_call_sync
#endif #endif
#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_HEADER(__G_DBUS_SERVER_H__)
#if IN_FILE(__G_DBUS_SERVER_C__) #if IN_FILE(__G_DBUS_SERVER_C__)
g_dbus_server_get_type G_GNUC_CONST g_dbus_server_get_type G_GNUC_CONST

View File

@ -741,6 +741,7 @@ typedef enum {
/** /**
* GBusType: * GBusType:
* @G_BUS_TYPE_STARTER: An alias for the message bus that activated the process, if any. * @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_SYSTEM: The system-wide message bus.
* @G_BUS_TYPE_SESSION: The login session message bus. * @G_BUS_TYPE_SESSION: The login session message bus.
* *
@ -750,7 +751,8 @@ typedef enum {
*/ */
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_SYSTEM = 1,
G_BUS_TYPE_SESSION = 2 G_BUS_TYPE_SESSION = 2
} GBusType; } GBusType;
@ -795,6 +797,9 @@ typedef enum
* @G_DBUS_PROXY_FLAGS_NONE: No flags set. * @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_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_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. * Flags used when constructing an instance of a #GDBusProxy derived class.
* *
@ -802,9 +807,10 @@ typedef enum
*/ */
typedef enum typedef enum
{ {
G_DBUS_PROXY_FLAGS_NONE = 0, /*< nick=none >*/ G_DBUS_PROXY_FLAGS_NONE = 0,
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES = (1<<0), /*< nick=do-not-load-properties >*/ G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES = (1<<0),
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS = (1<<1) /*< nick=do-not-connect-signals >*/ G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS = (1<<1),
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START = (1<<2)
} GDBusProxyFlags; } GDBusProxyFlags;
/** /**

View File

@ -48,6 +48,7 @@ TEST_PROGS += \
gdbus-connection \ gdbus-connection \
gdbus-names \ gdbus-names \
gdbus-proxy \ gdbus-proxy \
gdbus-proxy-well-known-name \
gdbus-introspection \ gdbus-introspection \
gdbus-threading \ gdbus-threading \
gdbus-export \ 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_SOURCES = gdbus-proxy.c gdbus-sessionbus.c gdbus-sessionbus.h gdbus-tests.h gdbus-tests.c
gdbus_proxy_LDADD = $(progs_ldadd) 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_SOURCES = gdbus-introspection.c gdbus-sessionbus.c gdbus-sessionbus.h gdbus-tests.h gdbus-tests.c
gdbus_introspection_LDADD = $(progs_ldadd) gdbus_introspection_LDADD = $(progs_ldadd)

View File

@ -360,9 +360,11 @@ test_connection_signals (void)
GDBusConnection *c2; GDBusConnection *c2;
GDBusConnection *c3; GDBusConnection *c3;
guint s1; guint s1;
guint s1b;
guint s2; guint s2;
guint s3; guint s3;
gint count_s1; gint count_s1;
gint count_s1b;
gint count_s2; gint count_s2;
gint count_name_owner_changed; gint count_name_owner_changed;
GError *error; GError *error;
@ -425,11 +427,26 @@ test_connection_signals (void)
test_connection_signal_handler, test_connection_signal_handler,
&count_name_owner_changed, &count_name_owner_changed,
NULL); 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 (s1 != 0);
g_assert (s1b != 0);
g_assert (s2 != 0); g_assert (s2 != 0);
g_assert (s3 != 0); g_assert (s3 != 0);
count_s1 = 0; count_s1 = 0;
count_s1b = 0;
count_s2 = 0; count_s2 = 0;
count_name_owner_changed = 0; count_name_owner_changed = 0;
@ -480,7 +497,7 @@ test_connection_signals (void)
&error); &error);
g_assert_no_error (error); g_assert_no_error (error);
g_assert (ret); g_assert (ret);
while (!(count_s1 == 1 && count_s2 == 1)) while (!(count_s1 >= 1 && count_s2 >= 1))
g_main_loop_run (loop); g_main_loop_run (loop);
g_assert_cmpint (count_s1, ==, 1); g_assert_cmpint (count_s1, ==, 1);
g_assert_cmpint (count_s2, ==, 1); g_assert_cmpint (count_s2, ==, 1);
@ -510,7 +527,7 @@ test_connection_signals (void)
guint quit_mainloop_id; guint quit_mainloop_id;
quit_mainloop_fired = FALSE; quit_mainloop_fired = FALSE;
quit_mainloop_id = g_timeout_add (5000, test_connection_signal_quit_mainloop, &quit_mainloop_fired); 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_main_loop_run (loop);
g_source_remove (quit_mainloop_id); g_source_remove (quit_mainloop_id);
g_assert_cmpint (count_s1, ==, 1); 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, s1);
g_dbus_connection_signal_unsubscribe (c1, s2); g_dbus_connection_signal_unsubscribe (c1, s2);
g_dbus_connection_signal_unsubscribe (c1, s3); 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 (c1);
_g_object_wait_for_single_ref (c2); _g_object_wait_for_single_ref (c2);

View File

@ -349,93 +349,10 @@ accounts_user_frobnicate_finish (AccountsUser *user,
return ret; return ret;
} }
/* ---------------------------------------------------------------------------------------------------- */
/* 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 gint
main (gint argc, gchar *argv[]) 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; return 0;
} }

View File

@ -4,7 +4,7 @@ static gchar *opt_name = NULL;
static gchar *opt_object_path = NULL; static gchar *opt_object_path = NULL;
static gchar *opt_interface = NULL; static gchar *opt_interface = NULL;
static gboolean opt_system_bus = FALSE; 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 gboolean opt_no_properties = FALSE;
static GOptionEntry opt_entries[] = 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 }, { "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 }, { "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 }, { "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}, { "no-properties", 'p', 0, G_OPTION_ARG_NONE, &opt_no_properties, "Do not load properties", NULL},
{ NULL} { NULL}
}; };
static GMainLoop *loop = NULL;
static void static void
print_properties (GDBusProxy *proxy) print_properties (GDBusProxy *proxy)
{ {
@ -100,64 +102,62 @@ on_signal (GDBusProxy *proxy,
} }
static void static void
on_proxy_appeared (GDBusConnection *connection, print_proxy (GDBusProxy *proxy)
const gchar *name,
const gchar *name_owner,
GDBusProxy *proxy,
gpointer user_data)
{ {
g_print ("+++ Acquired proxy object for remote object owned by %s\n" gchar *name_owner;
" 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); name_owner = g_dbus_proxy_get_name_owner (proxy);
if (name_owner != NULL)
g_signal_connect (proxy, {
"g-properties-changed", g_print ("+++ Proxy object points to remote object owned by %s\n"
G_CALLBACK (on_properties_changed), " bus: %s\n"
NULL); " name: %s\n"
" object path: %s\n"
g_signal_connect (proxy, " interface: %s\n",
"g-signal", name_owner,
G_CALLBACK (on_signal), opt_system_bus ? "System Bus" : "Session Bus",
NULL); 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 static void
on_proxy_vanished (GDBusConnection *connection, on_name_owner_notify (GObject *object,
const gchar *name, GParamSpec *pspec,
gpointer user_data) gpointer user_data)
{ {
g_print ("--- Cannot create proxy object for\n" GDBusProxy *proxy = G_DBUS_PROXY (object);
" bus: %s\n" print_proxy (proxy);
" name: %s\n"
" object path: %s\n"
" interface: %s\n",
opt_system_bus ? "System Bus" : "Session Bus",
opt_name,
opt_object_path,
opt_interface);
} }
int int
main (int argc, char *argv[]) main (int argc, char *argv[])
{ {
guint watcher_id;
GMainLoop *loop;
GOptionContext *opt_context; GOptionContext *opt_context;
GError *error; GError *error;
GBusNameWatcherFlags flags; GDBusProxyFlags flags;
GDBusProxyFlags proxy_flags; GDBusProxy *proxy;
g_type_init (); g_type_init ();
loop = NULL;
proxy = NULL;
opt_context = g_option_context_new ("g_bus_watch_proxy() example"); opt_context = g_option_context_new ("g_bus_watch_proxy() example");
g_option_context_set_summary (opt_context, g_option_context_set_summary (opt_context,
"Example: to watch the object of gdbus-example-server, use:\n" "Example: to watch the object of gdbus-example-server, use:\n"
@ -169,7 +169,7 @@ main (int argc, char *argv[])
error = NULL; error = NULL;
if (!g_option_context_parse (opt_context, &argc, &argv, &error)) 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; goto out;
} }
if (opt_name == NULL || opt_object_path == NULL || opt_interface == NULL) if (opt_name == NULL || opt_object_path == NULL || opt_interface == NULL)
@ -178,32 +178,51 @@ main (int argc, char *argv[])
goto out; goto out;
} }
flags = G_BUS_NAME_WATCHER_FLAGS_NONE; flags = G_DBUS_PROXY_FLAGS_NONE;
if (opt_auto_start)
flags |= G_BUS_NAME_WATCHER_FLAGS_AUTO_START;
proxy_flags = G_DBUS_PROXY_FLAGS_NONE;
if (opt_no_properties) if (opt_no_properties)
proxy_flags |= G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES; flags |= G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES;
if (opt_no_auto_start)
watcher_id = g_bus_watch_proxy (opt_system_bus ? G_BUS_TYPE_SYSTEM : G_BUS_TYPE_SESSION, flags |= G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START;
opt_name,
flags,
opt_object_path,
opt_interface,
G_TYPE_DBUS_PROXY,
proxy_flags,
on_proxy_appeared,
on_proxy_vanished,
NULL,
NULL);
loop = g_main_loop_new (NULL, FALSE); loop = g_main_loop_new (NULL, FALSE);
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); g_main_loop_run (loop);
g_bus_unwatch_proxy (watcher_id);
out: out:
if (proxy != NULL)
g_object_unref (proxy);
if (loop != NULL)
g_main_loop_unref (loop);
g_option_context_free (opt_context); g_option_context_free (opt_context);
g_free (opt_name); g_free (opt_name);
g_free (opt_object_path); g_free (opt_object_path);

View File

@ -343,7 +343,6 @@ get_nodes_at (GDBusConnection *c,
error = NULL; error = NULL;
proxy = g_dbus_proxy_new_sync (c, 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_LOAD_PROPERTIES |
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
NULL, NULL,
@ -400,7 +399,6 @@ has_interface (GDBusConnection *c,
error = NULL; error = NULL;
proxy = g_dbus_proxy_new_sync (c, 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_LOAD_PROPERTIES |
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
NULL, NULL,
@ -450,7 +448,6 @@ count_interfaces (GDBusConnection *c,
error = NULL; error = NULL;
proxy = g_dbus_proxy_new_sync (c, 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_LOAD_PROPERTIES |
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
NULL, NULL,
@ -522,7 +519,6 @@ dyna_create (GDBusConnection *c,
error = NULL; error = NULL;
proxy = g_dbus_proxy_new_sync (c, 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_LOAD_PROPERTIES |
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
NULL, NULL,
@ -745,7 +741,6 @@ test_dispatch_thread_func (gpointer user_data)
const gchar *value_str; const gchar *value_str;
foo_proxy = g_dbus_proxy_new_sync (c, 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_CONNECT_SIGNALS |
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
NULL, NULL,

View File

@ -34,11 +34,7 @@ static GMainLoop *loop = NULL;
/* ---------------------------------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------------------------------------- */
static void static void
introspection_on_proxy_appeared (GDBusConnection *connection, test_introspection (GDBusProxy *proxy)
const gchar *name,
const gchar *name_owner,
GDBusProxy *proxy,
gpointer user_data)
{ {
GError *error; GError *error;
const gchar *xml_data; const gchar *xml_data;
@ -104,48 +100,47 @@ introspection_on_proxy_appeared (GDBusConnection *connection,
g_main_loop_quit (loop); g_main_loop_quit (loop);
} }
static void
introspection_on_proxy_vanished (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
}
static void static void
test_introspection_parser (void) test_introspection_parser (void)
{ {
guint watcher_id; GDBusProxy *proxy;
GDBusConnection *connection;
GError *error;
session_bus_up (); 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 /* 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 * until one can connect to the bus but that's not how things work right now
*/ */
usleep (500 * 1000); 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 */ /* this is safe; testserver will exit once the bus goes away */
g_assert (g_spawn_command_line_async (SRCDIR "/gdbus-testserver.py", NULL)); 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 */ g_object_unref (proxy);
session_bus_down (); g_object_unref (connection);
} }
/* ---------------------------------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------------------------------------- */
int int

View File

@ -526,7 +526,6 @@ test_peer (void)
*/ */
error = NULL; error = NULL;
proxy = g_dbus_proxy_new_sync (c, proxy = g_dbus_proxy_new_sync (c,
G_TYPE_DBUS_PROXY,
G_DBUS_PROXY_FLAGS_NONE, G_DBUS_PROXY_FLAGS_NONE,
NULL, NULL,
NULL, /* bus_name */ NULL, /* bus_name */

View File

@ -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;
}

View File

@ -34,10 +34,7 @@ static GMainLoop *loop = NULL;
/* ---------------------------------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------------------------------------- */
static void static void
test_methods (GDBusConnection *connection, test_methods (GDBusProxy *proxy)
const gchar *name,
const gchar *name_owner,
GDBusProxy *proxy)
{ {
GVariant *result; GVariant *result;
GError *error; GError *error;
@ -133,10 +130,7 @@ test_methods (GDBusConnection *connection,
/* ---------------------------------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------------------------------------- */
static void static void
test_properties (GDBusConnection *connection, test_properties (GDBusProxy *proxy)
const gchar *name,
const gchar *name_owner,
GDBusProxy *proxy)
{ {
GError *error; GError *error;
GVariant *variant; GVariant *variant;
@ -281,10 +275,7 @@ test_proxy_signals_on_emit_signal_cb (GDBusProxy *proxy,
} }
static void static void
test_signals (GDBusConnection *connection, test_signals (GDBusProxy *proxy)
const gchar *name,
const gchar *name_owner,
GDBusProxy *proxy)
{ {
GError *error; GError *error;
GString *s; GString *s;
@ -359,10 +350,7 @@ test_signals (GDBusConnection *connection,
} }
static void static void
test_bogus_method_return (GDBusConnection *connection, test_bogus_method_return (GDBusProxy *proxy)
const gchar *name,
const gchar *name_owner,
GDBusProxy *proxy)
{ {
GError *error = NULL; GError *error = NULL;
GVariant *result; GVariant *result;
@ -401,16 +389,8 @@ static const gchar *frob_dbus_interface_xml =
static GDBusInterfaceInfo *frob_dbus_interface_info; static GDBusInterfaceInfo *frob_dbus_interface_info;
static void static void
on_proxy_appeared (GDBusConnection *connection, test_expected_interface (GDBusProxy *proxy)
const gchar *name,
const gchar *name_owner,
GDBusProxy *proxy,
gpointer user_data)
{ {
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... */ /* 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_string ("error_me_out!"));
g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_byte (42)); 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 */ /* Now repeat the method tests, with an expected interface set */
g_dbus_proxy_set_interface_info (proxy, frob_dbus_interface_info); 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 /* And now one more test where we deliberately set the expected
* interface definition incorrectly * 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 */ /* 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)) 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) */ /* this should work, however (since the type is correct) */
g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_byte (42)); 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 static void
test_proxy (void) test_proxy (void)
{ {
guint watcher_id; GDBusProxy *proxy;
GDBusConnection *connection;
GError *error;
session_bus_up (); session_bus_up ();
@ -466,27 +439,34 @@ test_proxy (void)
*/ */
usleep (500 * 1000); usleep (500 * 1000);
watcher_id = g_bus_watch_proxy (G_BUS_TYPE_SESSION, error = NULL;
"com.example.TestService", connection = g_bus_get_sync (G_BUS_TYPE_SESSION,
G_BUS_NAME_WATCHER_FLAGS_NONE, NULL,
"/com/example/TestObject", &error);
"com.example.Frob", g_assert_no_error (error);
G_TYPE_DBUS_PROXY, error = NULL;
G_DBUS_PROXY_FLAGS_NONE, proxy = g_dbus_proxy_new_sync (connection,
on_proxy_appeared, G_DBUS_PROXY_FLAGS_NONE,
on_proxy_vanished, NULL, /* GDBusInterfaceInfo */
NULL, "com.example.TestService", /* name */
NULL); "/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 */ /* this is safe; testserver will exit once the bus goes away */
g_assert (g_spawn_command_line_async (SRCDIR "/gdbus-testserver.py", NULL)); 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 */ g_object_unref (proxy);
session_bus_down (); g_object_unref (connection);
} }
/* ---------------------------------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------------------------------------- */

View File

@ -348,11 +348,7 @@ test_sleep_in_thread_func (gpointer _data)
} }
static void static void
on_proxy_appeared (GDBusConnection *connection, test_method_calls_on_proxy (GDBusProxy *proxy)
const gchar *name,
const gchar *name_owner,
GDBusProxy *proxy,
gpointer user_data)
{ {
guint n; guint n;
@ -453,33 +449,38 @@ on_proxy_appeared (GDBusConnection *connection,
g_main_loop_quit (loop); g_main_loop_quit (loop);
} }
static void
on_proxy_vanished (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
}
static void static void
test_method_calls_in_thread (void) test_method_calls_in_thread (void)
{ {
guint watcher_id; GDBusProxy *proxy;
GDBusConnection *connection;
GError *error;
gchar *name_owner;
watcher_id = g_bus_watch_proxy (G_BUS_TYPE_SESSION, error = NULL;
"com.example.TestService", connection = g_bus_get_sync (G_BUS_TYPE_SESSION,
G_BUS_NAME_WATCHER_FLAGS_NONE, NULL,
"/com/example/TestObject", &error);
"com.example.Frob", g_assert_no_error (error);
G_TYPE_DBUS_PROXY, error = NULL;
G_DBUS_PROXY_FLAGS_NONE, proxy = g_dbus_proxy_new_sync (connection,
on_proxy_appeared, G_DBUS_PROXY_FLAGS_NONE,
on_proxy_vanished, NULL, /* GDBusInterfaceInfo */
NULL, "com.example.TestService", /* name */
NULL); "/com/example/TestObject", /* object path */
"com.example.Frob", /* interface */
NULL, /* GCancellable */
&error);
g_assert_no_error (error);
g_main_loop_run (loop); name_owner = g_dbus_proxy_get_name_owner (proxy);
g_assert_cmpstr (name_owner, !=, NULL);
g_free (name_owner);
g_bus_unwatch_proxy (watcher_id); test_method_calls_on_proxy (proxy);
g_object_unref (proxy);
g_object_unref (connection);
} }
/* ---------------------------------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------------------------------------- */