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.1 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, see <http://www.gnu.org/licenses/>.
18 * Author: David Zeuthen <davidz@redhat.com>
23 #include "gdbusobjectmanager.h"
24 #include "gdbusobjectmanagerclient.h"
25 #include "gdbusobject.h"
26 #include "gdbusprivate.h"
27 #include "gioenumtypes.h"
28 #include "ginitable.h"
29 #include "gasyncresult.h"
30 #include "gasyncinitable.h"
31 #include "gdbusconnection.h"
32 #include "gdbusutils.h"
33 #include "gdbusobject.h"
34 #include "gdbusobjectproxy.h"
35 #include "gdbusproxy.h"
36 #include "gdbusinterface.h"
39 #include "gmarshal-internal.h"
42 * SECTION:gdbusobjectmanagerclient
43 * @short_description: Client-side object manager
46 * #GDBusObjectManagerClient is used to create, monitor and delete object
47 * proxies for remote objects exported by a #GDBusObjectManagerServer (or any
48 * code implementing the
49 * [org.freedesktop.DBus.ObjectManager](http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager)
52 * Once an instance of this type has been created, you can connect to
53 * the #GDBusObjectManager::object-added and
54 * #GDBusObjectManager::object-removed signals and inspect the
55 * #GDBusObjectProxy objects returned by
56 * g_dbus_object_manager_get_objects().
58 * If the name for a #GDBusObjectManagerClient is not owned by anyone at
59 * object construction time, the default behavior is to request the
60 * message bus to launch an owner for the name. This behavior can be
61 * disabled using the %G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START
62 * flag. It's also worth noting that this only works if the name of
63 * interest is activatable in the first place. E.g. in some cases it
64 * is not possible to launch an owner for the requested name. In this
65 * case, #GDBusObjectManagerClient object construction still succeeds but
66 * there will be no object proxies
67 * (e.g. g_dbus_object_manager_get_objects() returns the empty list) and
68 * the #GDBusObjectManagerClient:name-owner property is %NULL.
70 * The owner of the requested name can come and go (for example
71 * consider a system service being restarted) – #GDBusObjectManagerClient
72 * handles this case too; simply connect to the #GObject::notify
73 * signal to watch for changes on the #GDBusObjectManagerClient:name-owner
74 * property. When the name owner vanishes, the behavior is that
75 * #GDBusObjectManagerClient:name-owner is set to %NULL (this includes
76 * emission of the #GObject::notify signal) and then
77 * #GDBusObjectManager::object-removed signals are synthesized
78 * for all currently existing object proxies. Since
79 * #GDBusObjectManagerClient:name-owner is %NULL when this happens, you can
80 * use this information to disambiguate a synthesized signal from a
81 * genuine signal caused by object removal on the remote
82 * #GDBusObjectManager. Similarly, when a new name owner appears,
83 * #GDBusObjectManager::object-added signals are synthesized
84 * while #GDBusObjectManagerClient:name-owner is still %NULL. Only when all
85 * object proxies have been added, the #GDBusObjectManagerClient:name-owner
86 * is set to the new name owner (this includes emission of the
87 * #GObject::notify signal). Furthermore, you are guaranteed that
88 * #GDBusObjectManagerClient:name-owner will alternate between a name owner
89 * (e.g. `:1.42`) and %NULL even in the case where
90 * the name of interest is atomically replaced
92 * Ultimately, #GDBusObjectManagerClient is used to obtain #GDBusProxy
93 * instances. All signals (including the
94 * org.freedesktop.DBus.Properties::PropertiesChanged signal)
95 * delivered to #GDBusProxy instances are guaranteed to originate
96 * from the name owner. This guarantee along with the behavior
97 * described above, means that certain race conditions including the
98 * "half the proxy is from the old owner and the other half is from
99 * the new owner" problem cannot happen.
101 * To avoid having the application connect to signals on the returned
102 * #GDBusObjectProxy and #GDBusProxy objects, the
103 * #GDBusObject::interface-added,
104 * #GDBusObject::interface-removed,
105 * #GDBusProxy::g-properties-changed and
106 * #GDBusProxy::g-signal signals
107 * are also emitted on the #GDBusObjectManagerClient instance managing these
108 * objects. The signals emitted are
109 * #GDBusObjectManager::interface-added,
110 * #GDBusObjectManager::interface-removed,
111 * #GDBusObjectManagerClient::interface-proxy-properties-changed and
112 * #GDBusObjectManagerClient::interface-proxy-signal.
114 * Note that all callbacks and signals are emitted in the
115 * [thread-default main context][g-main-context-push-thread-default]
116 * that the #GDBusObjectManagerClient object was constructed
117 * in. Additionally, the #GDBusObjectProxy and #GDBusProxy objects
118 * originating from the #GDBusObjectManagerClient object will be created in
119 * the same context and, consequently, will deliver signals in the
123 struct _GDBusObjectManagerClientPrivate
128 GDBusConnection *connection;
132 GDBusObjectManagerClientFlags flags;
134 GDBusProxy *control_proxy;
136 GHashTable *map_object_path_to_object_proxy;
138 guint signal_subscription_id;
141 GDBusProxyTypeFunc get_proxy_type_func;
142 gpointer get_proxy_type_user_data;
143 GDestroyNotify get_proxy_type_destroy_notify;
155 PROP_GET_PROXY_TYPE_FUNC,
156 PROP_GET_PROXY_TYPE_USER_DATA,
157 PROP_GET_PROXY_TYPE_DESTROY_NOTIFY
162 INTERFACE_PROXY_SIGNAL_SIGNAL,
163 INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL,
167 static guint signals[LAST_SIGNAL] = { 0 };
169 static void initable_iface_init (GInitableIface *initable_iface);
170 static void async_initable_iface_init (GAsyncInitableIface *async_initable_iface);
171 static void dbus_object_manager_interface_init (GDBusObjectManagerIface *iface);
173 G_DEFINE_TYPE_WITH_CODE (GDBusObjectManagerClient, g_dbus_object_manager_client, G_TYPE_OBJECT,
174 G_ADD_PRIVATE (GDBusObjectManagerClient)
175 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)
176 G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init)
177 G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_OBJECT_MANAGER, dbus_object_manager_interface_init))
179 static void maybe_unsubscribe_signals (GDBusObjectManagerClient *manager);
181 static void on_control_proxy_g_signal (GDBusProxy *proxy,
182 const gchar *sender_name,
183 const gchar *signal_name,
184 GVariant *parameters,
187 static void process_get_all_result (GDBusObjectManagerClient *manager,
189 const gchar *name_owner);
192 g_dbus_object_manager_client_finalize (GObject *object)
194 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (object);
196 maybe_unsubscribe_signals (manager);
198 g_hash_table_unref (manager->priv->map_object_path_to_object_proxy);
200 if (manager->priv->control_proxy != NULL)
202 g_signal_handlers_disconnect_by_func (manager->priv->control_proxy,
203 on_control_proxy_g_signal,
205 g_object_unref (manager->priv->control_proxy);
207 if (manager->priv->connection != NULL)
208 g_object_unref (manager->priv->connection);
209 g_free (manager->priv->object_path);
210 g_free (manager->priv->name);
211 g_free (manager->priv->name_owner);
213 if (manager->priv->get_proxy_type_destroy_notify != NULL)
214 manager->priv->get_proxy_type_destroy_notify (manager->priv->get_proxy_type_user_data);
216 g_mutex_clear (&manager->priv->lock);
218 if (G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class)->finalize != NULL)
219 G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class)->finalize (object);
223 g_dbus_object_manager_client_get_property (GObject *_object,
228 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_object);
232 case PROP_CONNECTION:
233 g_value_set_object (value, g_dbus_object_manager_client_get_connection (manager));
236 case PROP_OBJECT_PATH:
237 g_value_set_string (value, g_dbus_object_manager_get_object_path (G_DBUS_OBJECT_MANAGER (manager)));
241 g_value_set_string (value, g_dbus_object_manager_client_get_name (manager));
245 g_value_set_flags (value, g_dbus_object_manager_client_get_flags (manager));
248 case PROP_NAME_OWNER:
249 g_value_take_string (value, g_dbus_object_manager_client_get_name_owner (manager));
253 G_OBJECT_WARN_INVALID_PROPERTY_ID (manager, prop_id, pspec);
259 g_dbus_object_manager_client_set_property (GObject *_object,
264 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_object);
270 manager->priv->bus_type = g_value_get_enum (value);
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);
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);
289 g_assert (manager->priv->name == NULL);
290 name = g_value_get_string (value);
291 g_assert (name == NULL || g_dbus_is_name (name));
292 manager->priv->name = g_strdup (name);
296 manager->priv->flags = g_value_get_flags (value);
299 case PROP_GET_PROXY_TYPE_FUNC:
300 manager->priv->get_proxy_type_func = g_value_get_pointer (value);
303 case PROP_GET_PROXY_TYPE_USER_DATA:
304 manager->priv->get_proxy_type_user_data = g_value_get_pointer (value);
307 case PROP_GET_PROXY_TYPE_DESTROY_NOTIFY:
308 manager->priv->get_proxy_type_destroy_notify = g_value_get_pointer (value);
312 G_OBJECT_WARN_INVALID_PROPERTY_ID (manager, prop_id, pspec);
318 g_dbus_object_manager_client_class_init (GDBusObjectManagerClientClass *klass)
320 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
322 gobject_class->finalize = g_dbus_object_manager_client_finalize;
323 gobject_class->set_property = g_dbus_object_manager_client_set_property;
324 gobject_class->get_property = g_dbus_object_manager_client_get_property;
327 * GDBusObjectManagerClient:connection:
329 * The #GDBusConnection to use.
333 g_object_class_install_property (gobject_class,
335 g_param_spec_object ("connection",
337 "The connection to use",
338 G_TYPE_DBUS_CONNECTION,
341 G_PARAM_CONSTRUCT_ONLY |
342 G_PARAM_STATIC_STRINGS));
345 * GDBusObjectManagerClient:bus-type:
347 * If this property is not %G_BUS_TYPE_NONE, then
348 * #GDBusObjectManagerClient:connection must be %NULL and will be set to the
349 * #GDBusConnection obtained by calling g_bus_get() with the value
354 g_object_class_install_property (gobject_class,
356 g_param_spec_enum ("bus-type",
358 "The bus to connect to, if any",
362 G_PARAM_CONSTRUCT_ONLY |
363 G_PARAM_STATIC_NAME |
364 G_PARAM_STATIC_BLURB |
365 G_PARAM_STATIC_NICK));
368 * GDBusObjectManagerClient:flags:
370 * Flags from the #GDBusObjectManagerClientFlags enumeration.
374 g_object_class_install_property (gobject_class,
376 g_param_spec_flags ("flags",
378 "Flags for the proxy manager",
379 G_TYPE_DBUS_OBJECT_MANAGER_CLIENT_FLAGS,
380 G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
383 G_PARAM_CONSTRUCT_ONLY |
384 G_PARAM_STATIC_NAME |
385 G_PARAM_STATIC_BLURB |
386 G_PARAM_STATIC_NICK));
389 * GDBusObjectManagerClient:object-path:
391 * The object path the manager is for.
395 g_object_class_install_property (gobject_class,
397 g_param_spec_string ("object-path",
399 "The object path of the control object",
403 G_PARAM_CONSTRUCT_ONLY |
404 G_PARAM_STATIC_STRINGS));
407 * GDBusObjectManagerClient:name:
409 * The well-known name or unique name that the manager is for.
413 g_object_class_install_property (gobject_class,
415 g_param_spec_string ("name",
417 "Name that the manager is for",
421 G_PARAM_CONSTRUCT_ONLY |
422 G_PARAM_STATIC_STRINGS));
425 * GDBusObjectManagerClient:name-owner:
427 * The unique name that owns #GDBusObjectManagerClient:name or %NULL if
428 * no-one is currently owning the name. Connect to the
429 * #GObject::notify signal to track changes to this property.
433 g_object_class_install_property (gobject_class,
435 g_param_spec_string ("name-owner",
437 "The owner of the name we are watching",
440 G_PARAM_STATIC_STRINGS));
443 * GDBusObjectManagerClient:get-proxy-type-func:
445 * The #GDBusProxyTypeFunc to use when determining what #GType to
446 * use for interface proxies or %NULL.
450 g_object_class_install_property (gobject_class,
451 PROP_GET_PROXY_TYPE_FUNC,
452 g_param_spec_pointer ("get-proxy-type-func",
453 "GDBusProxyTypeFunc Function Pointer",
454 "The GDBusProxyTypeFunc pointer to use",
457 G_PARAM_CONSTRUCT_ONLY |
458 G_PARAM_STATIC_STRINGS));
461 * GDBusObjectManagerClient:get-proxy-type-user-data:
463 * The #gpointer user_data to pass to #GDBusObjectManagerClient:get-proxy-type-func.
467 g_object_class_install_property (gobject_class,
468 PROP_GET_PROXY_TYPE_USER_DATA,
469 g_param_spec_pointer ("get-proxy-type-user-data",
470 "GDBusProxyTypeFunc User Data",
471 "The GDBusProxyTypeFunc user_data",
474 G_PARAM_CONSTRUCT_ONLY |
475 G_PARAM_STATIC_STRINGS));
478 * GDBusObjectManagerClient:get-proxy-type-destroy-notify:
480 * A #GDestroyNotify for the #gpointer user_data in #GDBusObjectManagerClient:get-proxy-type-user-data.
484 g_object_class_install_property (gobject_class,
485 PROP_GET_PROXY_TYPE_DESTROY_NOTIFY,
486 g_param_spec_pointer ("get-proxy-type-destroy-notify",
487 "GDBusProxyTypeFunc user data free function",
488 "The GDBusProxyTypeFunc user data free function",
491 G_PARAM_CONSTRUCT_ONLY |
492 G_PARAM_STATIC_STRINGS));
495 * GDBusObjectManagerClient::interface-proxy-signal:
496 * @manager: The #GDBusObjectManagerClient emitting the signal.
497 * @object_proxy: The #GDBusObjectProxy on which an interface is emitting a D-Bus signal.
498 * @interface_proxy: The #GDBusProxy that is emitting a D-Bus signal.
499 * @sender_name: The sender of the signal or NULL if the connection is not a bus connection.
500 * @signal_name: The signal name.
501 * @parameters: A #GVariant tuple with parameters for the signal.
503 * Emitted when a D-Bus signal is received on @interface_proxy.
505 * This signal exists purely as a convenience to avoid having to
506 * connect signals to all interface proxies managed by @manager.
508 * This signal is emitted in the
509 * [thread-default main context][g-main-context-push-thread-default]
510 * that @manager was constructed in.
514 signals[INTERFACE_PROXY_SIGNAL_SIGNAL] =
515 g_signal_new (I_("interface-proxy-signal"),
516 G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
518 G_STRUCT_OFFSET (GDBusObjectManagerClientClass, interface_proxy_signal),
521 _g_cclosure_marshal_VOID__OBJECT_OBJECT_STRING_STRING_VARIANT,
524 G_TYPE_DBUS_OBJECT_PROXY,
529 g_signal_set_va_marshaller (signals[INTERFACE_PROXY_SIGNAL_SIGNAL],
530 G_TYPE_FROM_CLASS (klass),
531 _g_cclosure_marshal_VOID__OBJECT_OBJECT_STRING_STRING_VARIANTv);
534 * GDBusObjectManagerClient::interface-proxy-properties-changed:
535 * @manager: The #GDBusObjectManagerClient emitting the signal.
536 * @object_proxy: The #GDBusObjectProxy on which an interface has properties that are changing.
537 * @interface_proxy: The #GDBusProxy that has properties that are changing.
538 * @changed_properties: A #GVariant containing the properties that changed (type: `a{sv}`).
539 * @invalidated_properties: (array zero-terminated=1) (element-type utf8): A %NULL terminated
540 * array of properties that were invalidated.
542 * Emitted when one or more D-Bus properties on proxy changes. The
543 * local cache has already been updated when this signal fires. Note
544 * that both @changed_properties and @invalidated_properties are
545 * guaranteed to never be %NULL (either may be empty though).
547 * This signal exists purely as a convenience to avoid having to
548 * connect signals to all interface proxies managed by @manager.
550 * This signal is emitted in the
551 * [thread-default main context][g-main-context-push-thread-default]
552 * that @manager was constructed in.
556 signals[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL] =
557 g_signal_new (I_("interface-proxy-properties-changed"),
558 G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
560 G_STRUCT_OFFSET (GDBusObjectManagerClientClass, interface_proxy_properties_changed),
563 _g_cclosure_marshal_VOID__OBJECT_OBJECT_VARIANT_BOXED,
566 G_TYPE_DBUS_OBJECT_PROXY,
570 g_signal_set_va_marshaller (signals[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL],
571 G_TYPE_FROM_CLASS (klass),
572 _g_cclosure_marshal_VOID__OBJECT_OBJECT_VARIANT_BOXEDv);
576 g_dbus_object_manager_client_init (GDBusObjectManagerClient *manager)
578 manager->priv = g_dbus_object_manager_client_get_instance_private (manager);
579 g_mutex_init (&manager->priv->lock);
580 manager->priv->map_object_path_to_object_proxy = g_hash_table_new_full (g_str_hash,
583 (GDestroyNotify) g_object_unref);
586 /* ---------------------------------------------------------------------------------------------------- */
589 * g_dbus_object_manager_client_new_sync:
590 * @connection: A #GDBusConnection.
591 * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
592 * @name: (nullable): The owner of the control object (unique or well-known name), or %NULL when not using a message bus connection.
593 * @object_path: The object path of the control object.
594 * @get_proxy_type_func: (nullable): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
595 * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
596 * @get_proxy_type_destroy_notify: (nullable): Free function for @get_proxy_type_user_data or %NULL.
597 * @cancellable: (nullable): A #GCancellable or %NULL
598 * @error: Return location for error or %NULL.
600 * Creates a new #GDBusObjectManagerClient object.
602 * This is a synchronous failable constructor - the calling thread is
603 * blocked until a reply is received. See g_dbus_object_manager_client_new()
604 * for the asynchronous version.
606 * Returns: (transfer full) (type GDBusObjectManagerClient): A
607 * #GDBusObjectManagerClient object or %NULL if @error is set. Free
608 * with g_object_unref().
613 g_dbus_object_manager_client_new_sync (GDBusConnection *connection,
614 GDBusObjectManagerClientFlags flags,
616 const gchar *object_path,
617 GDBusProxyTypeFunc get_proxy_type_func,
618 gpointer get_proxy_type_user_data,
619 GDestroyNotify get_proxy_type_destroy_notify,
620 GCancellable *cancellable,
625 g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
626 g_return_val_if_fail ((name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) ||
627 g_dbus_is_name (name), NULL);
628 g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
629 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
631 initable = g_initable_new (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
634 "connection", connection,
637 "object-path", object_path,
638 "get-proxy-type-func", get_proxy_type_func,
639 "get-proxy-type-user-data", get_proxy_type_user_data,
640 "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
642 if (initable != NULL)
643 return G_DBUS_OBJECT_MANAGER (initable);
649 * g_dbus_object_manager_client_new:
650 * @connection: A #GDBusConnection.
651 * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
652 * @name: The owner of the control object (unique or well-known name).
653 * @object_path: The object path of the control object.
654 * @get_proxy_type_func: (nullable): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
655 * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
656 * @get_proxy_type_destroy_notify: (nullable): Free function for @get_proxy_type_user_data or %NULL.
657 * @cancellable: (nullable): A #GCancellable or %NULL
658 * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
659 * @user_data: The data to pass to @callback.
661 * Asynchronously creates a new #GDBusObjectManagerClient object.
663 * This is an asynchronous failable constructor. When the result is
664 * ready, @callback will be invoked in the
665 * [thread-default main context][g-main-context-push-thread-default]
666 * of the thread you are calling this method from. You can
667 * then call g_dbus_object_manager_client_new_finish() to get the result. See
668 * g_dbus_object_manager_client_new_sync() for the synchronous version.
673 g_dbus_object_manager_client_new (GDBusConnection *connection,
674 GDBusObjectManagerClientFlags flags,
676 const gchar *object_path,
677 GDBusProxyTypeFunc get_proxy_type_func,
678 gpointer get_proxy_type_user_data,
679 GDestroyNotify get_proxy_type_destroy_notify,
680 GCancellable *cancellable,
681 GAsyncReadyCallback callback,
684 g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
685 g_return_if_fail ((name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) ||
686 g_dbus_is_name (name));
687 g_return_if_fail (g_variant_is_object_path (object_path));
689 g_async_initable_new_async (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
694 "connection", connection,
697 "object-path", object_path,
698 "get-proxy-type-func", get_proxy_type_func,
699 "get-proxy-type-user-data", get_proxy_type_user_data,
700 "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
705 * g_dbus_object_manager_client_new_finish:
706 * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_object_manager_client_new().
707 * @error: Return location for error or %NULL.
709 * Finishes an operation started with g_dbus_object_manager_client_new().
711 * Returns: (transfer full) (type GDBusObjectManagerClient): A
712 * #GDBusObjectManagerClient object or %NULL if @error is set. Free
713 * with g_object_unref().
718 g_dbus_object_manager_client_new_finish (GAsyncResult *res,
722 GObject *source_object;
724 source_object = g_async_result_get_source_object (res);
725 g_assert (source_object != NULL);
727 object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
730 g_object_unref (source_object);
733 return G_DBUS_OBJECT_MANAGER (object);
738 /* ---------------------------------------------------------------------------------------------------- */
741 * g_dbus_object_manager_client_new_for_bus_sync:
742 * @bus_type: A #GBusType.
743 * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
744 * @name: The owner of the control object (unique or well-known name).
745 * @object_path: The object path of the control object.
746 * @get_proxy_type_func: (nullable): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
747 * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
748 * @get_proxy_type_destroy_notify: (nullable): Free function for @get_proxy_type_user_data or %NULL.
749 * @cancellable: (nullable): A #GCancellable or %NULL
750 * @error: Return location for error or %NULL.
752 * Like g_dbus_object_manager_client_new_sync() but takes a #GBusType instead
753 * of a #GDBusConnection.
755 * This is a synchronous failable constructor - the calling thread is
756 * blocked until a reply is received. See g_dbus_object_manager_client_new_for_bus()
757 * for the asynchronous version.
759 * Returns: (transfer full) (type GDBusObjectManagerClient): A
760 * #GDBusObjectManagerClient object or %NULL if @error is set. Free
761 * with g_object_unref().
766 g_dbus_object_manager_client_new_for_bus_sync (GBusType bus_type,
767 GDBusObjectManagerClientFlags flags,
769 const gchar *object_path,
770 GDBusProxyTypeFunc get_proxy_type_func,
771 gpointer get_proxy_type_user_data,
772 GDestroyNotify get_proxy_type_destroy_notify,
773 GCancellable *cancellable,
778 g_return_val_if_fail (bus_type != G_BUS_TYPE_NONE, NULL);
779 g_return_val_if_fail (g_dbus_is_name (name), NULL);
780 g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
781 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
783 initable = g_initable_new (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
786 "bus-type", bus_type,
789 "object-path", object_path,
790 "get-proxy-type-func", get_proxy_type_func,
791 "get-proxy-type-user-data", get_proxy_type_user_data,
792 "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
794 if (initable != NULL)
795 return G_DBUS_OBJECT_MANAGER (initable);
801 * g_dbus_object_manager_client_new_for_bus:
802 * @bus_type: A #GBusType.
803 * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
804 * @name: The owner of the control object (unique or well-known name).
805 * @object_path: The object path of the control object.
806 * @get_proxy_type_func: (nullable): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
807 * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
808 * @get_proxy_type_destroy_notify: (nullable): Free function for @get_proxy_type_user_data or %NULL.
809 * @cancellable: (nullable): A #GCancellable or %NULL
810 * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
811 * @user_data: The data to pass to @callback.
813 * Like g_dbus_object_manager_client_new() but takes a #GBusType instead of a
816 * This is an asynchronous failable constructor. When the result is
817 * ready, @callback will be invoked in the
818 * [thread-default main loop][g-main-context-push-thread-default]
819 * of the thread you are calling this method from. You can
820 * then call g_dbus_object_manager_client_new_for_bus_finish() to get the result. See
821 * g_dbus_object_manager_client_new_for_bus_sync() for the synchronous version.
826 g_dbus_object_manager_client_new_for_bus (GBusType bus_type,
827 GDBusObjectManagerClientFlags flags,
829 const gchar *object_path,
830 GDBusProxyTypeFunc get_proxy_type_func,
831 gpointer get_proxy_type_user_data,
832 GDestroyNotify get_proxy_type_destroy_notify,
833 GCancellable *cancellable,
834 GAsyncReadyCallback callback,
837 g_return_if_fail (bus_type != G_BUS_TYPE_NONE);
838 g_return_if_fail (g_dbus_is_name (name));
839 g_return_if_fail (g_variant_is_object_path (object_path));
841 g_async_initable_new_async (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
846 "bus-type", bus_type,
849 "object-path", object_path,
850 "get-proxy-type-func", get_proxy_type_func,
851 "get-proxy-type-user-data", get_proxy_type_user_data,
852 "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
857 * g_dbus_object_manager_client_new_for_bus_finish:
858 * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_object_manager_client_new_for_bus().
859 * @error: Return location for error or %NULL.
861 * Finishes an operation started with g_dbus_object_manager_client_new_for_bus().
863 * Returns: (transfer full) (type GDBusObjectManagerClient): A
864 * #GDBusObjectManagerClient object or %NULL if @error is set. Free
865 * with g_object_unref().
870 g_dbus_object_manager_client_new_for_bus_finish (GAsyncResult *res,
874 GObject *source_object;
876 source_object = g_async_result_get_source_object (res);
877 g_assert (source_object != NULL);
879 object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
882 g_object_unref (source_object);
885 return G_DBUS_OBJECT_MANAGER (object);
890 /* ---------------------------------------------------------------------------------------------------- */
893 * g_dbus_object_manager_client_get_connection:
894 * @manager: A #GDBusObjectManagerClient
896 * Gets the #GDBusConnection used by @manager.
898 * Returns: (transfer none): A #GDBusConnection object. Do not free,
899 * the object belongs to @manager.
904 g_dbus_object_manager_client_get_connection (GDBusObjectManagerClient *manager)
906 GDBusConnection *ret;
907 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
908 g_mutex_lock (&manager->priv->lock);
909 ret = manager->priv->connection;
910 g_mutex_unlock (&manager->priv->lock);
915 * g_dbus_object_manager_client_get_name:
916 * @manager: A #GDBusObjectManagerClient
918 * Gets the name that @manager is for, or %NULL if not a message bus
921 * Returns: A unique or well-known name. Do not free, the string
922 * belongs to @manager.
927 g_dbus_object_manager_client_get_name (GDBusObjectManagerClient *manager)
930 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
931 g_mutex_lock (&manager->priv->lock);
932 ret = manager->priv->name;
933 g_mutex_unlock (&manager->priv->lock);
938 * g_dbus_object_manager_client_get_flags:
939 * @manager: A #GDBusObjectManagerClient
941 * Gets the flags that @manager was constructed with.
943 * Returns: Zero of more flags from the #GDBusObjectManagerClientFlags
948 GDBusObjectManagerClientFlags
949 g_dbus_object_manager_client_get_flags (GDBusObjectManagerClient *manager)
951 GDBusObjectManagerClientFlags ret;
952 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE);
953 g_mutex_lock (&manager->priv->lock);
954 ret = manager->priv->flags;
955 g_mutex_unlock (&manager->priv->lock);
960 * g_dbus_object_manager_client_get_name_owner:
961 * @manager: A #GDBusObjectManagerClient.
963 * The unique name that owns the name that @manager is for or %NULL if
964 * no-one currently owns that name. You can connect to the
965 * #GObject::notify signal to track changes to the
966 * #GDBusObjectManagerClient:name-owner property.
968 * Returns: (nullable): The name owner or %NULL if no name owner
969 * exists. Free with g_free().
974 g_dbus_object_manager_client_get_name_owner (GDBusObjectManagerClient *manager)
977 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
978 g_mutex_lock (&manager->priv->lock);
979 ret = g_strdup (manager->priv->name_owner);
980 g_mutex_unlock (&manager->priv->lock);
984 /* ---------------------------------------------------------------------------------------------------- */
986 /* signal handler for all objects we manage - we dispatch signals
987 * from here to the objects
990 signal_cb (GDBusConnection *connection,
991 const gchar *sender_name,
992 const gchar *object_path,
993 const gchar *interface_name,
994 const gchar *signal_name,
995 GVariant *parameters,
998 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (user_data);
999 GDBusObjectProxy *object_proxy;
1000 GDBusInterface *interface;
1002 g_mutex_lock (&manager->priv->lock);
1003 object_proxy = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1004 if (object_proxy == NULL)
1006 g_mutex_unlock (&manager->priv->lock);
1009 g_object_ref (object_proxy);
1010 g_mutex_unlock (&manager->priv->lock);
1012 //g_debug ("yay, signal_cb %s %s: %s\n", signal_name, object_path, g_variant_print (parameters, TRUE));
1014 g_object_ref (manager);
1015 if (g_strcmp0 (interface_name, "org.freedesktop.DBus.Properties") == 0)
1017 if (g_strcmp0 (signal_name, "PropertiesChanged") == 0)
1019 const gchar *interface_name;
1020 GVariant *changed_properties;
1021 const gchar **invalidated_properties;
1023 g_variant_get (parameters,
1026 &changed_properties,
1027 &invalidated_properties);
1029 interface = g_dbus_object_get_interface (G_DBUS_OBJECT (object_proxy), interface_name);
1030 if (interface != NULL)
1032 GVariantIter property_iter;
1033 const gchar *property_name;
1034 GVariant *property_value;
1037 /* update caches... */
1038 g_variant_iter_init (&property_iter, changed_properties);
1039 while (g_variant_iter_next (&property_iter,
1044 g_dbus_proxy_set_cached_property (G_DBUS_PROXY (interface),
1047 g_variant_unref (property_value);
1050 for (n = 0; invalidated_properties[n] != NULL; n++)
1052 g_dbus_proxy_set_cached_property (G_DBUS_PROXY (interface),
1053 invalidated_properties[n],
1056 /* ... and then synthesize the signal */
1057 g_signal_emit_by_name (interface,
1058 "g-properties-changed",
1060 invalidated_properties);
1061 g_signal_emit (manager,
1062 signals[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL],
1067 invalidated_properties);
1068 g_object_unref (interface);
1070 g_variant_unref (changed_properties);
1071 g_free (invalidated_properties);
1076 /* regular signal - just dispatch it */
1077 interface = g_dbus_object_get_interface (G_DBUS_OBJECT (object_proxy), interface_name);
1078 if (interface != NULL)
1080 g_signal_emit_by_name (interface,
1085 g_signal_emit (manager,
1086 signals[INTERFACE_PROXY_SIGNAL_SIGNAL],
1093 g_object_unref (interface);
1096 g_object_unref (manager);
1099 g_clear_object (&object_proxy);
1103 subscribe_signals (GDBusObjectManagerClient *manager,
1104 const gchar *name_owner)
1106 GError *error = NULL;
1109 g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager));
1110 g_return_if_fail (manager->priv->signal_subscription_id == 0);
1111 g_return_if_fail (name_owner == NULL || g_dbus_is_unique_name (name_owner));
1113 if (name_owner != NULL)
1115 /* Only add path_namespace if it's non-'/'. This removes a no-op key from
1116 * the match rule, and also works around a D-Bus bug where
1117 * path_namespace='/' matches nothing in D-Bus versions < 1.6.18.
1119 * See: https://bugs.freedesktop.org/show_bug.cgi?id=70799 */
1120 if (g_str_equal (manager->priv->object_path, "/"))
1122 manager->priv->match_rule = g_strdup_printf ("type='signal',sender='%s'",
1127 manager->priv->match_rule = g_strdup_printf ("type='signal',sender='%s',path_namespace='%s'",
1128 name_owner, manager->priv->object_path);
1131 /* The bus daemon may not implement path_namespace so gracefully
1132 * handle this by using a fallback triggered if @error is set. */
1133 ret = g_dbus_connection_call_sync (manager->priv->connection,
1134 "org.freedesktop.DBus",
1135 "/org/freedesktop/DBus",
1136 "org.freedesktop.DBus",
1138 g_variant_new ("(s)",
1139 manager->priv->match_rule),
1140 NULL, /* reply_type */
1141 G_DBUS_CALL_FLAGS_NONE,
1142 -1, /* default timeout */
1143 NULL, /* TODO: Cancellable */
1146 /* yay, bus daemon supports path_namespace */
1148 g_variant_unref (ret);
1153 /* still need to ask GDBusConnection for the callbacks */
1154 manager->priv->signal_subscription_id =
1155 g_dbus_connection_signal_subscribe (manager->priv->connection,
1157 NULL, /* interface */
1159 NULL, /* path - TODO: really want wilcard support here */
1161 G_DBUS_SIGNAL_FLAGS_NONE |
1162 G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
1165 NULL); /* user_data_free_func */
1170 /* TODO: we could report this to the user
1171 g_warning ("Message bus daemon does not support path_namespace: %s (%s %d)",
1173 g_quark_to_string (error->domain),
1177 g_error_free (error);
1179 /* no need to call RemoveMatch when done since it didn't work */
1180 g_free (manager->priv->match_rule);
1181 manager->priv->match_rule = NULL;
1183 /* Fallback is to subscribe to *all* signals from the name owner which
1184 * is rather wasteful. It's probably not a big practical problem because
1185 * users typically want all objects that the name owner supplies.
1187 manager->priv->signal_subscription_id =
1188 g_dbus_connection_signal_subscribe (manager->priv->connection,
1190 NULL, /* interface */
1192 NULL, /* path - TODO: really want wilcard support here */
1194 G_DBUS_SIGNAL_FLAGS_NONE,
1197 NULL); /* user_data_free_func */
1202 maybe_unsubscribe_signals (GDBusObjectManagerClient *manager)
1204 g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager));
1206 if (manager->priv->signal_subscription_id > 0)
1208 g_dbus_connection_signal_unsubscribe (manager->priv->connection,
1209 manager->priv->signal_subscription_id);
1210 manager->priv->signal_subscription_id = 0;
1213 if (manager->priv->match_rule != NULL)
1215 /* Since the AddMatch call succeeded this is guaranteed to not
1216 * fail - therefore, don't bother checking the return value
1218 g_dbus_connection_call (manager->priv->connection,
1219 "org.freedesktop.DBus",
1220 "/org/freedesktop/DBus",
1221 "org.freedesktop.DBus",
1223 g_variant_new ("(s)",
1224 manager->priv->match_rule),
1225 NULL, /* reply_type */
1226 G_DBUS_CALL_FLAGS_NONE,
1227 -1, /* default timeout */
1228 NULL, /* GCancellable */
1229 NULL, /* GAsyncReadyCallback */
1230 NULL); /* user data */
1231 g_free (manager->priv->match_rule);
1232 manager->priv->match_rule = NULL;
1237 /* ---------------------------------------------------------------------------------------------------- */
1240 on_notify_g_name_owner (GObject *object,
1244 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (user_data);
1245 gchar *old_name_owner;
1246 gchar *new_name_owner;
1248 g_mutex_lock (&manager->priv->lock);
1249 old_name_owner = manager->priv->name_owner;
1250 new_name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy);
1251 manager->priv->name_owner = NULL;
1253 g_object_ref (manager);
1254 if (g_strcmp0 (old_name_owner, new_name_owner) != 0)
1259 /* remote manager changed; nuke all local proxies */
1260 proxies = g_hash_table_get_values (manager->priv->map_object_path_to_object_proxy);
1261 g_list_foreach (proxies, (GFunc) g_object_ref, NULL);
1262 g_hash_table_remove_all (manager->priv->map_object_path_to_object_proxy);
1264 g_mutex_unlock (&manager->priv->lock);
1266 /* do the :name-owner notify with a NULL name - this way the user knows
1267 * the ::object-proxy-removed following is because the name owner went
1270 g_object_notify (G_OBJECT (manager), "name-owner");
1272 for (l = proxies; l != NULL; l = l->next)
1274 GDBusObjectProxy *object_proxy = G_DBUS_OBJECT_PROXY (l->data);
1275 g_signal_emit_by_name (manager, "object-removed", object_proxy);
1277 g_list_free_full (proxies, g_object_unref);
1279 /* nuke local filter */
1280 maybe_unsubscribe_signals (manager);
1284 g_mutex_unlock (&manager->priv->lock);
1287 if (new_name_owner != NULL)
1292 //g_debug ("repopulating for %s", new_name_owner);
1294 /* TODO: do this async! */
1295 subscribe_signals (manager,
1298 value = g_dbus_proxy_call_sync (manager->priv->control_proxy,
1299 "GetManagedObjects",
1300 NULL, /* parameters */
1301 G_DBUS_CALL_FLAGS_NONE,
1307 maybe_unsubscribe_signals (manager);
1308 g_warning ("Error calling GetManagedObjects() when name owner %s for name %s came back: %s",
1310 manager->priv->name,
1312 g_error_free (error);
1316 process_get_all_result (manager, value, new_name_owner);
1317 g_variant_unref (value);
1320 /* do the :name-owner notify *AFTER* emitting ::object-proxy-added signals - this
1321 * way the user knows that the signals were emitted because the name owner came back
1323 g_mutex_lock (&manager->priv->lock);
1324 manager->priv->name_owner = new_name_owner;
1325 g_mutex_unlock (&manager->priv->lock);
1326 g_object_notify (G_OBJECT (manager), "name-owner");
1329 g_free (old_name_owner);
1330 g_object_unref (manager);
1334 initable_init (GInitable *initable,
1335 GCancellable *cancellable,
1338 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (initable);
1341 GDBusProxyFlags proxy_flags;
1345 if (manager->priv->bus_type != G_BUS_TYPE_NONE)
1347 g_assert (manager->priv->connection == NULL);
1348 manager->priv->connection = g_bus_get_sync (manager->priv->bus_type, cancellable, error);
1349 if (manager->priv->connection == NULL)
1353 proxy_flags = G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES;
1354 if (manager->priv->flags & G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START)
1355 proxy_flags |= G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START;
1357 manager->priv->control_proxy = g_dbus_proxy_new_sync (manager->priv->connection,
1359 NULL, /* GDBusInterfaceInfo* */
1360 manager->priv->name,
1361 manager->priv->object_path,
1362 "org.freedesktop.DBus.ObjectManager",
1365 if (manager->priv->control_proxy == NULL)
1368 g_signal_connect (G_OBJECT (manager->priv->control_proxy),
1369 "notify::g-name-owner",
1370 G_CALLBACK (on_notify_g_name_owner),
1373 g_signal_connect (manager->priv->control_proxy,
1375 G_CALLBACK (on_control_proxy_g_signal),
1378 manager->priv->name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy);
1379 if (manager->priv->name_owner == NULL && manager->priv->name != NULL)
1381 /* it's perfectly fine if there's no name owner.. we're just going to
1382 * wait until one is ready
1387 /* yay, we can get the objects */
1388 subscribe_signals (manager,
1389 manager->priv->name_owner);
1390 value = g_dbus_proxy_call_sync (manager->priv->control_proxy,
1391 "GetManagedObjects",
1392 NULL, /* parameters */
1393 G_DBUS_CALL_FLAGS_NONE,
1399 maybe_unsubscribe_signals (manager);
1400 g_warn_if_fail (g_signal_handlers_disconnect_by_func (manager->priv->control_proxy,
1401 on_control_proxy_g_signal,
1403 g_object_unref (manager->priv->control_proxy);
1404 manager->priv->control_proxy = NULL;
1408 process_get_all_result (manager, value, manager->priv->name_owner);
1409 g_variant_unref (value);
1419 initable_iface_init (GInitableIface *initable_iface)
1421 initable_iface->init = initable_init;
1425 async_initable_iface_init (GAsyncInitableIface *async_initable_iface)
1427 /* for now, just use default: run GInitable code in thread */
1430 /* ---------------------------------------------------------------------------------------------------- */
1433 add_interfaces (GDBusObjectManagerClient *manager,
1434 const gchar *object_path,
1435 GVariant *ifaces_and_properties,
1436 const gchar *name_owner)
1438 GDBusObjectProxy *op;
1441 const gchar *interface_name;
1442 GVariant *properties;
1443 GList *interface_added_signals, *l;
1444 GDBusProxy *interface_proxy;
1446 g_return_if_fail (name_owner == NULL || g_dbus_is_unique_name (name_owner));
1448 g_mutex_lock (&manager->priv->lock);
1450 interface_added_signals = NULL;
1453 op = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1456 GType object_proxy_type;
1457 if (manager->priv->get_proxy_type_func != NULL)
1459 object_proxy_type = manager->priv->get_proxy_type_func (manager,
1462 manager->priv->get_proxy_type_user_data);
1463 g_warn_if_fail (g_type_is_a (object_proxy_type, G_TYPE_DBUS_OBJECT_PROXY));
1467 object_proxy_type = G_TYPE_DBUS_OBJECT_PROXY;
1469 op = g_object_new (object_proxy_type,
1470 "g-connection", manager->priv->connection,
1471 "g-object-path", object_path,
1477 g_variant_iter_init (&iter, ifaces_and_properties);
1478 while (g_variant_iter_next (&iter,
1484 GType interface_proxy_type;
1486 if (manager->priv->get_proxy_type_func != NULL)
1488 interface_proxy_type = manager->priv->get_proxy_type_func (manager,
1491 manager->priv->get_proxy_type_user_data);
1492 g_warn_if_fail (g_type_is_a (interface_proxy_type, G_TYPE_DBUS_PROXY));
1496 interface_proxy_type = G_TYPE_DBUS_PROXY;
1499 /* this is fine - there is no blocking IO because we pass DO_NOT_LOAD_PROPERTIES and
1500 * DO_NOT_CONNECT_SIGNALS and use a unique name
1503 interface_proxy = g_initable_new (interface_proxy_type,
1504 NULL, /* GCancellable */
1506 "g-connection", manager->priv->connection,
1507 "g-flags", G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
1508 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
1509 "g-name", name_owner,
1510 "g-object-path", object_path,
1511 "g-interface-name", interface_name,
1513 if (interface_proxy == NULL)
1515 g_warning ("%s: Error constructing proxy for path %s and interface %s: %s",
1520 g_error_free (error);
1524 GVariantIter property_iter;
1525 const gchar *property_name;
1526 GVariant *property_value;
1528 /* associate the interface proxy with the object */
1529 g_dbus_interface_set_object (G_DBUS_INTERFACE (interface_proxy),
1530 G_DBUS_OBJECT (op));
1532 g_variant_iter_init (&property_iter, properties);
1533 while (g_variant_iter_next (&property_iter,
1538 g_dbus_proxy_set_cached_property (interface_proxy,
1541 g_variant_unref (property_value);
1544 _g_dbus_object_proxy_add_interface (op, interface_proxy);
1546 interface_added_signals = g_list_append (interface_added_signals, g_object_ref (interface_proxy));
1547 g_object_unref (interface_proxy);
1549 g_variant_unref (properties);
1554 g_hash_table_insert (manager->priv->map_object_path_to_object_proxy,
1555 g_strdup (object_path),
1559 g_mutex_unlock (&manager->priv->lock);
1561 /* now that we don't hold the lock any more, emit signals */
1562 g_object_ref (manager);
1563 for (l = interface_added_signals; l != NULL; l = l->next)
1565 interface_proxy = G_DBUS_PROXY (l->data);
1566 g_signal_emit_by_name (manager, "interface-added", op, interface_proxy);
1567 g_object_unref (interface_proxy);
1569 g_list_free (interface_added_signals);
1572 g_signal_emit_by_name (manager, "object-added", op);
1574 g_object_unref (manager);
1575 g_object_unref (op);
1579 remove_interfaces (GDBusObjectManagerClient *manager,
1580 const gchar *object_path,
1581 const gchar *const *interface_names)
1583 GDBusObjectProxy *op;
1586 guint num_interfaces;
1587 guint num_interfaces_to_remove;
1589 g_mutex_lock (&manager->priv->lock);
1591 op = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1594 g_warning ("%s: Processing InterfaceRemoved signal for path %s but no object proxy exists",
1597 g_mutex_unlock (&manager->priv->lock);
1601 interfaces = g_dbus_object_get_interfaces (G_DBUS_OBJECT (op));
1602 num_interfaces = g_list_length (interfaces);
1603 g_list_free_full (interfaces, g_object_unref);
1605 num_interfaces_to_remove = g_strv_length ((gchar **) interface_names);
1607 /* see if we are going to completety remove the object */
1608 g_object_ref (manager);
1609 if (num_interfaces_to_remove == num_interfaces)
1612 g_warn_if_fail (g_hash_table_remove (manager->priv->map_object_path_to_object_proxy, object_path));
1613 g_mutex_unlock (&manager->priv->lock);
1614 g_signal_emit_by_name (manager, "object-removed", op);
1615 g_object_unref (op);
1620 g_mutex_unlock (&manager->priv->lock);
1621 for (n = 0; interface_names != NULL && interface_names[n] != NULL; n++)
1623 GDBusInterface *interface;
1624 interface = g_dbus_object_get_interface (G_DBUS_OBJECT (op), interface_names[n]);
1625 _g_dbus_object_proxy_remove_interface (op, interface_names[n]);
1626 if (interface != NULL)
1628 g_signal_emit_by_name (manager, "interface-removed", op, interface);
1629 g_object_unref (interface);
1632 g_object_unref (op);
1634 g_object_unref (manager);
1640 process_get_all_result (GDBusObjectManagerClient *manager,
1642 const gchar *name_owner)
1645 const gchar *object_path;
1646 GVariant *ifaces_and_properties;
1649 g_return_if_fail (name_owner == NULL || g_dbus_is_unique_name (name_owner));
1651 arg0 = g_variant_get_child_value (value, 0);
1652 g_variant_iter_init (&iter, arg0);
1653 while (g_variant_iter_next (&iter,
1656 &ifaces_and_properties))
1658 add_interfaces (manager, object_path, ifaces_and_properties, name_owner);
1659 g_variant_unref (ifaces_and_properties);
1661 g_variant_unref (arg0);
1665 on_control_proxy_g_signal (GDBusProxy *proxy,
1666 const gchar *sender_name,
1667 const gchar *signal_name,
1668 GVariant *parameters,
1671 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (user_data);
1672 const gchar *object_path;
1674 //g_debug ("yay, g_signal %s: %s\n", signal_name, g_variant_print (parameters, TRUE));
1676 if (g_strcmp0 (signal_name, "InterfacesAdded") == 0)
1678 GVariant *ifaces_and_properties;
1679 g_variant_get (parameters,
1682 &ifaces_and_properties);
1683 add_interfaces (manager, object_path, ifaces_and_properties, manager->priv->name_owner);
1684 g_variant_unref (ifaces_and_properties);
1686 else if (g_strcmp0 (signal_name, "InterfacesRemoved") == 0)
1688 const gchar **ifaces;
1689 g_variant_get (parameters,
1693 remove_interfaces (manager, object_path, ifaces);
1698 /* ---------------------------------------------------------------------------------------------------- */
1700 static const gchar *
1701 g_dbus_object_manager_client_get_object_path (GDBusObjectManager *_manager)
1703 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
1704 return manager->priv->object_path;
1707 static GDBusObject *
1708 g_dbus_object_manager_client_get_object (GDBusObjectManager *_manager,
1709 const gchar *object_path)
1711 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
1714 g_mutex_lock (&manager->priv->lock);
1715 ret = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1718 g_mutex_unlock (&manager->priv->lock);
1722 static GDBusInterface *
1723 g_dbus_object_manager_client_get_interface (GDBusObjectManager *_manager,
1724 const gchar *object_path,
1725 const gchar *interface_name)
1727 GDBusInterface *ret;
1728 GDBusObject *object;
1732 object = g_dbus_object_manager_get_object (_manager, object_path);
1736 ret = g_dbus_object_get_interface (object, interface_name);
1737 g_object_unref (object);
1744 g_dbus_object_manager_client_get_objects (GDBusObjectManager *_manager)
1746 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
1749 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
1751 g_mutex_lock (&manager->priv->lock);
1752 ret = g_hash_table_get_values (manager->priv->map_object_path_to_object_proxy);
1753 g_list_foreach (ret, (GFunc) g_object_ref, NULL);
1754 g_mutex_unlock (&manager->priv->lock);
1761 dbus_object_manager_interface_init (GDBusObjectManagerIface *iface)
1763 iface->get_object_path = g_dbus_object_manager_client_get_object_path;
1764 iface->get_objects = g_dbus_object_manager_client_get_objects;
1765 iface->get_object = g_dbus_object_manager_client_get_object;
1766 iface->get_interface = g_dbus_object_manager_client_get_interface;
1769 /* ---------------------------------------------------------------------------------------------------- */