1 /* GDBus - GLib D-Bus Library
3 * Copyright (C) 2008-2010 Red Hat, Inc.
5 * SPDX-License-Identifier: LGPL-2.1-or-later
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General
18 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 * Author: David Zeuthen <davidz@redhat.com>
25 #include "gcancellable.h"
26 #include "gdbusobjectmanager.h"
27 #include "gdbusobjectmanagerclient.h"
28 #include "gdbusobject.h"
29 #include "gdbusprivate.h"
30 #include "gioenumtypes.h"
32 #include "ginitable.h"
33 #include "gasyncresult.h"
34 #include "gasyncinitable.h"
35 #include "gdbusconnection.h"
36 #include "gdbusutils.h"
37 #include "gdbusobject.h"
38 #include "gdbusobjectproxy.h"
39 #include "gdbusproxy.h"
40 #include "gdbusinterface.h"
43 #include "gmarshal-internal.h"
46 * SECTION:gdbusobjectmanagerclient
47 * @short_description: Client-side object manager
50 * #GDBusObjectManagerClient is used to create, monitor and delete object
51 * proxies for remote objects exported by a #GDBusObjectManagerServer (or any
52 * code implementing the
53 * [org.freedesktop.DBus.ObjectManager](http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager)
56 * Once an instance of this type has been created, you can connect to
57 * the #GDBusObjectManager::object-added and
58 * #GDBusObjectManager::object-removed signals and inspect the
59 * #GDBusObjectProxy objects returned by
60 * g_dbus_object_manager_get_objects().
62 * If the name for a #GDBusObjectManagerClient is not owned by anyone at
63 * object construction time, the default behavior is to request the
64 * message bus to launch an owner for the name. This behavior can be
65 * disabled using the %G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START
66 * flag. It's also worth noting that this only works if the name of
67 * interest is activatable in the first place. E.g. in some cases it
68 * is not possible to launch an owner for the requested name. In this
69 * case, #GDBusObjectManagerClient object construction still succeeds but
70 * there will be no object proxies
71 * (e.g. g_dbus_object_manager_get_objects() returns the empty list) and
72 * the #GDBusObjectManagerClient:name-owner property is %NULL.
74 * The owner of the requested name can come and go (for example
75 * consider a system service being restarted) – #GDBusObjectManagerClient
76 * handles this case too; simply connect to the #GObject::notify
77 * signal to watch for changes on the #GDBusObjectManagerClient:name-owner
78 * property. When the name owner vanishes, the behavior is that
79 * #GDBusObjectManagerClient:name-owner is set to %NULL (this includes
80 * emission of the #GObject::notify signal) and then
81 * #GDBusObjectManager::object-removed signals are synthesized
82 * for all currently existing object proxies. Since
83 * #GDBusObjectManagerClient:name-owner is %NULL when this happens, you can
84 * use this information to disambiguate a synthesized signal from a
85 * genuine signal caused by object removal on the remote
86 * #GDBusObjectManager. Similarly, when a new name owner appears,
87 * #GDBusObjectManager::object-added signals are synthesized
88 * while #GDBusObjectManagerClient:name-owner is still %NULL. Only when all
89 * object proxies have been added, the #GDBusObjectManagerClient:name-owner
90 * is set to the new name owner (this includes emission of the
91 * #GObject::notify signal). Furthermore, you are guaranteed that
92 * #GDBusObjectManagerClient:name-owner will alternate between a name owner
93 * (e.g. `:1.42`) and %NULL even in the case where
94 * the name of interest is atomically replaced
96 * Ultimately, #GDBusObjectManagerClient is used to obtain #GDBusProxy
97 * instances. All signals (including the
98 * org.freedesktop.DBus.Properties::PropertiesChanged signal)
99 * delivered to #GDBusProxy instances are guaranteed to originate
100 * from the name owner. This guarantee along with the behavior
101 * described above, means that certain race conditions including the
102 * "half the proxy is from the old owner and the other half is from
103 * the new owner" problem cannot happen.
105 * To avoid having the application connect to signals on the returned
106 * #GDBusObjectProxy and #GDBusProxy objects, the
107 * #GDBusObject::interface-added,
108 * #GDBusObject::interface-removed,
109 * #GDBusProxy::g-properties-changed and
110 * #GDBusProxy::g-signal signals
111 * are also emitted on the #GDBusObjectManagerClient instance managing these
112 * objects. The signals emitted are
113 * #GDBusObjectManager::interface-added,
114 * #GDBusObjectManager::interface-removed,
115 * #GDBusObjectManagerClient::interface-proxy-properties-changed and
116 * #GDBusObjectManagerClient::interface-proxy-signal.
118 * Note that all callbacks and signals are emitted in the
119 * [thread-default main context][g-main-context-push-thread-default]
120 * that the #GDBusObjectManagerClient object was constructed
121 * in. Additionally, the #GDBusObjectProxy and #GDBusProxy objects
122 * originating from the #GDBusObjectManagerClient object will be created in
123 * the same context and, consequently, will deliver signals in the
127 struct _GDBusObjectManagerClientPrivate
132 GDBusConnection *connection;
136 GDBusObjectManagerClientFlags flags;
138 GDBusProxy *control_proxy;
140 GHashTable *map_object_path_to_object_proxy;
142 guint signal_subscription_id;
145 GDBusProxyTypeFunc get_proxy_type_func;
146 gpointer get_proxy_type_user_data;
147 GDestroyNotify get_proxy_type_destroy_notify;
149 gulong name_owner_signal_id;
150 gulong signal_signal_id;
151 GCancellable *cancel;
163 PROP_GET_PROXY_TYPE_FUNC,
164 PROP_GET_PROXY_TYPE_USER_DATA,
165 PROP_GET_PROXY_TYPE_DESTROY_NOTIFY
170 INTERFACE_PROXY_SIGNAL_SIGNAL,
171 INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL,
175 static guint signals[LAST_SIGNAL] = { 0 };
177 static void initable_iface_init (GInitableIface *initable_iface);
178 static void async_initable_iface_init (GAsyncInitableIface *async_initable_iface);
179 static void dbus_object_manager_interface_init (GDBusObjectManagerIface *iface);
181 G_DEFINE_TYPE_WITH_CODE (GDBusObjectManagerClient, g_dbus_object_manager_client, G_TYPE_OBJECT,
182 G_ADD_PRIVATE (GDBusObjectManagerClient)
183 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)
184 G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init)
185 G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_OBJECT_MANAGER, dbus_object_manager_interface_init))
187 static void maybe_unsubscribe_signals (GDBusObjectManagerClient *manager);
189 static void on_control_proxy_g_signal (GDBusProxy *proxy,
190 const gchar *sender_name,
191 const gchar *signal_name,
192 GVariant *parameters,
195 static void process_get_all_result (GDBusObjectManagerClient *manager,
197 const gchar *name_owner);
200 g_dbus_object_manager_client_dispose (GObject *object)
202 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (object);
204 if (manager->priv->cancel != NULL)
206 g_cancellable_cancel (manager->priv->cancel);
207 g_clear_object (&manager->priv->cancel);
210 G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class)->dispose (object);
214 g_dbus_object_manager_client_finalize (GObject *object)
216 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (object);
218 maybe_unsubscribe_signals (manager);
220 g_hash_table_unref (manager->priv->map_object_path_to_object_proxy);
222 if (manager->priv->control_proxy != NULL && manager->priv->signal_signal_id != 0)
223 g_signal_handler_disconnect (manager->priv->control_proxy,
224 manager->priv->signal_signal_id);
225 manager->priv->signal_signal_id = 0;
227 if (manager->priv->control_proxy != NULL && manager->priv->name_owner_signal_id != 0)
228 g_signal_handler_disconnect (manager->priv->control_proxy,
229 manager->priv->name_owner_signal_id);
230 manager->priv->name_owner_signal_id = 0;
232 g_clear_object (&manager->priv->control_proxy);
234 if (manager->priv->connection != NULL)
235 g_object_unref (manager->priv->connection);
236 g_free (manager->priv->object_path);
237 g_free (manager->priv->name);
238 g_free (manager->priv->name_owner);
240 if (manager->priv->get_proxy_type_destroy_notify != NULL)
241 manager->priv->get_proxy_type_destroy_notify (manager->priv->get_proxy_type_user_data);
243 g_mutex_clear (&manager->priv->lock);
245 if (G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class)->finalize != NULL)
246 G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class)->finalize (object);
250 g_dbus_object_manager_client_get_property (GObject *_object,
255 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_object);
259 case PROP_CONNECTION:
260 g_value_set_object (value, g_dbus_object_manager_client_get_connection (manager));
263 case PROP_OBJECT_PATH:
264 g_value_set_string (value, g_dbus_object_manager_get_object_path (G_DBUS_OBJECT_MANAGER (manager)));
268 g_value_set_string (value, g_dbus_object_manager_client_get_name (manager));
272 g_value_set_flags (value, g_dbus_object_manager_client_get_flags (manager));
275 case PROP_NAME_OWNER:
276 g_value_take_string (value, g_dbus_object_manager_client_get_name_owner (manager));
280 G_OBJECT_WARN_INVALID_PROPERTY_ID (manager, prop_id, pspec);
286 g_dbus_object_manager_client_set_property (GObject *_object,
291 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_object);
297 manager->priv->bus_type = g_value_get_enum (value);
300 case PROP_CONNECTION:
301 if (g_value_get_object (value) != NULL)
303 g_assert (manager->priv->connection == NULL);
304 g_assert (G_IS_DBUS_CONNECTION (g_value_get_object (value)));
305 manager->priv->connection = g_value_dup_object (value);
309 case PROP_OBJECT_PATH:
310 g_assert (manager->priv->object_path == NULL);
311 g_assert (g_variant_is_object_path (g_value_get_string (value)));
312 manager->priv->object_path = g_value_dup_string (value);
316 g_assert (manager->priv->name == NULL);
317 name = g_value_get_string (value);
318 g_assert (name == NULL || g_dbus_is_name (name));
319 manager->priv->name = g_strdup (name);
323 manager->priv->flags = g_value_get_flags (value);
326 case PROP_GET_PROXY_TYPE_FUNC:
327 manager->priv->get_proxy_type_func = g_value_get_pointer (value);
330 case PROP_GET_PROXY_TYPE_USER_DATA:
331 manager->priv->get_proxy_type_user_data = g_value_get_pointer (value);
334 case PROP_GET_PROXY_TYPE_DESTROY_NOTIFY:
335 manager->priv->get_proxy_type_destroy_notify = g_value_get_pointer (value);
339 G_OBJECT_WARN_INVALID_PROPERTY_ID (manager, prop_id, pspec);
345 g_dbus_object_manager_client_class_init (GDBusObjectManagerClientClass *klass)
347 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
349 gobject_class->dispose = g_dbus_object_manager_client_dispose;
350 gobject_class->finalize = g_dbus_object_manager_client_finalize;
351 gobject_class->set_property = g_dbus_object_manager_client_set_property;
352 gobject_class->get_property = g_dbus_object_manager_client_get_property;
355 * GDBusObjectManagerClient:connection:
357 * The #GDBusConnection to use.
361 g_object_class_install_property (gobject_class,
363 g_param_spec_object ("connection",
365 "The connection to use",
366 G_TYPE_DBUS_CONNECTION,
369 G_PARAM_CONSTRUCT_ONLY |
370 G_PARAM_STATIC_STRINGS));
373 * GDBusObjectManagerClient:bus-type:
375 * If this property is not %G_BUS_TYPE_NONE, then
376 * #GDBusObjectManagerClient:connection must be %NULL and will be set to the
377 * #GDBusConnection obtained by calling g_bus_get() with the value
382 g_object_class_install_property (gobject_class,
384 g_param_spec_enum ("bus-type",
386 "The bus to connect to, if any",
390 G_PARAM_CONSTRUCT_ONLY |
391 G_PARAM_STATIC_NAME |
392 G_PARAM_STATIC_BLURB |
393 G_PARAM_STATIC_NICK));
396 * GDBusObjectManagerClient:flags:
398 * Flags from the #GDBusObjectManagerClientFlags enumeration.
402 g_object_class_install_property (gobject_class,
404 g_param_spec_flags ("flags",
406 "Flags for the proxy manager",
407 G_TYPE_DBUS_OBJECT_MANAGER_CLIENT_FLAGS,
408 G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
411 G_PARAM_CONSTRUCT_ONLY |
412 G_PARAM_STATIC_NAME |
413 G_PARAM_STATIC_BLURB |
414 G_PARAM_STATIC_NICK));
417 * GDBusObjectManagerClient:object-path:
419 * The object path the manager is for.
423 g_object_class_install_property (gobject_class,
425 g_param_spec_string ("object-path",
427 "The object path of the control object",
431 G_PARAM_CONSTRUCT_ONLY |
432 G_PARAM_STATIC_STRINGS));
435 * GDBusObjectManagerClient:name:
437 * The well-known name or unique name that the manager is for.
441 g_object_class_install_property (gobject_class,
443 g_param_spec_string ("name",
445 "Name that the manager is for",
449 G_PARAM_CONSTRUCT_ONLY |
450 G_PARAM_STATIC_STRINGS));
453 * GDBusObjectManagerClient:name-owner:
455 * The unique name that owns #GDBusObjectManagerClient:name or %NULL if
456 * no-one is currently owning the name. Connect to the
457 * #GObject::notify signal to track changes to this property.
461 g_object_class_install_property (gobject_class,
463 g_param_spec_string ("name-owner",
465 "The owner of the name we are watching",
468 G_PARAM_STATIC_STRINGS));
471 * GDBusObjectManagerClient:get-proxy-type-func:
473 * The #GDBusProxyTypeFunc to use when determining what #GType to
474 * use for interface proxies or %NULL.
478 g_object_class_install_property (gobject_class,
479 PROP_GET_PROXY_TYPE_FUNC,
480 g_param_spec_pointer ("get-proxy-type-func",
481 "GDBusProxyTypeFunc Function Pointer",
482 "The GDBusProxyTypeFunc pointer to use",
485 G_PARAM_CONSTRUCT_ONLY |
486 G_PARAM_STATIC_STRINGS));
489 * GDBusObjectManagerClient:get-proxy-type-user-data:
491 * The #gpointer user_data to pass to #GDBusObjectManagerClient:get-proxy-type-func.
495 g_object_class_install_property (gobject_class,
496 PROP_GET_PROXY_TYPE_USER_DATA,
497 g_param_spec_pointer ("get-proxy-type-user-data",
498 "GDBusProxyTypeFunc User Data",
499 "The GDBusProxyTypeFunc user_data",
502 G_PARAM_CONSTRUCT_ONLY |
503 G_PARAM_STATIC_STRINGS));
506 * GDBusObjectManagerClient:get-proxy-type-destroy-notify:
508 * A #GDestroyNotify for the #gpointer user_data in #GDBusObjectManagerClient:get-proxy-type-user-data.
512 g_object_class_install_property (gobject_class,
513 PROP_GET_PROXY_TYPE_DESTROY_NOTIFY,
514 g_param_spec_pointer ("get-proxy-type-destroy-notify",
515 "GDBusProxyTypeFunc user data free function",
516 "The GDBusProxyTypeFunc user data free function",
519 G_PARAM_CONSTRUCT_ONLY |
520 G_PARAM_STATIC_STRINGS));
523 * GDBusObjectManagerClient::interface-proxy-signal:
524 * @manager: The #GDBusObjectManagerClient emitting the signal.
525 * @object_proxy: The #GDBusObjectProxy on which an interface is emitting a D-Bus signal.
526 * @interface_proxy: The #GDBusProxy that is emitting a D-Bus signal.
527 * @sender_name: The sender of the signal or NULL if the connection is not a bus connection.
528 * @signal_name: The signal name.
529 * @parameters: A #GVariant tuple with parameters for the signal.
531 * Emitted when a D-Bus signal is received on @interface_proxy.
533 * This signal exists purely as a convenience to avoid having to
534 * connect signals to all interface proxies managed by @manager.
536 * This signal is emitted in the
537 * [thread-default main context][g-main-context-push-thread-default]
538 * that @manager was constructed in.
542 signals[INTERFACE_PROXY_SIGNAL_SIGNAL] =
543 g_signal_new (I_("interface-proxy-signal"),
544 G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
546 G_STRUCT_OFFSET (GDBusObjectManagerClientClass, interface_proxy_signal),
549 _g_cclosure_marshal_VOID__OBJECT_OBJECT_STRING_STRING_VARIANT,
552 G_TYPE_DBUS_OBJECT_PROXY,
557 g_signal_set_va_marshaller (signals[INTERFACE_PROXY_SIGNAL_SIGNAL],
558 G_TYPE_FROM_CLASS (klass),
559 _g_cclosure_marshal_VOID__OBJECT_OBJECT_STRING_STRING_VARIANTv);
562 * GDBusObjectManagerClient::interface-proxy-properties-changed:
563 * @manager: The #GDBusObjectManagerClient emitting the signal.
564 * @object_proxy: The #GDBusObjectProxy on which an interface has properties that are changing.
565 * @interface_proxy: The #GDBusProxy that has properties that are changing.
566 * @changed_properties: A #GVariant containing the properties that changed (type: `a{sv}`).
567 * @invalidated_properties: (array zero-terminated=1) (element-type utf8): A %NULL terminated
568 * array of properties that were invalidated.
570 * Emitted when one or more D-Bus properties on proxy changes. The
571 * local cache has already been updated when this signal fires. Note
572 * that both @changed_properties and @invalidated_properties are
573 * guaranteed to never be %NULL (either may be empty though).
575 * This signal exists purely as a convenience to avoid having to
576 * connect signals to all interface proxies managed by @manager.
578 * This signal is emitted in the
579 * [thread-default main context][g-main-context-push-thread-default]
580 * that @manager was constructed in.
584 signals[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL] =
585 g_signal_new (I_("interface-proxy-properties-changed"),
586 G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
588 G_STRUCT_OFFSET (GDBusObjectManagerClientClass, interface_proxy_properties_changed),
591 _g_cclosure_marshal_VOID__OBJECT_OBJECT_VARIANT_BOXED,
594 G_TYPE_DBUS_OBJECT_PROXY,
598 g_signal_set_va_marshaller (signals[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL],
599 G_TYPE_FROM_CLASS (klass),
600 _g_cclosure_marshal_VOID__OBJECT_OBJECT_VARIANT_BOXEDv);
604 g_dbus_object_manager_client_init (GDBusObjectManagerClient *manager)
606 manager->priv = g_dbus_object_manager_client_get_instance_private (manager);
607 g_mutex_init (&manager->priv->lock);
608 manager->priv->map_object_path_to_object_proxy = g_hash_table_new_full (g_str_hash,
611 (GDestroyNotify) g_object_unref);
612 manager->priv->cancel = g_cancellable_new ();
615 /* ---------------------------------------------------------------------------------------------------- */
618 * g_dbus_object_manager_client_new_sync:
619 * @connection: A #GDBusConnection.
620 * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
621 * @name: (nullable): The owner of the control object (unique or well-known name), or %NULL when not using a message bus connection.
622 * @object_path: The object path of the control object.
623 * @get_proxy_type_func: (nullable): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
624 * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
625 * @get_proxy_type_destroy_notify: (nullable): Free function for @get_proxy_type_user_data or %NULL.
626 * @cancellable: (nullable): A #GCancellable or %NULL
627 * @error: Return location for error or %NULL.
629 * Creates a new #GDBusObjectManagerClient object.
631 * This is a synchronous failable constructor - the calling thread is
632 * blocked until a reply is received. See g_dbus_object_manager_client_new()
633 * for the asynchronous version.
635 * Returns: (transfer full) (type GDBusObjectManagerClient): A
636 * #GDBusObjectManagerClient object or %NULL if @error is set. Free
637 * with g_object_unref().
642 g_dbus_object_manager_client_new_sync (GDBusConnection *connection,
643 GDBusObjectManagerClientFlags flags,
645 const gchar *object_path,
646 GDBusProxyTypeFunc get_proxy_type_func,
647 gpointer get_proxy_type_user_data,
648 GDestroyNotify get_proxy_type_destroy_notify,
649 GCancellable *cancellable,
654 g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
655 g_return_val_if_fail ((name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) ||
656 g_dbus_is_name (name), NULL);
657 g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
658 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
660 initable = g_initable_new (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
663 "connection", connection,
666 "object-path", object_path,
667 "get-proxy-type-func", get_proxy_type_func,
668 "get-proxy-type-user-data", get_proxy_type_user_data,
669 "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
671 if (initable != NULL)
672 return G_DBUS_OBJECT_MANAGER (initable);
678 * g_dbus_object_manager_client_new:
679 * @connection: A #GDBusConnection.
680 * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
681 * @name: The owner of the control object (unique or well-known name).
682 * @object_path: The object path of the control object.
683 * @get_proxy_type_func: (nullable): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
684 * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
685 * @get_proxy_type_destroy_notify: (nullable): Free function for @get_proxy_type_user_data or %NULL.
686 * @cancellable: (nullable): A #GCancellable or %NULL
687 * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
688 * @user_data: The data to pass to @callback.
690 * Asynchronously creates a new #GDBusObjectManagerClient object.
692 * This is an asynchronous failable constructor. When the result is
693 * ready, @callback will be invoked in the
694 * [thread-default main context][g-main-context-push-thread-default]
695 * of the thread you are calling this method from. You can
696 * then call g_dbus_object_manager_client_new_finish() to get the result. See
697 * g_dbus_object_manager_client_new_sync() for the synchronous version.
702 g_dbus_object_manager_client_new (GDBusConnection *connection,
703 GDBusObjectManagerClientFlags flags,
705 const gchar *object_path,
706 GDBusProxyTypeFunc get_proxy_type_func,
707 gpointer get_proxy_type_user_data,
708 GDestroyNotify get_proxy_type_destroy_notify,
709 GCancellable *cancellable,
710 GAsyncReadyCallback callback,
713 g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
714 g_return_if_fail ((name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) ||
715 g_dbus_is_name (name));
716 g_return_if_fail (g_variant_is_object_path (object_path));
718 g_async_initable_new_async (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
723 "connection", connection,
726 "object-path", object_path,
727 "get-proxy-type-func", get_proxy_type_func,
728 "get-proxy-type-user-data", get_proxy_type_user_data,
729 "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
734 * g_dbus_object_manager_client_new_finish:
735 * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_object_manager_client_new().
736 * @error: Return location for error or %NULL.
738 * Finishes an operation started with g_dbus_object_manager_client_new().
740 * Returns: (transfer full) (type GDBusObjectManagerClient): A
741 * #GDBusObjectManagerClient object or %NULL if @error is set. Free
742 * with g_object_unref().
747 g_dbus_object_manager_client_new_finish (GAsyncResult *res,
751 GObject *source_object;
753 source_object = g_async_result_get_source_object (res);
754 g_assert (source_object != NULL);
756 object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
759 g_object_unref (source_object);
762 return G_DBUS_OBJECT_MANAGER (object);
767 /* ---------------------------------------------------------------------------------------------------- */
770 * g_dbus_object_manager_client_new_for_bus_sync:
771 * @bus_type: A #GBusType.
772 * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
773 * @name: The owner of the control object (unique or well-known name).
774 * @object_path: The object path of the control object.
775 * @get_proxy_type_func: (nullable): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
776 * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
777 * @get_proxy_type_destroy_notify: (nullable): Free function for @get_proxy_type_user_data or %NULL.
778 * @cancellable: (nullable): A #GCancellable or %NULL
779 * @error: Return location for error or %NULL.
781 * Like g_dbus_object_manager_client_new_sync() but takes a #GBusType instead
782 * of a #GDBusConnection.
784 * This is a synchronous failable constructor - the calling thread is
785 * blocked until a reply is received. See g_dbus_object_manager_client_new_for_bus()
786 * for the asynchronous version.
788 * Returns: (transfer full) (type GDBusObjectManagerClient): A
789 * #GDBusObjectManagerClient object or %NULL if @error is set. Free
790 * with g_object_unref().
795 g_dbus_object_manager_client_new_for_bus_sync (GBusType bus_type,
796 GDBusObjectManagerClientFlags flags,
798 const gchar *object_path,
799 GDBusProxyTypeFunc get_proxy_type_func,
800 gpointer get_proxy_type_user_data,
801 GDestroyNotify get_proxy_type_destroy_notify,
802 GCancellable *cancellable,
807 g_return_val_if_fail (bus_type != G_BUS_TYPE_NONE, NULL);
808 g_return_val_if_fail (g_dbus_is_name (name), NULL);
809 g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
810 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
812 initable = g_initable_new (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
815 "bus-type", bus_type,
818 "object-path", object_path,
819 "get-proxy-type-func", get_proxy_type_func,
820 "get-proxy-type-user-data", get_proxy_type_user_data,
821 "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
823 if (initable != NULL)
824 return G_DBUS_OBJECT_MANAGER (initable);
830 * g_dbus_object_manager_client_new_for_bus:
831 * @bus_type: A #GBusType.
832 * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
833 * @name: The owner of the control object (unique or well-known name).
834 * @object_path: The object path of the control object.
835 * @get_proxy_type_func: (nullable): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
836 * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
837 * @get_proxy_type_destroy_notify: (nullable): Free function for @get_proxy_type_user_data or %NULL.
838 * @cancellable: (nullable): A #GCancellable or %NULL
839 * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
840 * @user_data: The data to pass to @callback.
842 * Like g_dbus_object_manager_client_new() but takes a #GBusType instead of a
845 * This is an asynchronous failable constructor. When the result is
846 * ready, @callback will be invoked in the
847 * [thread-default main loop][g-main-context-push-thread-default]
848 * of the thread you are calling this method from. You can
849 * then call g_dbus_object_manager_client_new_for_bus_finish() to get the result. See
850 * g_dbus_object_manager_client_new_for_bus_sync() for the synchronous version.
855 g_dbus_object_manager_client_new_for_bus (GBusType bus_type,
856 GDBusObjectManagerClientFlags flags,
858 const gchar *object_path,
859 GDBusProxyTypeFunc get_proxy_type_func,
860 gpointer get_proxy_type_user_data,
861 GDestroyNotify get_proxy_type_destroy_notify,
862 GCancellable *cancellable,
863 GAsyncReadyCallback callback,
866 g_return_if_fail (bus_type != G_BUS_TYPE_NONE);
867 g_return_if_fail (g_dbus_is_name (name));
868 g_return_if_fail (g_variant_is_object_path (object_path));
870 g_async_initable_new_async (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
875 "bus-type", bus_type,
878 "object-path", object_path,
879 "get-proxy-type-func", get_proxy_type_func,
880 "get-proxy-type-user-data", get_proxy_type_user_data,
881 "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
886 * g_dbus_object_manager_client_new_for_bus_finish:
887 * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_object_manager_client_new_for_bus().
888 * @error: Return location for error or %NULL.
890 * Finishes an operation started with g_dbus_object_manager_client_new_for_bus().
892 * Returns: (transfer full) (type GDBusObjectManagerClient): A
893 * #GDBusObjectManagerClient object or %NULL if @error is set. Free
894 * with g_object_unref().
899 g_dbus_object_manager_client_new_for_bus_finish (GAsyncResult *res,
903 GObject *source_object;
905 source_object = g_async_result_get_source_object (res);
906 g_assert (source_object != NULL);
908 object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
911 g_object_unref (source_object);
914 return G_DBUS_OBJECT_MANAGER (object);
919 /* ---------------------------------------------------------------------------------------------------- */
922 * g_dbus_object_manager_client_get_connection:
923 * @manager: A #GDBusObjectManagerClient
925 * Gets the #GDBusConnection used by @manager.
927 * Returns: (transfer none): A #GDBusConnection object. Do not free,
928 * the object belongs to @manager.
933 g_dbus_object_manager_client_get_connection (GDBusObjectManagerClient *manager)
935 GDBusConnection *ret;
936 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
937 g_mutex_lock (&manager->priv->lock);
938 ret = manager->priv->connection;
939 g_mutex_unlock (&manager->priv->lock);
944 * g_dbus_object_manager_client_get_name:
945 * @manager: A #GDBusObjectManagerClient
947 * Gets the name that @manager is for, or %NULL if not a message bus
950 * Returns: A unique or well-known name. Do not free, the string
951 * belongs to @manager.
956 g_dbus_object_manager_client_get_name (GDBusObjectManagerClient *manager)
959 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
960 g_mutex_lock (&manager->priv->lock);
961 ret = manager->priv->name;
962 g_mutex_unlock (&manager->priv->lock);
967 * g_dbus_object_manager_client_get_flags:
968 * @manager: A #GDBusObjectManagerClient
970 * Gets the flags that @manager was constructed with.
972 * Returns: Zero of more flags from the #GDBusObjectManagerClientFlags
977 GDBusObjectManagerClientFlags
978 g_dbus_object_manager_client_get_flags (GDBusObjectManagerClient *manager)
980 GDBusObjectManagerClientFlags ret;
981 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE);
982 g_mutex_lock (&manager->priv->lock);
983 ret = manager->priv->flags;
984 g_mutex_unlock (&manager->priv->lock);
989 * g_dbus_object_manager_client_get_name_owner:
990 * @manager: A #GDBusObjectManagerClient.
992 * The unique name that owns the name that @manager is for or %NULL if
993 * no-one currently owns that name. You can connect to the
994 * #GObject::notify signal to track changes to the
995 * #GDBusObjectManagerClient:name-owner property.
997 * Returns: (nullable): The name owner or %NULL if no name owner
998 * exists. Free with g_free().
1003 g_dbus_object_manager_client_get_name_owner (GDBusObjectManagerClient *manager)
1006 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
1007 g_mutex_lock (&manager->priv->lock);
1008 ret = g_strdup (manager->priv->name_owner);
1009 g_mutex_unlock (&manager->priv->lock);
1013 /* ---------------------------------------------------------------------------------------------------- */
1015 /* signal handler for all objects we manage - we dispatch signals
1016 * from here to the objects
1019 signal_cb (GDBusConnection *connection,
1020 const gchar *sender_name,
1021 const gchar *object_path,
1022 const gchar *interface_name,
1023 const gchar *signal_name,
1024 GVariant *parameters,
1027 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (user_data);
1028 GDBusObjectProxy *object_proxy;
1029 GDBusInterface *interface;
1031 g_mutex_lock (&manager->priv->lock);
1032 object_proxy = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1033 if (object_proxy == NULL)
1035 g_mutex_unlock (&manager->priv->lock);
1038 g_object_ref (object_proxy);
1039 g_mutex_unlock (&manager->priv->lock);
1041 //g_debug ("yay, signal_cb %s %s: %s\n", signal_name, object_path, g_variant_print (parameters, TRUE));
1043 g_object_ref (manager);
1044 if (g_strcmp0 (interface_name, "org.freedesktop.DBus.Properties") == 0)
1046 if (g_strcmp0 (signal_name, "PropertiesChanged") == 0)
1048 const gchar *properties_interface_name;
1049 GVariant *changed_properties;
1050 const gchar **invalidated_properties;
1052 g_variant_get (parameters,
1054 &properties_interface_name,
1055 &changed_properties,
1056 &invalidated_properties);
1058 interface = g_dbus_object_get_interface (G_DBUS_OBJECT (object_proxy), properties_interface_name);
1059 if (interface != NULL)
1061 GVariantIter property_iter;
1062 const gchar *property_name;
1063 GVariant *property_value;
1066 /* update caches... */
1067 g_variant_iter_init (&property_iter, changed_properties);
1068 while (g_variant_iter_next (&property_iter,
1073 g_dbus_proxy_set_cached_property (G_DBUS_PROXY (interface),
1076 g_variant_unref (property_value);
1079 for (n = 0; invalidated_properties[n] != NULL; n++)
1081 g_dbus_proxy_set_cached_property (G_DBUS_PROXY (interface),
1082 invalidated_properties[n],
1085 /* ... and then synthesize the signal */
1086 g_signal_emit_by_name (interface,
1087 "g-properties-changed",
1089 invalidated_properties);
1090 g_signal_emit (manager,
1091 signals[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL],
1096 invalidated_properties);
1097 g_object_unref (interface);
1099 g_variant_unref (changed_properties);
1100 g_free (invalidated_properties);
1105 /* regular signal - just dispatch it */
1106 interface = g_dbus_object_get_interface (G_DBUS_OBJECT (object_proxy), interface_name);
1107 if (interface != NULL)
1109 g_signal_emit_by_name (interface,
1114 g_signal_emit (manager,
1115 signals[INTERFACE_PROXY_SIGNAL_SIGNAL],
1122 g_object_unref (interface);
1125 g_object_unref (manager);
1128 g_clear_object (&object_proxy);
1132 subscribe_signals (GDBusObjectManagerClient *manager,
1133 const gchar *name_owner)
1135 GError *error = NULL;
1138 g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager));
1139 g_return_if_fail (manager->priv->signal_subscription_id == 0);
1140 g_return_if_fail (name_owner == NULL || g_dbus_is_unique_name (name_owner));
1142 if (name_owner != NULL)
1144 /* Only add path_namespace if it's non-'/'. This removes a no-op key from
1145 * the match rule, and also works around a D-Bus bug where
1146 * path_namespace='/' matches nothing in D-Bus versions < 1.6.18.
1148 * See: https://bugs.freedesktop.org/show_bug.cgi?id=70799 */
1149 if (g_str_equal (manager->priv->object_path, "/"))
1151 manager->priv->match_rule = g_strdup_printf ("type='signal',sender='%s'",
1156 manager->priv->match_rule = g_strdup_printf ("type='signal',sender='%s',path_namespace='%s'",
1157 name_owner, manager->priv->object_path);
1160 /* The bus daemon may not implement path_namespace so gracefully
1161 * handle this by using a fallback triggered if @error is set. */
1162 ret = g_dbus_connection_call_sync (manager->priv->connection,
1163 "org.freedesktop.DBus",
1164 "/org/freedesktop/DBus",
1165 "org.freedesktop.DBus",
1167 g_variant_new ("(s)",
1168 manager->priv->match_rule),
1169 NULL, /* reply_type */
1170 G_DBUS_CALL_FLAGS_NONE,
1171 -1, /* default timeout */
1172 NULL, /* TODO: Cancellable */
1175 /* yay, bus daemon supports path_namespace */
1177 g_variant_unref (ret);
1182 /* still need to ask GDBusConnection for the callbacks */
1183 manager->priv->signal_subscription_id =
1184 g_dbus_connection_signal_subscribe (manager->priv->connection,
1186 NULL, /* interface */
1188 NULL, /* path - TODO: really want wildcard support here */
1190 G_DBUS_SIGNAL_FLAGS_NONE |
1191 G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
1194 NULL); /* user_data_free_func */
1199 /* TODO: we could report this to the user
1200 g_warning ("Message bus daemon does not support path_namespace: %s (%s %d)",
1202 g_quark_to_string (error->domain),
1206 g_error_free (error);
1208 /* no need to call RemoveMatch when done since it didn't work */
1209 g_free (manager->priv->match_rule);
1210 manager->priv->match_rule = NULL;
1212 /* Fallback is to subscribe to *all* signals from the name owner which
1213 * is rather wasteful. It's probably not a big practical problem because
1214 * users typically want all objects that the name owner supplies.
1216 manager->priv->signal_subscription_id =
1217 g_dbus_connection_signal_subscribe (manager->priv->connection,
1219 NULL, /* interface */
1221 NULL, /* path - TODO: really want wildcard support here */
1223 G_DBUS_SIGNAL_FLAGS_NONE,
1226 NULL); /* user_data_free_func */
1231 maybe_unsubscribe_signals (GDBusObjectManagerClient *manager)
1233 g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager));
1235 if (manager->priv->signal_subscription_id > 0)
1237 g_dbus_connection_signal_unsubscribe (manager->priv->connection,
1238 manager->priv->signal_subscription_id);
1239 manager->priv->signal_subscription_id = 0;
1242 if (manager->priv->match_rule != NULL)
1244 /* Since the AddMatch call succeeded this is guaranteed to not
1245 * fail - therefore, don't bother checking the return value
1247 g_dbus_connection_call (manager->priv->connection,
1248 "org.freedesktop.DBus",
1249 "/org/freedesktop/DBus",
1250 "org.freedesktop.DBus",
1252 g_variant_new ("(s)",
1253 manager->priv->match_rule),
1254 NULL, /* reply_type */
1255 G_DBUS_CALL_FLAGS_NONE,
1256 -1, /* default timeout */
1257 NULL, /* GCancellable */
1258 NULL, /* GAsyncReadyCallback */
1259 NULL); /* user data */
1260 g_free (manager->priv->match_rule);
1261 manager->priv->match_rule = NULL;
1266 /* ---------------------------------------------------------------------------------------------------- */
1269 weak_ref_new (GObject *object)
1271 GWeakRef *weak_ref = g_new0 (GWeakRef, 1);
1272 g_weak_ref_init (weak_ref, object);
1273 return g_steal_pointer (&weak_ref);
1277 weak_ref_free (GWeakRef *weak_ref)
1279 g_weak_ref_clear (weak_ref);
1284 on_get_managed_objects_finish (GObject *source,
1285 GAsyncResult *result,
1289 GDBusProxy *proxy = G_DBUS_PROXY (source);
1290 GWeakRef *manager_weak = user_data;
1291 GDBusObjectManagerClient *manager;
1292 GError *error = NULL;
1293 GVariant *value = NULL;
1294 gchar *new_name_owner = NULL;
1296 value = g_dbus_proxy_call_finish (proxy, result, &error);
1298 manager = G_DBUS_OBJECT_MANAGER_CLIENT (g_weak_ref_get (manager_weak));
1299 /* Manager got disposed, nothing to do */
1300 if (manager == NULL)
1305 new_name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy);
1308 maybe_unsubscribe_signals (manager);
1309 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
1311 g_warning ("Error calling GetManagedObjects() when name owner %s for name %s came back: %s",
1313 manager->priv->name,
1319 process_get_all_result (manager, value, new_name_owner);
1322 /* do the :name-owner notify *AFTER* emitting ::object-proxy-added signals - this
1323 * way the user knows that the signals were emitted because the name owner came back
1325 g_mutex_lock (&manager->priv->lock);
1326 manager->priv->name_owner = g_steal_pointer (&new_name_owner);
1327 g_mutex_unlock (&manager->priv->lock);
1328 g_object_notify (G_OBJECT (manager), "name-owner");
1330 g_object_unref (manager);
1332 g_clear_error (&error);
1333 g_clear_pointer (&value, g_variant_unref);
1334 weak_ref_free (manager_weak);
1338 on_notify_g_name_owner (GObject *object,
1342 GWeakRef *manager_weak = user_data;
1343 GDBusObjectManagerClient *manager = NULL;
1344 gchar *old_name_owner;
1345 gchar *new_name_owner;
1347 manager = G_DBUS_OBJECT_MANAGER_CLIENT (g_weak_ref_get (manager_weak));
1348 if (manager == NULL)
1351 g_mutex_lock (&manager->priv->lock);
1352 old_name_owner = manager->priv->name_owner;
1353 new_name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy);
1354 manager->priv->name_owner = NULL;
1356 if (g_strcmp0 (old_name_owner, new_name_owner) != 0)
1360 /* remote manager changed; nuke all local proxies */
1361 proxies = g_hash_table_steal_all_values (
1362 manager->priv->map_object_path_to_object_proxy);
1364 g_mutex_unlock (&manager->priv->lock);
1366 /* do the :name-owner notify with a NULL name - this way the user knows
1367 * the ::object-proxy-removed following is because the name owner went
1370 g_object_notify (G_OBJECT (manager), "name-owner");
1372 for (guint i = 0; i < proxies->len; ++i)
1374 GDBusObjectProxy *object_proxy =
1375 G_DBUS_OBJECT_PROXY (g_ptr_array_index (proxies, i));
1376 g_signal_emit_by_name (manager, "object-removed", object_proxy);
1378 g_clear_pointer (&proxies, g_ptr_array_unref);
1380 /* nuke local filter */
1381 maybe_unsubscribe_signals (manager);
1385 g_mutex_unlock (&manager->priv->lock);
1388 if (new_name_owner != NULL)
1390 //g_debug ("repopulating for %s", new_name_owner);
1392 subscribe_signals (manager,
1394 g_dbus_proxy_call (manager->priv->control_proxy,
1395 "GetManagedObjects",
1396 NULL, /* parameters */
1397 G_DBUS_CALL_FLAGS_NONE,
1399 manager->priv->cancel,
1400 on_get_managed_objects_finish,
1401 weak_ref_new (G_OBJECT (manager)));
1403 g_free (new_name_owner);
1404 g_free (old_name_owner);
1405 g_object_unref (manager);
1409 initable_init (GInitable *initable,
1410 GCancellable *cancellable,
1413 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (initable);
1416 GDBusProxyFlags proxy_flags;
1420 if (manager->priv->bus_type != G_BUS_TYPE_NONE)
1422 g_assert (manager->priv->connection == NULL);
1423 manager->priv->connection = g_bus_get_sync (manager->priv->bus_type, cancellable, error);
1424 if (manager->priv->connection == NULL)
1428 proxy_flags = G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES;
1429 if (manager->priv->flags & G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START)
1430 proxy_flags |= G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START;
1432 manager->priv->control_proxy = g_dbus_proxy_new_sync (manager->priv->connection,
1434 NULL, /* GDBusInterfaceInfo* */
1435 manager->priv->name,
1436 manager->priv->object_path,
1437 "org.freedesktop.DBus.ObjectManager",
1440 if (manager->priv->control_proxy == NULL)
1443 /* Use weak refs here. The @control_proxy will emit its signals in the current
1444 * #GMainContext (since we constructed it just above). However, the user may
1445 * drop the last external reference to this #GDBusObjectManagerClient in
1446 * another thread between a signal being emitted and scheduled in an idle
1447 * callback in this #GMainContext, and that idle callback being invoked. We
1448 * can’t use a strong reference here, as there’s no
1449 * g_dbus_object_manager_client_disconnect() (or similar) method to tell us
1450 * when the last external reference to this object has been dropped, so we
1451 * can’t break a strong reference count cycle. So use weak refs. */
1452 manager->priv->name_owner_signal_id =
1453 g_signal_connect_data (G_OBJECT (manager->priv->control_proxy),
1454 "notify::g-name-owner",
1455 G_CALLBACK (on_notify_g_name_owner),
1456 weak_ref_new (G_OBJECT (manager)),
1457 (GClosureNotify) weak_ref_free,
1460 manager->priv->signal_signal_id =
1461 g_signal_connect_data (manager->priv->control_proxy,
1463 G_CALLBACK (on_control_proxy_g_signal),
1464 weak_ref_new (G_OBJECT (manager)),
1465 (GClosureNotify) weak_ref_free,
1468 manager->priv->name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy);
1469 if (manager->priv->name_owner == NULL && manager->priv->name != NULL)
1471 /* it's perfectly fine if there's no name owner.. we're just going to
1472 * wait until one is ready
1477 /* yay, we can get the objects */
1478 subscribe_signals (manager,
1479 manager->priv->name_owner);
1480 value = g_dbus_proxy_call_sync (manager->priv->control_proxy,
1481 "GetManagedObjects",
1482 NULL, /* parameters */
1483 G_DBUS_CALL_FLAGS_NONE,
1489 maybe_unsubscribe_signals (manager);
1491 g_warn_if_fail (manager->priv->signal_signal_id != 0);
1492 g_signal_handler_disconnect (manager->priv->control_proxy,
1493 manager->priv->signal_signal_id);
1494 manager->priv->signal_signal_id = 0;
1496 g_warn_if_fail (manager->priv->name_owner_signal_id != 0);
1497 g_signal_handler_disconnect (manager->priv->control_proxy,
1498 manager->priv->name_owner_signal_id);
1499 manager->priv->name_owner_signal_id = 0;
1501 g_object_unref (manager->priv->control_proxy);
1502 manager->priv->control_proxy = NULL;
1507 process_get_all_result (manager, value, manager->priv->name_owner);
1508 g_variant_unref (value);
1518 initable_iface_init (GInitableIface *initable_iface)
1520 initable_iface->init = initable_init;
1524 async_initable_iface_init (GAsyncInitableIface *async_initable_iface)
1526 /* for now, just use default: run GInitable code in thread */
1529 /* ---------------------------------------------------------------------------------------------------- */
1532 add_interfaces (GDBusObjectManagerClient *manager,
1533 const gchar *object_path,
1534 GVariant *ifaces_and_properties,
1535 const gchar *name_owner)
1537 GDBusObjectProxy *op;
1540 const gchar *interface_name;
1541 GVariant *properties;
1542 GList *interface_added_signals, *l;
1543 GDBusProxy *interface_proxy;
1545 g_return_if_fail (name_owner == NULL || g_dbus_is_unique_name (name_owner));
1547 g_mutex_lock (&manager->priv->lock);
1549 interface_added_signals = NULL;
1552 op = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1555 GType object_proxy_type;
1556 if (manager->priv->get_proxy_type_func != NULL)
1558 object_proxy_type = manager->priv->get_proxy_type_func (manager,
1561 manager->priv->get_proxy_type_user_data);
1562 g_warn_if_fail (g_type_is_a (object_proxy_type, G_TYPE_DBUS_OBJECT_PROXY));
1566 object_proxy_type = G_TYPE_DBUS_OBJECT_PROXY;
1568 op = g_object_new (object_proxy_type,
1569 "g-connection", manager->priv->connection,
1570 "g-object-path", object_path,
1576 g_variant_iter_init (&iter, ifaces_and_properties);
1577 while (g_variant_iter_next (&iter,
1583 GType interface_proxy_type;
1585 if (manager->priv->get_proxy_type_func != NULL)
1587 interface_proxy_type = manager->priv->get_proxy_type_func (manager,
1590 manager->priv->get_proxy_type_user_data);
1591 g_warn_if_fail (g_type_is_a (interface_proxy_type, G_TYPE_DBUS_PROXY));
1595 interface_proxy_type = G_TYPE_DBUS_PROXY;
1598 /* this is fine - there is no blocking IO because we pass DO_NOT_LOAD_PROPERTIES and
1599 * DO_NOT_CONNECT_SIGNALS and use a unique name
1602 interface_proxy = g_initable_new (interface_proxy_type,
1603 NULL, /* GCancellable */
1605 "g-connection", manager->priv->connection,
1606 "g-flags", G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
1607 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
1608 "g-name", name_owner,
1609 "g-object-path", object_path,
1610 "g-interface-name", interface_name,
1612 if (interface_proxy == NULL)
1614 g_warning ("%s: Error constructing proxy for path %s and interface %s: %s",
1619 g_error_free (error);
1623 GVariantIter property_iter;
1624 const gchar *property_name;
1625 GVariant *property_value;
1627 /* associate the interface proxy with the object */
1628 g_dbus_interface_set_object (G_DBUS_INTERFACE (interface_proxy),
1629 G_DBUS_OBJECT (op));
1631 g_variant_iter_init (&property_iter, properties);
1632 while (g_variant_iter_next (&property_iter,
1637 g_dbus_proxy_set_cached_property (interface_proxy,
1640 g_variant_unref (property_value);
1643 _g_dbus_object_proxy_add_interface (op, interface_proxy);
1645 interface_added_signals = g_list_append (interface_added_signals, g_object_ref (interface_proxy));
1646 g_object_unref (interface_proxy);
1648 g_variant_unref (properties);
1653 g_hash_table_insert (manager->priv->map_object_path_to_object_proxy,
1654 g_strdup (object_path),
1658 g_mutex_unlock (&manager->priv->lock);
1660 /* now that we don't hold the lock any more, emit signals */
1661 g_object_ref (manager);
1662 for (l = interface_added_signals; l != NULL; l = l->next)
1664 interface_proxy = G_DBUS_PROXY (l->data);
1665 g_signal_emit_by_name (manager, "interface-added", op, interface_proxy);
1666 g_object_unref (interface_proxy);
1668 g_list_free (interface_added_signals);
1671 g_signal_emit_by_name (manager, "object-added", op);
1673 g_object_unref (manager);
1674 g_object_unref (op);
1678 remove_interfaces (GDBusObjectManagerClient *manager,
1679 const gchar *object_path,
1680 const gchar *const *interface_names)
1682 GDBusObjectProxy *op;
1685 guint num_interfaces;
1686 guint num_interfaces_to_remove;
1688 g_mutex_lock (&manager->priv->lock);
1690 op = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1693 g_debug ("%s: Processing InterfaceRemoved signal for path %s but no object proxy exists",
1696 g_mutex_unlock (&manager->priv->lock);
1700 interfaces = g_dbus_object_get_interfaces (G_DBUS_OBJECT (op));
1701 num_interfaces = g_list_length (interfaces);
1702 g_list_free_full (interfaces, g_object_unref);
1704 num_interfaces_to_remove = g_strv_length ((gchar **) interface_names);
1706 /* see if we are going to completety remove the object */
1707 g_object_ref (manager);
1708 if (num_interfaces_to_remove == num_interfaces)
1711 g_warn_if_fail (g_hash_table_remove (manager->priv->map_object_path_to_object_proxy, object_path));
1712 g_mutex_unlock (&manager->priv->lock);
1713 g_signal_emit_by_name (manager, "object-removed", op);
1714 g_object_unref (op);
1719 g_mutex_unlock (&manager->priv->lock);
1720 for (n = 0; interface_names != NULL && interface_names[n] != NULL; n++)
1722 GDBusInterface *interface;
1723 interface = g_dbus_object_get_interface (G_DBUS_OBJECT (op), interface_names[n]);
1724 _g_dbus_object_proxy_remove_interface (op, interface_names[n]);
1725 if (interface != NULL)
1727 g_signal_emit_by_name (manager, "interface-removed", op, interface);
1728 g_object_unref (interface);
1731 g_object_unref (op);
1733 g_object_unref (manager);
1737 process_get_all_result (GDBusObjectManagerClient *manager,
1739 const gchar *name_owner)
1742 const gchar *object_path;
1743 GVariant *ifaces_and_properties;
1746 g_return_if_fail (name_owner == NULL || g_dbus_is_unique_name (name_owner));
1748 arg0 = g_variant_get_child_value (value, 0);
1749 g_variant_iter_init (&iter, arg0);
1750 while (g_variant_iter_next (&iter,
1753 &ifaces_and_properties))
1755 add_interfaces (manager, object_path, ifaces_and_properties, name_owner);
1756 g_variant_unref (ifaces_and_properties);
1758 g_variant_unref (arg0);
1762 on_control_proxy_g_signal (GDBusProxy *proxy,
1763 const gchar *sender_name,
1764 const gchar *signal_name,
1765 GVariant *parameters,
1768 GWeakRef *manager_weak = user_data;
1769 GDBusObjectManagerClient *manager = NULL;
1770 const gchar *object_path;
1772 manager = G_DBUS_OBJECT_MANAGER_CLIENT (g_weak_ref_get (manager_weak));
1773 if (manager == NULL)
1776 //g_debug ("yay, g_signal %s: %s\n", signal_name, g_variant_print (parameters, TRUE));
1778 if (g_strcmp0 (signal_name, "InterfacesAdded") == 0)
1780 GVariant *ifaces_and_properties;
1781 g_variant_get (parameters,
1784 &ifaces_and_properties);
1785 add_interfaces (manager, object_path, ifaces_and_properties, manager->priv->name_owner);
1786 g_variant_unref (ifaces_and_properties);
1788 else if (g_strcmp0 (signal_name, "InterfacesRemoved") == 0)
1790 const gchar **ifaces;
1791 g_variant_get (parameters,
1795 remove_interfaces (manager, object_path, ifaces);
1799 g_object_unref (manager);
1802 /* ---------------------------------------------------------------------------------------------------- */
1804 static const gchar *
1805 g_dbus_object_manager_client_get_object_path (GDBusObjectManager *_manager)
1807 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
1808 return manager->priv->object_path;
1811 static GDBusObject *
1812 g_dbus_object_manager_client_get_object (GDBusObjectManager *_manager,
1813 const gchar *object_path)
1815 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
1818 g_mutex_lock (&manager->priv->lock);
1819 ret = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1822 g_mutex_unlock (&manager->priv->lock);
1826 static GDBusInterface *
1827 g_dbus_object_manager_client_get_interface (GDBusObjectManager *_manager,
1828 const gchar *object_path,
1829 const gchar *interface_name)
1831 GDBusInterface *ret;
1832 GDBusObject *object;
1836 object = g_dbus_object_manager_get_object (_manager, object_path);
1840 ret = g_dbus_object_get_interface (object, interface_name);
1841 g_object_unref (object);
1848 g_dbus_object_manager_client_get_objects (GDBusObjectManager *_manager)
1850 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
1853 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
1855 g_mutex_lock (&manager->priv->lock);
1856 ret = g_hash_table_get_values (manager->priv->map_object_path_to_object_proxy);
1857 g_list_foreach (ret, (GFunc) g_object_ref, NULL);
1858 g_mutex_unlock (&manager->priv->lock);
1865 dbus_object_manager_interface_init (GDBusObjectManagerIface *iface)
1867 iface->get_object_path = g_dbus_object_manager_client_get_object_path;
1868 iface->get_objects = g_dbus_object_manager_client_get_objects;
1869 iface->get_object = g_dbus_object_manager_client_get_object;
1870 iface->get_interface = g_dbus_object_manager_client_get_interface;
1873 /* ---------------------------------------------------------------------------------------------------- */