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>
<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">

View File

@ -2482,17 +2482,6 @@ g_bus_watch_name_with_closures
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
@ -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

View File

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

View File

@ -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 \

View File

@ -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)
signal_data_free (SignalData *signal_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);
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.
*
* 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 @connection is not a message bus connection, @sender must be
* %NULL.
*
* 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);
}
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:
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);
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);
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));
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()) */
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);
}

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;
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);

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/gdbusnamewatching.h>
#include <gio/gdbusproxy.h>
#include <gio/gdbusproxywatching.h>
#include <gio/gdbusserver.h>
#include <gio/gdbusutils.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_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

View File

@ -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;
/**

View File

@ -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)

View File

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

View File

@ -349,93 +349,10 @@ accounts_user_frobnicate_finish (AccountsUser *user,
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
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;
}

View File

@ -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);
gchar *name_owner;
print_properties (proxy);
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);
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_bus_unwatch_proxy (watcher_id);
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);

View File

@ -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,

View File

@ -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;
@ -104,48 +100,47 @@ introspection_on_proxy_appeared (GDBusConnection *connection,
g_main_loop_quit (loop);
}
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

View File

@ -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 */

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
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);
}
/* ---------------------------------------------------------------------------------------------------- */

View File

@ -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;
@ -453,33 +449,38 @@ on_proxy_appeared (GDBusConnection *connection,
g_main_loop_quit (loop);
}
static void
on_proxy_vanished (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
}
static 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,
"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);
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);
}
/* ---------------------------------------------------------------------------------------------------- */