1 /* GDBus - GLib D-Bus Library
3 * Copyright (C) 2008-2010 Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 * Author: David Zeuthen <davidz@redhat.com>
23 #include "gdbusobjectmanager.h"
24 #include "gdbusobjectmanagerclient.h"
25 #include "gdbusobject.h"
26 #include "gdbusprivate.h"
27 #include "gioenumtypes.h"
28 #include "ginitable.h"
29 #include "gasyncresult.h"
30 #include "gasyncinitable.h"
31 #include "gdbusconnection.h"
32 #include "gdbusutils.h"
33 #include "gdbusobject.h"
34 #include "gdbusobjectproxy.h"
35 #include "gdbusproxy.h"
36 #include "gdbusinterface.h"
41 * SECTION:gdbusobjectmanagerclient
42 * @short_description: Client-side object manager
45 * #GDBusObjectManagerClient is used to create, monitor and delete object
46 * proxies for remote objects exported by a #GDBusObjectManagerServer (or any
47 * code implementing the
48 * [org.freedesktop.DBus.ObjectManager](http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager)
51 * Once an instance of this type has been created, you can connect to
52 * the #GDBusObjectManager::object-added and
53 * #GDBusObjectManager::object-removed signals and inspect the
54 * #GDBusObjectProxy objects returned by
55 * g_dbus_object_manager_get_objects().
57 * If the name for a #GDBusObjectManagerClient is not owned by anyone at
58 * object construction time, the default behavior is to request the
59 * message bus to launch an owner for the name. This behavior can be
60 * disabled using the %G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START
61 * flag. It's also worth noting that this only works if the name of
62 * interest is activatable in the first place. E.g. in some cases it
63 * is not possible to launch an owner for the requested name. In this
64 * case, #GDBusObjectManagerClient object construction still succeeds but
65 * there will be no object proxies
66 * (e.g. g_dbus_object_manager_get_objects() returns the empty list) and
67 * the #GDBusObjectManagerClient:name-owner property is %NULL.
69 * The owner of the requested name can come and go (for example
70 * consider a system service being restarted) – #GDBusObjectManagerClient
71 * handles this case too; simply connect to the #GObject::notify
72 * signal to watch for changes on the #GDBusObjectManagerClient:name-owner
73 * property. When the name owner vanishes, the behavior is that
74 * #GDBusObjectManagerClient:name-owner is set to %NULL (this includes
75 * emission of the #GObject::notify signal) and then
76 * #GDBusObjectManager::object-removed signals are synthesized
77 * for all currently existing object proxies. Since
78 * #GDBusObjectManagerClient:name-owner is %NULL when this happens, you can
79 * use this information to disambiguate a synthesized signal from a
80 * genuine signal caused by object removal on the remote
81 * #GDBusObjectManager. Similarly, when a new name owner appears,
82 * #GDBusObjectManager::object-added signals are synthesized
83 * while #GDBusObjectManagerClient:name-owner is still %NULL. Only when all
84 * object proxies have been added, the #GDBusObjectManagerClient:name-owner
85 * is set to the new name owner (this includes emission of the
86 * #GObject::notify signal). Furthermore, you are guaranteed that
87 * #GDBusObjectManagerClient:name-owner will alternate between a name owner
88 * (e.g. `:1.42`) and %NULL even in the case where
89 * the name of interest is atomically replaced
91 * Ultimately, #GDBusObjectManagerClient is used to obtain #GDBusProxy
92 * instances. All signals (including the
93 * org.freedesktop.DBus.Properties::PropertiesChanged signal)
94 * delivered to #GDBusProxy instances are guaranteed to originate
95 * from the name owner. This guarantee along with the behavior
96 * described above, means that certain race conditions including the
97 * "half the proxy is from the old owner and the other half is from
98 * the new owner" problem cannot happen.
100 * To avoid having the application connect to signals on the returned
101 * #GDBusObjectProxy and #GDBusProxy objects, the
102 * #GDBusObject::interface-added,
103 * #GDBusObject::interface-removed,
104 * #GDBusProxy::g-properties-changed and
105 * #GDBusProxy::g-signal signals
106 * are also emitted on the #GDBusObjectManagerClient instance managing these
107 * objects. The signals emitted are
108 * #GDBusObjectManager::interface-added,
109 * #GDBusObjectManager::interface-removed,
110 * #GDBusObjectManagerClient::interface-proxy-properties-changed and
111 * #GDBusObjectManagerClient::interface-proxy-signal.
113 * Note that all callbacks and signals are emitted in the
114 * [thread-default main context][g-main-context-push-thread-default]
115 * that the #GDBusObjectManagerClient object was constructed
116 * in. Additionally, the #GDBusObjectProxy and #GDBusProxy objects
117 * originating from the #GDBusObjectManagerClient object will be created in
118 * the same context and, consequently, will deliver signals in the
122 struct _GDBusObjectManagerClientPrivate
127 GDBusConnection
*connection
;
131 GDBusObjectManagerClientFlags flags
;
133 GDBusProxy
*control_proxy
;
135 GHashTable
*map_object_path_to_object_proxy
;
137 guint signal_subscription_id
;
140 GDBusProxyTypeFunc get_proxy_type_func
;
141 gpointer get_proxy_type_user_data
;
142 GDestroyNotify get_proxy_type_destroy_notify
;
154 PROP_GET_PROXY_TYPE_FUNC
,
155 PROP_GET_PROXY_TYPE_USER_DATA
,
156 PROP_GET_PROXY_TYPE_DESTROY_NOTIFY
161 INTERFACE_PROXY_SIGNAL_SIGNAL
,
162 INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL
,
166 static guint signals
[LAST_SIGNAL
] = { 0 };
168 static void initable_iface_init (GInitableIface
*initable_iface
);
169 static void async_initable_iface_init (GAsyncInitableIface
*async_initable_iface
);
170 static void dbus_object_manager_interface_init (GDBusObjectManagerIface
*iface
);
172 G_DEFINE_TYPE_WITH_CODE (GDBusObjectManagerClient
, g_dbus_object_manager_client
, G_TYPE_OBJECT
,
173 G_ADD_PRIVATE (GDBusObjectManagerClient
)
174 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE
, initable_iface_init
)
175 G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE
, async_initable_iface_init
)
176 G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_OBJECT_MANAGER
, dbus_object_manager_interface_init
));
178 static void maybe_unsubscribe_signals (GDBusObjectManagerClient
*manager
);
180 static void on_control_proxy_g_signal (GDBusProxy
*proxy
,
181 const gchar
*sender_name
,
182 const gchar
*signal_name
,
183 GVariant
*parameters
,
186 static void process_get_all_result (GDBusObjectManagerClient
*manager
,
188 const gchar
*name_owner
);
191 g_dbus_object_manager_client_finalize (GObject
*object
)
193 GDBusObjectManagerClient
*manager
= G_DBUS_OBJECT_MANAGER_CLIENT (object
);
195 maybe_unsubscribe_signals (manager
);
197 g_hash_table_unref (manager
->priv
->map_object_path_to_object_proxy
);
199 if (manager
->priv
->control_proxy
!= NULL
)
201 g_signal_handlers_disconnect_by_func (manager
->priv
->control_proxy
,
202 on_control_proxy_g_signal
,
204 g_object_unref (manager
->priv
->control_proxy
);
206 if (manager
->priv
->connection
!= NULL
)
207 g_object_unref (manager
->priv
->connection
);
208 g_free (manager
->priv
->object_path
);
209 g_free (manager
->priv
->name
);
210 g_free (manager
->priv
->name_owner
);
212 if (manager
->priv
->get_proxy_type_destroy_notify
!= NULL
)
213 manager
->priv
->get_proxy_type_destroy_notify (manager
->priv
->get_proxy_type_user_data
);
215 g_mutex_clear (&manager
->priv
->lock
);
217 if (G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class
)->finalize
!= NULL
)
218 G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class
)->finalize (object
);
222 g_dbus_object_manager_client_get_property (GObject
*_object
,
227 GDBusObjectManagerClient
*manager
= G_DBUS_OBJECT_MANAGER_CLIENT (_object
);
231 case PROP_CONNECTION
:
232 g_value_set_object (value
, g_dbus_object_manager_client_get_connection (manager
));
235 case PROP_OBJECT_PATH
:
236 g_value_set_string (value
, g_dbus_object_manager_get_object_path (G_DBUS_OBJECT_MANAGER (manager
)));
240 g_value_set_string (value
, g_dbus_object_manager_client_get_name (manager
));
244 g_value_set_flags (value
, g_dbus_object_manager_client_get_flags (manager
));
247 case PROP_NAME_OWNER
:
248 g_value_take_string (value
, g_dbus_object_manager_client_get_name_owner (manager
));
252 G_OBJECT_WARN_INVALID_PROPERTY_ID (manager
, prop_id
, pspec
);
258 g_dbus_object_manager_client_set_property (GObject
*_object
,
263 GDBusObjectManagerClient
*manager
= G_DBUS_OBJECT_MANAGER_CLIENT (_object
);
269 manager
->priv
->bus_type
= g_value_get_enum (value
);
272 case PROP_CONNECTION
:
273 if (g_value_get_object (value
) != NULL
)
275 g_assert (manager
->priv
->connection
== NULL
);
276 g_assert (G_IS_DBUS_CONNECTION (g_value_get_object (value
)));
277 manager
->priv
->connection
= g_value_dup_object (value
);
281 case PROP_OBJECT_PATH
:
282 g_assert (manager
->priv
->object_path
== NULL
);
283 g_assert (g_variant_is_object_path (g_value_get_string (value
)));
284 manager
->priv
->object_path
= g_value_dup_string (value
);
288 g_assert (manager
->priv
->name
== NULL
);
289 name
= g_value_get_string (value
);
290 g_assert (name
== NULL
|| g_dbus_is_name (name
));
291 manager
->priv
->name
= g_strdup (name
);
295 manager
->priv
->flags
= g_value_get_flags (value
);
298 case PROP_GET_PROXY_TYPE_FUNC
:
299 manager
->priv
->get_proxy_type_func
= g_value_get_pointer (value
);
302 case PROP_GET_PROXY_TYPE_USER_DATA
:
303 manager
->priv
->get_proxy_type_user_data
= g_value_get_pointer (value
);
306 case PROP_GET_PROXY_TYPE_DESTROY_NOTIFY
:
307 manager
->priv
->get_proxy_type_destroy_notify
= g_value_get_pointer (value
);
311 G_OBJECT_WARN_INVALID_PROPERTY_ID (manager
, prop_id
, pspec
);
317 g_dbus_object_manager_client_class_init (GDBusObjectManagerClientClass
*klass
)
319 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
321 gobject_class
->finalize
= g_dbus_object_manager_client_finalize
;
322 gobject_class
->set_property
= g_dbus_object_manager_client_set_property
;
323 gobject_class
->get_property
= g_dbus_object_manager_client_get_property
;
326 * GDBusObjectManagerClient:connection:
328 * The #GDBusConnection to use.
332 g_object_class_install_property (gobject_class
,
334 g_param_spec_object ("connection",
336 "The connection to use",
337 G_TYPE_DBUS_CONNECTION
,
340 G_PARAM_CONSTRUCT_ONLY
|
341 G_PARAM_STATIC_STRINGS
));
344 * GDBusObjectManagerClient:bus-type:
346 * If this property is not %G_BUS_TYPE_NONE, then
347 * #GDBusObjectManagerClient:connection must be %NULL and will be set to the
348 * #GDBusConnection obtained by calling g_bus_get() with the value
353 g_object_class_install_property (gobject_class
,
355 g_param_spec_enum ("bus-type",
357 "The bus to connect to, if any",
361 G_PARAM_CONSTRUCT_ONLY
|
362 G_PARAM_STATIC_NAME
|
363 G_PARAM_STATIC_BLURB
|
364 G_PARAM_STATIC_NICK
));
367 * GDBusObjectManagerClient:flags:
369 * Flags from the #GDBusObjectManagerClientFlags enumeration.
373 g_object_class_install_property (gobject_class
,
375 g_param_spec_flags ("flags",
377 "Flags for the proxy manager",
378 G_TYPE_DBUS_OBJECT_MANAGER_CLIENT_FLAGS
,
379 G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE
,
382 G_PARAM_CONSTRUCT_ONLY
|
383 G_PARAM_STATIC_NAME
|
384 G_PARAM_STATIC_BLURB
|
385 G_PARAM_STATIC_NICK
));
388 * GDBusObjectManagerClient:object-path:
390 * The object path the manager is for.
394 g_object_class_install_property (gobject_class
,
396 g_param_spec_string ("object-path",
398 "The object path of the control object",
402 G_PARAM_CONSTRUCT_ONLY
|
403 G_PARAM_STATIC_STRINGS
));
406 * GDBusObjectManagerClient:name:
408 * The well-known name or unique name that the manager is for.
412 g_object_class_install_property (gobject_class
,
414 g_param_spec_string ("name",
416 "Name that the manager is for",
420 G_PARAM_CONSTRUCT_ONLY
|
421 G_PARAM_STATIC_STRINGS
));
424 * GDBusObjectManagerClient:name-owner:
426 * The unique name that owns #GDBusObjectManagerClient:name or %NULL if
427 * no-one is currently owning the name. Connect to the
428 * #GObject::notify signal to track changes to this property.
432 g_object_class_install_property (gobject_class
,
434 g_param_spec_string ("name-owner",
436 "The owner of the name we are watching",
439 G_PARAM_STATIC_STRINGS
));
442 * GDBusObjectManagerClient:get-proxy-type-func:
444 * The #GDBusProxyTypeFunc to use when determining what #GType to
445 * use for interface proxies or %NULL.
449 g_object_class_install_property (gobject_class
,
450 PROP_GET_PROXY_TYPE_FUNC
,
451 g_param_spec_pointer ("get-proxy-type-func",
452 "GDBusProxyTypeFunc Function Pointer",
453 "The GDBusProxyTypeFunc pointer to use",
456 G_PARAM_CONSTRUCT_ONLY
|
457 G_PARAM_STATIC_STRINGS
));
460 * GDBusObjectManagerClient:get-proxy-type-user-data:
462 * The #gpointer user_data to pass to #GDBusObjectManagerClient:get-proxy-type-func.
466 g_object_class_install_property (gobject_class
,
467 PROP_GET_PROXY_TYPE_USER_DATA
,
468 g_param_spec_pointer ("get-proxy-type-user-data",
469 "GDBusProxyTypeFunc User Data",
470 "The GDBusProxyTypeFunc user_data",
473 G_PARAM_CONSTRUCT_ONLY
|
474 G_PARAM_STATIC_STRINGS
));
477 * GDBusObjectManagerClient:get-proxy-type-destroy-notify:
479 * A #GDestroyNotify for the #gpointer user_data in #GDBusObjectManagerClient:get-proxy-type-user-data.
483 g_object_class_install_property (gobject_class
,
484 PROP_GET_PROXY_TYPE_DESTROY_NOTIFY
,
485 g_param_spec_pointer ("get-proxy-type-destroy-notify",
486 "GDBusProxyTypeFunc user data free function",
487 "The GDBusProxyTypeFunc user data free function",
490 G_PARAM_CONSTRUCT_ONLY
|
491 G_PARAM_STATIC_STRINGS
));
494 * GDBusObjectManagerClient::interface-proxy-signal:
495 * @manager: The #GDBusObjectManagerClient emitting the signal.
496 * @object_proxy: The #GDBusObjectProxy on which an interface is emitting a D-Bus signal.
497 * @interface_proxy: The #GDBusProxy that is emitting a D-Bus signal.
498 * @sender_name: The sender of the signal or NULL if the connection is not a bus connection.
499 * @signal_name: The signal name.
500 * @parameters: A #GVariant tuple with parameters for the signal.
502 * Emitted when a D-Bus signal is received on @interface_proxy.
504 * This signal exists purely as a convenience to avoid having to
505 * connect signals to all interface proxies managed by @manager.
507 * This signal is emitted in the
508 * [thread-default main context][g-main-context-push-thread-default]
509 * that @manager was constructed in.
513 signals
[INTERFACE_PROXY_SIGNAL_SIGNAL
] =
514 g_signal_new (I_("interface-proxy-signal"),
515 G_TYPE_DBUS_OBJECT_MANAGER_CLIENT
,
517 G_STRUCT_OFFSET (GDBusObjectManagerClientClass
, interface_proxy_signal
),
523 G_TYPE_DBUS_OBJECT_PROXY
,
530 * GDBusObjectManagerClient::interface-proxy-properties-changed:
531 * @manager: The #GDBusObjectManagerClient emitting the signal.
532 * @object_proxy: The #GDBusObjectProxy on which an interface has properties that are changing.
533 * @interface_proxy: The #GDBusProxy that has properties that are changing.
534 * @changed_properties: A #GVariant containing the properties that changed.
535 * @invalidated_properties: A %NULL terminated array of properties that was invalidated.
537 * Emitted when one or more D-Bus properties on proxy changes. The
538 * local cache has already been updated when this signal fires. Note
539 * that both @changed_properties and @invalidated_properties are
540 * guaranteed to never be %NULL (either may be empty though).
542 * This signal exists purely as a convenience to avoid having to
543 * connect signals to all interface proxies managed by @manager.
545 * This signal is emitted in the
546 * [thread-default main context][g-main-context-push-thread-default]
547 * that @manager was constructed in.
551 signals
[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL
] =
552 g_signal_new (I_("interface-proxy-properties-changed"),
553 G_TYPE_DBUS_OBJECT_MANAGER_CLIENT
,
555 G_STRUCT_OFFSET (GDBusObjectManagerClientClass
, interface_proxy_properties_changed
),
561 G_TYPE_DBUS_OBJECT_PROXY
,
568 g_dbus_object_manager_client_init (GDBusObjectManagerClient
*manager
)
570 manager
->priv
= g_dbus_object_manager_client_get_instance_private (manager
);
571 g_mutex_init (&manager
->priv
->lock
);
572 manager
->priv
->map_object_path_to_object_proxy
= g_hash_table_new_full (g_str_hash
,
575 (GDestroyNotify
) g_object_unref
);
578 /* ---------------------------------------------------------------------------------------------------- */
581 * g_dbus_object_manager_client_new_sync:
582 * @connection: A #GDBusConnection.
583 * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
584 * @name: (nullable): The owner of the control object (unique or well-known name), or %NULL when not using a message bus connection.
585 * @object_path: The object path of the control object.
586 * @get_proxy_type_func: (nullable): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
587 * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
588 * @get_proxy_type_destroy_notify: (nullable): Free function for @get_proxy_type_user_data or %NULL.
589 * @cancellable: (nullable): A #GCancellable or %NULL
590 * @error: Return location for error or %NULL.
592 * Creates a new #GDBusObjectManagerClient object.
594 * This is a synchronous failable constructor - the calling thread is
595 * blocked until a reply is received. See g_dbus_object_manager_client_new()
596 * for the asynchronous version.
598 * Returns: (transfer full) (type GDBusObjectManagerClient): A
599 * #GDBusObjectManagerClient object or %NULL if @error is set. Free
600 * with g_object_unref().
605 g_dbus_object_manager_client_new_sync (GDBusConnection
*connection
,
606 GDBusObjectManagerClientFlags flags
,
608 const gchar
*object_path
,
609 GDBusProxyTypeFunc get_proxy_type_func
,
610 gpointer get_proxy_type_user_data
,
611 GDestroyNotify get_proxy_type_destroy_notify
,
612 GCancellable
*cancellable
,
617 g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection
), NULL
);
618 g_return_val_if_fail ((name
== NULL
&& g_dbus_connection_get_unique_name (connection
) == NULL
) ||
619 g_dbus_is_name (name
), NULL
);
620 g_return_val_if_fail (g_variant_is_object_path (object_path
), NULL
);
621 g_return_val_if_fail (error
== NULL
|| *error
== NULL
, NULL
);
623 initable
= g_initable_new (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT
,
626 "connection", connection
,
629 "object-path", object_path
,
630 "get-proxy-type-func", get_proxy_type_func
,
631 "get-proxy-type-user-data", get_proxy_type_user_data
,
632 "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify
,
634 if (initable
!= NULL
)
635 return G_DBUS_OBJECT_MANAGER (initable
);
641 * g_dbus_object_manager_client_new:
642 * @connection: A #GDBusConnection.
643 * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
644 * @name: The owner of the control object (unique or well-known name).
645 * @object_path: The object path of the control object.
646 * @get_proxy_type_func: (nullable): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
647 * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
648 * @get_proxy_type_destroy_notify: (nullable): Free function for @get_proxy_type_user_data or %NULL.
649 * @cancellable: (nullable): A #GCancellable or %NULL
650 * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
651 * @user_data: The data to pass to @callback.
653 * Asynchronously creates a new #GDBusObjectManagerClient object.
655 * This is an asynchronous failable constructor. When the result is
656 * ready, @callback will be invoked in the
657 * [thread-default main context][g-main-context-push-thread-default]
658 * of the thread you are calling this method from. You can
659 * then call g_dbus_object_manager_client_new_finish() to get the result. See
660 * g_dbus_object_manager_client_new_sync() for the synchronous version.
665 g_dbus_object_manager_client_new (GDBusConnection
*connection
,
666 GDBusObjectManagerClientFlags flags
,
668 const gchar
*object_path
,
669 GDBusProxyTypeFunc get_proxy_type_func
,
670 gpointer get_proxy_type_user_data
,
671 GDestroyNotify get_proxy_type_destroy_notify
,
672 GCancellable
*cancellable
,
673 GAsyncReadyCallback callback
,
676 g_return_if_fail (G_IS_DBUS_CONNECTION (connection
));
677 g_return_if_fail ((name
== NULL
&& g_dbus_connection_get_unique_name (connection
) == NULL
) ||
678 g_dbus_is_name (name
));
679 g_return_if_fail (g_variant_is_object_path (object_path
));
681 g_async_initable_new_async (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT
,
686 "connection", connection
,
689 "object-path", object_path
,
690 "get-proxy-type-func", get_proxy_type_func
,
691 "get-proxy-type-user-data", get_proxy_type_user_data
,
692 "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify
,
697 * g_dbus_object_manager_client_new_finish:
698 * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_object_manager_client_new().
699 * @error: Return location for error or %NULL.
701 * Finishes an operation started with g_dbus_object_manager_client_new().
703 * Returns: (transfer full) (type GDBusObjectManagerClient): A
704 * #GDBusObjectManagerClient object or %NULL if @error is set. Free
705 * with g_object_unref().
710 g_dbus_object_manager_client_new_finish (GAsyncResult
*res
,
714 GObject
*source_object
;
716 source_object
= g_async_result_get_source_object (res
);
717 g_assert (source_object
!= NULL
);
719 object
= g_async_initable_new_finish (G_ASYNC_INITABLE (source_object
),
722 g_object_unref (source_object
);
725 return G_DBUS_OBJECT_MANAGER (object
);
730 /* ---------------------------------------------------------------------------------------------------- */
733 * g_dbus_object_manager_client_new_for_bus_sync:
734 * @bus_type: A #GBusType.
735 * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
736 * @name: The owner of the control object (unique or well-known name).
737 * @object_path: The object path of the control object.
738 * @get_proxy_type_func: (nullable): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
739 * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
740 * @get_proxy_type_destroy_notify: (nullable): Free function for @get_proxy_type_user_data or %NULL.
741 * @cancellable: (nullable): A #GCancellable or %NULL
742 * @error: Return location for error or %NULL.
744 * Like g_dbus_object_manager_client_new_sync() but takes a #GBusType instead
745 * of a #GDBusConnection.
747 * This is a synchronous failable constructor - the calling thread is
748 * blocked until a reply is received. See g_dbus_object_manager_client_new_for_bus()
749 * for the asynchronous version.
751 * Returns: (transfer full) (type GDBusObjectManagerClient): A
752 * #GDBusObjectManagerClient object or %NULL if @error is set. Free
753 * with g_object_unref().
758 g_dbus_object_manager_client_new_for_bus_sync (GBusType bus_type
,
759 GDBusObjectManagerClientFlags flags
,
761 const gchar
*object_path
,
762 GDBusProxyTypeFunc get_proxy_type_func
,
763 gpointer get_proxy_type_user_data
,
764 GDestroyNotify get_proxy_type_destroy_notify
,
765 GCancellable
*cancellable
,
770 g_return_val_if_fail (bus_type
!= G_BUS_TYPE_NONE
, NULL
);
771 g_return_val_if_fail (g_dbus_is_name (name
), NULL
);
772 g_return_val_if_fail (g_variant_is_object_path (object_path
), NULL
);
773 g_return_val_if_fail (error
== NULL
|| *error
== NULL
, NULL
);
775 initable
= g_initable_new (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT
,
778 "bus-type", bus_type
,
781 "object-path", object_path
,
782 "get-proxy-type-func", get_proxy_type_func
,
783 "get-proxy-type-user-data", get_proxy_type_user_data
,
784 "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify
,
786 if (initable
!= NULL
)
787 return G_DBUS_OBJECT_MANAGER (initable
);
793 * g_dbus_object_manager_client_new_for_bus:
794 * @bus_type: A #GBusType.
795 * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
796 * @name: The owner of the control object (unique or well-known name).
797 * @object_path: The object path of the control object.
798 * @get_proxy_type_func: (nullable): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
799 * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
800 * @get_proxy_type_destroy_notify: (nullable): Free function for @get_proxy_type_user_data or %NULL.
801 * @cancellable: (nullable): A #GCancellable or %NULL
802 * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
803 * @user_data: The data to pass to @callback.
805 * Like g_dbus_object_manager_client_new() but takes a #GBusType instead of a
808 * This is an asynchronous failable constructor. When the result is
809 * ready, @callback will be invoked in the
810 * [thread-default main loop][g-main-context-push-thread-default]
811 * of the thread you are calling this method from. You can
812 * then call g_dbus_object_manager_client_new_for_bus_finish() to get the result. See
813 * g_dbus_object_manager_client_new_for_bus_sync() for the synchronous version.
818 g_dbus_object_manager_client_new_for_bus (GBusType bus_type
,
819 GDBusObjectManagerClientFlags flags
,
821 const gchar
*object_path
,
822 GDBusProxyTypeFunc get_proxy_type_func
,
823 gpointer get_proxy_type_user_data
,
824 GDestroyNotify get_proxy_type_destroy_notify
,
825 GCancellable
*cancellable
,
826 GAsyncReadyCallback callback
,
829 g_return_if_fail (bus_type
!= G_BUS_TYPE_NONE
);
830 g_return_if_fail (g_dbus_is_name (name
));
831 g_return_if_fail (g_variant_is_object_path (object_path
));
833 g_async_initable_new_async (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT
,
838 "bus-type", bus_type
,
841 "object-path", object_path
,
842 "get-proxy-type-func", get_proxy_type_func
,
843 "get-proxy-type-user-data", get_proxy_type_user_data
,
844 "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify
,
849 * g_dbus_object_manager_client_new_for_bus_finish:
850 * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_object_manager_client_new_for_bus().
851 * @error: Return location for error or %NULL.
853 * Finishes an operation started with g_dbus_object_manager_client_new_for_bus().
855 * Returns: (transfer full) (type GDBusObjectManagerClient): A
856 * #GDBusObjectManagerClient object or %NULL if @error is set. Free
857 * with g_object_unref().
862 g_dbus_object_manager_client_new_for_bus_finish (GAsyncResult
*res
,
866 GObject
*source_object
;
868 source_object
= g_async_result_get_source_object (res
);
869 g_assert (source_object
!= NULL
);
871 object
= g_async_initable_new_finish (G_ASYNC_INITABLE (source_object
),
874 g_object_unref (source_object
);
877 return G_DBUS_OBJECT_MANAGER (object
);
882 /* ---------------------------------------------------------------------------------------------------- */
885 * g_dbus_object_manager_client_get_connection:
886 * @manager: A #GDBusObjectManagerClient
888 * Gets the #GDBusConnection used by @manager.
890 * Returns: (transfer none): A #GDBusConnection object. Do not free,
891 * the object belongs to @manager.
896 g_dbus_object_manager_client_get_connection (GDBusObjectManagerClient
*manager
)
898 GDBusConnection
*ret
;
899 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager
), NULL
);
900 g_mutex_lock (&manager
->priv
->lock
);
901 ret
= manager
->priv
->connection
;
902 g_mutex_unlock (&manager
->priv
->lock
);
907 * g_dbus_object_manager_client_get_name:
908 * @manager: A #GDBusObjectManagerClient
910 * Gets the name that @manager is for, or %NULL if not a message bus
913 * Returns: A unique or well-known name. Do not free, the string
914 * belongs to @manager.
919 g_dbus_object_manager_client_get_name (GDBusObjectManagerClient
*manager
)
922 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager
), NULL
);
923 g_mutex_lock (&manager
->priv
->lock
);
924 ret
= manager
->priv
->name
;
925 g_mutex_unlock (&manager
->priv
->lock
);
930 * g_dbus_object_manager_client_get_flags:
931 * @manager: A #GDBusObjectManagerClient
933 * Gets the flags that @manager was constructed with.
935 * Returns: Zero of more flags from the #GDBusObjectManagerClientFlags
940 GDBusObjectManagerClientFlags
941 g_dbus_object_manager_client_get_flags (GDBusObjectManagerClient
*manager
)
943 GDBusObjectManagerClientFlags ret
;
944 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager
), G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE
);
945 g_mutex_lock (&manager
->priv
->lock
);
946 ret
= manager
->priv
->flags
;
947 g_mutex_unlock (&manager
->priv
->lock
);
952 * g_dbus_object_manager_client_get_name_owner:
953 * @manager: A #GDBusObjectManagerClient.
955 * The unique name that owns the name that @manager is for or %NULL if
956 * no-one currently owns that name. You can connect to the
957 * #GObject::notify signal to track changes to the
958 * #GDBusObjectManagerClient:name-owner property.
960 * Returns: (nullable): The name owner or %NULL if no name owner
961 * exists. Free with g_free().
966 g_dbus_object_manager_client_get_name_owner (GDBusObjectManagerClient
*manager
)
969 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager
), NULL
);
970 g_mutex_lock (&manager
->priv
->lock
);
971 ret
= g_strdup (manager
->priv
->name_owner
);
972 g_mutex_unlock (&manager
->priv
->lock
);
976 /* ---------------------------------------------------------------------------------------------------- */
978 /* signal handler for all objects we manage - we dispatch signals
979 * from here to the objects
982 signal_cb (GDBusConnection
*connection
,
983 const gchar
*sender_name
,
984 const gchar
*object_path
,
985 const gchar
*interface_name
,
986 const gchar
*signal_name
,
987 GVariant
*parameters
,
990 GDBusObjectManagerClient
*manager
= G_DBUS_OBJECT_MANAGER_CLIENT (user_data
);
991 GDBusObjectProxy
*object_proxy
;
992 GDBusInterface
*interface
;
994 g_mutex_lock (&manager
->priv
->lock
);
995 object_proxy
= g_hash_table_lookup (manager
->priv
->map_object_path_to_object_proxy
, object_path
);
996 if (object_proxy
== NULL
)
998 g_mutex_unlock (&manager
->priv
->lock
);
1001 g_object_ref (object_proxy
);
1002 g_mutex_unlock (&manager
->priv
->lock
);
1004 //g_debug ("yay, signal_cb %s %s: %s\n", signal_name, object_path, g_variant_print (parameters, TRUE));
1006 g_object_ref (manager
);
1007 if (g_strcmp0 (interface_name
, "org.freedesktop.DBus.Properties") == 0)
1009 if (g_strcmp0 (signal_name
, "PropertiesChanged") == 0)
1011 const gchar
*interface_name
;
1012 GVariant
*changed_properties
;
1013 const gchar
**invalidated_properties
;
1015 g_variant_get (parameters
,
1018 &changed_properties
,
1019 &invalidated_properties
);
1021 interface
= g_dbus_object_get_interface (G_DBUS_OBJECT (object_proxy
), interface_name
);
1022 if (interface
!= NULL
)
1024 GVariantIter property_iter
;
1025 const gchar
*property_name
;
1026 GVariant
*property_value
;
1029 /* update caches... */
1030 g_variant_iter_init (&property_iter
, changed_properties
);
1031 while (g_variant_iter_next (&property_iter
,
1036 g_dbus_proxy_set_cached_property (G_DBUS_PROXY (interface
),
1039 g_variant_unref (property_value
);
1042 for (n
= 0; invalidated_properties
[n
] != NULL
; n
++)
1044 g_dbus_proxy_set_cached_property (G_DBUS_PROXY (interface
),
1045 invalidated_properties
[n
],
1048 /* ... and then synthesize the signal */
1049 g_signal_emit_by_name (interface
,
1050 "g-properties-changed",
1052 invalidated_properties
);
1053 g_signal_emit (manager
,
1054 signals
[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL
],
1059 invalidated_properties
);
1060 g_object_unref (interface
);
1062 g_variant_unref (changed_properties
);
1063 g_free (invalidated_properties
);
1068 /* regular signal - just dispatch it */
1069 interface
= g_dbus_object_get_interface (G_DBUS_OBJECT (object_proxy
), interface_name
);
1070 if (interface
!= NULL
)
1072 g_signal_emit_by_name (interface
,
1077 g_signal_emit (manager
,
1078 signals
[INTERFACE_PROXY_SIGNAL_SIGNAL
],
1085 g_object_unref (interface
);
1088 g_object_unref (manager
);
1091 g_clear_object (&object_proxy
);
1095 subscribe_signals (GDBusObjectManagerClient
*manager
,
1096 const gchar
*name_owner
)
1098 GError
*error
= NULL
;
1101 g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager
));
1102 g_return_if_fail (manager
->priv
->signal_subscription_id
== 0);
1103 g_return_if_fail (name_owner
== NULL
|| g_dbus_is_unique_name (name_owner
));
1105 if (name_owner
!= NULL
)
1107 /* Only add path_namespace if it's non-'/'. This removes a no-op key from
1108 * the match rule, and also works around a D-Bus bug where
1109 * path_namespace='/' matches nothing in D-Bus versions < 1.6.18.
1111 * See: https://bugs.freedesktop.org/show_bug.cgi?id=70799 */
1112 if (g_str_equal (manager
->priv
->object_path
, "/"))
1114 manager
->priv
->match_rule
= g_strdup_printf ("type='signal',sender='%s'",
1119 manager
->priv
->match_rule
= g_strdup_printf ("type='signal',sender='%s',path_namespace='%s'",
1120 name_owner
, manager
->priv
->object_path
);
1123 /* The bus daemon may not implement path_namespace so gracefully
1124 * handle this by using a fallback triggered if @error is set. */
1125 ret
= g_dbus_connection_call_sync (manager
->priv
->connection
,
1126 "org.freedesktop.DBus",
1127 "/org/freedesktop/DBus",
1128 "org.freedesktop.DBus",
1130 g_variant_new ("(s)",
1131 manager
->priv
->match_rule
),
1132 NULL
, /* reply_type */
1133 G_DBUS_CALL_FLAGS_NONE
,
1134 -1, /* default timeout */
1135 NULL
, /* TODO: Cancellable */
1138 /* yay, bus daemon supports path_namespace */
1140 g_variant_unref (ret
);
1145 /* still need to ask GDBusConnection for the callbacks */
1146 manager
->priv
->signal_subscription_id
=
1147 g_dbus_connection_signal_subscribe (manager
->priv
->connection
,
1149 NULL
, /* interface */
1151 NULL
, /* path - TODO: really want wilcard support here */
1153 G_DBUS_SIGNAL_FLAGS_NONE
|
1154 G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE
,
1157 NULL
); /* user_data_free_func */
1162 /* TODO: we could report this to the user
1163 g_warning ("Message bus daemon does not support path_namespace: %s (%s %d)",
1165 g_quark_to_string (error->domain),
1169 g_error_free (error
);
1171 /* no need to call RemoveMatch when done since it didn't work */
1172 g_free (manager
->priv
->match_rule
);
1173 manager
->priv
->match_rule
= NULL
;
1175 /* Fallback is to subscribe to *all* signals from the name owner which
1176 * is rather wasteful. It's probably not a big practical problem because
1177 * users typically want all objects that the name owner supplies.
1179 manager
->priv
->signal_subscription_id
=
1180 g_dbus_connection_signal_subscribe (manager
->priv
->connection
,
1182 NULL
, /* interface */
1184 NULL
, /* path - TODO: really want wilcard support here */
1186 G_DBUS_SIGNAL_FLAGS_NONE
,
1189 NULL
); /* user_data_free_func */
1194 maybe_unsubscribe_signals (GDBusObjectManagerClient
*manager
)
1196 g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager
));
1198 if (manager
->priv
->signal_subscription_id
> 0)
1200 g_dbus_connection_signal_unsubscribe (manager
->priv
->connection
,
1201 manager
->priv
->signal_subscription_id
);
1202 manager
->priv
->signal_subscription_id
= 0;
1205 if (manager
->priv
->match_rule
!= NULL
)
1207 /* Since the AddMatch call succeeded this is guaranteed to not
1208 * fail - therefore, don't bother checking the return value
1210 g_dbus_connection_call (manager
->priv
->connection
,
1211 "org.freedesktop.DBus",
1212 "/org/freedesktop/DBus",
1213 "org.freedesktop.DBus",
1215 g_variant_new ("(s)",
1216 manager
->priv
->match_rule
),
1217 NULL
, /* reply_type */
1218 G_DBUS_CALL_FLAGS_NONE
,
1219 -1, /* default timeout */
1220 NULL
, /* GCancellable */
1221 NULL
, /* GAsyncReadyCallback */
1222 NULL
); /* user data */
1223 g_free (manager
->priv
->match_rule
);
1224 manager
->priv
->match_rule
= NULL
;
1229 /* ---------------------------------------------------------------------------------------------------- */
1232 on_notify_g_name_owner (GObject
*object
,
1236 GDBusObjectManagerClient
*manager
= G_DBUS_OBJECT_MANAGER_CLIENT (user_data
);
1237 gchar
*old_name_owner
;
1238 gchar
*new_name_owner
;
1240 g_mutex_lock (&manager
->priv
->lock
);
1241 old_name_owner
= manager
->priv
->name_owner
;
1242 new_name_owner
= g_dbus_proxy_get_name_owner (manager
->priv
->control_proxy
);
1243 manager
->priv
->name_owner
= NULL
;
1245 g_object_ref (manager
);
1246 if (g_strcmp0 (old_name_owner
, new_name_owner
) != 0)
1251 /* remote manager changed; nuke all local proxies */
1252 proxies
= g_hash_table_get_values (manager
->priv
->map_object_path_to_object_proxy
);
1253 g_list_foreach (proxies
, (GFunc
) g_object_ref
, NULL
);
1254 g_hash_table_remove_all (manager
->priv
->map_object_path_to_object_proxy
);
1256 g_mutex_unlock (&manager
->priv
->lock
);
1258 /* do the :name-owner notify with a NULL name - this way the user knows
1259 * the ::object-proxy-removed following is because the name owner went
1262 g_object_notify (G_OBJECT (manager
), "name-owner");
1264 for (l
= proxies
; l
!= NULL
; l
= l
->next
)
1266 GDBusObjectProxy
*object_proxy
= G_DBUS_OBJECT_PROXY (l
->data
);
1267 g_signal_emit_by_name (manager
, "object-removed", object_proxy
);
1269 g_list_free_full (proxies
, g_object_unref
);
1271 /* nuke local filter */
1272 maybe_unsubscribe_signals (manager
);
1276 g_mutex_unlock (&manager
->priv
->lock
);
1279 if (new_name_owner
!= NULL
)
1284 //g_debug ("repopulating for %s", new_name_owner);
1286 /* TODO: do this async! */
1287 subscribe_signals (manager
,
1290 value
= g_dbus_proxy_call_sync (manager
->priv
->control_proxy
,
1291 "GetManagedObjects",
1292 NULL
, /* parameters */
1293 G_DBUS_CALL_FLAGS_NONE
,
1299 maybe_unsubscribe_signals (manager
);
1300 g_warning ("Error calling GetManagedObjects() when name owner %s for name %s came back: %s",
1302 manager
->priv
->name
,
1304 g_error_free (error
);
1308 process_get_all_result (manager
, value
, new_name_owner
);
1309 g_variant_unref (value
);
1312 /* do the :name-owner notify *AFTER* emitting ::object-proxy-added signals - this
1313 * way the user knows that the signals were emitted because the name owner came back
1315 g_mutex_lock (&manager
->priv
->lock
);
1316 manager
->priv
->name_owner
= new_name_owner
;
1317 g_mutex_unlock (&manager
->priv
->lock
);
1318 g_object_notify (G_OBJECT (manager
), "name-owner");
1321 g_free (old_name_owner
);
1322 g_object_unref (manager
);
1326 initable_init (GInitable
*initable
,
1327 GCancellable
*cancellable
,
1330 GDBusObjectManagerClient
*manager
= G_DBUS_OBJECT_MANAGER_CLIENT (initable
);
1333 GDBusProxyFlags proxy_flags
;
1337 if (manager
->priv
->bus_type
!= G_BUS_TYPE_NONE
)
1339 g_assert (manager
->priv
->connection
== NULL
);
1340 manager
->priv
->connection
= g_bus_get_sync (manager
->priv
->bus_type
, cancellable
, error
);
1341 if (manager
->priv
->connection
== NULL
)
1345 proxy_flags
= G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES
;
1346 if (manager
->priv
->flags
& G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START
)
1347 proxy_flags
|= G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START
;
1349 manager
->priv
->control_proxy
= g_dbus_proxy_new_sync (manager
->priv
->connection
,
1351 NULL
, /* GDBusInterfaceInfo* */
1352 manager
->priv
->name
,
1353 manager
->priv
->object_path
,
1354 "org.freedesktop.DBus.ObjectManager",
1357 if (manager
->priv
->control_proxy
== NULL
)
1360 g_signal_connect (G_OBJECT (manager
->priv
->control_proxy
),
1361 "notify::g-name-owner",
1362 G_CALLBACK (on_notify_g_name_owner
),
1365 g_signal_connect (manager
->priv
->control_proxy
,
1367 G_CALLBACK (on_control_proxy_g_signal
),
1370 manager
->priv
->name_owner
= g_dbus_proxy_get_name_owner (manager
->priv
->control_proxy
);
1371 if (manager
->priv
->name_owner
== NULL
&& manager
->priv
->name
!= NULL
)
1373 /* it's perfectly fine if there's no name owner.. we're just going to
1374 * wait until one is ready
1379 /* yay, we can get the objects */
1380 subscribe_signals (manager
,
1381 manager
->priv
->name_owner
);
1382 value
= g_dbus_proxy_call_sync (manager
->priv
->control_proxy
,
1383 "GetManagedObjects",
1384 NULL
, /* parameters */
1385 G_DBUS_CALL_FLAGS_NONE
,
1391 maybe_unsubscribe_signals (manager
);
1392 g_warn_if_fail (g_signal_handlers_disconnect_by_func (manager
->priv
->control_proxy
,
1393 on_control_proxy_g_signal
,
1395 g_object_unref (manager
->priv
->control_proxy
);
1396 manager
->priv
->control_proxy
= NULL
;
1400 process_get_all_result (manager
, value
, manager
->priv
->name_owner
);
1401 g_variant_unref (value
);
1411 initable_iface_init (GInitableIface
*initable_iface
)
1413 initable_iface
->init
= initable_init
;
1417 async_initable_iface_init (GAsyncInitableIface
*async_initable_iface
)
1419 /* for now, just use default: run GInitable code in thread */
1422 /* ---------------------------------------------------------------------------------------------------- */
1425 add_interfaces (GDBusObjectManagerClient
*manager
,
1426 const gchar
*object_path
,
1427 GVariant
*ifaces_and_properties
,
1428 const gchar
*name_owner
)
1430 GDBusObjectProxy
*op
;
1433 const gchar
*interface_name
;
1434 GVariant
*properties
;
1435 GList
*interface_added_signals
, *l
;
1436 GDBusProxy
*interface_proxy
;
1438 g_return_if_fail (name_owner
== NULL
|| g_dbus_is_unique_name (name_owner
));
1440 g_mutex_lock (&manager
->priv
->lock
);
1442 interface_added_signals
= NULL
;
1445 op
= g_hash_table_lookup (manager
->priv
->map_object_path_to_object_proxy
, object_path
);
1448 GType object_proxy_type
;
1449 if (manager
->priv
->get_proxy_type_func
!= NULL
)
1451 object_proxy_type
= manager
->priv
->get_proxy_type_func (manager
,
1454 manager
->priv
->get_proxy_type_user_data
);
1455 g_warn_if_fail (g_type_is_a (object_proxy_type
, G_TYPE_DBUS_OBJECT_PROXY
));
1459 object_proxy_type
= G_TYPE_DBUS_OBJECT_PROXY
;
1461 op
= g_object_new (object_proxy_type
,
1462 "g-connection", manager
->priv
->connection
,
1463 "g-object-path", object_path
,
1469 g_variant_iter_init (&iter
, ifaces_and_properties
);
1470 while (g_variant_iter_next (&iter
,
1476 GType interface_proxy_type
;
1478 if (manager
->priv
->get_proxy_type_func
!= NULL
)
1480 interface_proxy_type
= manager
->priv
->get_proxy_type_func (manager
,
1483 manager
->priv
->get_proxy_type_user_data
);
1484 g_warn_if_fail (g_type_is_a (interface_proxy_type
, G_TYPE_DBUS_PROXY
));
1488 interface_proxy_type
= G_TYPE_DBUS_PROXY
;
1491 /* this is fine - there is no blocking IO because we pass DO_NOT_LOAD_PROPERTIES and
1492 * DO_NOT_CONNECT_SIGNALS and use a unique name
1495 interface_proxy
= g_initable_new (interface_proxy_type
,
1496 NULL
, /* GCancellable */
1498 "g-connection", manager
->priv
->connection
,
1499 "g-flags", G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES
|
1500 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS
,
1501 "g-name", name_owner
,
1502 "g-object-path", object_path
,
1503 "g-interface-name", interface_name
,
1505 if (interface_proxy
== NULL
)
1507 g_warning ("%s: Error constructing proxy for path %s and interface %s: %s",
1512 g_error_free (error
);
1516 GVariantIter property_iter
;
1517 const gchar
*property_name
;
1518 GVariant
*property_value
;
1520 /* associate the interface proxy with the object */
1521 g_dbus_interface_set_object (G_DBUS_INTERFACE (interface_proxy
),
1522 G_DBUS_OBJECT (op
));
1524 g_variant_iter_init (&property_iter
, properties
);
1525 while (g_variant_iter_next (&property_iter
,
1530 g_dbus_proxy_set_cached_property (interface_proxy
,
1533 g_variant_unref (property_value
);
1536 _g_dbus_object_proxy_add_interface (op
, interface_proxy
);
1538 interface_added_signals
= g_list_append (interface_added_signals
, g_object_ref (interface_proxy
));
1539 g_object_unref (interface_proxy
);
1541 g_variant_unref (properties
);
1544 g_mutex_unlock (&manager
->priv
->lock
);
1546 /* now that we don't hold the lock any more, emit signals */
1547 g_object_ref (manager
);
1548 for (l
= interface_added_signals
; l
!= NULL
; l
= l
->next
)
1550 interface_proxy
= G_DBUS_PROXY (l
->data
);
1551 g_signal_emit_by_name (manager
, "interface-added", op
, interface_proxy
);
1552 g_object_unref (interface_proxy
);
1554 g_list_free (interface_added_signals
);
1558 g_hash_table_insert (manager
->priv
->map_object_path_to_object_proxy
,
1559 g_strdup (object_path
),
1561 g_signal_emit_by_name (manager
, "object-added", op
);
1563 g_object_unref (manager
);
1564 g_object_unref (op
);
1568 remove_interfaces (GDBusObjectManagerClient
*manager
,
1569 const gchar
*object_path
,
1570 const gchar
*const *interface_names
)
1572 GDBusObjectProxy
*op
;
1575 guint num_interfaces
;
1576 guint num_interfaces_to_remove
;
1578 g_mutex_lock (&manager
->priv
->lock
);
1580 op
= g_hash_table_lookup (manager
->priv
->map_object_path_to_object_proxy
, object_path
);
1583 g_warning ("%s: Processing InterfaceRemoved signal for path %s but no object proxy exists",
1586 g_mutex_unlock (&manager
->priv
->lock
);
1590 interfaces
= g_dbus_object_get_interfaces (G_DBUS_OBJECT (op
));
1591 num_interfaces
= g_list_length (interfaces
);
1592 g_list_free_full (interfaces
, g_object_unref
);
1594 num_interfaces_to_remove
= g_strv_length ((gchar
**) interface_names
);
1596 /* see if we are going to completety remove the object */
1597 g_object_ref (manager
);
1598 if (num_interfaces_to_remove
== num_interfaces
)
1601 g_warn_if_fail (g_hash_table_remove (manager
->priv
->map_object_path_to_object_proxy
, object_path
));
1602 g_mutex_unlock (&manager
->priv
->lock
);
1603 g_signal_emit_by_name (manager
, "object-removed", op
);
1604 g_object_unref (op
);
1609 g_mutex_unlock (&manager
->priv
->lock
);
1610 for (n
= 0; interface_names
!= NULL
&& interface_names
[n
] != NULL
; n
++)
1612 GDBusInterface
*interface
;
1613 interface
= g_dbus_object_get_interface (G_DBUS_OBJECT (op
), interface_names
[n
]);
1614 _g_dbus_object_proxy_remove_interface (op
, interface_names
[n
]);
1615 if (interface
!= NULL
)
1617 g_signal_emit_by_name (manager
, "interface-removed", op
, interface
);
1618 g_object_unref (interface
);
1621 g_object_unref (op
);
1623 g_object_unref (manager
);
1629 process_get_all_result (GDBusObjectManagerClient
*manager
,
1631 const gchar
*name_owner
)
1634 const gchar
*object_path
;
1635 GVariant
*ifaces_and_properties
;
1638 g_return_if_fail (name_owner
== NULL
|| g_dbus_is_unique_name (name_owner
));
1640 arg0
= g_variant_get_child_value (value
, 0);
1641 g_variant_iter_init (&iter
, arg0
);
1642 while (g_variant_iter_next (&iter
,
1645 &ifaces_and_properties
))
1647 add_interfaces (manager
, object_path
, ifaces_and_properties
, name_owner
);
1648 g_variant_unref (ifaces_and_properties
);
1650 g_variant_unref (arg0
);
1654 on_control_proxy_g_signal (GDBusProxy
*proxy
,
1655 const gchar
*sender_name
,
1656 const gchar
*signal_name
,
1657 GVariant
*parameters
,
1660 GDBusObjectManagerClient
*manager
= G_DBUS_OBJECT_MANAGER_CLIENT (user_data
);
1661 const gchar
*object_path
;
1663 //g_debug ("yay, g_signal %s: %s\n", signal_name, g_variant_print (parameters, TRUE));
1665 if (g_strcmp0 (signal_name
, "InterfacesAdded") == 0)
1667 GVariant
*ifaces_and_properties
;
1668 g_variant_get (parameters
,
1671 &ifaces_and_properties
);
1672 add_interfaces (manager
, object_path
, ifaces_and_properties
, manager
->priv
->name_owner
);
1673 g_variant_unref (ifaces_and_properties
);
1675 else if (g_strcmp0 (signal_name
, "InterfacesRemoved") == 0)
1677 const gchar
**ifaces
;
1678 g_variant_get (parameters
,
1682 remove_interfaces (manager
, object_path
, ifaces
);
1687 /* ---------------------------------------------------------------------------------------------------- */
1689 static const gchar
*
1690 g_dbus_object_manager_client_get_object_path (GDBusObjectManager
*_manager
)
1692 GDBusObjectManagerClient
*manager
= G_DBUS_OBJECT_MANAGER_CLIENT (_manager
);
1693 return manager
->priv
->object_path
;
1696 static GDBusObject
*
1697 g_dbus_object_manager_client_get_object (GDBusObjectManager
*_manager
,
1698 const gchar
*object_path
)
1700 GDBusObjectManagerClient
*manager
= G_DBUS_OBJECT_MANAGER_CLIENT (_manager
);
1703 g_mutex_lock (&manager
->priv
->lock
);
1704 ret
= g_hash_table_lookup (manager
->priv
->map_object_path_to_object_proxy
, object_path
);
1707 g_mutex_unlock (&manager
->priv
->lock
);
1711 static GDBusInterface
*
1712 g_dbus_object_manager_client_get_interface (GDBusObjectManager
*_manager
,
1713 const gchar
*object_path
,
1714 const gchar
*interface_name
)
1716 GDBusInterface
*ret
;
1717 GDBusObject
*object
;
1721 object
= g_dbus_object_manager_get_object (_manager
, object_path
);
1725 ret
= g_dbus_object_get_interface (object
, interface_name
);
1726 g_object_unref (object
);
1733 g_dbus_object_manager_client_get_objects (GDBusObjectManager
*_manager
)
1735 GDBusObjectManagerClient
*manager
= G_DBUS_OBJECT_MANAGER_CLIENT (_manager
);
1738 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager
), NULL
);
1740 g_mutex_lock (&manager
->priv
->lock
);
1741 ret
= g_hash_table_get_values (manager
->priv
->map_object_path_to_object_proxy
);
1742 g_list_foreach (ret
, (GFunc
) g_object_ref
, NULL
);
1743 g_mutex_unlock (&manager
->priv
->lock
);
1750 dbus_object_manager_interface_init (GDBusObjectManagerIface
*iface
)
1752 iface
->get_object_path
= g_dbus_object_manager_client_get_object_path
;
1753 iface
->get_objects
= g_dbus_object_manager_client_get_objects
;
1754 iface
->get_object
= g_dbus_object_manager_client_get_object
;
1755 iface
->get_interface
= g_dbus_object_manager_client_get_interface
;
1758 /* ---------------------------------------------------------------------------------------------------- */