Commit 32f2e9a8 authored by David Zeuthen's avatar David Zeuthen

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=621213Signed-off-by: default avatarDavid Zeuthen <davidz@redhat.com>
parent e0f8d30d
......@@ -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">
......
......@@ -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
......
<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>
......
......@@ -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 \
......
......@@ -144,7 +144,7 @@
*
* This class is rarely used directly in D-Bus clients. If you are writing
* an D-Bus client, it is often easier to use the g_bus_own_name(),
* g_bus_watch_name() or g_bus_watch_proxy() APIs.
* g_bus_watch_name() or g_dbus_proxy_new_for_bus() APIs.
*
* <example id="gdbus-server"><title>D-Bus server example</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gdbus-example-server.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting></example>
*
......@@ -265,9 +265,9 @@ struct _GDBusConnectionPrivate
GHashTable *map_method_serial_to_send_message_data; /* guint32 -> SendMessageData* */
/* Maps used for managing signal subscription */
GHashTable *map_rule_to_signal_data; /* gchar* -> SignalData */
GHashTable *map_id_to_signal_data; /* guint -> SignalData */
GHashTable *map_sender_to_signal_data_array; /* gchar* -> GPtrArray* of SignalData */
GHashTable *map_rule_to_signal_data; /* match rule (gchar*) -> SignalData */
GHashTable *map_id_to_signal_data; /* id (guint) -> SignalData */
GHashTable *map_sender_unique_name_to_signal_data_array; /* unique sender (gchar*) -> GPtrArray* of SignalData */
/* Maps used for managing exported objects and subtrees */
GHashTable *map_object_path_to_eo; /* gchar* -> ExportedObject* */
......@@ -408,7 +408,7 @@ g_dbus_connection_finalize (GObject *object)
purge_all_signal_subscriptions (connection);
g_hash_table_unref (connection->priv->map_rule_to_signal_data);
g_hash_table_unref (connection->priv->map_id_to_signal_data);
g_hash_table_unref (connection->priv->map_sender_to_signal_data_array);
g_hash_table_unref (connection->priv->map_sender_unique_name_to_signal_data_array);
g_hash_table_unref (connection->priv->map_id_to_ei);
g_hash_table_unref (connection->priv->map_object_path_to_eo);
......@@ -785,10 +785,10 @@ g_dbus_connection_init (GDBusConnection *connection)
g_str_equal);
connection->priv->map_id_to_signal_data = g_hash_table_new (g_direct_hash,
g_direct_equal);
connection->priv->map_sender_to_signal_data_array = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
NULL);
connection->priv->map_sender_unique_name_to_signal_data_array = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
NULL);
connection->priv->map_object_path_to_eo = g_hash_table_new_full (g_str_hash,
g_str_equal,
......@@ -2372,6 +2372,7 @@ typedef struct
{
gchar *rule;
gchar *sender;
gchar *sender_unique_name; /* if sender is unique or org.freedesktop.DBus, then that name... otherwise blank */
gchar *interface_name;
gchar *member;
gchar *object_path;
......@@ -2389,16 +2390,17 @@ typedef struct
} SignalSubscriber;
static void
signal_data_free (SignalData *data)
{
g_free (data->rule);
g_free (data->sender);
g_free (data->interface_name);
g_free (data->member);
g_free (data->object_path);
g_free (data->arg0);
g_array_free (data->subscribers, TRUE);
g_free (data);
signal_data_free (SignalData *signal_data)
{
g_free (signal_data->rule);
g_free (signal_data->sender);
g_free (signal_data->sender_unique_name);
g_free (signal_data->interface_name);
g_free (signal_data->member);
g_free (signal_data->object_path);
g_free (signal_data->arg0);
g_array_free (signal_data->subscribers, TRUE);
g_free (signal_data);
}
static gchar *
......@@ -2444,7 +2446,6 @@ add_match_rule (GDBusConnection *connection,
"org.freedesktop.DBus", /* interface */
"AddMatch");
g_dbus_message_set_body (message, g_variant_new ("(s)", match_rule));
error = NULL;
if (!g_dbus_connection_send_message_unlocked (connection,
message,
......@@ -2490,7 +2491,7 @@ remove_match_rule (GDBusConnection *connection,
static gboolean
is_signal_data_for_name_lost_or_acquired (SignalData *signal_data)
{
return g_strcmp0 (signal_data->sender, "org.freedesktop.DBus") == 0 &&
return g_strcmp0 (signal_data->sender_unique_name, "org.freedesktop.DBus") == 0 &&
g_strcmp0 (signal_data->interface_name, "org.freedesktop.DBus") == 0 &&
g_strcmp0 (signal_data->object_path, "/org/freedesktop/DBus") == 0 &&
(g_strcmp0 (signal_data->member, "NameLost") == 0 ||
......@@ -2502,7 +2503,7 @@ is_signal_data_for_name_lost_or_acquired (SignalData *signal_data)
/**
* g_dbus_connection_signal_subscribe:
* @connection: A #GDBusConnection.
* @sender: Sender name to match on. Must be either <literal>org.freedesktop.DBus</literal> (for listening to signals from the message bus daemon) or a unique name or %NULL to listen from all senders.
* @sender: Sender name to match on (unique or well-known name) or %NULL to listen from all senders.
* @interface_name: D-Bus interface name to match on or %NULL to match on all interfaces.
* @member: D-Bus signal name to match on or %NULL to match on all signals.
* @object_path: Object path to match on or %NULL to match on all object paths.
......@@ -2517,14 +2518,18 @@ is_signal_data_for_name_lost_or_acquired (SignalData *signal_data)
* linkend="g-main-context-push-thread-default">thread-default main
* loop</link> of the thread you are calling this method from.
*
* It is considered a programming error to use this function if @connection is closed.
* It is considered a programming error to use this function if
* @connection is closed.
*
* If @connection is not a message bus connection, @sender must be
* %NULL.
*
* Note that if @sender is not <literal>org.freedesktop.DBus</literal> (for listening to signals from the
* message bus daemon), then it needs to be a unique bus name or %NULL (for listening to signals from any
* name) - you cannot pass a name like <literal>com.example.MyApp</literal>.
* Use e.g. g_bus_watch_name() to find the unique name for the owner of the name you are interested in. Also note
* that this function does not remove a subscription if @sender vanishes from the bus. You have to manually
* call g_dbus_connection_signal_unsubscribe() to remove a subscription.
* If @sender is a well-known name note that @callback is invoked with
* the unique name for the owner of @sender, not the well-known name
* as one would expect. This is because the message bus rewrites the
* name. As such, to avoid certain race conditions, users should be
* tracking the name owner of the well-known name and use that when
* processing the received signal.
*
* Returns: A subscription identifier that can be used with g_dbus_connection_signal_unsubscribe().
*
......@@ -2545,6 +2550,7 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection,
SignalData *signal_data;
SignalSubscriber subscriber;
GPtrArray *signal_data_array;
const gchar *sender_unique_name;
/* Right now we abort if AddMatch() fails since it can only fail with the bus being in
* an OOM condition. We might want to change that but that would involve making
......@@ -2558,8 +2564,7 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection,
g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
g_return_val_if_fail (!g_dbus_connection_is_closed (connection), 0);
g_return_val_if_fail (sender == NULL || ((strcmp (sender, "org.freedesktop.DBus") == 0 || sender[0] == ':') &&
(connection->priv->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION)), 0);
g_return_val_if_fail (sender == NULL || (g_dbus_is_name (sender) && (connection->priv->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION)), 0);
g_return_val_if_fail (interface_name == NULL || g_dbus_is_interface_name (interface_name), 0);
g_return_val_if_fail (member == NULL || g_dbus_is_member_name (member), 0);
g_return_val_if_fail (object_path == NULL || g_variant_is_object_path (object_path), 0);
......@@ -2569,8 +2574,10 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection,
rule = args_to_rule (sender, interface_name, member, object_path, arg0);
if (sender == NULL)
sender = "";
if (sender != NULL && (g_dbus_is_unique_name (sender) || g_strcmp0 (sender, "org.freedesktop.DBus") == 0))
sender_unique_name = sender;
else
sender_unique_name = "";
subscriber.callback = callback;
subscriber.user_data = user_data;
......@@ -2590,13 +2597,14 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection,
}
signal_data = g_new0 (SignalData, 1);
signal_data->rule = rule;
signal_data->sender = g_strdup (sender);
signal_data->interface_name = g_strdup (interface_name);
signal_data->member = g_strdup (member);
signal_data->object_path = g_strdup (object_path);
signal_data->arg0 = g_strdup (arg0);
signal_data->subscribers = g_array_new (FALSE, FALSE, sizeof (SignalSubscriber));
signal_data->rule = rule;
signal_data->sender = g_strdup (sender);
signal_data->sender_unique_name = g_strdup (sender_unique_name);
signal_data->interface_name = g_strdup (interface_name);
signal_data->member = g_strdup (member);
signal_data->object_path = g_strdup (object_path);
signal_data->arg0 = g_strdup (arg0);
signal_data->subscribers = g_array_new (FALSE, FALSE, sizeof (SignalSubscriber));
g_array_append_val (signal_data->subscribers, subscriber);
g_hash_table_insert (connection->priv->map_rule_to_signal_data,
......@@ -2614,22 +2622,22 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection,
add_match_rule (connection, signal_data->rule);
}
out:
g_hash_table_insert (connection->priv->map_id_to_signal_data,
GUINT_TO_POINTER (subscriber.id),
signal_data);
signal_data_array = g_hash_table_lookup (connection->priv->map_sender_to_signal_data_array,
signal_data->sender);
signal_data_array = g_hash_table_lookup (connection->priv->map_sender_unique_name_to_signal_data_array,
signal_data->sender_unique_name);
if (signal_data_array == NULL)
{
signal_data_array = g_ptr_array_new ();
g_hash_table_insert (connection->priv->map_sender_to_signal_data_array,
g_strdup (signal_data->sender),
g_hash_table_insert (connection->priv->map_sender_unique_name_to_signal_data_array,
g_strdup (signal_data->sender_unique_name),
signal_data_array);
}
g_ptr_array_add (signal_data_array, signal_data);
out:
g_hash_table_insert (connection->priv->map_id_to_signal_data,
GUINT_TO_POINTER (subscriber.id),
signal_data);
CONNECTION_UNLOCK (connection);
return subscriber.id;
......@@ -2669,24 +2677,27 @@ unsubscribe_id_internal (GDBusConnection *connection,
g_array_remove_index (signal_data->subscribers, n);
if (signal_data->subscribers->len == 0)
g_warn_if_fail (g_hash_table_remove (connection->priv->map_rule_to_signal_data, signal_data->rule));
{
g_warn_if_fail (g_hash_table_remove (connection->priv->map_rule_to_signal_data, signal_data->rule));
signal_data_array = g_hash_table_lookup (connection->priv->map_sender_to_signal_data_array,
signal_data->sender);
g_warn_if_fail (signal_data_array != NULL);
g_warn_if_fail (g_ptr_array_remove (signal_data_array, signal_data));
signal_data_array = g_hash_table_lookup (connection->priv->map_sender_unique_name_to_signal_data_array,
signal_data->sender_unique_name);
g_warn_if_fail (signal_data_array != NULL);
g_warn_if_fail (g_ptr_array_remove (signal_data_array, signal_data));
if (signal_data_array->len == 0)
{
g_warn_if_fail (g_hash_table_remove (connection->priv->map_sender_to_signal_data_array, signal_data->sender));
if (signal_data_array->len == 0)
{
g_warn_if_fail (g_hash_table_remove (connection->priv->map_sender_unique_name_to_signal_data_array,
signal_data->sender_unique_name));
}
/* remove the match rule from the bus unless NameLost or NameAcquired (see subscribe()) */
if (connection->priv->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION)
{
if (!is_signal_data_for_name_lost_or_acquired (signal_data))
remove_match_rule (connection, signal_data->rule);
if (!connection->priv->closed)
remove_match_rule (connection, signal_data->rule);
}
signal_data_free (signal_data);
}
......@@ -2779,7 +2790,8 @@ emit_signal_instance_in_idle_cb (gpointer data)
}
#if 0
g_debug ("in emit_signal_instance_in_idle_cb (sender=%s path=%s interface=%s member=%s params=%s)",
g_print ("in emit_signal_instance_in_idle_cb (id=%d sender=%s path=%s interface=%s member=%s params=%s)\n",
signal_instance->subscription_id,
signal_instance->sender,
signal_instance->path,
signal_instance->interface,
......@@ -2842,11 +2854,17 @@ schedule_callbacks (GDBusConnection *connection,
arg0 = g_dbus_message_get_arg0 (message);
#if 0
g_debug ("sender = `%s'", sender);
g_debug ("interface = `%s'", interface);
g_debug ("member = `%s'", member);
g_debug ("path = `%s'", path);
g_debug ("arg0 = `%s'", arg0);
g_print ("In schedule_callbacks:\n"
" sender = `%s'\n"
" interface = `%s'\n"
" member = `%s'\n"
" path = `%s'\n"
" arg0 = `%s'\n",
sender,
interface,
member,
path,
arg0);
#endif
/* TODO: if this is slow, then we can change signal_data_array into
......@@ -2912,13 +2930,13 @@ distribute_signals (GDBusConnection *connection,
/* collect subscribers that match on sender */
if (sender != NULL)
{
signal_data_array = g_hash_table_lookup (connection->priv->map_sender_to_signal_data_array, sender);
signal_data_array = g_hash_table_lookup (connection->priv->map_sender_unique_name_to_signal_data_array, sender);
if (signal_data_array != NULL)
schedule_callbacks (connection, signal_data_array, message, sender);
}
/* collect subscribers not matching on sender */
signal_data_array = g_hash_table_lookup (connection->priv->map_sender_to_signal_data_array, "");
signal_data_array = g_hash_table_lookup (connection->priv->map_sender_unique_name_to_signal_data_array, "");
if (signal_data_array != NULL)
schedule_callbacks (connection, signal_data_array, message, sender);
}
......
This diff is collapsed.
......@@ -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);
......
This diff is collapsed.
/* 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__ */
......@@ -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>
......
......@@ -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
......
......@@ -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;
/**
......
......@@ -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)
......
......@@ -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",