Visual C++ projects: Clean/fix up
[glib.git] / gio / gdbusobjectmanagerclient.c
blob1869e317a2a63374c41a68005df4043c3986795a
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_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)
178 G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init)
179 G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_OBJECT_MANAGER, dbus_object_manager_interface_init));
181 static void maybe_unsubscribe_signals (GDBusObjectManagerClient *manager);
183 static void on_control_proxy_g_signal (GDBusProxy *proxy,
184 const gchar *sender_name,
185 const gchar *signal_name,
186 GVariant *parameters,
187 gpointer user_data);
189 static void process_get_all_result (GDBusObjectManagerClient *manager,
190 GVariant *value,
191 const gchar *name_owner);
193 static void
194 g_dbus_object_manager_client_finalize (GObject *object)
196 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (object);
198 maybe_unsubscribe_signals (manager);
200 g_hash_table_unref (manager->priv->map_object_path_to_object_proxy);
202 if (manager->priv->control_proxy != NULL)
204 g_signal_handlers_disconnect_by_func (manager->priv->control_proxy,
205 on_control_proxy_g_signal,
206 manager);
207 g_object_unref (manager->priv->control_proxy);
209 g_object_unref (manager->priv->connection);
210 g_free (manager->priv->object_path);
211 g_free (manager->priv->name);
212 g_free (manager->priv->name_owner);
214 if (manager->priv->get_proxy_type_destroy_notify != NULL)
215 manager->priv->get_proxy_type_destroy_notify (manager->priv->get_proxy_type_user_data);
217 g_mutex_clear (&manager->priv->lock);
219 if (G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class)->finalize != NULL)
220 G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class)->finalize (object);
223 static void
224 g_dbus_object_manager_client_get_property (GObject *_object,
225 guint prop_id,
226 GValue *value,
227 GParamSpec *pspec)
229 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_object);
231 switch (prop_id)
233 case PROP_CONNECTION:
234 g_value_set_object (value, g_dbus_object_manager_client_get_connection (manager));
235 break;
237 case PROP_OBJECT_PATH:
238 g_value_set_string (value, g_dbus_object_manager_get_object_path (G_DBUS_OBJECT_MANAGER (manager)));
239 break;
241 case PROP_NAME:
242 g_value_set_string (value, g_dbus_object_manager_client_get_name (manager));
243 break;
245 case PROP_FLAGS:
246 g_value_set_flags (value, g_dbus_object_manager_client_get_flags (manager));
247 break;
249 case PROP_NAME_OWNER:
250 g_value_take_string (value, g_dbus_object_manager_client_get_name_owner (manager));
251 break;
253 default:
254 G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);
255 break;
259 static void
260 g_dbus_object_manager_client_set_property (GObject *_object,
261 guint prop_id,
262 const GValue *value,
263 GParamSpec *pspec)
265 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_object);
267 switch (prop_id)
269 case PROP_BUS_TYPE:
270 manager->priv->bus_type = g_value_get_enum (value);
271 break;
273 case PROP_CONNECTION:
274 if (g_value_get_object (value) != NULL)
276 g_assert (manager->priv->connection == NULL);
277 g_assert (G_IS_DBUS_CONNECTION (g_value_get_object (value)));
278 manager->priv->connection = g_value_dup_object (value);
280 break;
282 case PROP_OBJECT_PATH:
283 g_assert (manager->priv->object_path == NULL);
284 g_assert (g_variant_is_object_path (g_value_get_string (value)));
285 manager->priv->object_path = g_value_dup_string (value);
286 break;
288 case PROP_NAME:
289 g_assert (manager->priv->name == NULL);
290 g_assert (g_dbus_is_name (g_value_get_string (value)));
291 manager->priv->name = g_value_dup_string (value);
292 break;
294 case PROP_FLAGS:
295 manager->priv->flags = g_value_get_flags (value);
296 break;
298 case PROP_GET_PROXY_TYPE_FUNC:
299 manager->priv->get_proxy_type_func = g_value_get_pointer (value);
300 break;
302 case PROP_GET_PROXY_TYPE_USER_DATA:
303 manager->priv->get_proxy_type_user_data = g_value_get_pointer (value);
304 break;
306 case PROP_GET_PROXY_TYPE_DESTROY_NOTIFY:
307 manager->priv->get_proxy_type_destroy_notify = g_value_get_pointer (value);
308 break;
310 default:
311 G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);
312 break;
316 static void
317 g_dbus_object_manager_client_class_init (GDBusObjectManagerClientClass *klass)
319 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
321 gobject_class->finalize = g_dbus_object_manager_client_finalize;
322 gobject_class->set_property = g_dbus_object_manager_client_set_property;
323 gobject_class->get_property = g_dbus_object_manager_client_get_property;
326 * GDBusObjectManagerClient:connection:
328 * The #GDBusConnection to use.
330 * Since: 2.30
332 g_object_class_install_property (gobject_class,
333 PROP_CONNECTION,
334 g_param_spec_object ("connection",
335 "Connection",
336 "The connection to use",
337 G_TYPE_DBUS_CONNECTION,
338 G_PARAM_READABLE |
339 G_PARAM_WRITABLE |
340 G_PARAM_CONSTRUCT_ONLY |
341 G_PARAM_STATIC_STRINGS));
344 * GDBusObjectManagerClient:bus-type:
346 * If this property is not %G_BUS_TYPE_NONE, then
347 * #GDBusObjectManagerClient:connection must be %NULL and will be set to the
348 * #GDBusConnection obtained by calling g_bus_get() with the value
349 * of this property.
351 * Since: 2.30
353 g_object_class_install_property (gobject_class,
354 PROP_BUS_TYPE,
355 g_param_spec_enum ("bus-type",
356 "Bus Type",
357 "The bus to connect to, if any",
358 G_TYPE_BUS_TYPE,
359 G_BUS_TYPE_NONE,
360 G_PARAM_WRITABLE |
361 G_PARAM_CONSTRUCT_ONLY |
362 G_PARAM_STATIC_NAME |
363 G_PARAM_STATIC_BLURB |
364 G_PARAM_STATIC_NICK));
367 * GDBusObjectManagerClient:flags:
369 * Flags from the #GDBusObjectManagerClientFlags enumeration.
371 * Since: 2.30
373 g_object_class_install_property (gobject_class,
374 PROP_FLAGS,
375 g_param_spec_flags ("flags",
376 "Flags",
377 "Flags for the proxy manager",
378 G_TYPE_DBUS_OBJECT_MANAGER_CLIENT_FLAGS,
379 G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
380 G_PARAM_READABLE |
381 G_PARAM_WRITABLE |
382 G_PARAM_CONSTRUCT_ONLY |
383 G_PARAM_STATIC_NAME |
384 G_PARAM_STATIC_BLURB |
385 G_PARAM_STATIC_NICK));
388 * GDBusObjectManagerClient:object-path:
390 * The object path the manager is for.
392 * Since: 2.30
394 g_object_class_install_property (gobject_class,
395 PROP_OBJECT_PATH,
396 g_param_spec_string ("object-path",
397 "Object Path",
398 "The object path of the control object",
399 NULL,
400 G_PARAM_READABLE |
401 G_PARAM_WRITABLE |
402 G_PARAM_CONSTRUCT_ONLY |
403 G_PARAM_STATIC_STRINGS));
406 * GDBusObjectManagerClient:name:
408 * The well-known name or unique name that the manager is for.
410 * Since: 2.30
412 g_object_class_install_property (gobject_class,
413 PROP_NAME,
414 g_param_spec_string ("name",
415 "Name",
416 "Name that the manager is for",
417 NULL,
418 G_PARAM_READABLE |
419 G_PARAM_WRITABLE |
420 G_PARAM_CONSTRUCT_ONLY |
421 G_PARAM_STATIC_STRINGS));
424 * GDBusObjectManagerClient:name-owner:
426 * The unique name that owns #GDBusObjectManagerClient:name or %NULL if
427 * no-one is currently owning the name. Connect to the
428 * #GObject::notify signal to track changes to this property.
430 * Since: 2.30
432 g_object_class_install_property (gobject_class,
433 PROP_NAME_OWNER,
434 g_param_spec_string ("name-owner",
435 "Name Owner",
436 "The owner of the name we are watching",
437 NULL,
438 G_PARAM_READABLE |
439 G_PARAM_STATIC_STRINGS));
442 * GDBusObjectManagerClient:get-proxy-type-func:
444 * The #GDBusProxyTypeFunc to use when determining what #GType to
445 * use for interface proxies or %NULL.
447 * Since: 2.30
449 g_object_class_install_property (gobject_class,
450 PROP_GET_PROXY_TYPE_FUNC,
451 g_param_spec_pointer ("get-proxy-type-func",
452 "GDBusProxyTypeFunc Function Pointer",
453 "The GDBusProxyTypeFunc pointer to use",
454 G_PARAM_READABLE |
455 G_PARAM_WRITABLE |
456 G_PARAM_CONSTRUCT_ONLY |
457 G_PARAM_STATIC_STRINGS));
460 * GDBusObjectManagerClient:get-proxy-type-user-data:
462 * The #gpointer user_data to pass to #GDBusObjectManagerClient:get-proxy-type-func.
464 * Since: 2.30
466 g_object_class_install_property (gobject_class,
467 PROP_GET_PROXY_TYPE_USER_DATA,
468 g_param_spec_pointer ("get-proxy-type-user-data",
469 "GDBusProxyTypeFunc User Data",
470 "The GDBusProxyTypeFunc user_data",
471 G_PARAM_READABLE |
472 G_PARAM_WRITABLE |
473 G_PARAM_CONSTRUCT_ONLY |
474 G_PARAM_STATIC_STRINGS));
477 * GDBusObjectManagerClient:get-proxy-type-destroy-notify:
479 * A #GDestroyNotify for the #gpointer user_data in #GDBusObjectManagerClient:get-proxy-type-user-data.
481 * Since: 2.30
483 g_object_class_install_property (gobject_class,
484 PROP_GET_PROXY_TYPE_DESTROY_NOTIFY,
485 g_param_spec_pointer ("get-proxy-type-destroy-notify",
486 "GDBusProxyTypeFunc user data free function",
487 "The GDBusProxyTypeFunc user data free function",
488 G_PARAM_READABLE |
489 G_PARAM_WRITABLE |
490 G_PARAM_CONSTRUCT_ONLY |
491 G_PARAM_STATIC_STRINGS));
494 * GDBusObjectManagerClient::interface-proxy-signal:
495 * @manager: The #GDBusObjectManagerClient emitting the signal.
496 * @object_proxy: The #GDBusObjectProxy on which an interface is emitting a D-Bus signal.
497 * @interface_proxy: The #GDBusProxy that is emitting a D-Bus signal.
498 * @sender_name: The sender of the signal or NULL if the connection is not a bus connection.
499 * @signal_name: The signal name.
500 * @parameters: A #GVariant tuple with parameters for the signal.
502 * Emitted when a D-Bus signal is received on @interface_proxy.
504 * This signal exists purely as a convenience to avoid having to
505 * connect signals to all interface proxies managed by @manager.
507 * This signal is emitted in the
508 * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
509 * that @manager was constructed in.
511 * Since: 2.30
513 signals[INTERFACE_PROXY_SIGNAL_SIGNAL] =
514 g_signal_new ("interface-proxy-signal",
515 G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
516 G_SIGNAL_RUN_LAST,
517 G_STRUCT_OFFSET (GDBusObjectManagerClientClass, interface_proxy_signal),
518 NULL,
519 NULL,
520 NULL,
521 G_TYPE_NONE,
523 G_TYPE_DBUS_OBJECT_PROXY,
524 G_TYPE_DBUS_PROXY,
525 G_TYPE_STRING,
526 G_TYPE_STRING,
527 G_TYPE_VARIANT);
530 * GDBusObjectManagerClient::interface-proxy-properties-changed:
531 * @manager: The #GDBusObjectManagerClient emitting the signal.
532 * @object_proxy: The #GDBusObjectProxy on which an interface has properties that are changing.
533 * @interface_proxy: The #GDBusProxy that has properties that are changing.
534 * @changed_properties: A #GVariant containing the properties that changed.
535 * @invalidated_properties: A %NULL terminated array of properties that was invalidated.
537 * Emitted when one or more D-Bus properties on proxy changes. The
538 * local cache has already been updated when this signal fires. Note
539 * that both @changed_properties and @invalidated_properties are
540 * guaranteed to never be %NULL (either may be empty though).
542 * This signal exists purely as a convenience to avoid having to
543 * connect signals to all interface proxies managed by @manager.
545 * This signal is emitted in the
546 * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
547 * that @manager was constructed in.
549 * Since: 2.30
551 signals[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL] =
552 g_signal_new ("interface-proxy-properties-changed",
553 G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
554 G_SIGNAL_RUN_LAST,
555 G_STRUCT_OFFSET (GDBusObjectManagerClientClass, interface_proxy_properties_changed),
556 NULL,
557 NULL,
558 NULL,
559 G_TYPE_NONE,
561 G_TYPE_DBUS_OBJECT_PROXY,
562 G_TYPE_DBUS_PROXY,
563 G_TYPE_VARIANT,
564 G_TYPE_STRV);
566 g_type_class_add_private (klass, sizeof (GDBusObjectManagerClientPrivate));
569 static void
570 g_dbus_object_manager_client_init (GDBusObjectManagerClient *manager)
572 manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
573 G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
574 GDBusObjectManagerClientPrivate);
575 g_mutex_init (&manager->priv->lock);
576 manager->priv->map_object_path_to_object_proxy = g_hash_table_new_full (g_str_hash,
577 g_str_equal,
578 g_free,
579 (GDestroyNotify) g_object_unref);
582 /* ---------------------------------------------------------------------------------------------------- */
585 * g_dbus_object_manager_client_new_sync:
586 * @connection: A #GDBusConnection.
587 * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
588 * @name: The owner of the control object (unique or well-known name).
589 * @object_path: The object path of the control object.
590 * @get_proxy_type_func: (allow-none): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
591 * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
592 * @get_proxy_type_destroy_notify: (allow-none): Free function for @get_proxy_type_user_data or %NULL.
593 * @cancellable: (allow-none): A #GCancellable or %NULL
594 * @error: Return location for error or %NULL.
596 * Creates a new #GDBusObjectManagerClient object.
598 * This is a synchronous failable constructor - the calling thread is
599 * blocked until a reply is received. See g_dbus_object_manager_client_new()
600 * for the asynchronous version.
602 * Returns: (transfer full) (type GDBusObjectManagerClient): A
603 * #GDBusObjectManagerClient object or %NULL if @error is set. Free
604 * with g_object_unref().
606 * Since: 2.30
608 GDBusObjectManager *
609 g_dbus_object_manager_client_new_sync (GDBusConnection *connection,
610 GDBusObjectManagerClientFlags flags,
611 const gchar *name,
612 const gchar *object_path,
613 GDBusProxyTypeFunc get_proxy_type_func,
614 gpointer get_proxy_type_user_data,
615 GDestroyNotify get_proxy_type_destroy_notify,
616 GCancellable *cancellable,
617 GError **error)
619 GInitable *initable;
621 g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
622 g_return_val_if_fail ((name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) ||
623 g_dbus_is_name (name), NULL);
624 g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
625 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
627 initable = g_initable_new (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
628 cancellable,
629 error,
630 "connection", connection,
631 "flags", flags,
632 "name", name,
633 "object-path", object_path,
634 "get-proxy-type-func", get_proxy_type_func,
635 "get-proxy-type-user-data", get_proxy_type_user_data,
636 "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
637 NULL);
638 if (initable != NULL)
639 return G_DBUS_OBJECT_MANAGER (initable);
640 else
641 return NULL;
645 * g_dbus_object_manager_client_new:
646 * @connection: A #GDBusConnection.
647 * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
648 * @name: The owner of the control object (unique or well-known name).
649 * @object_path: The object path of the control object.
650 * @get_proxy_type_func: (allow-none): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
651 * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
652 * @get_proxy_type_destroy_notify: (allow-none): Free function for @get_proxy_type_user_data or %NULL.
653 * @cancellable: (allow-none): A #GCancellable or %NULL
654 * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
655 * @user_data: The data to pass to @callback.
657 * Asynchronously creates a new #GDBusObjectManagerClient object.
659 * This is an asynchronous failable constructor. When the result is
660 * ready, @callback will be invoked in the
661 * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
662 * of the thread you are calling this method from. You can
663 * then call g_dbus_object_manager_client_new_finish() to get the result. See
664 * g_dbus_object_manager_client_new_sync() for the synchronous version.
666 * Since: 2.30
668 void
669 g_dbus_object_manager_client_new (GDBusConnection *connection,
670 GDBusObjectManagerClientFlags flags,
671 const gchar *name,
672 const gchar *object_path,
673 GDBusProxyTypeFunc get_proxy_type_func,
674 gpointer get_proxy_type_user_data,
675 GDestroyNotify get_proxy_type_destroy_notify,
676 GCancellable *cancellable,
677 GAsyncReadyCallback callback,
678 gpointer user_data)
680 g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
681 g_return_if_fail ((name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) ||
682 g_dbus_is_name (name));
683 g_return_if_fail (g_variant_is_object_path (object_path));
685 g_async_initable_new_async (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
686 G_PRIORITY_DEFAULT,
687 cancellable,
688 callback,
689 user_data,
690 "connection", connection,
691 "flags", flags,
692 "name", name,
693 "object-path", object_path,
694 "get-proxy-type-func", get_proxy_type_func,
695 "get-proxy-type-user-data", get_proxy_type_user_data,
696 "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
697 NULL);
701 * g_dbus_object_manager_client_new_finish:
702 * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_object_manager_client_new().
703 * @error: Return location for error or %NULL.
705 * Finishes an operation started with g_dbus_object_manager_client_new().
707 * Returns: (transfer full) (type GDBusObjectManagerClient): A
708 * #GDBusObjectManagerClient object or %NULL if @error is set. Free
709 * with g_object_unref().
711 * Since: 2.30
713 GDBusObjectManager *
714 g_dbus_object_manager_client_new_finish (GAsyncResult *res,
715 GError **error)
717 GObject *object;
718 GObject *source_object;
720 source_object = g_async_result_get_source_object (res);
721 g_assert (source_object != NULL);
723 object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
724 res,
725 error);
726 g_object_unref (source_object);
728 if (object != NULL)
729 return G_DBUS_OBJECT_MANAGER (object);
730 else
731 return NULL;
734 /* ---------------------------------------------------------------------------------------------------- */
737 * g_dbus_object_manager_client_new_for_bus_sync:
738 * @bus_type: A #GBusType.
739 * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
740 * @name: The owner of the control object (unique or well-known name).
741 * @object_path: The object path of the control object.
742 * @get_proxy_type_func: (allow-none): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
743 * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
744 * @get_proxy_type_destroy_notify: (allow-none): Free function for @get_proxy_type_user_data or %NULL.
745 * @cancellable: (allow-none): A #GCancellable or %NULL
746 * @error: Return location for error or %NULL.
748 * Like g_dbus_object_manager_client_new_sync() but takes a #GBusType instead
749 * of a #GDBusConnection.
751 * This is a synchronous failable constructor - the calling thread is
752 * blocked until a reply is received. See g_dbus_object_manager_client_new_for_bus()
753 * for the asynchronous version.
755 * Returns: (transfer full) (type GDBusObjectManagerClient): A
756 * #GDBusObjectManagerClient object or %NULL if @error is set. Free
757 * with g_object_unref().
759 * Since: 2.30
761 GDBusObjectManager *
762 g_dbus_object_manager_client_new_for_bus_sync (GBusType bus_type,
763 GDBusObjectManagerClientFlags flags,
764 const gchar *name,
765 const gchar *object_path,
766 GDBusProxyTypeFunc get_proxy_type_func,
767 gpointer get_proxy_type_user_data,
768 GDestroyNotify get_proxy_type_destroy_notify,
769 GCancellable *cancellable,
770 GError **error)
772 GInitable *initable;
774 g_return_val_if_fail (bus_type != G_BUS_TYPE_NONE, NULL);
775 g_return_val_if_fail (g_dbus_is_name (name), NULL);
776 g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
777 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
779 initable = g_initable_new (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
780 cancellable,
781 error,
782 "bus-type", bus_type,
783 "flags", flags,
784 "name", name,
785 "object-path", object_path,
786 "get-proxy-type-func", get_proxy_type_func,
787 "get-proxy-type-user-data", get_proxy_type_user_data,
788 "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
789 NULL);
790 if (initable != NULL)
791 return G_DBUS_OBJECT_MANAGER (initable);
792 else
793 return NULL;
797 * g_dbus_object_manager_client_new_for_bus:
798 * @bus_type: A #GBusType.
799 * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
800 * @name: The owner of the control object (unique or well-known name).
801 * @object_path: The object path of the control object.
802 * @get_proxy_type_func: (allow-none): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
803 * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
804 * @get_proxy_type_destroy_notify: (allow-none): Free function for @get_proxy_type_user_data or %NULL.
805 * @cancellable: (allow-none): A #GCancellable or %NULL
806 * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
807 * @user_data: The data to pass to @callback.
809 * Like g_dbus_object_manager_client_new() but takes a #GBusType instead of a
810 * #GDBusConnection.
812 * This is an asynchronous failable constructor. When the result is
813 * ready, @callback will be invoked in the
814 * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
815 * of the thread you are calling this method from. You can
816 * then call g_dbus_object_manager_client_new_for_bus_finish() to get the result. See
817 * g_dbus_object_manager_client_new_for_bus_sync() for the synchronous version.
819 * Since: 2.30
821 void
822 g_dbus_object_manager_client_new_for_bus (GBusType bus_type,
823 GDBusObjectManagerClientFlags flags,
824 const gchar *name,
825 const gchar *object_path,
826 GDBusProxyTypeFunc get_proxy_type_func,
827 gpointer get_proxy_type_user_data,
828 GDestroyNotify get_proxy_type_destroy_notify,
829 GCancellable *cancellable,
830 GAsyncReadyCallback callback,
831 gpointer user_data)
833 g_return_if_fail (bus_type != G_BUS_TYPE_NONE);
834 g_return_if_fail (g_dbus_is_name (name));
835 g_return_if_fail (g_variant_is_object_path (object_path));
837 g_async_initable_new_async (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
838 G_PRIORITY_DEFAULT,
839 cancellable,
840 callback,
841 user_data,
842 "bus-type", bus_type,
843 "flags", flags,
844 "name", name,
845 "object-path", object_path,
846 "get-proxy-type-func", get_proxy_type_func,
847 "get-proxy-type-user-data", get_proxy_type_user_data,
848 "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
849 NULL);
853 * g_dbus_object_manager_client_new_for_bus_finish:
854 * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_object_manager_client_new_for_bus().
855 * @error: Return location for error or %NULL.
857 * Finishes an operation started with g_dbus_object_manager_client_new_for_bus().
859 * Returns: (transfer full) (type GDBusObjectManagerClient): A
860 * #GDBusObjectManagerClient object or %NULL if @error is set. Free
861 * with g_object_unref().
863 * Since: 2.30
865 GDBusObjectManager *
866 g_dbus_object_manager_client_new_for_bus_finish (GAsyncResult *res,
867 GError **error)
869 GObject *object;
870 GObject *source_object;
872 source_object = g_async_result_get_source_object (res);
873 g_assert (source_object != NULL);
875 object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
876 res,
877 error);
878 g_object_unref (source_object);
880 if (object != NULL)
881 return G_DBUS_OBJECT_MANAGER (object);
882 else
883 return NULL;
886 /* ---------------------------------------------------------------------------------------------------- */
889 * g_dbus_object_manager_client_get_connection:
890 * @manager: A #GDBusObjectManagerClient
892 * Gets the #GDBusConnection used by @manager.
894 * Returns: (transfer none): A #GDBusConnection object. Do not free,
895 * the object belongs to @manager.
897 * Since: 2.30
899 GDBusConnection *
900 g_dbus_object_manager_client_get_connection (GDBusObjectManagerClient *manager)
902 GDBusConnection *ret;
903 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
904 g_mutex_lock (&manager->priv->lock);
905 ret = manager->priv->connection;
906 g_mutex_unlock (&manager->priv->lock);
907 return ret;
911 * g_dbus_object_manager_client_get_name:
912 * @manager: A #GDBusObjectManagerClient
914 * Gets the name that @manager is for.
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 if (g_strcmp0 (interface_name, "org.freedesktop.DBus.Properties") == 0)
1011 if (g_strcmp0 (signal_name, "PropertiesChanged") == 0)
1013 const gchar *interface_name;
1014 GVariant *changed_properties;
1015 const gchar **invalidated_properties;
1017 g_variant_get (parameters,
1018 "(&s@a{sv}^a&s)",
1019 &interface_name,
1020 &changed_properties,
1021 &invalidated_properties);
1023 interface = g_dbus_object_get_interface (G_DBUS_OBJECT (object_proxy), interface_name);
1024 if (interface != NULL)
1026 GVariantIter property_iter;
1027 const gchar *property_name;
1028 GVariant *property_value;
1029 guint n;
1031 /* update caches... */
1032 g_variant_iter_init (&property_iter, changed_properties);
1033 while (g_variant_iter_next (&property_iter,
1034 "{&sv}",
1035 &property_name,
1036 &property_value))
1038 g_dbus_proxy_set_cached_property (G_DBUS_PROXY (interface),
1039 property_name,
1040 property_value);
1041 g_variant_unref (property_value);
1044 for (n = 0; invalidated_properties[n] != NULL; n++)
1046 g_dbus_proxy_set_cached_property (G_DBUS_PROXY (interface),
1047 invalidated_properties[n],
1048 NULL);
1050 /* ... and then synthesize the signal */
1051 g_signal_emit_by_name (interface,
1052 "g-properties-changed",
1053 changed_properties,
1054 invalidated_properties);
1055 g_signal_emit (manager,
1056 signals[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL],
1058 object_proxy,
1059 interface,
1060 changed_properties,
1061 invalidated_properties);
1062 g_object_unref (interface);
1064 g_variant_unref (changed_properties);
1065 g_free (invalidated_properties);
1068 else
1070 /* regular signal - just dispatch it */
1071 interface = g_dbus_object_get_interface (G_DBUS_OBJECT (object_proxy), interface_name);
1072 if (interface != NULL)
1074 g_signal_emit_by_name (interface,
1075 "g-signal",
1076 sender_name,
1077 signal_name,
1078 parameters);
1079 g_signal_emit (manager,
1080 signals[INTERFACE_PROXY_SIGNAL_SIGNAL],
1082 object_proxy,
1083 interface,
1084 sender_name,
1085 signal_name,
1086 parameters);
1087 g_object_unref (interface);
1091 out:
1092 g_clear_object (&object_proxy);
1095 static void
1096 subscribe_signals (GDBusObjectManagerClient *manager,
1097 const gchar *name_owner)
1099 GError *error;
1100 GVariant *ret;
1102 g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager));
1103 g_return_if_fail (manager->priv->signal_subscription_id == 0);
1104 g_return_if_fail (g_dbus_is_unique_name (name_owner));
1106 /* the bus daemon may not implement path_prefix so gracefully
1107 * handle this by using a fallback
1109 manager->priv->match_rule = g_strdup_printf ("type='signal',sender='%s',path_namespace='%s'",
1110 name_owner,
1111 manager->priv->object_path);
1113 error = NULL;
1114 ret = g_dbus_connection_call_sync (manager->priv->connection,
1115 "org.freedesktop.DBus",
1116 "/org/freedeskop/DBus",
1117 "org.freedesktop.DBus",
1118 "AddMatch",
1119 g_variant_new ("(s)",
1120 manager->priv->match_rule),
1121 NULL, /* reply_type */
1122 G_DBUS_CALL_FLAGS_NONE,
1123 -1, /* default timeout */
1124 NULL, /* TODO: Cancellable */
1125 &error);
1126 if (ret != NULL)
1128 /* yay, bus daemon supports path_namespace */
1129 g_variant_unref (ret);
1131 /* still need to ask GDBusConnection for the callbacks */
1132 manager->priv->signal_subscription_id =
1133 g_dbus_connection_signal_subscribe (manager->priv->connection,
1134 name_owner,
1135 NULL, /* interface */
1136 NULL, /* member */
1137 NULL, /* path - TODO: really want wilcard support here */
1138 NULL, /* arg0 */
1139 G_DBUS_SIGNAL_FLAGS_NONE |
1140 G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
1141 signal_cb,
1142 manager,
1143 NULL); /* user_data_free_func */
1146 else
1148 /* TODO: we could report this to the user
1149 g_warning ("Message bus daemon does not support path_namespace: %s (%s %d)",
1150 error->message,
1151 g_quark_to_string (error->domain),
1152 error->code);
1155 g_error_free (error);
1157 /* no need to call RemoveMatch when done since it didn't work */
1158 g_free (manager->priv->match_rule);
1159 manager->priv->match_rule = NULL;
1161 /* Fallback is to subscribe to *all* signals from the name owner which
1162 * is rather wasteful. It's probably not a big practical problem because
1163 * users typically want all objects that the name owner supplies.
1165 manager->priv->signal_subscription_id =
1166 g_dbus_connection_signal_subscribe (manager->priv->connection,
1167 name_owner,
1168 NULL, /* interface */
1169 NULL, /* member */
1170 NULL, /* path - TODO: really want wilcard support here */
1171 NULL, /* arg0 */
1172 G_DBUS_SIGNAL_FLAGS_NONE,
1173 signal_cb,
1174 manager,
1175 NULL); /* user_data_free_func */
1179 static void
1180 maybe_unsubscribe_signals (GDBusObjectManagerClient *manager)
1182 g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager));
1184 if (manager->priv->signal_subscription_id > 0)
1186 g_dbus_connection_signal_unsubscribe (manager->priv->connection,
1187 manager->priv->signal_subscription_id);
1188 manager->priv->signal_subscription_id = 0;
1191 if (manager->priv->match_rule != NULL)
1193 /* Since the AddMatch call succeeded this is guaranteed to not
1194 * fail - therefore, don't bother checking the return value
1196 g_dbus_connection_call (manager->priv->connection,
1197 "org.freedesktop.DBus",
1198 "/org/freedeskop/DBus",
1199 "org.freedesktop.DBus",
1200 "RemoveMatch",
1201 g_variant_new ("(s)",
1202 manager->priv->match_rule),
1203 NULL, /* reply_type */
1204 G_DBUS_CALL_FLAGS_NONE,
1205 -1, /* default timeout */
1206 NULL, /* GCancellable */
1207 NULL, /* GAsyncReadyCallback */
1208 NULL); /* user data */
1209 g_free (manager->priv->match_rule);
1210 manager->priv->match_rule = NULL;
1215 /* ---------------------------------------------------------------------------------------------------- */
1217 static void
1218 on_notify_g_name_owner (GObject *object,
1219 GParamSpec *pspec,
1220 gpointer user_data)
1222 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (user_data);
1223 gchar *old_name_owner;
1224 gchar *new_name_owner;
1226 g_mutex_lock (&manager->priv->lock);
1227 old_name_owner = manager->priv->name_owner;
1228 new_name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy);
1229 manager->priv->name_owner = NULL;
1231 if (g_strcmp0 (old_name_owner, new_name_owner) != 0)
1233 GList *l;
1234 GList *proxies;
1236 /* remote manager changed; nuke all local proxies */
1237 proxies = g_hash_table_get_values (manager->priv->map_object_path_to_object_proxy);
1238 g_list_foreach (proxies, (GFunc) g_object_ref, NULL);
1239 g_hash_table_remove_all (manager->priv->map_object_path_to_object_proxy);
1241 g_mutex_unlock (&manager->priv->lock);
1243 /* do the :name-owner notify with a NULL name - this way the user knows
1244 * the ::object-proxy-removed following is because the name owner went
1245 * away
1247 g_object_notify (G_OBJECT (manager), "name-owner");
1249 for (l = proxies; l != NULL; l = l->next)
1251 GDBusObjectProxy *object_proxy = G_DBUS_OBJECT_PROXY (l->data);
1252 g_signal_emit_by_name (manager, "object-removed", object_proxy);
1254 g_list_free_full (proxies, g_object_unref);
1256 /* nuke local filter */
1257 maybe_unsubscribe_signals (manager);
1259 else
1261 g_mutex_unlock (&manager->priv->lock);
1264 if (new_name_owner != NULL)
1266 GError *error;
1267 GVariant *value;
1269 //g_debug ("repopulating for %s", new_name_owner);
1271 /* TODO: do this async! */
1272 subscribe_signals (manager,
1273 new_name_owner);
1274 error = NULL;
1275 value = g_dbus_proxy_call_sync (manager->priv->control_proxy,
1276 "GetManagedObjects",
1277 NULL, /* parameters */
1278 G_DBUS_CALL_FLAGS_NONE,
1280 NULL,
1281 &error);
1282 if (value == NULL)
1284 maybe_unsubscribe_signals (manager);
1285 g_warning ("Error calling GetManagedObjects() when name owner %s for name %s came back: %s",
1286 new_name_owner,
1287 manager->priv->name,
1288 error->message);
1289 g_error_free (error);
1291 else
1293 process_get_all_result (manager, value, new_name_owner);
1294 g_variant_unref (value);
1297 /* do the :name-owner notify *AFTER* emitting ::object-proxy-added signals - this
1298 * way the user knows that the signals were emitted because the name owner came back
1300 g_mutex_lock (&manager->priv->lock);
1301 manager->priv->name_owner = new_name_owner;
1302 g_mutex_unlock (&manager->priv->lock);
1303 g_object_notify (G_OBJECT (manager), "name-owner");
1306 g_free (old_name_owner);
1309 static gboolean
1310 initable_init (GInitable *initable,
1311 GCancellable *cancellable,
1312 GError **error)
1314 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (initable);
1315 gboolean ret;
1316 GVariant *value;
1317 GDBusProxyFlags proxy_flags;
1319 ret = FALSE;
1321 if (manager->priv->bus_type != G_BUS_TYPE_NONE)
1323 g_assert (manager->priv->connection == NULL);
1324 manager->priv->connection = g_bus_get_sync (manager->priv->bus_type, cancellable, error);
1325 if (manager->priv->connection == NULL)
1326 goto out;
1329 proxy_flags = G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES;
1330 if (manager->priv->flags & G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START)
1331 proxy_flags |= G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START;;
1333 manager->priv->control_proxy = g_dbus_proxy_new_sync (manager->priv->connection,
1334 proxy_flags,
1335 NULL, /* GDBusInterfaceInfo* */
1336 manager->priv->name,
1337 manager->priv->object_path,
1338 "org.freedesktop.DBus.ObjectManager",
1339 cancellable,
1340 error);
1341 if (manager->priv->control_proxy == NULL)
1342 goto out;
1344 g_signal_connect (G_OBJECT (manager->priv->control_proxy),
1345 "notify::g-name-owner",
1346 G_CALLBACK (on_notify_g_name_owner),
1347 manager);
1349 manager->priv->name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy);
1350 if (manager->priv->name_owner == NULL)
1352 /* it's perfectly fine if there's no name owner.. we're just going to
1353 * wait until one is ready
1356 else
1358 /* yay, we have a name owner */
1359 g_signal_connect (manager->priv->control_proxy,
1360 "g-signal",
1361 G_CALLBACK (on_control_proxy_g_signal),
1362 manager);
1363 subscribe_signals (manager,
1364 manager->priv->name_owner);
1365 value = g_dbus_proxy_call_sync (manager->priv->control_proxy,
1366 "GetManagedObjects",
1367 NULL, /* parameters */
1368 G_DBUS_CALL_FLAGS_NONE,
1370 cancellable,
1371 error);
1372 if (value == NULL)
1374 maybe_unsubscribe_signals (manager);
1375 g_warn_if_fail (g_signal_handlers_disconnect_by_func (manager->priv->control_proxy,
1376 on_control_proxy_g_signal,
1377 manager) == 1);
1378 g_object_unref (manager->priv->control_proxy);
1379 manager->priv->control_proxy = NULL;
1380 goto out;
1383 process_get_all_result (manager, value, manager->priv->name_owner);
1384 g_variant_unref (value);
1387 ret = TRUE;
1389 out:
1390 return ret;
1393 static void
1394 initable_iface_init (GInitableIface *initable_iface)
1396 initable_iface->init = initable_init;
1399 static void
1400 async_initable_iface_init (GAsyncInitableIface *async_initable_iface)
1402 /* for now, just use default: run GInitable code in thread */
1405 /* ---------------------------------------------------------------------------------------------------- */
1407 static void
1408 add_interfaces (GDBusObjectManagerClient *manager,
1409 const gchar *object_path,
1410 GVariant *ifaces_and_properties,
1411 const gchar *name_owner)
1413 GDBusObjectProxy *op;
1414 gboolean added;
1415 GVariantIter iter;
1416 const gchar *interface_name;
1417 GVariant *properties;
1418 GList *interface_added_signals, *l;
1419 GDBusProxy *interface_proxy;
1421 g_return_if_fail (g_dbus_is_unique_name (name_owner));
1423 g_mutex_lock (&manager->priv->lock);
1425 interface_added_signals = NULL;
1426 added = FALSE;
1428 op = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1429 if (op == NULL)
1431 GType object_proxy_type;
1432 if (manager->priv->get_proxy_type_func != NULL)
1434 object_proxy_type = manager->priv->get_proxy_type_func (manager,
1435 object_path,
1436 NULL,
1437 manager->priv->get_proxy_type_user_data);
1438 g_warn_if_fail (g_type_is_a (object_proxy_type, G_TYPE_DBUS_OBJECT_PROXY));
1440 else
1442 object_proxy_type = G_TYPE_DBUS_OBJECT_PROXY;
1444 op = g_object_new (object_proxy_type,
1445 "g-connection", manager->priv->connection,
1446 "g-object-path", object_path,
1447 NULL);
1448 added = TRUE;
1450 g_object_ref (op);
1452 g_variant_iter_init (&iter, ifaces_and_properties);
1453 while (g_variant_iter_next (&iter,
1454 "{&s@a{sv}}",
1455 &interface_name,
1456 &properties))
1458 GError *error;
1459 GType interface_proxy_type;
1461 if (manager->priv->get_proxy_type_func != NULL)
1463 interface_proxy_type = manager->priv->get_proxy_type_func (manager,
1464 object_path,
1465 interface_name,
1466 manager->priv->get_proxy_type_user_data);
1467 g_warn_if_fail (g_type_is_a (interface_proxy_type, G_TYPE_DBUS_PROXY));
1469 else
1471 interface_proxy_type = G_TYPE_DBUS_PROXY;
1474 /* this is fine - there is no blocking IO because we pass DO_NOT_LOAD_PROPERTIES and
1475 * DO_NOT_CONNECT_SIGNALS and use a unique name
1477 error = NULL;
1478 interface_proxy = g_initable_new (interface_proxy_type,
1479 NULL, /* GCancellable */
1480 &error,
1481 "g-connection", manager->priv->connection,
1482 "g-flags", G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
1483 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
1484 "g-name", name_owner,
1485 "g-object-path", object_path,
1486 "g-interface-name", interface_name,
1487 NULL);
1488 if (interface_proxy == NULL)
1490 g_warning ("%s: Error constructing proxy for path %s and interface %s: %s",
1491 G_STRLOC,
1492 object_path,
1493 interface_name,
1494 error->message);
1495 g_error_free (error);
1497 else
1499 GVariantIter property_iter;
1500 const gchar *property_name;
1501 GVariant *property_value;
1503 /* associate the interface proxy with the object */
1504 g_dbus_interface_set_object (G_DBUS_INTERFACE (interface_proxy),
1505 G_DBUS_OBJECT (op));
1507 g_variant_iter_init (&property_iter, properties);
1508 while (g_variant_iter_next (&property_iter,
1509 "{&sv}",
1510 &property_name,
1511 &property_value))
1513 g_dbus_proxy_set_cached_property (interface_proxy,
1514 property_name,
1515 property_value);
1516 g_variant_unref (property_value);
1519 _g_dbus_object_proxy_add_interface (op, interface_proxy);
1520 if (!added)
1521 interface_added_signals = g_list_append (interface_added_signals, g_object_ref (interface_proxy));
1522 g_object_unref (interface_proxy);
1524 g_variant_unref (properties);
1527 g_mutex_unlock (&manager->priv->lock);
1529 /* now that we don't hold the lock any more, emit signals */
1530 for (l = interface_added_signals; l != NULL; l = l->next)
1532 interface_proxy = G_DBUS_PROXY (l->data);
1533 g_signal_emit_by_name (manager, "interface-added", op, interface_proxy);
1534 g_object_unref (interface_proxy);
1536 g_list_free (interface_added_signals);
1538 if (added)
1540 g_hash_table_insert (manager->priv->map_object_path_to_object_proxy,
1541 g_strdup (object_path),
1542 op);
1543 g_signal_emit_by_name (manager, "object-added", op);
1545 g_object_unref (op);
1549 static void
1550 remove_interfaces (GDBusObjectManagerClient *manager,
1551 const gchar *object_path,
1552 const gchar *const *interface_names)
1554 GDBusObjectProxy *op;
1555 GList *interfaces;
1556 guint n;
1557 guint num_interfaces;
1558 guint num_interfaces_to_remove;
1560 g_mutex_lock (&manager->priv->lock);
1562 op = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1563 if (op == NULL)
1565 g_warning ("%s: Processing InterfaceRemoved signal for path %s but no object proxy exists",
1566 G_STRLOC,
1567 object_path);
1568 g_mutex_unlock (&manager->priv->lock);
1569 goto out;
1572 interfaces = g_dbus_object_get_interfaces (G_DBUS_OBJECT (op));
1573 num_interfaces = g_list_length (interfaces);
1574 g_list_free_full (interfaces, g_object_unref);
1576 num_interfaces_to_remove = g_strv_length ((gchar **) interface_names);
1578 /* see if we are going to completety remove the object */
1579 if (num_interfaces_to_remove == num_interfaces)
1581 g_object_ref (op);
1582 g_warn_if_fail (g_hash_table_remove (manager->priv->map_object_path_to_object_proxy, object_path));
1583 g_mutex_unlock (&manager->priv->lock);
1584 g_signal_emit_by_name (manager, "object-removed", op);
1585 g_object_unref (op);
1587 else
1589 g_object_ref (op);
1590 g_mutex_unlock (&manager->priv->lock);
1591 for (n = 0; interface_names != NULL && interface_names[n] != NULL; n++)
1593 GDBusInterface *interface;
1594 interface = g_dbus_object_get_interface (G_DBUS_OBJECT (op), interface_names[n]);
1595 _g_dbus_object_proxy_remove_interface (op, interface_names[n]);
1596 if (interface != NULL)
1598 g_signal_emit_by_name (manager, "interface-removed", op, interface);
1599 g_object_unref (interface);
1602 g_object_unref (op);
1604 out:
1608 static void
1609 process_get_all_result (GDBusObjectManagerClient *manager,
1610 GVariant *value,
1611 const gchar *name_owner)
1613 GVariant *arg0;
1614 const gchar *object_path;
1615 GVariant *ifaces_and_properties;
1616 GVariantIter iter;
1618 g_return_if_fail (g_dbus_is_unique_name (name_owner));
1620 arg0 = g_variant_get_child_value (value, 0);
1621 g_variant_iter_init (&iter, arg0);
1622 while (g_variant_iter_next (&iter,
1623 "{&o@a{sa{sv}}}",
1624 &object_path,
1625 &ifaces_and_properties))
1627 add_interfaces (manager, object_path, ifaces_and_properties, name_owner);
1628 g_variant_unref (ifaces_and_properties);
1630 g_variant_unref (arg0);
1633 static void
1634 on_control_proxy_g_signal (GDBusProxy *proxy,
1635 const gchar *sender_name,
1636 const gchar *signal_name,
1637 GVariant *parameters,
1638 gpointer user_data)
1640 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (user_data);
1641 const gchar *object_path;
1643 //g_debug ("yay, g_signal %s: %s\n", signal_name, g_variant_print (parameters, TRUE));
1645 if (g_strcmp0 (signal_name, "InterfacesAdded") == 0)
1647 GVariant *ifaces_and_properties;
1648 g_variant_get (parameters,
1649 "(&o@a{sa{sv}})",
1650 &object_path,
1651 &ifaces_and_properties);
1652 add_interfaces (manager, object_path, ifaces_and_properties, manager->priv->name_owner);
1653 g_variant_unref (ifaces_and_properties);
1655 else if (g_strcmp0 (signal_name, "InterfacesRemoved") == 0)
1657 const gchar **ifaces;
1658 g_variant_get (parameters,
1659 "(&o^a&s)",
1660 &object_path,
1661 &ifaces);
1662 remove_interfaces (manager, object_path, ifaces);
1663 g_free (ifaces);
1667 /* ---------------------------------------------------------------------------------------------------- */
1669 static const gchar *
1670 g_dbus_object_manager_client_get_object_path (GDBusObjectManager *_manager)
1672 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
1673 return manager->priv->object_path;
1676 static GDBusObject *
1677 g_dbus_object_manager_client_get_object (GDBusObjectManager *_manager,
1678 const gchar *object_path)
1680 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
1681 GDBusObject *ret;
1683 g_mutex_lock (&manager->priv->lock);
1684 ret = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1685 if (ret != NULL)
1686 g_object_ref (ret);
1687 g_mutex_unlock (&manager->priv->lock);
1688 return ret;
1691 static GDBusInterface *
1692 g_dbus_object_manager_client_get_interface (GDBusObjectManager *_manager,
1693 const gchar *object_path,
1694 const gchar *interface_name)
1696 GDBusInterface *ret;
1697 GDBusObject *object;
1699 ret = NULL;
1701 object = g_dbus_object_manager_get_object (_manager, object_path);
1702 if (object == NULL)
1703 goto out;
1705 ret = g_dbus_object_get_interface (object, interface_name);
1706 g_object_unref (object);
1708 out:
1709 return ret;
1712 static GList *
1713 g_dbus_object_manager_client_get_objects (GDBusObjectManager *_manager)
1715 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
1716 GList *ret;
1718 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
1720 g_mutex_lock (&manager->priv->lock);
1721 ret = g_hash_table_get_values (manager->priv->map_object_path_to_object_proxy);
1722 g_list_foreach (ret, (GFunc) g_object_ref, NULL);
1723 g_mutex_unlock (&manager->priv->lock);
1725 return ret;
1729 static void
1730 dbus_object_manager_interface_init (GDBusObjectManagerIface *iface)
1732 iface->get_object_path = g_dbus_object_manager_client_get_object_path;
1733 iface->get_objects = g_dbus_object_manager_client_get_objects;
1734 iface->get_object = g_dbus_object_manager_client_get_object;
1735 iface->get_interface = g_dbus_object_manager_client_get_interface;
1738 /* ---------------------------------------------------------------------------------------------------- */