glib/tests: Fix non-debug build of slice test
[glib.git] / gio / gdbusobjectmanagerclient.c
blobf33ca21cff3ce93ad943d45cc5f3c152a2aff21b
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>
23 #include "config.h"
25 #include "gdbusobjectmanager.h"
26 #include "gdbusobjectmanagerclient.h"
27 #include "gdbusobject.h"
28 #include "gdbusprivate.h"
29 #include "gioenumtypes.h"
30 #include "ginitable.h"
31 #include "gasyncresult.h"
32 #include "gsimpleasyncresult.h"
33 #include "gasyncinitable.h"
34 #include "gdbusconnection.h"
35 #include "gdbusutils.h"
36 #include "gdbusobject.h"
37 #include "gdbusobjectproxy.h"
38 #include "gdbusproxy.h"
39 #include "gdbusinterface.h"
41 #include "glibintl.h"
43 /**
44 * SECTION:gdbusobjectmanagerclient
45 * @short_description: Client-side object manager
46 * @include: gio/gio.h
48 * #GDBusObjectManagerClient is used to create, monitor and delete object
49 * proxies for remote objects exported by a #GDBusObjectManagerServer (or any
50 * code implementing the <ulink
51 * url="http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager">org.freedesktop.DBus.ObjectManager</ulink>
52 * interface).
54 * Once an instance of this type has been created, you can connect to
55 * the #GDBusObjectManager::object-added and
56 * #GDBusObjectManager::object-removed signals and inspect the
57 * #GDBusObjectProxy objects returned by
58 * g_dbus_object_manager_get_objects().
60 * If the name for a #GDBusObjectManagerClient is not owned by anyone at
61 * object construction time, the default behavior is to request the
62 * message bus to launch an owner for the name. This behavior can be
63 * disabled using the %G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START
64 * flag. It's also worth noting that this only works if the name of
65 * interest is activatable in the first place. E.g. in some cases it
66 * is not possible to launch an owner for the requested name. In this
67 * case, #GDBusObjectManagerClient object construction still succeeds but
68 * there will be no object proxies
69 * (e.g. g_dbus_object_manager_get_objects() returns the empty list) and
70 * the #GDBusObjectManagerClient:name-owner property is %NULL.
72 * The owner of the requested name can come and go (for example
73 * consider a system service being restarted) – #GDBusObjectManagerClient
74 * handles this case too; simply connect to the #GObject::notify
75 * signal to watch for changes on the #GDBusObjectManagerClient:name-owner
76 * property. When the name owner vanishes, the behavior is that
77 * #GDBusObjectManagerClient:name-owner is set to %NULL (this includes
78 * emission of the #GObject::notify signal) and then
79 * #GDBusObjectManager::object-removed signals are synthesized
80 * for all currently existing object proxies. Since
81 * #GDBusObjectManagerClient:name-owner is %NULL when this happens, you can
82 * use this information to disambiguate a synthesized signal from a
83 * genuine signal caused by object removal on the remote
84 * #GDBusObjectManager. Similarly, when a new name owner appears,
85 * #GDBusObjectManager::object-added signals are synthesized
86 * while #GDBusObjectManagerClient:name-owner is still %NULL. Only when all
87 * object proxies have been added, the #GDBusObjectManagerClient:name-owner
88 * is set to the new name owner (this includes emission of the
89 * #GObject::notify signal). Furthermore, you are guaranteed that
90 * #GDBusObjectManagerClient:name-owner will alternate between a name owner
91 * (e.g. <literal>:1.42</literal>) and %NULL even in the case where
92 * the name of interest is atomically replaced
94 * Ultimately, #GDBusObjectManagerClient is used to obtain #GDBusProxy
95 * instances. All signals (including the
96 * <literal>org.freedesktop.DBus.Properties::PropertiesChanged</literal>
97 * signal) delivered to #GDBusProxy instances are guaranteed to
98 * originate from the name owner. This guarantee along with the
99 * behavior described above, means that certain race conditions
100 * including the <emphasis><quote>half the proxy is from the old owner
101 * and the other half is from the new owner</quote></emphasis> problem
102 * cannot happen.
104 * To avoid having the application connect to signals on the returned
105 * #GDBusObjectProxy and #GDBusProxy objects, the
106 * #GDBusObject::interface-added,
107 * #GDBusObject::interface-removed,
108 * #GDBusProxy::g-properties-changed and
109 * #GDBusProxy::g-signal signals
110 * are also emitted on the #GDBusObjectManagerClient instance managing these
111 * objects. The signals emitted are
112 * #GDBusObjectManager::interface-added,
113 * #GDBusObjectManager::interface-removed,
114 * #GDBusObjectManagerClient::interface-proxy-properties-changed and
115 * #GDBusObjectManagerClient::interface-proxy-signal.
117 * Note that all callbacks and signals are emitted in the
118 * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
119 * that the #GDBusObjectManagerClient object was constructed
120 * in. Additionally, the #GDBusObjectProxy and #GDBusProxy objects
121 * originating from the #GDBusObjectManagerClient object will be created in
122 * the same context and, consequently, will deliver signals in the
123 * same main loop.
126 struct _GDBusObjectManagerClientPrivate
128 GMutex lock;
130 GBusType bus_type;
131 GDBusConnection *connection;
132 gchar *object_path;
133 gchar *name;
134 gchar *name_owner;
135 GDBusObjectManagerClientFlags flags;
137 GDBusProxy *control_proxy;
139 GHashTable *map_object_path_to_object_proxy;
141 guint signal_subscription_id;
142 gchar *match_rule;
144 GDBusProxyTypeFunc get_proxy_type_func;
145 gpointer get_proxy_type_user_data;
146 GDestroyNotify get_proxy_type_destroy_notify;
149 enum
151 PROP_0,
152 PROP_BUS_TYPE,
153 PROP_CONNECTION,
154 PROP_FLAGS,
155 PROP_OBJECT_PATH,
156 PROP_NAME,
157 PROP_NAME_OWNER,
158 PROP_GET_PROXY_TYPE_FUNC,
159 PROP_GET_PROXY_TYPE_USER_DATA,
160 PROP_GET_PROXY_TYPE_DESTROY_NOTIFY
163 enum
165 INTERFACE_PROXY_SIGNAL_SIGNAL,
166 INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL,
167 LAST_SIGNAL
170 static guint signals[LAST_SIGNAL] = { 0 };
172 static void initable_iface_init (GInitableIface *initable_iface);
173 static void async_initable_iface_init (GAsyncInitableIface *async_initable_iface);
174 static void dbus_object_manager_interface_init (GDBusObjectManagerIface *iface);
176 G_DEFINE_TYPE_WITH_CODE (GDBusObjectManagerClient, g_dbus_object_manager_client, G_TYPE_OBJECT,
177 G_ADD_PRIVATE (GDBusObjectManagerClient)
178 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)
179 G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init)
180 G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_OBJECT_MANAGER, dbus_object_manager_interface_init));
182 static void maybe_unsubscribe_signals (GDBusObjectManagerClient *manager);
184 static void on_control_proxy_g_signal (GDBusProxy *proxy,
185 const gchar *sender_name,
186 const gchar *signal_name,
187 GVariant *parameters,
188 gpointer user_data);
190 static void process_get_all_result (GDBusObjectManagerClient *manager,
191 GVariant *value,
192 const gchar *name_owner);
194 static void
195 g_dbus_object_manager_client_finalize (GObject *object)
197 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (object);
199 maybe_unsubscribe_signals (manager);
201 g_hash_table_unref (manager->priv->map_object_path_to_object_proxy);
203 if (manager->priv->control_proxy != NULL)
205 g_signal_handlers_disconnect_by_func (manager->priv->control_proxy,
206 on_control_proxy_g_signal,
207 manager);
208 g_object_unref (manager->priv->control_proxy);
210 g_object_unref (manager->priv->connection);
211 g_free (manager->priv->object_path);
212 g_free (manager->priv->name);
213 g_free (manager->priv->name_owner);
215 if (manager->priv->get_proxy_type_destroy_notify != NULL)
216 manager->priv->get_proxy_type_destroy_notify (manager->priv->get_proxy_type_user_data);
218 g_mutex_clear (&manager->priv->lock);
220 if (G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class)->finalize != NULL)
221 G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class)->finalize (object);
224 static void
225 g_dbus_object_manager_client_get_property (GObject *_object,
226 guint prop_id,
227 GValue *value,
228 GParamSpec *pspec)
230 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_object);
232 switch (prop_id)
234 case PROP_CONNECTION:
235 g_value_set_object (value, g_dbus_object_manager_client_get_connection (manager));
236 break;
238 case PROP_OBJECT_PATH:
239 g_value_set_string (value, g_dbus_object_manager_get_object_path (G_DBUS_OBJECT_MANAGER (manager)));
240 break;
242 case PROP_NAME:
243 g_value_set_string (value, g_dbus_object_manager_client_get_name (manager));
244 break;
246 case PROP_FLAGS:
247 g_value_set_flags (value, g_dbus_object_manager_client_get_flags (manager));
248 break;
250 case PROP_NAME_OWNER:
251 g_value_take_string (value, g_dbus_object_manager_client_get_name_owner (manager));
252 break;
254 default:
255 G_OBJECT_WARN_INVALID_PROPERTY_ID (manager, prop_id, pspec);
256 break;
260 static void
261 g_dbus_object_manager_client_set_property (GObject *_object,
262 guint prop_id,
263 const GValue *value,
264 GParamSpec *pspec)
266 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_object);
267 const gchar *name;
269 switch (prop_id)
271 case PROP_BUS_TYPE:
272 manager->priv->bus_type = g_value_get_enum (value);
273 break;
275 case PROP_CONNECTION:
276 if (g_value_get_object (value) != NULL)
278 g_assert (manager->priv->connection == NULL);
279 g_assert (G_IS_DBUS_CONNECTION (g_value_get_object (value)));
280 manager->priv->connection = g_value_dup_object (value);
282 break;
284 case PROP_OBJECT_PATH:
285 g_assert (manager->priv->object_path == NULL);
286 g_assert (g_variant_is_object_path (g_value_get_string (value)));
287 manager->priv->object_path = g_value_dup_string (value);
288 break;
290 case PROP_NAME:
291 g_assert (manager->priv->name == NULL);
292 name = g_value_get_string (value);
293 g_assert (name == NULL || g_dbus_is_name (name));
294 manager->priv->name = g_strdup (name);
295 break;
297 case PROP_FLAGS:
298 manager->priv->flags = g_value_get_flags (value);
299 break;
301 case PROP_GET_PROXY_TYPE_FUNC:
302 manager->priv->get_proxy_type_func = g_value_get_pointer (value);
303 break;
305 case PROP_GET_PROXY_TYPE_USER_DATA:
306 manager->priv->get_proxy_type_user_data = g_value_get_pointer (value);
307 break;
309 case PROP_GET_PROXY_TYPE_DESTROY_NOTIFY:
310 manager->priv->get_proxy_type_destroy_notify = g_value_get_pointer (value);
311 break;
313 default:
314 G_OBJECT_WARN_INVALID_PROPERTY_ID (manager, prop_id, pspec);
315 break;
319 static void
320 g_dbus_object_manager_client_class_init (GDBusObjectManagerClientClass *klass)
322 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
324 gobject_class->finalize = g_dbus_object_manager_client_finalize;
325 gobject_class->set_property = g_dbus_object_manager_client_set_property;
326 gobject_class->get_property = g_dbus_object_manager_client_get_property;
329 * GDBusObjectManagerClient:connection:
331 * The #GDBusConnection to use.
333 * Since: 2.30
335 g_object_class_install_property (gobject_class,
336 PROP_CONNECTION,
337 g_param_spec_object ("connection",
338 "Connection",
339 "The connection to use",
340 G_TYPE_DBUS_CONNECTION,
341 G_PARAM_READABLE |
342 G_PARAM_WRITABLE |
343 G_PARAM_CONSTRUCT_ONLY |
344 G_PARAM_STATIC_STRINGS));
347 * GDBusObjectManagerClient:bus-type:
349 * If this property is not %G_BUS_TYPE_NONE, then
350 * #GDBusObjectManagerClient:connection must be %NULL and will be set to the
351 * #GDBusConnection obtained by calling g_bus_get() with the value
352 * of this property.
354 * Since: 2.30
356 g_object_class_install_property (gobject_class,
357 PROP_BUS_TYPE,
358 g_param_spec_enum ("bus-type",
359 "Bus Type",
360 "The bus to connect to, if any",
361 G_TYPE_BUS_TYPE,
362 G_BUS_TYPE_NONE,
363 G_PARAM_WRITABLE |
364 G_PARAM_CONSTRUCT_ONLY |
365 G_PARAM_STATIC_NAME |
366 G_PARAM_STATIC_BLURB |
367 G_PARAM_STATIC_NICK));
370 * GDBusObjectManagerClient:flags:
372 * Flags from the #GDBusObjectManagerClientFlags enumeration.
374 * Since: 2.30
376 g_object_class_install_property (gobject_class,
377 PROP_FLAGS,
378 g_param_spec_flags ("flags",
379 "Flags",
380 "Flags for the proxy manager",
381 G_TYPE_DBUS_OBJECT_MANAGER_CLIENT_FLAGS,
382 G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
383 G_PARAM_READABLE |
384 G_PARAM_WRITABLE |
385 G_PARAM_CONSTRUCT_ONLY |
386 G_PARAM_STATIC_NAME |
387 G_PARAM_STATIC_BLURB |
388 G_PARAM_STATIC_NICK));
391 * GDBusObjectManagerClient:object-path:
393 * The object path the manager is for.
395 * Since: 2.30
397 g_object_class_install_property (gobject_class,
398 PROP_OBJECT_PATH,
399 g_param_spec_string ("object-path",
400 "Object Path",
401 "The object path of the control object",
402 NULL,
403 G_PARAM_READABLE |
404 G_PARAM_WRITABLE |
405 G_PARAM_CONSTRUCT_ONLY |
406 G_PARAM_STATIC_STRINGS));
409 * GDBusObjectManagerClient:name:
411 * The well-known name or unique name that the manager is for.
413 * Since: 2.30
415 g_object_class_install_property (gobject_class,
416 PROP_NAME,
417 g_param_spec_string ("name",
418 "Name",
419 "Name that the manager is for",
420 NULL,
421 G_PARAM_READABLE |
422 G_PARAM_WRITABLE |
423 G_PARAM_CONSTRUCT_ONLY |
424 G_PARAM_STATIC_STRINGS));
427 * GDBusObjectManagerClient:name-owner:
429 * The unique name that owns #GDBusObjectManagerClient:name or %NULL if
430 * no-one is currently owning the name. Connect to the
431 * #GObject::notify signal to track changes to this property.
433 * Since: 2.30
435 g_object_class_install_property (gobject_class,
436 PROP_NAME_OWNER,
437 g_param_spec_string ("name-owner",
438 "Name Owner",
439 "The owner of the name we are watching",
440 NULL,
441 G_PARAM_READABLE |
442 G_PARAM_STATIC_STRINGS));
445 * GDBusObjectManagerClient:get-proxy-type-func:
447 * The #GDBusProxyTypeFunc to use when determining what #GType to
448 * use for interface proxies or %NULL.
450 * Since: 2.30
452 g_object_class_install_property (gobject_class,
453 PROP_GET_PROXY_TYPE_FUNC,
454 g_param_spec_pointer ("get-proxy-type-func",
455 "GDBusProxyTypeFunc Function Pointer",
456 "The GDBusProxyTypeFunc pointer to use",
457 G_PARAM_READABLE |
458 G_PARAM_WRITABLE |
459 G_PARAM_CONSTRUCT_ONLY |
460 G_PARAM_STATIC_STRINGS));
463 * GDBusObjectManagerClient:get-proxy-type-user-data:
465 * The #gpointer user_data to pass to #GDBusObjectManagerClient:get-proxy-type-func.
467 * Since: 2.30
469 g_object_class_install_property (gobject_class,
470 PROP_GET_PROXY_TYPE_USER_DATA,
471 g_param_spec_pointer ("get-proxy-type-user-data",
472 "GDBusProxyTypeFunc User Data",
473 "The GDBusProxyTypeFunc user_data",
474 G_PARAM_READABLE |
475 G_PARAM_WRITABLE |
476 G_PARAM_CONSTRUCT_ONLY |
477 G_PARAM_STATIC_STRINGS));
480 * GDBusObjectManagerClient:get-proxy-type-destroy-notify:
482 * A #GDestroyNotify for the #gpointer user_data in #GDBusObjectManagerClient:get-proxy-type-user-data.
484 * Since: 2.30
486 g_object_class_install_property (gobject_class,
487 PROP_GET_PROXY_TYPE_DESTROY_NOTIFY,
488 g_param_spec_pointer ("get-proxy-type-destroy-notify",
489 "GDBusProxyTypeFunc user data free function",
490 "The GDBusProxyTypeFunc user data free function",
491 G_PARAM_READABLE |
492 G_PARAM_WRITABLE |
493 G_PARAM_CONSTRUCT_ONLY |
494 G_PARAM_STATIC_STRINGS));
497 * GDBusObjectManagerClient::interface-proxy-signal:
498 * @manager: The #GDBusObjectManagerClient emitting the signal.
499 * @object_proxy: The #GDBusObjectProxy on which an interface is emitting a D-Bus signal.
500 * @interface_proxy: The #GDBusProxy that is emitting a D-Bus signal.
501 * @sender_name: The sender of the signal or NULL if the connection is not a bus connection.
502 * @signal_name: The signal name.
503 * @parameters: A #GVariant tuple with parameters for the signal.
505 * Emitted when a D-Bus signal is received on @interface_proxy.
507 * This signal exists purely as a convenience to avoid having to
508 * connect signals to all interface proxies managed by @manager.
510 * This signal is emitted in the
511 * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
512 * that @manager was constructed in.
514 * Since: 2.30
516 signals[INTERFACE_PROXY_SIGNAL_SIGNAL] =
517 g_signal_new ("interface-proxy-signal",
518 G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
519 G_SIGNAL_RUN_LAST,
520 G_STRUCT_OFFSET (GDBusObjectManagerClientClass, interface_proxy_signal),
521 NULL,
522 NULL,
523 NULL,
524 G_TYPE_NONE,
526 G_TYPE_DBUS_OBJECT_PROXY,
527 G_TYPE_DBUS_PROXY,
528 G_TYPE_STRING,
529 G_TYPE_STRING,
530 G_TYPE_VARIANT);
533 * GDBusObjectManagerClient::interface-proxy-properties-changed:
534 * @manager: The #GDBusObjectManagerClient emitting the signal.
535 * @object_proxy: The #GDBusObjectProxy on which an interface has properties that are changing.
536 * @interface_proxy: The #GDBusProxy that has properties that are changing.
537 * @changed_properties: A #GVariant containing the properties that changed.
538 * @invalidated_properties: A %NULL terminated array of properties that was invalidated.
540 * Emitted when one or more D-Bus properties on proxy changes. The
541 * local cache has already been updated when this signal fires. Note
542 * that both @changed_properties and @invalidated_properties are
543 * guaranteed to never be %NULL (either may be empty though).
545 * This signal exists purely as a convenience to avoid having to
546 * connect signals to all interface proxies managed by @manager.
548 * This signal is emitted in the
549 * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
550 * that @manager was constructed in.
552 * Since: 2.30
554 signals[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL] =
555 g_signal_new ("interface-proxy-properties-changed",
556 G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
557 G_SIGNAL_RUN_LAST,
558 G_STRUCT_OFFSET (GDBusObjectManagerClientClass, interface_proxy_properties_changed),
559 NULL,
560 NULL,
561 NULL,
562 G_TYPE_NONE,
564 G_TYPE_DBUS_OBJECT_PROXY,
565 G_TYPE_DBUS_PROXY,
566 G_TYPE_VARIANT,
567 G_TYPE_STRV);
570 static void
571 g_dbus_object_manager_client_init (GDBusObjectManagerClient *manager)
573 manager->priv = g_dbus_object_manager_client_get_instance_private (manager);
574 g_mutex_init (&manager->priv->lock);
575 manager->priv->map_object_path_to_object_proxy = g_hash_table_new_full (g_str_hash,
576 g_str_equal,
577 g_free,
578 (GDestroyNotify) g_object_unref);
581 /* ---------------------------------------------------------------------------------------------------- */
584 * g_dbus_object_manager_client_new_sync:
585 * @connection: A #GDBusConnection.
586 * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
587 * @name: (allow-none): The owner of the control object (unique or well-known name), or %NULL when not using a message bus connection.
588 * @object_path: The object path of the control object.
589 * @get_proxy_type_func: (allow-none): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
590 * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
591 * @get_proxy_type_destroy_notify: (allow-none): Free function for @get_proxy_type_user_data or %NULL.
592 * @cancellable: (allow-none): A #GCancellable or %NULL
593 * @error: Return location for error or %NULL.
595 * Creates a new #GDBusObjectManagerClient object.
597 * This is a synchronous failable constructor - the calling thread is
598 * blocked until a reply is received. See g_dbus_object_manager_client_new()
599 * for the asynchronous version.
601 * Returns: (transfer full) (type GDBusObjectManagerClient): A
602 * #GDBusObjectManagerClient object or %NULL if @error is set. Free
603 * with g_object_unref().
605 * Since: 2.30
607 GDBusObjectManager *
608 g_dbus_object_manager_client_new_sync (GDBusConnection *connection,
609 GDBusObjectManagerClientFlags flags,
610 const gchar *name,
611 const gchar *object_path,
612 GDBusProxyTypeFunc get_proxy_type_func,
613 gpointer get_proxy_type_user_data,
614 GDestroyNotify get_proxy_type_destroy_notify,
615 GCancellable *cancellable,
616 GError **error)
618 GInitable *initable;
620 g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
621 g_return_val_if_fail ((name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) ||
622 g_dbus_is_name (name), NULL);
623 g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
624 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
626 initable = g_initable_new (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
627 cancellable,
628 error,
629 "connection", connection,
630 "flags", flags,
631 "name", name,
632 "object-path", object_path,
633 "get-proxy-type-func", get_proxy_type_func,
634 "get-proxy-type-user-data", get_proxy_type_user_data,
635 "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
636 NULL);
637 if (initable != NULL)
638 return G_DBUS_OBJECT_MANAGER (initable);
639 else
640 return NULL;
644 * g_dbus_object_manager_client_new:
645 * @connection: A #GDBusConnection.
646 * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
647 * @name: The owner of the control object (unique or well-known name).
648 * @object_path: The object path of the control object.
649 * @get_proxy_type_func: (allow-none): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
650 * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
651 * @get_proxy_type_destroy_notify: (allow-none): Free function for @get_proxy_type_user_data or %NULL.
652 * @cancellable: (allow-none): A #GCancellable or %NULL
653 * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
654 * @user_data: The data to pass to @callback.
656 * Asynchronously creates a new #GDBusObjectManagerClient object.
658 * This is an asynchronous failable constructor. When the result is
659 * ready, @callback will be invoked in the
660 * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
661 * of the thread you are calling this method from. You can
662 * then call g_dbus_object_manager_client_new_finish() to get the result. See
663 * g_dbus_object_manager_client_new_sync() for the synchronous version.
665 * Since: 2.30
667 void
668 g_dbus_object_manager_client_new (GDBusConnection *connection,
669 GDBusObjectManagerClientFlags flags,
670 const gchar *name,
671 const gchar *object_path,
672 GDBusProxyTypeFunc get_proxy_type_func,
673 gpointer get_proxy_type_user_data,
674 GDestroyNotify get_proxy_type_destroy_notify,
675 GCancellable *cancellable,
676 GAsyncReadyCallback callback,
677 gpointer user_data)
679 g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
680 g_return_if_fail ((name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) ||
681 g_dbus_is_name (name));
682 g_return_if_fail (g_variant_is_object_path (object_path));
684 g_async_initable_new_async (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
685 G_PRIORITY_DEFAULT,
686 cancellable,
687 callback,
688 user_data,
689 "connection", connection,
690 "flags", flags,
691 "name", name,
692 "object-path", object_path,
693 "get-proxy-type-func", get_proxy_type_func,
694 "get-proxy-type-user-data", get_proxy_type_user_data,
695 "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
696 NULL);
700 * g_dbus_object_manager_client_new_finish:
701 * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_object_manager_client_new().
702 * @error: Return location for error or %NULL.
704 * Finishes an operation started with g_dbus_object_manager_client_new().
706 * Returns: (transfer full) (type GDBusObjectManagerClient): A
707 * #GDBusObjectManagerClient object or %NULL if @error is set. Free
708 * with g_object_unref().
710 * Since: 2.30
712 GDBusObjectManager *
713 g_dbus_object_manager_client_new_finish (GAsyncResult *res,
714 GError **error)
716 GObject *object;
717 GObject *source_object;
719 source_object = g_async_result_get_source_object (res);
720 g_assert (source_object != NULL);
722 object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
723 res,
724 error);
725 g_object_unref (source_object);
727 if (object != NULL)
728 return G_DBUS_OBJECT_MANAGER (object);
729 else
730 return NULL;
733 /* ---------------------------------------------------------------------------------------------------- */
736 * g_dbus_object_manager_client_new_for_bus_sync:
737 * @bus_type: A #GBusType.
738 * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
739 * @name: The owner of the control object (unique or well-known name).
740 * @object_path: The object path of the control object.
741 * @get_proxy_type_func: (allow-none): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
742 * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
743 * @get_proxy_type_destroy_notify: (allow-none): Free function for @get_proxy_type_user_data or %NULL.
744 * @cancellable: (allow-none): A #GCancellable or %NULL
745 * @error: Return location for error or %NULL.
747 * Like g_dbus_object_manager_client_new_sync() but takes a #GBusType instead
748 * of a #GDBusConnection.
750 * This is a synchronous failable constructor - the calling thread is
751 * blocked until a reply is received. See g_dbus_object_manager_client_new_for_bus()
752 * for the asynchronous version.
754 * Returns: (transfer full) (type GDBusObjectManagerClient): A
755 * #GDBusObjectManagerClient object or %NULL if @error is set. Free
756 * with g_object_unref().
758 * Since: 2.30
760 GDBusObjectManager *
761 g_dbus_object_manager_client_new_for_bus_sync (GBusType bus_type,
762 GDBusObjectManagerClientFlags flags,
763 const gchar *name,
764 const gchar *object_path,
765 GDBusProxyTypeFunc get_proxy_type_func,
766 gpointer get_proxy_type_user_data,
767 GDestroyNotify get_proxy_type_destroy_notify,
768 GCancellable *cancellable,
769 GError **error)
771 GInitable *initable;
773 g_return_val_if_fail (bus_type != G_BUS_TYPE_NONE, NULL);
774 g_return_val_if_fail (g_dbus_is_name (name), NULL);
775 g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
776 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
778 initable = g_initable_new (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
779 cancellable,
780 error,
781 "bus-type", bus_type,
782 "flags", flags,
783 "name", name,
784 "object-path", object_path,
785 "get-proxy-type-func", get_proxy_type_func,
786 "get-proxy-type-user-data", get_proxy_type_user_data,
787 "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
788 NULL);
789 if (initable != NULL)
790 return G_DBUS_OBJECT_MANAGER (initable);
791 else
792 return NULL;
796 * g_dbus_object_manager_client_new_for_bus:
797 * @bus_type: A #GBusType.
798 * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
799 * @name: The owner of the control object (unique or well-known name).
800 * @object_path: The object path of the control object.
801 * @get_proxy_type_func: (allow-none): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
802 * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
803 * @get_proxy_type_destroy_notify: (allow-none): Free function for @get_proxy_type_user_data or %NULL.
804 * @cancellable: (allow-none): A #GCancellable or %NULL
805 * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
806 * @user_data: The data to pass to @callback.
808 * Like g_dbus_object_manager_client_new() but takes a #GBusType instead of a
809 * #GDBusConnection.
811 * This is an asynchronous failable constructor. When the result is
812 * ready, @callback will be invoked in the
813 * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
814 * of the thread you are calling this method from. You can
815 * then call g_dbus_object_manager_client_new_for_bus_finish() to get the result. See
816 * g_dbus_object_manager_client_new_for_bus_sync() for the synchronous version.
818 * Since: 2.30
820 void
821 g_dbus_object_manager_client_new_for_bus (GBusType bus_type,
822 GDBusObjectManagerClientFlags flags,
823 const gchar *name,
824 const gchar *object_path,
825 GDBusProxyTypeFunc get_proxy_type_func,
826 gpointer get_proxy_type_user_data,
827 GDestroyNotify get_proxy_type_destroy_notify,
828 GCancellable *cancellable,
829 GAsyncReadyCallback callback,
830 gpointer user_data)
832 g_return_if_fail (bus_type != G_BUS_TYPE_NONE);
833 g_return_if_fail (g_dbus_is_name (name));
834 g_return_if_fail (g_variant_is_object_path (object_path));
836 g_async_initable_new_async (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
837 G_PRIORITY_DEFAULT,
838 cancellable,
839 callback,
840 user_data,
841 "bus-type", bus_type,
842 "flags", flags,
843 "name", name,
844 "object-path", object_path,
845 "get-proxy-type-func", get_proxy_type_func,
846 "get-proxy-type-user-data", get_proxy_type_user_data,
847 "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
848 NULL);
852 * g_dbus_object_manager_client_new_for_bus_finish:
853 * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_object_manager_client_new_for_bus().
854 * @error: Return location for error or %NULL.
856 * Finishes an operation started with g_dbus_object_manager_client_new_for_bus().
858 * Returns: (transfer full) (type GDBusObjectManagerClient): A
859 * #GDBusObjectManagerClient object or %NULL if @error is set. Free
860 * with g_object_unref().
862 * Since: 2.30
864 GDBusObjectManager *
865 g_dbus_object_manager_client_new_for_bus_finish (GAsyncResult *res,
866 GError **error)
868 GObject *object;
869 GObject *source_object;
871 source_object = g_async_result_get_source_object (res);
872 g_assert (source_object != NULL);
874 object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
875 res,
876 error);
877 g_object_unref (source_object);
879 if (object != NULL)
880 return G_DBUS_OBJECT_MANAGER (object);
881 else
882 return NULL;
885 /* ---------------------------------------------------------------------------------------------------- */
888 * g_dbus_object_manager_client_get_connection:
889 * @manager: A #GDBusObjectManagerClient
891 * Gets the #GDBusConnection used by @manager.
893 * Returns: (transfer none): A #GDBusConnection object. Do not free,
894 * the object belongs to @manager.
896 * Since: 2.30
898 GDBusConnection *
899 g_dbus_object_manager_client_get_connection (GDBusObjectManagerClient *manager)
901 GDBusConnection *ret;
902 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
903 g_mutex_lock (&manager->priv->lock);
904 ret = manager->priv->connection;
905 g_mutex_unlock (&manager->priv->lock);
906 return ret;
910 * g_dbus_object_manager_client_get_name:
911 * @manager: A #GDBusObjectManagerClient
913 * Gets the name that @manager is for, or %NULL if not a message bus
914 * connection.
916 * Returns: A unique or well-known name. Do not free, the string
917 * belongs to @manager.
919 * Since: 2.30
921 const gchar *
922 g_dbus_object_manager_client_get_name (GDBusObjectManagerClient *manager)
924 const gchar *ret;
925 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
926 g_mutex_lock (&manager->priv->lock);
927 ret = manager->priv->name;
928 g_mutex_unlock (&manager->priv->lock);
929 return ret;
933 * g_dbus_object_manager_client_get_flags:
934 * @manager: A #GDBusObjectManagerClient
936 * Gets the flags that @manager was constructed with.
938 * Returns: Zero of more flags from the #GDBusObjectManagerClientFlags
939 * enumeration.
941 * Since: 2.30
943 GDBusObjectManagerClientFlags
944 g_dbus_object_manager_client_get_flags (GDBusObjectManagerClient *manager)
946 GDBusObjectManagerClientFlags ret;
947 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE);
948 g_mutex_lock (&manager->priv->lock);
949 ret = manager->priv->flags;
950 g_mutex_unlock (&manager->priv->lock);
951 return ret;
955 * g_dbus_object_manager_client_get_name_owner:
956 * @manager: A #GDBusObjectManagerClient.
958 * The unique name that owns the name that @manager is for or %NULL if
959 * no-one currently owns that name. You can connect to the
960 * #GObject::notify signal to track changes to the
961 * #GDBusObjectManagerClient:name-owner property.
963 * Returns: The name owner or %NULL if no name owner exists. Free with
964 * g_free().
966 * Since: 2.30
968 gchar *
969 g_dbus_object_manager_client_get_name_owner (GDBusObjectManagerClient *manager)
971 gchar *ret;
972 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
973 g_mutex_lock (&manager->priv->lock);
974 ret = g_strdup (manager->priv->name_owner);
975 g_mutex_unlock (&manager->priv->lock);
976 return ret;
979 /* ---------------------------------------------------------------------------------------------------- */
981 /* signal handler for all objects we manage - we dispatch signals
982 * from here to the objects
984 static void
985 signal_cb (GDBusConnection *connection,
986 const gchar *sender_name,
987 const gchar *object_path,
988 const gchar *interface_name,
989 const gchar *signal_name,
990 GVariant *parameters,
991 gpointer user_data)
993 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (user_data);
994 GDBusObjectProxy *object_proxy;
995 GDBusInterface *interface;
997 g_mutex_lock (&manager->priv->lock);
998 object_proxy = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
999 if (object_proxy == NULL)
1001 g_mutex_unlock (&manager->priv->lock);
1002 goto out;
1004 g_object_ref (object_proxy);
1005 g_mutex_unlock (&manager->priv->lock);
1007 //g_debug ("yay, signal_cb %s %s: %s\n", signal_name, object_path, g_variant_print (parameters, TRUE));
1009 g_object_ref (manager);
1010 if (g_strcmp0 (interface_name, "org.freedesktop.DBus.Properties") == 0)
1012 if (g_strcmp0 (signal_name, "PropertiesChanged") == 0)
1014 const gchar *interface_name;
1015 GVariant *changed_properties;
1016 const gchar **invalidated_properties;
1018 g_variant_get (parameters,
1019 "(&s@a{sv}^a&s)",
1020 &interface_name,
1021 &changed_properties,
1022 &invalidated_properties);
1024 interface = g_dbus_object_get_interface (G_DBUS_OBJECT (object_proxy), interface_name);
1025 if (interface != NULL)
1027 GVariantIter property_iter;
1028 const gchar *property_name;
1029 GVariant *property_value;
1030 guint n;
1032 /* update caches... */
1033 g_variant_iter_init (&property_iter, changed_properties);
1034 while (g_variant_iter_next (&property_iter,
1035 "{&sv}",
1036 &property_name,
1037 &property_value))
1039 g_dbus_proxy_set_cached_property (G_DBUS_PROXY (interface),
1040 property_name,
1041 property_value);
1042 g_variant_unref (property_value);
1045 for (n = 0; invalidated_properties[n] != NULL; n++)
1047 g_dbus_proxy_set_cached_property (G_DBUS_PROXY (interface),
1048 invalidated_properties[n],
1049 NULL);
1051 /* ... and then synthesize the signal */
1052 g_signal_emit_by_name (interface,
1053 "g-properties-changed",
1054 changed_properties,
1055 invalidated_properties);
1056 g_signal_emit (manager,
1057 signals[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL],
1059 object_proxy,
1060 interface,
1061 changed_properties,
1062 invalidated_properties);
1063 g_object_unref (interface);
1065 g_variant_unref (changed_properties);
1066 g_free (invalidated_properties);
1069 else
1071 /* regular signal - just dispatch it */
1072 interface = g_dbus_object_get_interface (G_DBUS_OBJECT (object_proxy), interface_name);
1073 if (interface != NULL)
1075 g_signal_emit_by_name (interface,
1076 "g-signal",
1077 sender_name,
1078 signal_name,
1079 parameters);
1080 g_signal_emit (manager,
1081 signals[INTERFACE_PROXY_SIGNAL_SIGNAL],
1083 object_proxy,
1084 interface,
1085 sender_name,
1086 signal_name,
1087 parameters);
1088 g_object_unref (interface);
1091 g_object_unref (manager);
1093 out:
1094 g_clear_object (&object_proxy);
1097 static void
1098 subscribe_signals (GDBusObjectManagerClient *manager,
1099 const gchar *name_owner)
1101 GError *error = NULL;
1102 GVariant *ret;
1104 g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager));
1105 g_return_if_fail (manager->priv->signal_subscription_id == 0);
1106 g_return_if_fail (name_owner == NULL || g_dbus_is_unique_name (name_owner));
1108 if (name_owner != NULL)
1110 /* Only add path_namespace if it's non-'/'. This removes a no-op key from
1111 * the match rule, and also works around a D-Bus bug where
1112 * path_namespace='/' matches nothing in D-Bus versions < 1.6.18.
1114 * See: https://bugs.freedesktop.org/show_bug.cgi?id=70799 */
1115 if (g_str_equal (manager->priv->object_path, "/"))
1117 manager->priv->match_rule = g_strdup_printf ("type='signal',sender='%s'",
1118 name_owner);
1120 else
1122 manager->priv->match_rule = g_strdup_printf ("type='signal',sender='%s',path_namespace='%s'",
1123 name_owner, manager->priv->object_path);
1126 /* The bus daemon may not implement path_namespace so gracefully
1127 * handle this by using a fallback triggered if @error is set. */
1128 ret = g_dbus_connection_call_sync (manager->priv->connection,
1129 "org.freedesktop.DBus",
1130 "/org/freedesktop/DBus",
1131 "org.freedesktop.DBus",
1132 "AddMatch",
1133 g_variant_new ("(s)",
1134 manager->priv->match_rule),
1135 NULL, /* reply_type */
1136 G_DBUS_CALL_FLAGS_NONE,
1137 -1, /* default timeout */
1138 NULL, /* TODO: Cancellable */
1139 &error);
1141 /* yay, bus daemon supports path_namespace */
1142 if (ret != NULL)
1143 g_variant_unref (ret);
1146 if (error == NULL)
1148 /* still need to ask GDBusConnection for the callbacks */
1149 manager->priv->signal_subscription_id =
1150 g_dbus_connection_signal_subscribe (manager->priv->connection,
1151 name_owner,
1152 NULL, /* interface */
1153 NULL, /* member */
1154 NULL, /* path - TODO: really want wilcard support here */
1155 NULL, /* arg0 */
1156 G_DBUS_SIGNAL_FLAGS_NONE |
1157 G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
1158 signal_cb,
1159 manager,
1160 NULL); /* user_data_free_func */
1163 else
1165 /* TODO: we could report this to the user
1166 g_warning ("Message bus daemon does not support path_namespace: %s (%s %d)",
1167 error->message,
1168 g_quark_to_string (error->domain),
1169 error->code);
1172 g_error_free (error);
1174 /* no need to call RemoveMatch when done since it didn't work */
1175 g_free (manager->priv->match_rule);
1176 manager->priv->match_rule = NULL;
1178 /* Fallback is to subscribe to *all* signals from the name owner which
1179 * is rather wasteful. It's probably not a big practical problem because
1180 * users typically want all objects that the name owner supplies.
1182 manager->priv->signal_subscription_id =
1183 g_dbus_connection_signal_subscribe (manager->priv->connection,
1184 name_owner,
1185 NULL, /* interface */
1186 NULL, /* member */
1187 NULL, /* path - TODO: really want wilcard support here */
1188 NULL, /* arg0 */
1189 G_DBUS_SIGNAL_FLAGS_NONE,
1190 signal_cb,
1191 manager,
1192 NULL); /* user_data_free_func */
1196 static void
1197 maybe_unsubscribe_signals (GDBusObjectManagerClient *manager)
1199 g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager));
1201 if (manager->priv->signal_subscription_id > 0)
1203 g_dbus_connection_signal_unsubscribe (manager->priv->connection,
1204 manager->priv->signal_subscription_id);
1205 manager->priv->signal_subscription_id = 0;
1208 if (manager->priv->match_rule != NULL)
1210 /* Since the AddMatch call succeeded this is guaranteed to not
1211 * fail - therefore, don't bother checking the return value
1213 g_dbus_connection_call (manager->priv->connection,
1214 "org.freedesktop.DBus",
1215 "/org/freedesktop/DBus",
1216 "org.freedesktop.DBus",
1217 "RemoveMatch",
1218 g_variant_new ("(s)",
1219 manager->priv->match_rule),
1220 NULL, /* reply_type */
1221 G_DBUS_CALL_FLAGS_NONE,
1222 -1, /* default timeout */
1223 NULL, /* GCancellable */
1224 NULL, /* GAsyncReadyCallback */
1225 NULL); /* user data */
1226 g_free (manager->priv->match_rule);
1227 manager->priv->match_rule = NULL;
1232 /* ---------------------------------------------------------------------------------------------------- */
1234 static void
1235 on_notify_g_name_owner (GObject *object,
1236 GParamSpec *pspec,
1237 gpointer user_data)
1239 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (user_data);
1240 gchar *old_name_owner;
1241 gchar *new_name_owner;
1243 g_mutex_lock (&manager->priv->lock);
1244 old_name_owner = manager->priv->name_owner;
1245 new_name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy);
1246 manager->priv->name_owner = NULL;
1248 g_object_ref (manager);
1249 if (g_strcmp0 (old_name_owner, new_name_owner) != 0)
1251 GList *l;
1252 GList *proxies;
1254 /* remote manager changed; nuke all local proxies */
1255 proxies = g_hash_table_get_values (manager->priv->map_object_path_to_object_proxy);
1256 g_list_foreach (proxies, (GFunc) g_object_ref, NULL);
1257 g_hash_table_remove_all (manager->priv->map_object_path_to_object_proxy);
1259 g_mutex_unlock (&manager->priv->lock);
1261 /* do the :name-owner notify with a NULL name - this way the user knows
1262 * the ::object-proxy-removed following is because the name owner went
1263 * away
1265 g_object_notify (G_OBJECT (manager), "name-owner");
1267 for (l = proxies; l != NULL; l = l->next)
1269 GDBusObjectProxy *object_proxy = G_DBUS_OBJECT_PROXY (l->data);
1270 g_signal_emit_by_name (manager, "object-removed", object_proxy);
1272 g_list_free_full (proxies, g_object_unref);
1274 /* nuke local filter */
1275 maybe_unsubscribe_signals (manager);
1277 else
1279 g_mutex_unlock (&manager->priv->lock);
1282 if (new_name_owner != NULL)
1284 GError *error;
1285 GVariant *value;
1287 //g_debug ("repopulating for %s", new_name_owner);
1289 /* TODO: do this async! */
1290 subscribe_signals (manager,
1291 new_name_owner);
1292 error = NULL;
1293 value = g_dbus_proxy_call_sync (manager->priv->control_proxy,
1294 "GetManagedObjects",
1295 NULL, /* parameters */
1296 G_DBUS_CALL_FLAGS_NONE,
1298 NULL,
1299 &error);
1300 if (value == NULL)
1302 maybe_unsubscribe_signals (manager);
1303 g_warning ("Error calling GetManagedObjects() when name owner %s for name %s came back: %s",
1304 new_name_owner,
1305 manager->priv->name,
1306 error->message);
1307 g_error_free (error);
1309 else
1311 process_get_all_result (manager, value, new_name_owner);
1312 g_variant_unref (value);
1315 /* do the :name-owner notify *AFTER* emitting ::object-proxy-added signals - this
1316 * way the user knows that the signals were emitted because the name owner came back
1318 g_mutex_lock (&manager->priv->lock);
1319 manager->priv->name_owner = new_name_owner;
1320 g_mutex_unlock (&manager->priv->lock);
1321 g_object_notify (G_OBJECT (manager), "name-owner");
1324 g_free (old_name_owner);
1325 g_object_unref (manager);
1328 static gboolean
1329 initable_init (GInitable *initable,
1330 GCancellable *cancellable,
1331 GError **error)
1333 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (initable);
1334 gboolean ret;
1335 GVariant *value;
1336 GDBusProxyFlags proxy_flags;
1338 ret = FALSE;
1340 if (manager->priv->bus_type != G_BUS_TYPE_NONE)
1342 g_assert (manager->priv->connection == NULL);
1343 manager->priv->connection = g_bus_get_sync (manager->priv->bus_type, cancellable, error);
1344 if (manager->priv->connection == NULL)
1345 goto out;
1348 proxy_flags = G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES;
1349 if (manager->priv->flags & G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START)
1350 proxy_flags |= G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START;
1352 manager->priv->control_proxy = g_dbus_proxy_new_sync (manager->priv->connection,
1353 proxy_flags,
1354 NULL, /* GDBusInterfaceInfo* */
1355 manager->priv->name,
1356 manager->priv->object_path,
1357 "org.freedesktop.DBus.ObjectManager",
1358 cancellable,
1359 error);
1360 if (manager->priv->control_proxy == NULL)
1361 goto out;
1363 g_signal_connect (G_OBJECT (manager->priv->control_proxy),
1364 "notify::g-name-owner",
1365 G_CALLBACK (on_notify_g_name_owner),
1366 manager);
1368 g_signal_connect (manager->priv->control_proxy,
1369 "g-signal",
1370 G_CALLBACK (on_control_proxy_g_signal),
1371 manager);
1373 manager->priv->name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy);
1374 if (manager->priv->name_owner == NULL && manager->priv->name != NULL)
1376 /* it's perfectly fine if there's no name owner.. we're just going to
1377 * wait until one is ready
1380 else
1382 /* yay, we can get the objects */
1383 subscribe_signals (manager,
1384 manager->priv->name_owner);
1385 value = g_dbus_proxy_call_sync (manager->priv->control_proxy,
1386 "GetManagedObjects",
1387 NULL, /* parameters */
1388 G_DBUS_CALL_FLAGS_NONE,
1390 cancellable,
1391 error);
1392 if (value == NULL)
1394 maybe_unsubscribe_signals (manager);
1395 g_warn_if_fail (g_signal_handlers_disconnect_by_func (manager->priv->control_proxy,
1396 on_control_proxy_g_signal,
1397 manager) == 1);
1398 g_object_unref (manager->priv->control_proxy);
1399 manager->priv->control_proxy = NULL;
1400 goto out;
1403 process_get_all_result (manager, value, manager->priv->name_owner);
1404 g_variant_unref (value);
1407 ret = TRUE;
1409 out:
1410 return ret;
1413 static void
1414 initable_iface_init (GInitableIface *initable_iface)
1416 initable_iface->init = initable_init;
1419 static void
1420 async_initable_iface_init (GAsyncInitableIface *async_initable_iface)
1422 /* for now, just use default: run GInitable code in thread */
1425 /* ---------------------------------------------------------------------------------------------------- */
1427 static void
1428 add_interfaces (GDBusObjectManagerClient *manager,
1429 const gchar *object_path,
1430 GVariant *ifaces_and_properties,
1431 const gchar *name_owner)
1433 GDBusObjectProxy *op;
1434 gboolean added;
1435 GVariantIter iter;
1436 const gchar *interface_name;
1437 GVariant *properties;
1438 GList *interface_added_signals, *l;
1439 GDBusProxy *interface_proxy;
1441 g_return_if_fail (name_owner == NULL || g_dbus_is_unique_name (name_owner));
1443 g_mutex_lock (&manager->priv->lock);
1445 interface_added_signals = NULL;
1446 added = FALSE;
1448 op = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1449 if (op == NULL)
1451 GType object_proxy_type;
1452 if (manager->priv->get_proxy_type_func != NULL)
1454 object_proxy_type = manager->priv->get_proxy_type_func (manager,
1455 object_path,
1456 NULL,
1457 manager->priv->get_proxy_type_user_data);
1458 g_warn_if_fail (g_type_is_a (object_proxy_type, G_TYPE_DBUS_OBJECT_PROXY));
1460 else
1462 object_proxy_type = G_TYPE_DBUS_OBJECT_PROXY;
1464 op = g_object_new (object_proxy_type,
1465 "g-connection", manager->priv->connection,
1466 "g-object-path", object_path,
1467 NULL);
1468 added = TRUE;
1470 g_object_ref (op);
1472 g_variant_iter_init (&iter, ifaces_and_properties);
1473 while (g_variant_iter_next (&iter,
1474 "{&s@a{sv}}",
1475 &interface_name,
1476 &properties))
1478 GError *error;
1479 GType interface_proxy_type;
1481 if (manager->priv->get_proxy_type_func != NULL)
1483 interface_proxy_type = manager->priv->get_proxy_type_func (manager,
1484 object_path,
1485 interface_name,
1486 manager->priv->get_proxy_type_user_data);
1487 g_warn_if_fail (g_type_is_a (interface_proxy_type, G_TYPE_DBUS_PROXY));
1489 else
1491 interface_proxy_type = G_TYPE_DBUS_PROXY;
1494 /* this is fine - there is no blocking IO because we pass DO_NOT_LOAD_PROPERTIES and
1495 * DO_NOT_CONNECT_SIGNALS and use a unique name
1497 error = NULL;
1498 interface_proxy = g_initable_new (interface_proxy_type,
1499 NULL, /* GCancellable */
1500 &error,
1501 "g-connection", manager->priv->connection,
1502 "g-flags", G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
1503 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
1504 "g-name", name_owner,
1505 "g-object-path", object_path,
1506 "g-interface-name", interface_name,
1507 NULL);
1508 if (interface_proxy == NULL)
1510 g_warning ("%s: Error constructing proxy for path %s and interface %s: %s",
1511 G_STRLOC,
1512 object_path,
1513 interface_name,
1514 error->message);
1515 g_error_free (error);
1517 else
1519 GVariantIter property_iter;
1520 const gchar *property_name;
1521 GVariant *property_value;
1523 /* associate the interface proxy with the object */
1524 g_dbus_interface_set_object (G_DBUS_INTERFACE (interface_proxy),
1525 G_DBUS_OBJECT (op));
1527 g_variant_iter_init (&property_iter, properties);
1528 while (g_variant_iter_next (&property_iter,
1529 "{&sv}",
1530 &property_name,
1531 &property_value))
1533 g_dbus_proxy_set_cached_property (interface_proxy,
1534 property_name,
1535 property_value);
1536 g_variant_unref (property_value);
1539 _g_dbus_object_proxy_add_interface (op, interface_proxy);
1540 if (!added)
1541 interface_added_signals = g_list_append (interface_added_signals, g_object_ref (interface_proxy));
1542 g_object_unref (interface_proxy);
1544 g_variant_unref (properties);
1547 g_mutex_unlock (&manager->priv->lock);
1549 /* now that we don't hold the lock any more, emit signals */
1550 g_object_ref (manager);
1551 for (l = interface_added_signals; l != NULL; l = l->next)
1553 interface_proxy = G_DBUS_PROXY (l->data);
1554 g_signal_emit_by_name (manager, "interface-added", op, interface_proxy);
1555 g_object_unref (interface_proxy);
1557 g_list_free (interface_added_signals);
1559 if (added)
1561 g_hash_table_insert (manager->priv->map_object_path_to_object_proxy,
1562 g_strdup (object_path),
1563 op);
1564 g_signal_emit_by_name (manager, "object-added", op);
1566 g_object_unref (manager);
1567 g_object_unref (op);
1570 static void
1571 remove_interfaces (GDBusObjectManagerClient *manager,
1572 const gchar *object_path,
1573 const gchar *const *interface_names)
1575 GDBusObjectProxy *op;
1576 GList *interfaces;
1577 guint n;
1578 guint num_interfaces;
1579 guint num_interfaces_to_remove;
1581 g_mutex_lock (&manager->priv->lock);
1583 op = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1584 if (op == NULL)
1586 g_warning ("%s: Processing InterfaceRemoved signal for path %s but no object proxy exists",
1587 G_STRLOC,
1588 object_path);
1589 g_mutex_unlock (&manager->priv->lock);
1590 goto out;
1593 interfaces = g_dbus_object_get_interfaces (G_DBUS_OBJECT (op));
1594 num_interfaces = g_list_length (interfaces);
1595 g_list_free_full (interfaces, g_object_unref);
1597 num_interfaces_to_remove = g_strv_length ((gchar **) interface_names);
1599 /* see if we are going to completety remove the object */
1600 g_object_ref (manager);
1601 if (num_interfaces_to_remove == num_interfaces)
1603 g_object_ref (op);
1604 g_warn_if_fail (g_hash_table_remove (manager->priv->map_object_path_to_object_proxy, object_path));
1605 g_mutex_unlock (&manager->priv->lock);
1606 g_signal_emit_by_name (manager, "object-removed", op);
1607 g_object_unref (op);
1609 else
1611 g_object_ref (op);
1612 g_mutex_unlock (&manager->priv->lock);
1613 for (n = 0; interface_names != NULL && interface_names[n] != NULL; n++)
1615 GDBusInterface *interface;
1616 interface = g_dbus_object_get_interface (G_DBUS_OBJECT (op), interface_names[n]);
1617 _g_dbus_object_proxy_remove_interface (op, interface_names[n]);
1618 if (interface != NULL)
1620 g_signal_emit_by_name (manager, "interface-removed", op, interface);
1621 g_object_unref (interface);
1624 g_object_unref (op);
1626 g_object_unref (manager);
1627 out:
1631 static void
1632 process_get_all_result (GDBusObjectManagerClient *manager,
1633 GVariant *value,
1634 const gchar *name_owner)
1636 GVariant *arg0;
1637 const gchar *object_path;
1638 GVariant *ifaces_and_properties;
1639 GVariantIter iter;
1641 g_return_if_fail (name_owner == NULL || g_dbus_is_unique_name (name_owner));
1643 arg0 = g_variant_get_child_value (value, 0);
1644 g_variant_iter_init (&iter, arg0);
1645 while (g_variant_iter_next (&iter,
1646 "{&o@a{sa{sv}}}",
1647 &object_path,
1648 &ifaces_and_properties))
1650 add_interfaces (manager, object_path, ifaces_and_properties, name_owner);
1651 g_variant_unref (ifaces_and_properties);
1653 g_variant_unref (arg0);
1656 static void
1657 on_control_proxy_g_signal (GDBusProxy *proxy,
1658 const gchar *sender_name,
1659 const gchar *signal_name,
1660 GVariant *parameters,
1661 gpointer user_data)
1663 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (user_data);
1664 const gchar *object_path;
1666 //g_debug ("yay, g_signal %s: %s\n", signal_name, g_variant_print (parameters, TRUE));
1668 if (g_strcmp0 (signal_name, "InterfacesAdded") == 0)
1670 GVariant *ifaces_and_properties;
1671 g_variant_get (parameters,
1672 "(&o@a{sa{sv}})",
1673 &object_path,
1674 &ifaces_and_properties);
1675 add_interfaces (manager, object_path, ifaces_and_properties, manager->priv->name_owner);
1676 g_variant_unref (ifaces_and_properties);
1678 else if (g_strcmp0 (signal_name, "InterfacesRemoved") == 0)
1680 const gchar **ifaces;
1681 g_variant_get (parameters,
1682 "(&o^a&s)",
1683 &object_path,
1684 &ifaces);
1685 remove_interfaces (manager, object_path, ifaces);
1686 g_free (ifaces);
1690 /* ---------------------------------------------------------------------------------------------------- */
1692 static const gchar *
1693 g_dbus_object_manager_client_get_object_path (GDBusObjectManager *_manager)
1695 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
1696 return manager->priv->object_path;
1699 static GDBusObject *
1700 g_dbus_object_manager_client_get_object (GDBusObjectManager *_manager,
1701 const gchar *object_path)
1703 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
1704 GDBusObject *ret;
1706 g_mutex_lock (&manager->priv->lock);
1707 ret = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1708 if (ret != NULL)
1709 g_object_ref (ret);
1710 g_mutex_unlock (&manager->priv->lock);
1711 return ret;
1714 static GDBusInterface *
1715 g_dbus_object_manager_client_get_interface (GDBusObjectManager *_manager,
1716 const gchar *object_path,
1717 const gchar *interface_name)
1719 GDBusInterface *ret;
1720 GDBusObject *object;
1722 ret = NULL;
1724 object = g_dbus_object_manager_get_object (_manager, object_path);
1725 if (object == NULL)
1726 goto out;
1728 ret = g_dbus_object_get_interface (object, interface_name);
1729 g_object_unref (object);
1731 out:
1732 return ret;
1735 static GList *
1736 g_dbus_object_manager_client_get_objects (GDBusObjectManager *_manager)
1738 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
1739 GList *ret;
1741 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
1743 g_mutex_lock (&manager->priv->lock);
1744 ret = g_hash_table_get_values (manager->priv->map_object_path_to_object_proxy);
1745 g_list_foreach (ret, (GFunc) g_object_ref, NULL);
1746 g_mutex_unlock (&manager->priv->lock);
1748 return ret;
1752 static void
1753 dbus_object_manager_interface_init (GDBusObjectManagerIface *iface)
1755 iface->get_object_path = g_dbus_object_manager_client_get_object_path;
1756 iface->get_objects = g_dbus_object_manager_client_get_objects;
1757 iface->get_object = g_dbus_object_manager_client_get_object;
1758 iface->get_interface = g_dbus_object_manager_client_get_interface;
1761 /* ---------------------------------------------------------------------------------------------------- */