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 "gcancellable.h"
24 #include "gdbusobjectmanager.h"
25 #include "gdbusobjectmanagerclient.h"
26 #include "gdbusobject.h"
27 #include "gdbusprivate.h"
28 #include "gioenumtypes.h"
30 #include "ginitable.h"
31 #include "gasyncresult.h"
32 #include "gasyncinitable.h"
33 #include "gdbusconnection.h"
34 #include "gdbusutils.h"
35 #include "gdbusobject.h"
36 #include "gdbusobjectproxy.h"
37 #include "gdbusproxy.h"
38 #include "gdbusinterface.h"
41 #include "gmarshal-internal.h"
44 * SECTION:gdbusobjectmanagerclient
45 * @short_description: Client-side object manager
48 * #GDBusObjectManagerClient is used to create, monitor and delete object
49 * proxies for remote objects exported by a #GDBusObjectManagerServer (or any
50 * code implementing the
51 * [org.freedesktop.DBus.ObjectManager](http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager)
54 * Once an instance of this type has been created, you can connect to
55 * the #GDBusObjectManager::object-added and
56 * #GDBusObjectManager::object-removed signals and inspect the
57 * #GDBusObjectProxy objects returned by
58 * g_dbus_object_manager_get_objects().
60 * If the name for a #GDBusObjectManagerClient is not owned by anyone at
61 * object construction time, the default behavior is to request the
62 * message bus to launch an owner for the name. This behavior can be
63 * disabled using the %G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START
64 * flag. It's also worth noting that this only works if the name of
65 * interest is activatable in the first place. E.g. in some cases it
66 * is not possible to launch an owner for the requested name. In this
67 * case, #GDBusObjectManagerClient object construction still succeeds but
68 * there will be no object proxies
69 * (e.g. g_dbus_object_manager_get_objects() returns the empty list) and
70 * the #GDBusObjectManagerClient:name-owner property is %NULL.
72 * The owner of the requested name can come and go (for example
73 * consider a system service being restarted) – #GDBusObjectManagerClient
74 * handles this case too; simply connect to the #GObject::notify
75 * signal to watch for changes on the #GDBusObjectManagerClient:name-owner
76 * property. When the name owner vanishes, the behavior is that
77 * #GDBusObjectManagerClient:name-owner is set to %NULL (this includes
78 * emission of the #GObject::notify signal) and then
79 * #GDBusObjectManager::object-removed signals are synthesized
80 * for all currently existing object proxies. Since
81 * #GDBusObjectManagerClient:name-owner is %NULL when this happens, you can
82 * use this information to disambiguate a synthesized signal from a
83 * genuine signal caused by object removal on the remote
84 * #GDBusObjectManager. Similarly, when a new name owner appears,
85 * #GDBusObjectManager::object-added signals are synthesized
86 * while #GDBusObjectManagerClient:name-owner is still %NULL. Only when all
87 * object proxies have been added, the #GDBusObjectManagerClient:name-owner
88 * is set to the new name owner (this includes emission of the
89 * #GObject::notify signal). Furthermore, you are guaranteed that
90 * #GDBusObjectManagerClient:name-owner will alternate between a name owner
91 * (e.g. `:1.42`) and %NULL even in the case where
92 * the name of interest is atomically replaced
94 * Ultimately, #GDBusObjectManagerClient is used to obtain #GDBusProxy
95 * instances. All signals (including the
96 * org.freedesktop.DBus.Properties::PropertiesChanged signal)
97 * delivered to #GDBusProxy instances are guaranteed to originate
98 * from the name owner. This guarantee along with the behavior
99 * described above, means that certain race conditions including the
100 * "half the proxy is from the old owner and the other half is from
101 * the new owner" problem cannot happen.
103 * To avoid having the application connect to signals on the returned
104 * #GDBusObjectProxy and #GDBusProxy objects, the
105 * #GDBusObject::interface-added,
106 * #GDBusObject::interface-removed,
107 * #GDBusProxy::g-properties-changed and
108 * #GDBusProxy::g-signal signals
109 * are also emitted on the #GDBusObjectManagerClient instance managing these
110 * objects. The signals emitted are
111 * #GDBusObjectManager::interface-added,
112 * #GDBusObjectManager::interface-removed,
113 * #GDBusObjectManagerClient::interface-proxy-properties-changed and
114 * #GDBusObjectManagerClient::interface-proxy-signal.
116 * Note that all callbacks and signals are emitted in the
117 * [thread-default main context][g-main-context-push-thread-default]
118 * that the #GDBusObjectManagerClient object was constructed
119 * in. Additionally, the #GDBusObjectProxy and #GDBusProxy objects
120 * originating from the #GDBusObjectManagerClient object will be created in
121 * the same context and, consequently, will deliver signals in the
125 struct _GDBusObjectManagerClientPrivate
130 GDBusConnection *connection;
134 GDBusObjectManagerClientFlags flags;
136 GDBusProxy *control_proxy;
138 GHashTable *map_object_path_to_object_proxy;
140 guint signal_subscription_id;
143 GDBusProxyTypeFunc get_proxy_type_func;
144 gpointer get_proxy_type_user_data;
145 GDestroyNotify get_proxy_type_destroy_notify;
147 gulong name_owner_signal_id;
148 gulong signal_signal_id;
149 GCancellable *cancel;
161 PROP_GET_PROXY_TYPE_FUNC,
162 PROP_GET_PROXY_TYPE_USER_DATA,
163 PROP_GET_PROXY_TYPE_DESTROY_NOTIFY
168 INTERFACE_PROXY_SIGNAL_SIGNAL,
169 INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL,
173 static guint signals[LAST_SIGNAL] = { 0 };
175 static void initable_iface_init (GInitableIface *initable_iface);
176 static void async_initable_iface_init (GAsyncInitableIface *async_initable_iface);
177 static void dbus_object_manager_interface_init (GDBusObjectManagerIface *iface);
179 G_DEFINE_TYPE_WITH_CODE (GDBusObjectManagerClient, g_dbus_object_manager_client, G_TYPE_OBJECT,
180 G_ADD_PRIVATE (GDBusObjectManagerClient)
181 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)
182 G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init)
183 G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_OBJECT_MANAGER, dbus_object_manager_interface_init))
185 static void maybe_unsubscribe_signals (GDBusObjectManagerClient *manager);
187 static void on_control_proxy_g_signal (GDBusProxy *proxy,
188 const gchar *sender_name,
189 const gchar *signal_name,
190 GVariant *parameters,
193 static void process_get_all_result (GDBusObjectManagerClient *manager,
195 const gchar *name_owner);
198 g_dbus_object_manager_client_dispose (GObject *object)
200 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (object);
202 if (manager->priv->cancel != NULL)
204 g_cancellable_cancel (manager->priv->cancel);
205 g_clear_object (&manager->priv->cancel);
208 G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class)->dispose (object);
212 g_dbus_object_manager_client_finalize (GObject *object)
214 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (object);
216 maybe_unsubscribe_signals (manager);
218 g_hash_table_unref (manager->priv->map_object_path_to_object_proxy);
220 if (manager->priv->control_proxy != NULL && manager->priv->signal_signal_id != 0)
221 g_signal_handler_disconnect (manager->priv->control_proxy,
222 manager->priv->signal_signal_id);
223 manager->priv->signal_signal_id = 0;
225 if (manager->priv->control_proxy != NULL && manager->priv->name_owner_signal_id != 0)
226 g_signal_handler_disconnect (manager->priv->control_proxy,
227 manager->priv->name_owner_signal_id);
228 manager->priv->name_owner_signal_id = 0;
230 g_clear_object (&manager->priv->control_proxy);
232 if (manager->priv->connection != NULL)
233 g_object_unref (manager->priv->connection);
234 g_free (manager->priv->object_path);
235 g_free (manager->priv->name);
236 g_free (manager->priv->name_owner);
238 if (manager->priv->get_proxy_type_destroy_notify != NULL)
239 manager->priv->get_proxy_type_destroy_notify (manager->priv->get_proxy_type_user_data);
241 g_mutex_clear (&manager->priv->lock);
243 if (G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class)->finalize != NULL)
244 G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class)->finalize (object);
248 g_dbus_object_manager_client_get_property (GObject *_object,
253 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_object);
257 case PROP_CONNECTION:
258 g_value_set_object (value, g_dbus_object_manager_client_get_connection (manager));
261 case PROP_OBJECT_PATH:
262 g_value_set_string (value, g_dbus_object_manager_get_object_path (G_DBUS_OBJECT_MANAGER (manager)));
266 g_value_set_string (value, g_dbus_object_manager_client_get_name (manager));
270 g_value_set_flags (value, g_dbus_object_manager_client_get_flags (manager));
273 case PROP_NAME_OWNER:
274 g_value_take_string (value, g_dbus_object_manager_client_get_name_owner (manager));
278 G_OBJECT_WARN_INVALID_PROPERTY_ID (manager, prop_id, pspec);
284 g_dbus_object_manager_client_set_property (GObject *_object,
289 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_object);
295 manager->priv->bus_type = g_value_get_enum (value);
298 case PROP_CONNECTION:
299 if (g_value_get_object (value) != NULL)
301 g_assert (manager->priv->connection == NULL);
302 g_assert (G_IS_DBUS_CONNECTION (g_value_get_object (value)));
303 manager->priv->connection = g_value_dup_object (value);
307 case PROP_OBJECT_PATH:
308 g_assert (manager->priv->object_path == NULL);
309 g_assert (g_variant_is_object_path (g_value_get_string (value)));
310 manager->priv->object_path = g_value_dup_string (value);
314 g_assert (manager->priv->name == NULL);
315 name = g_value_get_string (value);
316 g_assert (name == NULL || g_dbus_is_name (name));
317 manager->priv->name = g_strdup (name);
321 manager->priv->flags = g_value_get_flags (value);
324 case PROP_GET_PROXY_TYPE_FUNC:
325 manager->priv->get_proxy_type_func = g_value_get_pointer (value);
328 case PROP_GET_PROXY_TYPE_USER_DATA:
329 manager->priv->get_proxy_type_user_data = g_value_get_pointer (value);
332 case PROP_GET_PROXY_TYPE_DESTROY_NOTIFY:
333 manager->priv->get_proxy_type_destroy_notify = g_value_get_pointer (value);
337 G_OBJECT_WARN_INVALID_PROPERTY_ID (manager, prop_id, pspec);
343 g_dbus_object_manager_client_class_init (GDBusObjectManagerClientClass *klass)
345 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
347 gobject_class->dispose = g_dbus_object_manager_client_dispose;
348 gobject_class->finalize = g_dbus_object_manager_client_finalize;
349 gobject_class->set_property = g_dbus_object_manager_client_set_property;
350 gobject_class->get_property = g_dbus_object_manager_client_get_property;
353 * GDBusObjectManagerClient:connection:
355 * The #GDBusConnection to use.
359 g_object_class_install_property (gobject_class,
361 g_param_spec_object ("connection",
363 "The connection to use",
364 G_TYPE_DBUS_CONNECTION,
367 G_PARAM_CONSTRUCT_ONLY |
368 G_PARAM_STATIC_STRINGS));
371 * GDBusObjectManagerClient:bus-type:
373 * If this property is not %G_BUS_TYPE_NONE, then
374 * #GDBusObjectManagerClient:connection must be %NULL and will be set to the
375 * #GDBusConnection obtained by calling g_bus_get() with the value
380 g_object_class_install_property (gobject_class,
382 g_param_spec_enum ("bus-type",
384 "The bus to connect to, if any",
388 G_PARAM_CONSTRUCT_ONLY |
389 G_PARAM_STATIC_NAME |
390 G_PARAM_STATIC_BLURB |
391 G_PARAM_STATIC_NICK));
394 * GDBusObjectManagerClient:flags:
396 * Flags from the #GDBusObjectManagerClientFlags enumeration.
400 g_object_class_install_property (gobject_class,
402 g_param_spec_flags ("flags",
404 "Flags for the proxy manager",
405 G_TYPE_DBUS_OBJECT_MANAGER_CLIENT_FLAGS,
406 G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
409 G_PARAM_CONSTRUCT_ONLY |
410 G_PARAM_STATIC_NAME |
411 G_PARAM_STATIC_BLURB |
412 G_PARAM_STATIC_NICK));
415 * GDBusObjectManagerClient:object-path:
417 * The object path the manager is for.
421 g_object_class_install_property (gobject_class,
423 g_param_spec_string ("object-path",
425 "The object path of the control object",
429 G_PARAM_CONSTRUCT_ONLY |
430 G_PARAM_STATIC_STRINGS));
433 * GDBusObjectManagerClient:name:
435 * The well-known name or unique name that the manager is for.
439 g_object_class_install_property (gobject_class,
441 g_param_spec_string ("name",
443 "Name that the manager is for",
447 G_PARAM_CONSTRUCT_ONLY |
448 G_PARAM_STATIC_STRINGS));
451 * GDBusObjectManagerClient:name-owner:
453 * The unique name that owns #GDBusObjectManagerClient:name or %NULL if
454 * no-one is currently owning the name. Connect to the
455 * #GObject::notify signal to track changes to this property.
459 g_object_class_install_property (gobject_class,
461 g_param_spec_string ("name-owner",
463 "The owner of the name we are watching",
466 G_PARAM_STATIC_STRINGS));
469 * GDBusObjectManagerClient:get-proxy-type-func:
471 * The #GDBusProxyTypeFunc to use when determining what #GType to
472 * use for interface proxies or %NULL.
476 g_object_class_install_property (gobject_class,
477 PROP_GET_PROXY_TYPE_FUNC,
478 g_param_spec_pointer ("get-proxy-type-func",
479 "GDBusProxyTypeFunc Function Pointer",
480 "The GDBusProxyTypeFunc pointer to use",
483 G_PARAM_CONSTRUCT_ONLY |
484 G_PARAM_STATIC_STRINGS));
487 * GDBusObjectManagerClient:get-proxy-type-user-data:
489 * The #gpointer user_data to pass to #GDBusObjectManagerClient:get-proxy-type-func.
493 g_object_class_install_property (gobject_class,
494 PROP_GET_PROXY_TYPE_USER_DATA,
495 g_param_spec_pointer ("get-proxy-type-user-data",
496 "GDBusProxyTypeFunc User Data",
497 "The GDBusProxyTypeFunc user_data",
500 G_PARAM_CONSTRUCT_ONLY |
501 G_PARAM_STATIC_STRINGS));
504 * GDBusObjectManagerClient:get-proxy-type-destroy-notify:
506 * A #GDestroyNotify for the #gpointer user_data in #GDBusObjectManagerClient:get-proxy-type-user-data.
510 g_object_class_install_property (gobject_class,
511 PROP_GET_PROXY_TYPE_DESTROY_NOTIFY,
512 g_param_spec_pointer ("get-proxy-type-destroy-notify",
513 "GDBusProxyTypeFunc user data free function",
514 "The GDBusProxyTypeFunc user data free function",
517 G_PARAM_CONSTRUCT_ONLY |
518 G_PARAM_STATIC_STRINGS));
521 * GDBusObjectManagerClient::interface-proxy-signal:
522 * @manager: The #GDBusObjectManagerClient emitting the signal.
523 * @object_proxy: The #GDBusObjectProxy on which an interface is emitting a D-Bus signal.
524 * @interface_proxy: The #GDBusProxy that is emitting a D-Bus signal.
525 * @sender_name: The sender of the signal or NULL if the connection is not a bus connection.
526 * @signal_name: The signal name.
527 * @parameters: A #GVariant tuple with parameters for the signal.
529 * Emitted when a D-Bus signal is received on @interface_proxy.
531 * This signal exists purely as a convenience to avoid having to
532 * connect signals to all interface proxies managed by @manager.
534 * This signal is emitted in the
535 * [thread-default main context][g-main-context-push-thread-default]
536 * that @manager was constructed in.
540 signals[INTERFACE_PROXY_SIGNAL_SIGNAL] =
541 g_signal_new (I_("interface-proxy-signal"),
542 G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
544 G_STRUCT_OFFSET (GDBusObjectManagerClientClass, interface_proxy_signal),
547 _g_cclosure_marshal_VOID__OBJECT_OBJECT_STRING_STRING_VARIANT,
550 G_TYPE_DBUS_OBJECT_PROXY,
555 g_signal_set_va_marshaller (signals[INTERFACE_PROXY_SIGNAL_SIGNAL],
556 G_TYPE_FROM_CLASS (klass),
557 _g_cclosure_marshal_VOID__OBJECT_OBJECT_STRING_STRING_VARIANTv);
560 * GDBusObjectManagerClient::interface-proxy-properties-changed:
561 * @manager: The #GDBusObjectManagerClient emitting the signal.
562 * @object_proxy: The #GDBusObjectProxy on which an interface has properties that are changing.
563 * @interface_proxy: The #GDBusProxy that has properties that are changing.
564 * @changed_properties: A #GVariant containing the properties that changed (type: `a{sv}`).
565 * @invalidated_properties: (array zero-terminated=1) (element-type utf8): A %NULL terminated
566 * array of properties that were invalidated.
568 * Emitted when one or more D-Bus properties on proxy changes. The
569 * local cache has already been updated when this signal fires. Note
570 * that both @changed_properties and @invalidated_properties are
571 * guaranteed to never be %NULL (either may be empty though).
573 * This signal exists purely as a convenience to avoid having to
574 * connect signals to all interface proxies managed by @manager.
576 * This signal is emitted in the
577 * [thread-default main context][g-main-context-push-thread-default]
578 * that @manager was constructed in.
582 signals[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL] =
583 g_signal_new (I_("interface-proxy-properties-changed"),
584 G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
586 G_STRUCT_OFFSET (GDBusObjectManagerClientClass, interface_proxy_properties_changed),
589 _g_cclosure_marshal_VOID__OBJECT_OBJECT_VARIANT_BOXED,
592 G_TYPE_DBUS_OBJECT_PROXY,
596 g_signal_set_va_marshaller (signals[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL],
597 G_TYPE_FROM_CLASS (klass),
598 _g_cclosure_marshal_VOID__OBJECT_OBJECT_VARIANT_BOXEDv);
602 g_dbus_object_manager_client_init (GDBusObjectManagerClient *manager)
604 manager->priv = g_dbus_object_manager_client_get_instance_private (manager);
605 g_mutex_init (&manager->priv->lock);
606 manager->priv->map_object_path_to_object_proxy = g_hash_table_new_full (g_str_hash,
609 (GDestroyNotify) g_object_unref);
610 manager->priv->cancel = g_cancellable_new ();
613 /* ---------------------------------------------------------------------------------------------------- */
616 * g_dbus_object_manager_client_new_sync:
617 * @connection: A #GDBusConnection.
618 * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
619 * @name: (nullable): The owner of the control object (unique or well-known name), or %NULL when not using a message bus connection.
620 * @object_path: The object path of the control object.
621 * @get_proxy_type_func: (nullable): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
622 * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
623 * @get_proxy_type_destroy_notify: (nullable): Free function for @get_proxy_type_user_data or %NULL.
624 * @cancellable: (nullable): A #GCancellable or %NULL
625 * @error: Return location for error or %NULL.
627 * Creates a new #GDBusObjectManagerClient object.
629 * This is a synchronous failable constructor - the calling thread is
630 * blocked until a reply is received. See g_dbus_object_manager_client_new()
631 * for the asynchronous version.
633 * Returns: (transfer full) (type GDBusObjectManagerClient): A
634 * #GDBusObjectManagerClient object or %NULL if @error is set. Free
635 * with g_object_unref().
640 g_dbus_object_manager_client_new_sync (GDBusConnection *connection,
641 GDBusObjectManagerClientFlags flags,
643 const gchar *object_path,
644 GDBusProxyTypeFunc get_proxy_type_func,
645 gpointer get_proxy_type_user_data,
646 GDestroyNotify get_proxy_type_destroy_notify,
647 GCancellable *cancellable,
652 g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
653 g_return_val_if_fail ((name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) ||
654 g_dbus_is_name (name), NULL);
655 g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
656 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
658 initable = g_initable_new (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
661 "connection", connection,
664 "object-path", object_path,
665 "get-proxy-type-func", get_proxy_type_func,
666 "get-proxy-type-user-data", get_proxy_type_user_data,
667 "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
669 if (initable != NULL)
670 return G_DBUS_OBJECT_MANAGER (initable);
676 * g_dbus_object_manager_client_new:
677 * @connection: A #GDBusConnection.
678 * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
679 * @name: The owner of the control object (unique or well-known name).
680 * @object_path: The object path of the control object.
681 * @get_proxy_type_func: (nullable): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
682 * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
683 * @get_proxy_type_destroy_notify: (nullable): Free function for @get_proxy_type_user_data or %NULL.
684 * @cancellable: (nullable): A #GCancellable or %NULL
685 * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
686 * @user_data: The data to pass to @callback.
688 * Asynchronously creates a new #GDBusObjectManagerClient object.
690 * This is an asynchronous failable constructor. When the result is
691 * ready, @callback will be invoked in the
692 * [thread-default main context][g-main-context-push-thread-default]
693 * of the thread you are calling this method from. You can
694 * then call g_dbus_object_manager_client_new_finish() to get the result. See
695 * g_dbus_object_manager_client_new_sync() for the synchronous version.
700 g_dbus_object_manager_client_new (GDBusConnection *connection,
701 GDBusObjectManagerClientFlags flags,
703 const gchar *object_path,
704 GDBusProxyTypeFunc get_proxy_type_func,
705 gpointer get_proxy_type_user_data,
706 GDestroyNotify get_proxy_type_destroy_notify,
707 GCancellable *cancellable,
708 GAsyncReadyCallback callback,
711 g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
712 g_return_if_fail ((name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) ||
713 g_dbus_is_name (name));
714 g_return_if_fail (g_variant_is_object_path (object_path));
716 g_async_initable_new_async (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
721 "connection", connection,
724 "object-path", object_path,
725 "get-proxy-type-func", get_proxy_type_func,
726 "get-proxy-type-user-data", get_proxy_type_user_data,
727 "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
732 * g_dbus_object_manager_client_new_finish:
733 * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_object_manager_client_new().
734 * @error: Return location for error or %NULL.
736 * Finishes an operation started with g_dbus_object_manager_client_new().
738 * Returns: (transfer full) (type GDBusObjectManagerClient): A
739 * #GDBusObjectManagerClient object or %NULL if @error is set. Free
740 * with g_object_unref().
745 g_dbus_object_manager_client_new_finish (GAsyncResult *res,
749 GObject *source_object;
751 source_object = g_async_result_get_source_object (res);
752 g_assert (source_object != NULL);
754 object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
757 g_object_unref (source_object);
760 return G_DBUS_OBJECT_MANAGER (object);
765 /* ---------------------------------------------------------------------------------------------------- */
768 * g_dbus_object_manager_client_new_for_bus_sync:
769 * @bus_type: A #GBusType.
770 * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
771 * @name: The owner of the control object (unique or well-known name).
772 * @object_path: The object path of the control object.
773 * @get_proxy_type_func: (nullable): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
774 * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
775 * @get_proxy_type_destroy_notify: (nullable): Free function for @get_proxy_type_user_data or %NULL.
776 * @cancellable: (nullable): A #GCancellable or %NULL
777 * @error: Return location for error or %NULL.
779 * Like g_dbus_object_manager_client_new_sync() but takes a #GBusType instead
780 * of a #GDBusConnection.
782 * This is a synchronous failable constructor - the calling thread is
783 * blocked until a reply is received. See g_dbus_object_manager_client_new_for_bus()
784 * for the asynchronous version.
786 * Returns: (transfer full) (type GDBusObjectManagerClient): A
787 * #GDBusObjectManagerClient object or %NULL if @error is set. Free
788 * with g_object_unref().
793 g_dbus_object_manager_client_new_for_bus_sync (GBusType bus_type,
794 GDBusObjectManagerClientFlags flags,
796 const gchar *object_path,
797 GDBusProxyTypeFunc get_proxy_type_func,
798 gpointer get_proxy_type_user_data,
799 GDestroyNotify get_proxy_type_destroy_notify,
800 GCancellable *cancellable,
805 g_return_val_if_fail (bus_type != G_BUS_TYPE_NONE, NULL);
806 g_return_val_if_fail (g_dbus_is_name (name), NULL);
807 g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
808 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
810 initable = g_initable_new (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
813 "bus-type", bus_type,
816 "object-path", object_path,
817 "get-proxy-type-func", get_proxy_type_func,
818 "get-proxy-type-user-data", get_proxy_type_user_data,
819 "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
821 if (initable != NULL)
822 return G_DBUS_OBJECT_MANAGER (initable);
828 * g_dbus_object_manager_client_new_for_bus:
829 * @bus_type: A #GBusType.
830 * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
831 * @name: The owner of the control object (unique or well-known name).
832 * @object_path: The object path of the control object.
833 * @get_proxy_type_func: (nullable): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
834 * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
835 * @get_proxy_type_destroy_notify: (nullable): Free function for @get_proxy_type_user_data or %NULL.
836 * @cancellable: (nullable): A #GCancellable or %NULL
837 * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
838 * @user_data: The data to pass to @callback.
840 * Like g_dbus_object_manager_client_new() but takes a #GBusType instead of a
843 * This is an asynchronous failable constructor. When the result is
844 * ready, @callback will be invoked in the
845 * [thread-default main loop][g-main-context-push-thread-default]
846 * of the thread you are calling this method from. You can
847 * then call g_dbus_object_manager_client_new_for_bus_finish() to get the result. See
848 * g_dbus_object_manager_client_new_for_bus_sync() for the synchronous version.
853 g_dbus_object_manager_client_new_for_bus (GBusType bus_type,
854 GDBusObjectManagerClientFlags flags,
856 const gchar *object_path,
857 GDBusProxyTypeFunc get_proxy_type_func,
858 gpointer get_proxy_type_user_data,
859 GDestroyNotify get_proxy_type_destroy_notify,
860 GCancellable *cancellable,
861 GAsyncReadyCallback callback,
864 g_return_if_fail (bus_type != G_BUS_TYPE_NONE);
865 g_return_if_fail (g_dbus_is_name (name));
866 g_return_if_fail (g_variant_is_object_path (object_path));
868 g_async_initable_new_async (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
873 "bus-type", bus_type,
876 "object-path", object_path,
877 "get-proxy-type-func", get_proxy_type_func,
878 "get-proxy-type-user-data", get_proxy_type_user_data,
879 "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
884 * g_dbus_object_manager_client_new_for_bus_finish:
885 * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_object_manager_client_new_for_bus().
886 * @error: Return location for error or %NULL.
888 * Finishes an operation started with g_dbus_object_manager_client_new_for_bus().
890 * Returns: (transfer full) (type GDBusObjectManagerClient): A
891 * #GDBusObjectManagerClient object or %NULL if @error is set. Free
892 * with g_object_unref().
897 g_dbus_object_manager_client_new_for_bus_finish (GAsyncResult *res,
901 GObject *source_object;
903 source_object = g_async_result_get_source_object (res);
904 g_assert (source_object != NULL);
906 object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
909 g_object_unref (source_object);
912 return G_DBUS_OBJECT_MANAGER (object);
917 /* ---------------------------------------------------------------------------------------------------- */
920 * g_dbus_object_manager_client_get_connection:
921 * @manager: A #GDBusObjectManagerClient
923 * Gets the #GDBusConnection used by @manager.
925 * Returns: (transfer none): A #GDBusConnection object. Do not free,
926 * the object belongs to @manager.
931 g_dbus_object_manager_client_get_connection (GDBusObjectManagerClient *manager)
933 GDBusConnection *ret;
934 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
935 g_mutex_lock (&manager->priv->lock);
936 ret = manager->priv->connection;
937 g_mutex_unlock (&manager->priv->lock);
942 * g_dbus_object_manager_client_get_name:
943 * @manager: A #GDBusObjectManagerClient
945 * Gets the name that @manager is for, or %NULL if not a message bus
948 * Returns: A unique or well-known name. Do not free, the string
949 * belongs to @manager.
954 g_dbus_object_manager_client_get_name (GDBusObjectManagerClient *manager)
957 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
958 g_mutex_lock (&manager->priv->lock);
959 ret = manager->priv->name;
960 g_mutex_unlock (&manager->priv->lock);
965 * g_dbus_object_manager_client_get_flags:
966 * @manager: A #GDBusObjectManagerClient
968 * Gets the flags that @manager was constructed with.
970 * Returns: Zero of more flags from the #GDBusObjectManagerClientFlags
975 GDBusObjectManagerClientFlags
976 g_dbus_object_manager_client_get_flags (GDBusObjectManagerClient *manager)
978 GDBusObjectManagerClientFlags ret;
979 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE);
980 g_mutex_lock (&manager->priv->lock);
981 ret = manager->priv->flags;
982 g_mutex_unlock (&manager->priv->lock);
987 * g_dbus_object_manager_client_get_name_owner:
988 * @manager: A #GDBusObjectManagerClient.
990 * The unique name that owns the name that @manager is for or %NULL if
991 * no-one currently owns that name. You can connect to the
992 * #GObject::notify signal to track changes to the
993 * #GDBusObjectManagerClient:name-owner property.
995 * Returns: (nullable): The name owner or %NULL if no name owner
996 * exists. Free with g_free().
1001 g_dbus_object_manager_client_get_name_owner (GDBusObjectManagerClient *manager)
1004 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
1005 g_mutex_lock (&manager->priv->lock);
1006 ret = g_strdup (manager->priv->name_owner);
1007 g_mutex_unlock (&manager->priv->lock);
1011 /* ---------------------------------------------------------------------------------------------------- */
1013 /* signal handler for all objects we manage - we dispatch signals
1014 * from here to the objects
1017 signal_cb (GDBusConnection *connection,
1018 const gchar *sender_name,
1019 const gchar *object_path,
1020 const gchar *interface_name,
1021 const gchar *signal_name,
1022 GVariant *parameters,
1025 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (user_data);
1026 GDBusObjectProxy *object_proxy;
1027 GDBusInterface *interface;
1029 g_mutex_lock (&manager->priv->lock);
1030 object_proxy = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1031 if (object_proxy == NULL)
1033 g_mutex_unlock (&manager->priv->lock);
1036 g_object_ref (object_proxy);
1037 g_mutex_unlock (&manager->priv->lock);
1039 //g_debug ("yay, signal_cb %s %s: %s\n", signal_name, object_path, g_variant_print (parameters, TRUE));
1041 g_object_ref (manager);
1042 if (g_strcmp0 (interface_name, "org.freedesktop.DBus.Properties") == 0)
1044 if (g_strcmp0 (signal_name, "PropertiesChanged") == 0)
1046 const gchar *interface_name;
1047 GVariant *changed_properties;
1048 const gchar **invalidated_properties;
1050 g_variant_get (parameters,
1053 &changed_properties,
1054 &invalidated_properties);
1056 interface = g_dbus_object_get_interface (G_DBUS_OBJECT (object_proxy), interface_name);
1057 if (interface != NULL)
1059 GVariantIter property_iter;
1060 const gchar *property_name;
1061 GVariant *property_value;
1064 /* update caches... */
1065 g_variant_iter_init (&property_iter, changed_properties);
1066 while (g_variant_iter_next (&property_iter,
1071 g_dbus_proxy_set_cached_property (G_DBUS_PROXY (interface),
1074 g_variant_unref (property_value);
1077 for (n = 0; invalidated_properties[n] != NULL; n++)
1079 g_dbus_proxy_set_cached_property (G_DBUS_PROXY (interface),
1080 invalidated_properties[n],
1083 /* ... and then synthesize the signal */
1084 g_signal_emit_by_name (interface,
1085 "g-properties-changed",
1087 invalidated_properties);
1088 g_signal_emit (manager,
1089 signals[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL],
1094 invalidated_properties);
1095 g_object_unref (interface);
1097 g_variant_unref (changed_properties);
1098 g_free (invalidated_properties);
1103 /* regular signal - just dispatch it */
1104 interface = g_dbus_object_get_interface (G_DBUS_OBJECT (object_proxy), interface_name);
1105 if (interface != NULL)
1107 g_signal_emit_by_name (interface,
1112 g_signal_emit (manager,
1113 signals[INTERFACE_PROXY_SIGNAL_SIGNAL],
1120 g_object_unref (interface);
1123 g_object_unref (manager);
1126 g_clear_object (&object_proxy);
1130 subscribe_signals (GDBusObjectManagerClient *manager,
1131 const gchar *name_owner)
1133 GError *error = NULL;
1135 g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager));
1136 g_return_if_fail (manager->priv->signal_subscription_id == 0);
1137 g_return_if_fail (name_owner == NULL || g_dbus_is_unique_name (name_owner));
1139 if (name_owner != NULL)
1141 /* Only add path_namespace if it's non-'/'. This removes a no-op key from
1142 * the match rule, and also works around a D-Bus bug where
1143 * path_namespace='/' matches nothing in D-Bus versions < 1.6.18.
1145 * See: https://bugs.freedesktop.org/show_bug.cgi?id=70799 */
1146 if (g_str_equal (manager->priv->object_path, "/"))
1148 manager->priv->match_rule = g_strdup_printf ("type='signal',sender='%s'",
1153 manager->priv->match_rule = g_strdup_printf ("type='signal',sender='%s',path_namespace='%s'",
1154 name_owner, manager->priv->object_path);
1157 /* The bus daemon may not implement path_namespace so gracefully
1158 * handle this by using a fallback triggered if @error is set. */
1159 g_dbus_add_match (manager->priv->connection, manager->priv->match_rule, &error);
1164 /* still need to ask GDBusConnection for the callbacks */
1165 manager->priv->signal_subscription_id =
1166 g_dbus_connection_signal_subscribe (manager->priv->connection,
1168 NULL, /* interface */
1170 NULL, /* path - TODO: really want wildcard support here */
1172 G_DBUS_SIGNAL_FLAGS_NONE |
1173 G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
1176 NULL); /* user_data_free_func */
1181 /* TODO: we could report this to the user
1182 g_warning ("Message bus daemon does not support path_namespace: %s (%s %d)",
1184 g_quark_to_string (error->domain),
1188 g_error_free (error);
1190 /* no need to call RemoveMatch when done since it didn't work */
1191 g_free (manager->priv->match_rule);
1192 manager->priv->match_rule = NULL;
1194 /* Fallback is to subscribe to *all* signals from the name owner which
1195 * is rather wasteful. It's probably not a big practical problem because
1196 * users typically want all objects that the name owner supplies.
1198 manager->priv->signal_subscription_id =
1199 g_dbus_connection_signal_subscribe (manager->priv->connection,
1201 NULL, /* interface */
1203 NULL, /* path - TODO: really want wildcard support here */
1205 G_DBUS_SIGNAL_FLAGS_NONE,
1208 NULL); /* user_data_free_func */
1213 maybe_unsubscribe_signals (GDBusObjectManagerClient *manager)
1215 g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager));
1217 if (manager->priv->signal_subscription_id > 0)
1219 g_dbus_connection_signal_unsubscribe (manager->priv->connection,
1220 manager->priv->signal_subscription_id);
1221 manager->priv->signal_subscription_id = 0;
1224 if (manager->priv->match_rule != NULL)
1226 /* Since the AddMatch call succeeded this is guaranteed to not
1227 * fail - therefore, don't bother checking the return value
1229 g_dbus_remove_match (manager->priv->connection,
1230 manager->priv->match_rule,
1232 g_free (manager->priv->match_rule);
1233 manager->priv->match_rule = NULL;
1238 /* ---------------------------------------------------------------------------------------------------- */
1241 weak_ref_new (GObject *object)
1243 GWeakRef *weak_ref = g_new0 (GWeakRef, 1);
1244 g_weak_ref_init (weak_ref, object);
1245 return g_steal_pointer (&weak_ref);
1249 weak_ref_free (GWeakRef *weak_ref)
1251 g_weak_ref_clear (weak_ref);
1256 on_get_managed_objects_finish (GObject *source,
1257 GAsyncResult *result,
1261 GDBusProxy *proxy = G_DBUS_PROXY (source);
1262 GWeakRef *manager_weak = user_data;
1263 GDBusObjectManagerClient *manager;
1264 GError *error = NULL;
1265 GVariant *value = NULL;
1266 gchar *new_name_owner = NULL;
1268 value = g_dbus_proxy_call_finish (proxy, result, &error);
1270 manager = G_DBUS_OBJECT_MANAGER_CLIENT (g_weak_ref_get (manager_weak));
1271 /* Manager got disposed, nothing to do */
1272 if (manager == NULL)
1277 new_name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy);
1280 maybe_unsubscribe_signals (manager);
1281 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
1283 g_warning ("Error calling GetManagedObjects() when name owner %s for name %s came back: %s",
1285 manager->priv->name,
1291 process_get_all_result (manager, value, new_name_owner);
1294 /* do the :name-owner notify *AFTER* emitting ::object-proxy-added signals - this
1295 * way the user knows that the signals were emitted because the name owner came back
1297 g_mutex_lock (&manager->priv->lock);
1298 manager->priv->name_owner = g_steal_pointer (&new_name_owner);
1299 g_mutex_unlock (&manager->priv->lock);
1300 g_object_notify (G_OBJECT (manager), "name-owner");
1302 g_object_unref (manager);
1304 g_clear_error (&error);
1305 g_clear_pointer (&value, g_variant_unref);
1306 weak_ref_free (manager_weak);
1310 on_notify_g_name_owner (GObject *object,
1314 GWeakRef *manager_weak = user_data;
1315 GDBusObjectManagerClient *manager = NULL;
1316 gchar *old_name_owner;
1317 gchar *new_name_owner;
1319 manager = G_DBUS_OBJECT_MANAGER_CLIENT (g_weak_ref_get (manager_weak));
1320 if (manager == NULL)
1323 g_mutex_lock (&manager->priv->lock);
1324 old_name_owner = manager->priv->name_owner;
1325 new_name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy);
1326 manager->priv->name_owner = NULL;
1328 if (g_strcmp0 (old_name_owner, new_name_owner) != 0)
1333 /* remote manager changed; nuke all local proxies */
1334 proxies = g_hash_table_get_values (manager->priv->map_object_path_to_object_proxy);
1335 g_list_foreach (proxies, (GFunc) g_object_ref, NULL);
1336 g_hash_table_remove_all (manager->priv->map_object_path_to_object_proxy);
1338 g_mutex_unlock (&manager->priv->lock);
1340 /* do the :name-owner notify with a NULL name - this way the user knows
1341 * the ::object-proxy-removed following is because the name owner went
1344 g_object_notify (G_OBJECT (manager), "name-owner");
1346 for (l = proxies; l != NULL; l = l->next)
1348 GDBusObjectProxy *object_proxy = G_DBUS_OBJECT_PROXY (l->data);
1349 g_signal_emit_by_name (manager, "object-removed", object_proxy);
1351 g_list_free_full (proxies, g_object_unref);
1353 /* nuke local filter */
1354 maybe_unsubscribe_signals (manager);
1358 g_mutex_unlock (&manager->priv->lock);
1361 if (new_name_owner != NULL)
1363 //g_debug ("repopulating for %s", new_name_owner);
1365 subscribe_signals (manager,
1367 g_dbus_proxy_call (manager->priv->control_proxy,
1368 "GetManagedObjects",
1369 NULL, /* parameters */
1370 G_DBUS_CALL_FLAGS_NONE,
1372 manager->priv->cancel,
1373 on_get_managed_objects_finish,
1374 weak_ref_new (G_OBJECT (manager)));
1376 g_free (new_name_owner);
1377 g_free (old_name_owner);
1378 g_object_unref (manager);
1382 initable_init (GInitable *initable,
1383 GCancellable *cancellable,
1386 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (initable);
1389 GDBusProxyFlags proxy_flags;
1393 if (manager->priv->bus_type != G_BUS_TYPE_NONE)
1395 g_assert (manager->priv->connection == NULL);
1396 manager->priv->connection = g_bus_get_sync (manager->priv->bus_type, cancellable, error);
1397 if (manager->priv->connection == NULL)
1401 proxy_flags = G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES;
1402 if (manager->priv->flags & G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START)
1403 proxy_flags |= G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START;
1405 manager->priv->control_proxy = g_dbus_proxy_new_sync (manager->priv->connection,
1407 NULL, /* GDBusInterfaceInfo* */
1408 manager->priv->name,
1409 manager->priv->object_path,
1410 "org.freedesktop.DBus.ObjectManager",
1413 if (manager->priv->control_proxy == NULL)
1416 /* Use weak refs here. The @control_proxy will emit its signals in the current
1417 * #GMainContext (since we constructed it just above). However, the user may
1418 * drop the last external reference to this #GDBusObjectManagerClient in
1419 * another thread between a signal being emitted and scheduled in an idle
1420 * callback in this #GMainContext, and that idle callback being invoked. We
1421 * can’t use a strong reference here, as there’s no
1422 * g_dbus_object_manager_client_disconnect() (or similar) method to tell us
1423 * when the last external reference to this object has been dropped, so we
1424 * can’t break a strong reference count cycle. So use weak refs. */
1425 manager->priv->name_owner_signal_id =
1426 g_signal_connect_data (G_OBJECT (manager->priv->control_proxy),
1427 "notify::g-name-owner",
1428 G_CALLBACK (on_notify_g_name_owner),
1429 weak_ref_new (G_OBJECT (manager)),
1430 (GClosureNotify) weak_ref_free,
1433 manager->priv->signal_signal_id =
1434 g_signal_connect_data (manager->priv->control_proxy,
1436 G_CALLBACK (on_control_proxy_g_signal),
1437 weak_ref_new (G_OBJECT (manager)),
1438 (GClosureNotify) weak_ref_free,
1441 manager->priv->name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy);
1442 if (manager->priv->name_owner == NULL && manager->priv->name != NULL)
1444 /* it's perfectly fine if there's no name owner.. we're just going to
1445 * wait until one is ready
1450 /* yay, we can get the objects */
1451 subscribe_signals (manager,
1452 manager->priv->name_owner);
1453 value = g_dbus_proxy_call_sync (manager->priv->control_proxy,
1454 "GetManagedObjects",
1455 NULL, /* parameters */
1456 G_DBUS_CALL_FLAGS_NONE,
1462 maybe_unsubscribe_signals (manager);
1464 g_warn_if_fail (manager->priv->signal_signal_id != 0);
1465 g_signal_handler_disconnect (manager->priv->control_proxy,
1466 manager->priv->signal_signal_id);
1467 manager->priv->signal_signal_id = 0;
1469 g_warn_if_fail (manager->priv->name_owner_signal_id != 0);
1470 g_signal_handler_disconnect (manager->priv->control_proxy,
1471 manager->priv->name_owner_signal_id);
1472 manager->priv->name_owner_signal_id = 0;
1474 g_object_unref (manager->priv->control_proxy);
1475 manager->priv->control_proxy = NULL;
1480 process_get_all_result (manager, value, manager->priv->name_owner);
1481 g_variant_unref (value);
1491 initable_iface_init (GInitableIface *initable_iface)
1493 initable_iface->init = initable_init;
1497 async_initable_iface_init (GAsyncInitableIface *async_initable_iface)
1499 /* for now, just use default: run GInitable code in thread */
1502 /* ---------------------------------------------------------------------------------------------------- */
1505 add_interfaces (GDBusObjectManagerClient *manager,
1506 const gchar *object_path,
1507 GVariant *ifaces_and_properties,
1508 const gchar *name_owner)
1510 GDBusObjectProxy *op;
1513 const gchar *interface_name;
1514 GVariant *properties;
1515 GList *interface_added_signals, *l;
1516 GDBusProxy *interface_proxy;
1518 g_return_if_fail (name_owner == NULL || g_dbus_is_unique_name (name_owner));
1520 g_mutex_lock (&manager->priv->lock);
1522 interface_added_signals = NULL;
1525 op = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1528 GType object_proxy_type;
1529 if (manager->priv->get_proxy_type_func != NULL)
1531 object_proxy_type = manager->priv->get_proxy_type_func (manager,
1534 manager->priv->get_proxy_type_user_data);
1535 g_warn_if_fail (g_type_is_a (object_proxy_type, G_TYPE_DBUS_OBJECT_PROXY));
1539 object_proxy_type = G_TYPE_DBUS_OBJECT_PROXY;
1541 op = g_object_new (object_proxy_type,
1542 "g-connection", manager->priv->connection,
1543 "g-object-path", object_path,
1549 g_variant_iter_init (&iter, ifaces_and_properties);
1550 while (g_variant_iter_next (&iter,
1556 GType interface_proxy_type;
1558 if (manager->priv->get_proxy_type_func != NULL)
1560 interface_proxy_type = manager->priv->get_proxy_type_func (manager,
1563 manager->priv->get_proxy_type_user_data);
1564 g_warn_if_fail (g_type_is_a (interface_proxy_type, G_TYPE_DBUS_PROXY));
1568 interface_proxy_type = G_TYPE_DBUS_PROXY;
1571 /* this is fine - there is no blocking IO because we pass DO_NOT_LOAD_PROPERTIES and
1572 * DO_NOT_CONNECT_SIGNALS and use a unique name
1575 interface_proxy = g_initable_new (interface_proxy_type,
1576 NULL, /* GCancellable */
1578 "g-connection", manager->priv->connection,
1579 "g-flags", G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
1580 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
1581 "g-name", name_owner,
1582 "g-object-path", object_path,
1583 "g-interface-name", interface_name,
1585 if (interface_proxy == NULL)
1587 g_warning ("%s: Error constructing proxy for path %s and interface %s: %s",
1592 g_error_free (error);
1596 GVariantIter property_iter;
1597 const gchar *property_name;
1598 GVariant *property_value;
1600 /* associate the interface proxy with the object */
1601 g_dbus_interface_set_object (G_DBUS_INTERFACE (interface_proxy),
1602 G_DBUS_OBJECT (op));
1604 g_variant_iter_init (&property_iter, properties);
1605 while (g_variant_iter_next (&property_iter,
1610 g_dbus_proxy_set_cached_property (interface_proxy,
1613 g_variant_unref (property_value);
1616 _g_dbus_object_proxy_add_interface (op, interface_proxy);
1618 interface_added_signals = g_list_append (interface_added_signals, g_object_ref (interface_proxy));
1619 g_object_unref (interface_proxy);
1621 g_variant_unref (properties);
1626 g_hash_table_insert (manager->priv->map_object_path_to_object_proxy,
1627 g_strdup (object_path),
1631 g_mutex_unlock (&manager->priv->lock);
1633 /* now that we don't hold the lock any more, emit signals */
1634 g_object_ref (manager);
1635 for (l = interface_added_signals; l != NULL; l = l->next)
1637 interface_proxy = G_DBUS_PROXY (l->data);
1638 g_signal_emit_by_name (manager, "interface-added", op, interface_proxy);
1639 g_object_unref (interface_proxy);
1641 g_list_free (interface_added_signals);
1644 g_signal_emit_by_name (manager, "object-added", op);
1646 g_object_unref (manager);
1647 g_object_unref (op);
1651 remove_interfaces (GDBusObjectManagerClient *manager,
1652 const gchar *object_path,
1653 const gchar *const *interface_names)
1655 GDBusObjectProxy *op;
1658 guint num_interfaces;
1659 guint num_interfaces_to_remove;
1661 g_mutex_lock (&manager->priv->lock);
1663 op = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1666 g_warning ("%s: Processing InterfaceRemoved signal for path %s but no object proxy exists",
1669 g_mutex_unlock (&manager->priv->lock);
1673 interfaces = g_dbus_object_get_interfaces (G_DBUS_OBJECT (op));
1674 num_interfaces = g_list_length (interfaces);
1675 g_list_free_full (interfaces, g_object_unref);
1677 num_interfaces_to_remove = g_strv_length ((gchar **) interface_names);
1679 /* see if we are going to completety remove the object */
1680 g_object_ref (manager);
1681 if (num_interfaces_to_remove == num_interfaces)
1684 g_warn_if_fail (g_hash_table_remove (manager->priv->map_object_path_to_object_proxy, object_path));
1685 g_mutex_unlock (&manager->priv->lock);
1686 g_signal_emit_by_name (manager, "object-removed", op);
1687 g_object_unref (op);
1692 g_mutex_unlock (&manager->priv->lock);
1693 for (n = 0; interface_names != NULL && interface_names[n] != NULL; n++)
1695 GDBusInterface *interface;
1696 interface = g_dbus_object_get_interface (G_DBUS_OBJECT (op), interface_names[n]);
1697 _g_dbus_object_proxy_remove_interface (op, interface_names[n]);
1698 if (interface != NULL)
1700 g_signal_emit_by_name (manager, "interface-removed", op, interface);
1701 g_object_unref (interface);
1704 g_object_unref (op);
1706 g_object_unref (manager);
1712 process_get_all_result (GDBusObjectManagerClient *manager,
1714 const gchar *name_owner)
1717 const gchar *object_path;
1718 GVariant *ifaces_and_properties;
1721 g_return_if_fail (name_owner == NULL || g_dbus_is_unique_name (name_owner));
1723 arg0 = g_variant_get_child_value (value, 0);
1724 g_variant_iter_init (&iter, arg0);
1725 while (g_variant_iter_next (&iter,
1728 &ifaces_and_properties))
1730 add_interfaces (manager, object_path, ifaces_and_properties, name_owner);
1731 g_variant_unref (ifaces_and_properties);
1733 g_variant_unref (arg0);
1737 on_control_proxy_g_signal (GDBusProxy *proxy,
1738 const gchar *sender_name,
1739 const gchar *signal_name,
1740 GVariant *parameters,
1743 GWeakRef *manager_weak = user_data;
1744 GDBusObjectManagerClient *manager = NULL;
1745 const gchar *object_path;
1747 manager = G_DBUS_OBJECT_MANAGER_CLIENT (g_weak_ref_get (manager_weak));
1748 if (manager == NULL)
1751 //g_debug ("yay, g_signal %s: %s\n", signal_name, g_variant_print (parameters, TRUE));
1753 if (g_strcmp0 (signal_name, "InterfacesAdded") == 0)
1755 GVariant *ifaces_and_properties;
1756 g_variant_get (parameters,
1759 &ifaces_and_properties);
1760 add_interfaces (manager, object_path, ifaces_and_properties, manager->priv->name_owner);
1761 g_variant_unref (ifaces_and_properties);
1763 else if (g_strcmp0 (signal_name, "InterfacesRemoved") == 0)
1765 const gchar **ifaces;
1766 g_variant_get (parameters,
1770 remove_interfaces (manager, object_path, ifaces);
1774 g_object_unref (manager);
1777 /* ---------------------------------------------------------------------------------------------------- */
1779 static const gchar *
1780 g_dbus_object_manager_client_get_object_path (GDBusObjectManager *_manager)
1782 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
1783 return manager->priv->object_path;
1786 static GDBusObject *
1787 g_dbus_object_manager_client_get_object (GDBusObjectManager *_manager,
1788 const gchar *object_path)
1790 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
1793 g_mutex_lock (&manager->priv->lock);
1794 ret = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1797 g_mutex_unlock (&manager->priv->lock);
1801 static GDBusInterface *
1802 g_dbus_object_manager_client_get_interface (GDBusObjectManager *_manager,
1803 const gchar *object_path,
1804 const gchar *interface_name)
1806 GDBusInterface *ret;
1807 GDBusObject *object;
1811 object = g_dbus_object_manager_get_object (_manager, object_path);
1815 ret = g_dbus_object_get_interface (object, interface_name);
1816 g_object_unref (object);
1823 g_dbus_object_manager_client_get_objects (GDBusObjectManager *_manager)
1825 GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
1828 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
1830 g_mutex_lock (&manager->priv->lock);
1831 ret = g_hash_table_get_values (manager->priv->map_object_path_to_object_proxy);
1832 g_list_foreach (ret, (GFunc) g_object_ref, NULL);
1833 g_mutex_unlock (&manager->priv->lock);
1840 dbus_object_manager_interface_init (GDBusObjectManagerIface *iface)
1842 iface->get_object_path = g_dbus_object_manager_client_get_object_path;
1843 iface->get_objects = g_dbus_object_manager_client_get_objects;
1844 iface->get_object = g_dbus_object_manager_client_get_object;
1845 iface->get_interface = g_dbus_object_manager_client_get_interface;
1848 /* ---------------------------------------------------------------------------------------------------- */