1 /* GDBus - GLib D-Bus Library
3 * Copyright (C) 2008-2010 Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18 * Boston, MA 02111-1307, USA.
20 * Author: David Zeuthen <davidz@redhat.com>
27 #include "gdbusutils.h"
28 #include "gdbusconnection.h"
29 #include "gdbusnamewatching.h"
30 #include "gdbusproxywatching.h"
31 #include "gdbuserror.h"
32 #include "gdbusprivate.h"
33 #include "gdbusproxy.h"
34 #include "gdbusnamewatching.h"
35 #include "gcancellable.h"
41 * SECTION:gdbusproxywatching
42 * @title: Watching Proxies
43 * @short_description: Simple API for watching proxies
46 * Convenience API for watching bus proxies.
48 * <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>
51 /* ---------------------------------------------------------------------------------------------------- */
53 G_LOCK_DEFINE_STATIC (lock);
55 static guint next_global_id = 1;
56 static GHashTable *map_id_to_client = NULL;
58 /* ---------------------------------------------------------------------------------------------------- */
63 GBusProxyAppearedCallback proxy_appeared_handler;
64 GBusProxyVanishedCallback proxy_vanished_handler;
66 GDestroyNotify user_data_free_func;
67 GMainContext *main_context;
71 GDBusConnection *connection;
72 guint name_watcher_id;
74 GCancellable *cancellable;
77 gchar *interface_name;
79 GDBusProxyFlags proxy_flags;
82 gboolean initial_construction;
86 client_unref (Client *client)
88 /* ensure we're only called from g_bus_unwatch_proxy */
89 g_assert (client->name_watcher_id == 0);
91 g_free (client->name_owner);
92 if (client->connection != NULL)
93 g_object_unref (client->connection);
94 if (client->proxy != NULL)
95 g_object_unref (client->proxy);
97 g_free (client->name);
98 g_free (client->object_path);
99 g_free (client->interface_name);
101 if (client->main_context != NULL)
102 g_main_context_unref (client->main_context);
104 if (client->user_data_free_func != NULL)
105 client->user_data_free_func (client->user_data);
109 /* ---------------------------------------------------------------------------------------------------- */
112 proxy_constructed_cb (GObject *source_object,
116 Client *client = user_data;
121 proxy = g_dbus_proxy_new_finish (res, &error);
124 /* g_warning ("error while constructing proxy: %s", error->message); */
125 g_error_free (error);
127 /* handle initial construction, send out vanished if the name
128 * is there but we constructing a proxy fails
130 if (client->initial_construction)
132 if (client->proxy_vanished_handler != NULL)
134 client->proxy_vanished_handler (client->connection,
138 client->initial_construction = FALSE;
143 g_assert (client->proxy == NULL);
144 g_assert (client->cancellable != NULL);
145 client->proxy = G_DBUS_PROXY (proxy);
147 g_object_unref (client->cancellable);
148 client->cancellable = NULL;
150 /* perform callback */
151 if (client->proxy_appeared_handler != NULL)
153 client->proxy_appeared_handler (client->connection,
159 client->initial_construction = FALSE;
164 on_name_appeared (GDBusConnection *connection,
166 const gchar *name_owner,
169 Client *client = user_data;
171 //g_debug ("\n\nname appeared (owner `%s')", name_owner);
174 g_assert (client->name_owner == NULL);
175 g_assert (client->connection == NULL);
176 g_assert (client->cancellable == NULL);
178 client->name_owner = g_strdup (name_owner);
179 client->connection = g_object_ref (connection);
180 client->cancellable = g_cancellable_new ();
182 g_dbus_proxy_new (client->connection,
183 client->interface_type,
185 NULL, /* GDBusInterfaceInfo */
188 client->interface_name,
190 proxy_constructed_cb,
195 on_name_vanished (GDBusConnection *connection,
199 Client *client = user_data;
201 /*g_debug ("\n\nname vanished");*/
203 g_free (client->name_owner);
204 if (client->connection != NULL)
205 g_object_unref (client->connection);
206 client->name_owner = NULL;
207 client->connection = NULL;
209 /* free the proxy if we have it */
210 if (client->proxy != NULL)
212 g_assert (client->cancellable == NULL);
214 g_object_unref (client->proxy);
215 client->proxy = NULL;
217 /* if we have the proxy, it means we last sent out a 'appeared'
218 * callback - so send out a 'vanished' callback
220 if (client->proxy_vanished_handler != NULL)
222 client->proxy_vanished_handler (client->connection,
226 client->initial_construction = FALSE;
230 /* otherwise cancel construction of the proxy if applicable */
231 if (client->cancellable != NULL)
233 g_cancellable_cancel (client->cancellable);
234 g_object_unref (client->cancellable);
235 client->cancellable = NULL;
239 /* handle initial construction, send out vanished if
240 * the name isn't there
242 if (client->initial_construction)
244 if (client->proxy_vanished_handler != NULL)
246 client->proxy_vanished_handler (client->connection,
250 client->initial_construction = FALSE;
258 * @bus_type: The type of bus to watch a name on (can't be #G_BUS_TYPE_NONE).
259 * @name: The name (well-known or unique) to watch.
260 * @flags: Flags from the #GBusNameWatcherFlags enumeration.
261 * @object_path: The object path of the remote object to watch.
262 * @interface_name: The D-Bus interface name for the proxy.
263 * @interface_type: The #GType for the kind of proxy to create. This must be a #GDBusProxy derived type.
264 * @proxy_flags: Flags from #GDBusProxyFlags to use when constructing the proxy.
265 * @proxy_appeared_handler: Handler to invoke when @name is known to exist and the
266 * requested proxy is available.
267 * @proxy_vanished_handler: Handler to invoke when @name is known to not exist
268 * and the previously created proxy is no longer available.
269 * @user_data: User data to pass to handlers.
270 * @user_data_free_func: Function for freeing @user_data or %NULL.
272 * Starts watching a remote object at @object_path owned by @name on
273 * the bus specified by @bus_type. When the object is available, a
274 * #GDBusProxy (or derived class cf. @interface_type) instance is
275 * constructed for the @interface_name D-Bus interface and then
276 * @proxy_appeared_handler will be called when the proxy is ready and
277 * all properties have been loaded. When @name vanishes,
278 * @proxy_vanished_handler is called.
280 * This function makes it very simple to write applications that wants
281 * to watch a well-known remote object on a well-known name, see <xref
282 * linkend="gdbus-watching-proxy"/>. Basically, the application simply
283 * starts using the proxy when @proxy_appeared_handler is called and
284 * stops using it when @proxy_vanished_handler is called. Callbacks
285 * will be invoked in the <link
286 * linkend="g-main-context-push-thread-default">thread-default main
287 * loop</link> of the thread you are calling this function from.
289 * Applications typically use this function to watch the
290 * <quote>manager</quote> object of a well-known name. Upon acquiring
291 * a proxy for the manager object, applications typically construct
292 * additional proxies in response to the result of enumeration methods
293 * on the manager object.
295 * Many of the comments that apply to g_bus_watch_name() also apply
296 * here. For example, you are guaranteed that one of the handlers will
297 * be invoked (on the main thread) after calling this function and
298 * also that the two handlers alternate. When you are done watching the
299 * proxy, just call g_bus_unwatch_proxy().
301 * Returns: An identifier (never 0) that can be used with
302 * g_bus_unwatch_proxy() to stop watching the remote object.
307 g_bus_watch_proxy (GBusType bus_type,
309 GBusNameWatcherFlags flags,
310 const gchar *object_path,
311 const gchar *interface_name,
312 GType interface_type,
313 GDBusProxyFlags proxy_flags,
314 GBusProxyAppearedCallback proxy_appeared_handler,
315 GBusProxyVanishedCallback proxy_vanished_handler,
317 GDestroyNotify user_data_free_func)
321 g_return_val_if_fail (bus_type != G_BUS_TYPE_NONE, 0);
322 g_return_val_if_fail (g_dbus_is_name (name), 0);
323 g_return_val_if_fail (g_variant_is_object_path (object_path), 0);
324 g_return_val_if_fail (g_dbus_is_interface_name (interface_name), 0);
325 g_return_val_if_fail (g_type_is_a (interface_type, G_TYPE_DBUS_PROXY), 0);
329 client = g_new0 (Client, 1);
330 client->id = next_global_id++; /* TODO: uh oh, handle overflow */
331 client->name = g_strdup (name);
332 client->proxy_appeared_handler = proxy_appeared_handler;
333 client->proxy_vanished_handler = proxy_vanished_handler;
334 client->user_data = user_data;
335 client->user_data_free_func = user_data_free_func;
336 client->main_context = g_main_context_get_thread_default ();
337 if (client->main_context != NULL)
338 g_main_context_ref (client->main_context);
339 client->name_watcher_id = g_bus_watch_name (bus_type,
347 client->object_path = g_strdup (object_path);
348 client->interface_name = g_strdup (interface_name);
349 client->interface_type = interface_type;
350 client->proxy_flags = proxy_flags;
351 client->initial_construction = TRUE;
353 if (map_id_to_client == NULL)
355 map_id_to_client = g_hash_table_new (g_direct_hash, g_direct_equal);
357 g_hash_table_insert (map_id_to_client,
358 GUINT_TO_POINTER (client->id),
367 * g_bus_watch_proxy_on_connection:
368 * @connection: A #GDBusConnection that is not closed.
369 * @name: The name (well-known or unique) to watch.
370 * @flags: Flags from the #GBusNameWatcherFlags enumeration.
371 * @object_path: The object path of the remote object to watch.
372 * @interface_name: The D-Bus interface name for the proxy.
373 * @interface_type: The #GType for the kind of proxy to create. This must be a #GDBusProxy derived type.
374 * @proxy_flags: Flags from #GDBusProxyFlags to use when constructing the proxy.
375 * @proxy_appeared_handler: Handler to invoke when @name is known to exist and the
376 * requested proxy is available.
377 * @proxy_vanished_handler: Handler to invoke when @name is known to not exist
378 * and the previously created proxy is no longer available.
379 * @user_data: User data to pass to handlers.
380 * @user_data_free_func: Function for freeing @user_data or %NULL.
382 * Like g_bus_watch_proxy() but takes a #GDBusConnection instead of a
385 * Returns: An identifier (never 0) that can be used with
386 * g_bus_unwatch_proxy() to stop watching the remote object.
391 g_bus_watch_proxy_on_connection (GDBusConnection *connection,
393 GBusNameWatcherFlags flags,
394 const gchar *object_path,
395 const gchar *interface_name,
396 GType interface_type,
397 GDBusProxyFlags proxy_flags,
398 GBusProxyAppearedCallback proxy_appeared_handler,
399 GBusProxyVanishedCallback proxy_vanished_handler,
401 GDestroyNotify user_data_free_func)
405 g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
406 g_return_val_if_fail (g_dbus_is_name (name), 0);
407 g_return_val_if_fail (g_variant_is_object_path (object_path), 0);
408 g_return_val_if_fail (g_dbus_is_interface_name (interface_name), 0);
409 g_return_val_if_fail (g_type_is_a (interface_type, G_TYPE_DBUS_PROXY), 0);
413 client = g_new0 (Client, 1);
414 client->id = next_global_id++; /* TODO: uh oh, handle overflow */
415 client->name = g_strdup (name);
416 client->proxy_appeared_handler = proxy_appeared_handler;
417 client->proxy_vanished_handler = proxy_vanished_handler;
418 client->user_data = user_data;
419 client->user_data_free_func = user_data_free_func;
420 client->main_context = g_main_context_get_thread_default ();
421 if (client->main_context != NULL)
422 g_main_context_ref (client->main_context);
423 client->name_watcher_id = g_bus_watch_name_on_connection (connection,
431 client->object_path = g_strdup (object_path);
432 client->interface_name = g_strdup (interface_name);
433 client->interface_type = interface_type;
434 client->proxy_flags = proxy_flags;
435 client->initial_construction = TRUE;
437 if (map_id_to_client == NULL)
439 map_id_to_client = g_hash_table_new (g_direct_hash, g_direct_equal);
441 g_hash_table_insert (map_id_to_client,
442 GUINT_TO_POINTER (client->id),
452 * g_bus_unwatch_proxy:
453 * @watcher_id: An identifier obtained from g_bus_watch_proxy()
455 * Stops watching proxy.
460 g_bus_unwatch_proxy (guint watcher_id)
464 g_return_if_fail (watcher_id > 0);
469 if (watcher_id == 0 ||
470 map_id_to_client == NULL ||
471 (client = g_hash_table_lookup (map_id_to_client, GUINT_TO_POINTER (watcher_id))) == NULL)
473 g_warning ("Invalid id %d passed to g_bus_unwatch_proxy()", watcher_id);
477 g_warn_if_fail (g_hash_table_remove (map_id_to_client, GUINT_TO_POINTER (watcher_id)));
484 g_bus_unwatch_name (client->name_watcher_id);
485 client->name_watcher_id = 0;
486 client_unref (client);
490 #define __G_DBUS_PROXY_WATCHING_C__
491 #include "gioaliasdef.c"