Change LGPL-2.1+ to LGPL-2.1-or-later
[platform/upstream/glib.git] / gio / gdbusobjectmanagerclient.c
1 /* GDBus - GLib D-Bus Library
2  *
3  * Copyright (C) 2008-2010 Red Hat, Inc.
4  *
5  * SPDX-License-Identifier: LGPL-2.1-or-later
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General
18  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19  *
20  * Author: David Zeuthen <davidz@redhat.com>
21  */
22
23 #include "config.h"
24
25 #include "gcancellable.h"
26 #include "gdbusobjectmanager.h"
27 #include "gdbusobjectmanagerclient.h"
28 #include "gdbusobject.h"
29 #include "gdbusprivate.h"
30 #include "gioenumtypes.h"
31 #include "gioerror.h"
32 #include "ginitable.h"
33 #include "gasyncresult.h"
34 #include "gasyncinitable.h"
35 #include "gdbusconnection.h"
36 #include "gdbusutils.h"
37 #include "gdbusobject.h"
38 #include "gdbusobjectproxy.h"
39 #include "gdbusproxy.h"
40 #include "gdbusinterface.h"
41
42 #include "glibintl.h"
43 #include "gmarshal-internal.h"
44
45 /**
46  * SECTION:gdbusobjectmanagerclient
47  * @short_description: Client-side object manager
48  * @include: gio/gio.h
49  *
50  * #GDBusObjectManagerClient is used to create, monitor and delete object
51  * proxies for remote objects exported by a #GDBusObjectManagerServer (or any
52  * code implementing the
53  * [org.freedesktop.DBus.ObjectManager](http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager)
54  * interface).
55  *
56  * Once an instance of this type has been created, you can connect to
57  * the #GDBusObjectManager::object-added and
58  * #GDBusObjectManager::object-removed signals and inspect the
59  * #GDBusObjectProxy objects returned by
60  * g_dbus_object_manager_get_objects().
61  *
62  * If the name for a #GDBusObjectManagerClient is not owned by anyone at
63  * object construction time, the default behavior is to request the
64  * message bus to launch an owner for the name. This behavior can be
65  * disabled using the %G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START
66  * flag. It's also worth noting that this only works if the name of
67  * interest is activatable in the first place. E.g. in some cases it
68  * is not possible to launch an owner for the requested name. In this
69  * case, #GDBusObjectManagerClient object construction still succeeds but
70  * there will be no object proxies
71  * (e.g. g_dbus_object_manager_get_objects() returns the empty list) and
72  * the #GDBusObjectManagerClient:name-owner property is %NULL.
73  *
74  * The owner of the requested name can come and go (for example
75  * consider a system service being restarted) – #GDBusObjectManagerClient
76  * handles this case too; simply connect to the #GObject::notify
77  * signal to watch for changes on the #GDBusObjectManagerClient:name-owner
78  * property. When the name owner vanishes, the behavior is that
79  * #GDBusObjectManagerClient:name-owner is set to %NULL (this includes
80  * emission of the #GObject::notify signal) and then
81  * #GDBusObjectManager::object-removed signals are synthesized
82  * for all currently existing object proxies. Since
83  * #GDBusObjectManagerClient:name-owner is %NULL when this happens, you can
84  * use this information to disambiguate a synthesized signal from a
85  * genuine signal caused by object removal on the remote
86  * #GDBusObjectManager. Similarly, when a new name owner appears,
87  * #GDBusObjectManager::object-added signals are synthesized
88  * while #GDBusObjectManagerClient:name-owner is still %NULL. Only when all
89  * object proxies have been added, the #GDBusObjectManagerClient:name-owner
90  * is set to the new name owner (this includes emission of the
91  * #GObject::notify signal).  Furthermore, you are guaranteed that
92  * #GDBusObjectManagerClient:name-owner will alternate between a name owner
93  * (e.g. `:1.42`) and %NULL even in the case where
94  * the name of interest is atomically replaced
95  *
96  * Ultimately, #GDBusObjectManagerClient is used to obtain #GDBusProxy
97  * instances. All signals (including the
98  * org.freedesktop.DBus.Properties::PropertiesChanged signal)
99  * delivered to #GDBusProxy instances are guaranteed to originate
100  * from the name owner. This guarantee along with the behavior
101  * described above, means that certain race conditions including the
102  * "half the proxy is from the old owner and the other half is from
103  * the new owner" problem cannot happen.
104  *
105  * To avoid having the application connect to signals on the returned
106  * #GDBusObjectProxy and #GDBusProxy objects, the
107  * #GDBusObject::interface-added,
108  * #GDBusObject::interface-removed,
109  * #GDBusProxy::g-properties-changed and
110  * #GDBusProxy::g-signal signals
111  * are also emitted on the #GDBusObjectManagerClient instance managing these
112  * objects. The signals emitted are
113  * #GDBusObjectManager::interface-added,
114  * #GDBusObjectManager::interface-removed,
115  * #GDBusObjectManagerClient::interface-proxy-properties-changed and
116  * #GDBusObjectManagerClient::interface-proxy-signal.
117  *
118  * Note that all callbacks and signals are emitted in the
119  * [thread-default main context][g-main-context-push-thread-default]
120  * that the #GDBusObjectManagerClient object was constructed
121  * in. Additionally, the #GDBusObjectProxy and #GDBusProxy objects
122  * originating from the #GDBusObjectManagerClient object will be created in
123  * the same context and, consequently, will deliver signals in the
124  * same main loop.
125  */
126
127 struct _GDBusObjectManagerClientPrivate
128 {
129   GMutex lock;
130
131   GBusType bus_type;
132   GDBusConnection *connection;
133   gchar *object_path;
134   gchar *name;
135   gchar *name_owner;
136   GDBusObjectManagerClientFlags flags;
137
138   GDBusProxy *control_proxy;
139
140   GHashTable *map_object_path_to_object_proxy;
141
142   guint signal_subscription_id;
143   gchar *match_rule;
144
145   GDBusProxyTypeFunc get_proxy_type_func;
146   gpointer get_proxy_type_user_data;
147   GDestroyNotify get_proxy_type_destroy_notify;
148
149   gulong name_owner_signal_id;
150   gulong signal_signal_id;
151   GCancellable *cancel;
152 };
153
154 enum
155 {
156   PROP_0,
157   PROP_BUS_TYPE,
158   PROP_CONNECTION,
159   PROP_FLAGS,
160   PROP_OBJECT_PATH,
161   PROP_NAME,
162   PROP_NAME_OWNER,
163   PROP_GET_PROXY_TYPE_FUNC,
164   PROP_GET_PROXY_TYPE_USER_DATA,
165   PROP_GET_PROXY_TYPE_DESTROY_NOTIFY
166 };
167
168 enum
169 {
170   INTERFACE_PROXY_SIGNAL_SIGNAL,
171   INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL,
172   LAST_SIGNAL
173 };
174
175 static guint signals[LAST_SIGNAL] = { 0 };
176
177 static void initable_iface_init       (GInitableIface *initable_iface);
178 static void async_initable_iface_init (GAsyncInitableIface *async_initable_iface);
179 static void dbus_object_manager_interface_init (GDBusObjectManagerIface *iface);
180
181 G_DEFINE_TYPE_WITH_CODE (GDBusObjectManagerClient, g_dbus_object_manager_client, G_TYPE_OBJECT,
182                          G_ADD_PRIVATE (GDBusObjectManagerClient)
183                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)
184                          G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init)
185                          G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_OBJECT_MANAGER, dbus_object_manager_interface_init))
186
187 static void maybe_unsubscribe_signals (GDBusObjectManagerClient *manager);
188
189 static void on_control_proxy_g_signal (GDBusProxy   *proxy,
190                                        const gchar  *sender_name,
191                                        const gchar  *signal_name,
192                                        GVariant     *parameters,
193                                        gpointer      user_data);
194
195 static void process_get_all_result (GDBusObjectManagerClient *manager,
196                                     GVariant          *value,
197                                     const gchar       *name_owner);
198
199 static void
200 g_dbus_object_manager_client_dispose (GObject *object)
201 {
202   GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (object);
203
204   if (manager->priv->cancel != NULL)
205     {
206       g_cancellable_cancel (manager->priv->cancel);
207       g_clear_object (&manager->priv->cancel);
208     }
209
210   G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class)->dispose (object);
211 }
212
213 static void
214 g_dbus_object_manager_client_finalize (GObject *object)
215 {
216   GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (object);
217
218   maybe_unsubscribe_signals (manager);
219
220   g_hash_table_unref (manager->priv->map_object_path_to_object_proxy);
221
222   if (manager->priv->control_proxy != NULL && manager->priv->signal_signal_id != 0)
223     g_signal_handler_disconnect (manager->priv->control_proxy,
224                                  manager->priv->signal_signal_id);
225   manager->priv->signal_signal_id = 0;
226
227   if (manager->priv->control_proxy != NULL && manager->priv->name_owner_signal_id != 0)
228     g_signal_handler_disconnect (manager->priv->control_proxy,
229                                  manager->priv->name_owner_signal_id);
230   manager->priv->name_owner_signal_id = 0;
231
232   g_clear_object (&manager->priv->control_proxy);
233
234   if (manager->priv->connection != NULL)
235     g_object_unref (manager->priv->connection);
236   g_free (manager->priv->object_path);
237   g_free (manager->priv->name);
238   g_free (manager->priv->name_owner);
239
240   if (manager->priv->get_proxy_type_destroy_notify != NULL)
241     manager->priv->get_proxy_type_destroy_notify (manager->priv->get_proxy_type_user_data);
242
243   g_mutex_clear (&manager->priv->lock);
244
245   if (G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class)->finalize != NULL)
246     G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class)->finalize (object);
247 }
248
249 static void
250 g_dbus_object_manager_client_get_property (GObject    *_object,
251                                            guint       prop_id,
252                                            GValue     *value,
253                                            GParamSpec *pspec)
254 {
255   GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_object);
256
257   switch (prop_id)
258     {
259     case PROP_CONNECTION:
260       g_value_set_object (value, g_dbus_object_manager_client_get_connection (manager));
261       break;
262
263     case PROP_OBJECT_PATH:
264       g_value_set_string (value, g_dbus_object_manager_get_object_path (G_DBUS_OBJECT_MANAGER (manager)));
265       break;
266
267     case PROP_NAME:
268       g_value_set_string (value, g_dbus_object_manager_client_get_name (manager));
269       break;
270
271     case PROP_FLAGS:
272       g_value_set_flags (value, g_dbus_object_manager_client_get_flags (manager));
273       break;
274
275     case PROP_NAME_OWNER:
276       g_value_take_string (value, g_dbus_object_manager_client_get_name_owner (manager));
277       break;
278
279     default:
280       G_OBJECT_WARN_INVALID_PROPERTY_ID (manager, prop_id, pspec);
281       break;
282     }
283 }
284
285 static void
286 g_dbus_object_manager_client_set_property (GObject       *_object,
287                                            guint          prop_id,
288                                            const GValue  *value,
289                                            GParamSpec    *pspec)
290 {
291   GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_object);
292   const gchar *name;
293
294   switch (prop_id)
295     {
296     case PROP_BUS_TYPE:
297       manager->priv->bus_type = g_value_get_enum (value);
298       break;
299
300     case PROP_CONNECTION:
301       if (g_value_get_object (value) != NULL)
302         {
303           g_assert (manager->priv->connection == NULL);
304           g_assert (G_IS_DBUS_CONNECTION (g_value_get_object (value)));
305           manager->priv->connection = g_value_dup_object (value);
306         }
307       break;
308
309     case PROP_OBJECT_PATH:
310       g_assert (manager->priv->object_path == NULL);
311       g_assert (g_variant_is_object_path (g_value_get_string (value)));
312       manager->priv->object_path = g_value_dup_string (value);
313       break;
314
315     case PROP_NAME:
316       g_assert (manager->priv->name == NULL);
317       name = g_value_get_string (value);
318       g_assert (name == NULL || g_dbus_is_name (name));
319       manager->priv->name = g_strdup (name);
320       break;
321
322     case PROP_FLAGS:
323       manager->priv->flags = g_value_get_flags (value);
324       break;
325
326     case PROP_GET_PROXY_TYPE_FUNC:
327       manager->priv->get_proxy_type_func = g_value_get_pointer (value);
328       break;
329
330     case PROP_GET_PROXY_TYPE_USER_DATA:
331       manager->priv->get_proxy_type_user_data = g_value_get_pointer (value);
332       break;
333
334     case PROP_GET_PROXY_TYPE_DESTROY_NOTIFY:
335       manager->priv->get_proxy_type_destroy_notify = g_value_get_pointer (value);
336       break;
337
338     default:
339       G_OBJECT_WARN_INVALID_PROPERTY_ID (manager, prop_id, pspec);
340       break;
341     }
342 }
343
344 static void
345 g_dbus_object_manager_client_class_init (GDBusObjectManagerClientClass *klass)
346 {
347   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
348
349   gobject_class->dispose      = g_dbus_object_manager_client_dispose;
350   gobject_class->finalize     = g_dbus_object_manager_client_finalize;
351   gobject_class->set_property = g_dbus_object_manager_client_set_property;
352   gobject_class->get_property = g_dbus_object_manager_client_get_property;
353
354   /**
355    * GDBusObjectManagerClient:connection:
356    *
357    * The #GDBusConnection to use.
358    *
359    * Since: 2.30
360    */
361   g_object_class_install_property (gobject_class,
362                                    PROP_CONNECTION,
363                                    g_param_spec_object ("connection",
364                                                         "Connection",
365                                                         "The connection to use",
366                                                         G_TYPE_DBUS_CONNECTION,
367                                                         G_PARAM_READABLE |
368                                                         G_PARAM_WRITABLE |
369                                                         G_PARAM_CONSTRUCT_ONLY |
370                                                         G_PARAM_STATIC_STRINGS));
371
372   /**
373    * GDBusObjectManagerClient:bus-type:
374    *
375    * If this property is not %G_BUS_TYPE_NONE, then
376    * #GDBusObjectManagerClient:connection must be %NULL and will be set to the
377    * #GDBusConnection obtained by calling g_bus_get() with the value
378    * of this property.
379    *
380    * Since: 2.30
381    */
382   g_object_class_install_property (gobject_class,
383                                    PROP_BUS_TYPE,
384                                    g_param_spec_enum ("bus-type",
385                                                       "Bus Type",
386                                                       "The bus to connect to, if any",
387                                                       G_TYPE_BUS_TYPE,
388                                                       G_BUS_TYPE_NONE,
389                                                       G_PARAM_WRITABLE |
390                                                       G_PARAM_CONSTRUCT_ONLY |
391                                                       G_PARAM_STATIC_NAME |
392                                                       G_PARAM_STATIC_BLURB |
393                                                       G_PARAM_STATIC_NICK));
394
395   /**
396    * GDBusObjectManagerClient:flags:
397    *
398    * Flags from the #GDBusObjectManagerClientFlags enumeration.
399    *
400    * Since: 2.30
401    */
402   g_object_class_install_property (gobject_class,
403                                    PROP_FLAGS,
404                                    g_param_spec_flags ("flags",
405                                                        "Flags",
406                                                        "Flags for the proxy manager",
407                                                        G_TYPE_DBUS_OBJECT_MANAGER_CLIENT_FLAGS,
408                                                        G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
409                                                        G_PARAM_READABLE |
410                                                        G_PARAM_WRITABLE |
411                                                        G_PARAM_CONSTRUCT_ONLY |
412                                                        G_PARAM_STATIC_NAME |
413                                                        G_PARAM_STATIC_BLURB |
414                                                        G_PARAM_STATIC_NICK));
415
416   /**
417    * GDBusObjectManagerClient:object-path:
418    *
419    * The object path the manager is for.
420    *
421    * Since: 2.30
422    */
423   g_object_class_install_property (gobject_class,
424                                    PROP_OBJECT_PATH,
425                                    g_param_spec_string ("object-path",
426                                                         "Object Path",
427                                                         "The object path of the control object",
428                                                         NULL,
429                                                         G_PARAM_READABLE |
430                                                         G_PARAM_WRITABLE |
431                                                         G_PARAM_CONSTRUCT_ONLY |
432                                                         G_PARAM_STATIC_STRINGS));
433
434   /**
435    * GDBusObjectManagerClient:name:
436    *
437    * The well-known name or unique name that the manager is for.
438    *
439    * Since: 2.30
440    */
441   g_object_class_install_property (gobject_class,
442                                    PROP_NAME,
443                                    g_param_spec_string ("name",
444                                                         "Name",
445                                                         "Name that the manager is for",
446                                                         NULL,
447                                                         G_PARAM_READABLE |
448                                                         G_PARAM_WRITABLE |
449                                                         G_PARAM_CONSTRUCT_ONLY |
450                                                         G_PARAM_STATIC_STRINGS));
451
452   /**
453    * GDBusObjectManagerClient:name-owner:
454    *
455    * The unique name that owns #GDBusObjectManagerClient:name or %NULL if
456    * no-one is currently owning the name. Connect to the
457    * #GObject::notify signal to track changes to this property.
458    *
459    * Since: 2.30
460    */
461   g_object_class_install_property (gobject_class,
462                                    PROP_NAME_OWNER,
463                                    g_param_spec_string ("name-owner",
464                                                         "Name Owner",
465                                                         "The owner of the name we are watching",
466                                                         NULL,
467                                                         G_PARAM_READABLE |
468                                                         G_PARAM_STATIC_STRINGS));
469
470   /**
471    * GDBusObjectManagerClient:get-proxy-type-func:
472    *
473    * The #GDBusProxyTypeFunc to use when determining what #GType to
474    * use for interface proxies or %NULL.
475    *
476    * Since: 2.30
477    */
478   g_object_class_install_property (gobject_class,
479                                    PROP_GET_PROXY_TYPE_FUNC,
480                                    g_param_spec_pointer ("get-proxy-type-func",
481                                                          "GDBusProxyTypeFunc Function Pointer",
482                                                          "The GDBusProxyTypeFunc pointer to use",
483                                                          G_PARAM_READABLE |
484                                                          G_PARAM_WRITABLE |
485                                                          G_PARAM_CONSTRUCT_ONLY |
486                                                          G_PARAM_STATIC_STRINGS));
487
488   /**
489    * GDBusObjectManagerClient:get-proxy-type-user-data:
490    *
491    * The #gpointer user_data to pass to #GDBusObjectManagerClient:get-proxy-type-func.
492    *
493    * Since: 2.30
494    */
495   g_object_class_install_property (gobject_class,
496                                    PROP_GET_PROXY_TYPE_USER_DATA,
497                                    g_param_spec_pointer ("get-proxy-type-user-data",
498                                                          "GDBusProxyTypeFunc User Data",
499                                                          "The GDBusProxyTypeFunc user_data",
500                                                          G_PARAM_READABLE |
501                                                          G_PARAM_WRITABLE |
502                                                          G_PARAM_CONSTRUCT_ONLY |
503                                                          G_PARAM_STATIC_STRINGS));
504
505   /**
506    * GDBusObjectManagerClient:get-proxy-type-destroy-notify:
507    *
508    * A #GDestroyNotify for the #gpointer user_data in #GDBusObjectManagerClient:get-proxy-type-user-data.
509    *
510    * Since: 2.30
511    */
512   g_object_class_install_property (gobject_class,
513                                    PROP_GET_PROXY_TYPE_DESTROY_NOTIFY,
514                                    g_param_spec_pointer ("get-proxy-type-destroy-notify",
515                                                          "GDBusProxyTypeFunc user data free function",
516                                                          "The GDBusProxyTypeFunc user data free function",
517                                                          G_PARAM_READABLE |
518                                                          G_PARAM_WRITABLE |
519                                                          G_PARAM_CONSTRUCT_ONLY |
520                                                          G_PARAM_STATIC_STRINGS));
521
522   /**
523    * GDBusObjectManagerClient::interface-proxy-signal:
524    * @manager: The #GDBusObjectManagerClient emitting the signal.
525    * @object_proxy: The #GDBusObjectProxy on which an interface is emitting a D-Bus signal.
526    * @interface_proxy: The #GDBusProxy that is emitting a D-Bus signal.
527    * @sender_name: The sender of the signal or NULL if the connection is not a bus connection.
528    * @signal_name: The signal name.
529    * @parameters: A #GVariant tuple with parameters for the signal.
530    *
531    * Emitted when a D-Bus signal is received on @interface_proxy.
532    *
533    * This signal exists purely as a convenience to avoid having to
534    * connect signals to all interface proxies managed by @manager.
535    *
536    * This signal is emitted in the
537    * [thread-default main context][g-main-context-push-thread-default]
538    * that @manager was constructed in.
539    *
540    * Since: 2.30
541    */
542   signals[INTERFACE_PROXY_SIGNAL_SIGNAL] =
543     g_signal_new (I_("interface-proxy-signal"),
544                   G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
545                   G_SIGNAL_RUN_LAST,
546                   G_STRUCT_OFFSET (GDBusObjectManagerClientClass, interface_proxy_signal),
547                   NULL,
548                   NULL,
549                   _g_cclosure_marshal_VOID__OBJECT_OBJECT_STRING_STRING_VARIANT,
550                   G_TYPE_NONE,
551                   5,
552                   G_TYPE_DBUS_OBJECT_PROXY,
553                   G_TYPE_DBUS_PROXY,
554                   G_TYPE_STRING,
555                   G_TYPE_STRING,
556                   G_TYPE_VARIANT);
557   g_signal_set_va_marshaller (signals[INTERFACE_PROXY_SIGNAL_SIGNAL],
558                               G_TYPE_FROM_CLASS (klass),
559                               _g_cclosure_marshal_VOID__OBJECT_OBJECT_STRING_STRING_VARIANTv);
560
561   /**
562    * GDBusObjectManagerClient::interface-proxy-properties-changed:
563    * @manager: The #GDBusObjectManagerClient emitting the signal.
564    * @object_proxy: The #GDBusObjectProxy on which an interface has properties that are changing.
565    * @interface_proxy: The #GDBusProxy that has properties that are changing.
566    * @changed_properties: A #GVariant containing the properties that changed (type: `a{sv}`).
567    * @invalidated_properties: (array zero-terminated=1) (element-type utf8): A %NULL terminated
568    *   array of properties that were invalidated.
569    *
570    * Emitted when one or more D-Bus properties on proxy changes. The
571    * local cache has already been updated when this signal fires. Note
572    * that both @changed_properties and @invalidated_properties are
573    * guaranteed to never be %NULL (either may be empty though).
574    *
575    * This signal exists purely as a convenience to avoid having to
576    * connect signals to all interface proxies managed by @manager.
577    *
578    * This signal is emitted in the
579    * [thread-default main context][g-main-context-push-thread-default]
580    * that @manager was constructed in.
581    *
582    * Since: 2.30
583    */
584   signals[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL] =
585     g_signal_new (I_("interface-proxy-properties-changed"),
586                   G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
587                   G_SIGNAL_RUN_LAST,
588                   G_STRUCT_OFFSET (GDBusObjectManagerClientClass, interface_proxy_properties_changed),
589                   NULL,
590                   NULL,
591                   _g_cclosure_marshal_VOID__OBJECT_OBJECT_VARIANT_BOXED,
592                   G_TYPE_NONE,
593                   4,
594                   G_TYPE_DBUS_OBJECT_PROXY,
595                   G_TYPE_DBUS_PROXY,
596                   G_TYPE_VARIANT,
597                   G_TYPE_STRV);
598   g_signal_set_va_marshaller (signals[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL],
599                               G_TYPE_FROM_CLASS (klass),
600                               _g_cclosure_marshal_VOID__OBJECT_OBJECT_VARIANT_BOXEDv);
601 }
602
603 static void
604 g_dbus_object_manager_client_init (GDBusObjectManagerClient *manager)
605 {
606   manager->priv = g_dbus_object_manager_client_get_instance_private (manager);
607   g_mutex_init (&manager->priv->lock);
608   manager->priv->map_object_path_to_object_proxy = g_hash_table_new_full (g_str_hash,
609                                                                           g_str_equal,
610                                                                           g_free,
611                                                                           (GDestroyNotify) g_object_unref);
612   manager->priv->cancel = g_cancellable_new ();
613 }
614
615 /* ---------------------------------------------------------------------------------------------------- */
616
617 /**
618  * g_dbus_object_manager_client_new_sync:
619  * @connection: A #GDBusConnection.
620  * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
621  * @name: (nullable): The owner of the control object (unique or well-known name), or %NULL when not using a message bus connection.
622  * @object_path: The object path of the control object.
623  * @get_proxy_type_func: (nullable): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
624  * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
625  * @get_proxy_type_destroy_notify: (nullable): Free function for @get_proxy_type_user_data or %NULL.
626  * @cancellable: (nullable): A #GCancellable or %NULL
627  * @error: Return location for error or %NULL.
628  *
629  * Creates a new #GDBusObjectManagerClient object.
630  *
631  * This is a synchronous failable constructor - the calling thread is
632  * blocked until a reply is received. See g_dbus_object_manager_client_new()
633  * for the asynchronous version.
634  *
635  * Returns: (transfer full) (type GDBusObjectManagerClient): A
636  *   #GDBusObjectManagerClient object or %NULL if @error is set. Free
637  *   with g_object_unref().
638  *
639  * Since: 2.30
640  */
641 GDBusObjectManager *
642 g_dbus_object_manager_client_new_sync (GDBusConnection               *connection,
643                                        GDBusObjectManagerClientFlags  flags,
644                                        const gchar                   *name,
645                                        const gchar                   *object_path,
646                                        GDBusProxyTypeFunc             get_proxy_type_func,
647                                        gpointer                       get_proxy_type_user_data,
648                                        GDestroyNotify                 get_proxy_type_destroy_notify,
649                                        GCancellable                  *cancellable,
650                                        GError                       **error)
651 {
652   GInitable *initable;
653
654   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
655   g_return_val_if_fail ((name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) ||
656                         g_dbus_is_name (name), NULL);
657   g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
658   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
659
660   initable = g_initable_new (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
661                              cancellable,
662                              error,
663                              "connection", connection,
664                              "flags", flags,
665                              "name", name,
666                              "object-path", object_path,
667                              "get-proxy-type-func", get_proxy_type_func,
668                              "get-proxy-type-user-data", get_proxy_type_user_data,
669                              "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
670                              NULL);
671   if (initable != NULL)
672     return G_DBUS_OBJECT_MANAGER (initable);
673   else
674     return NULL;
675 }
676
677 /**
678  * g_dbus_object_manager_client_new:
679  * @connection: A #GDBusConnection.
680  * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
681  * @name: The owner of the control object (unique or well-known name).
682  * @object_path: The object path of the control object.
683  * @get_proxy_type_func: (nullable): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
684  * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
685  * @get_proxy_type_destroy_notify: (nullable): Free function for @get_proxy_type_user_data or %NULL.
686  * @cancellable: (nullable): A #GCancellable or %NULL
687  * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
688  * @user_data: The data to pass to @callback.
689  *
690  * Asynchronously creates a new #GDBusObjectManagerClient object.
691  *
692  * This is an asynchronous failable constructor. When the result is
693  * ready, @callback will be invoked in the
694  * [thread-default main context][g-main-context-push-thread-default]
695  * of the thread you are calling this method from. You can
696  * then call g_dbus_object_manager_client_new_finish() to get the result. See
697  * g_dbus_object_manager_client_new_sync() for the synchronous version.
698  *
699  * Since: 2.30
700  */
701 void
702 g_dbus_object_manager_client_new (GDBusConnection               *connection,
703                                   GDBusObjectManagerClientFlags  flags,
704                                   const gchar                   *name,
705                                   const gchar                   *object_path,
706                                   GDBusProxyTypeFunc             get_proxy_type_func,
707                                   gpointer                       get_proxy_type_user_data,
708                                   GDestroyNotify                 get_proxy_type_destroy_notify,
709                                   GCancellable                  *cancellable,
710                                   GAsyncReadyCallback            callback,
711                                   gpointer                       user_data)
712 {
713   g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
714   g_return_if_fail ((name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) ||
715                         g_dbus_is_name (name));
716   g_return_if_fail (g_variant_is_object_path (object_path));
717
718   g_async_initable_new_async (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
719                               G_PRIORITY_DEFAULT,
720                               cancellable,
721                               callback,
722                               user_data,
723                               "connection", connection,
724                               "flags", flags,
725                               "name", name,
726                               "object-path", object_path,
727                               "get-proxy-type-func", get_proxy_type_func,
728                               "get-proxy-type-user-data", get_proxy_type_user_data,
729                               "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
730                               NULL);
731 }
732
733 /**
734  * g_dbus_object_manager_client_new_finish:
735  * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_object_manager_client_new().
736  * @error: Return location for error or %NULL.
737  *
738  * Finishes an operation started with g_dbus_object_manager_client_new().
739  *
740  * Returns: (transfer full) (type GDBusObjectManagerClient): A
741  *   #GDBusObjectManagerClient object or %NULL if @error is set. Free
742  *   with g_object_unref().
743  *
744  * Since: 2.30
745  */
746 GDBusObjectManager *
747 g_dbus_object_manager_client_new_finish (GAsyncResult   *res,
748                                          GError        **error)
749 {
750   GObject *object;
751   GObject *source_object;
752
753   source_object = g_async_result_get_source_object (res);
754   g_assert (source_object != NULL);
755
756   object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
757                                         res,
758                                         error);
759   g_object_unref (source_object);
760
761   if (object != NULL)
762     return G_DBUS_OBJECT_MANAGER (object);
763   else
764     return NULL;
765 }
766
767 /* ---------------------------------------------------------------------------------------------------- */
768
769 /**
770  * g_dbus_object_manager_client_new_for_bus_sync:
771  * @bus_type: A #GBusType.
772  * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
773  * @name: The owner of the control object (unique or well-known name).
774  * @object_path: The object path of the control object.
775  * @get_proxy_type_func: (nullable): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
776  * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
777  * @get_proxy_type_destroy_notify: (nullable): Free function for @get_proxy_type_user_data or %NULL.
778  * @cancellable: (nullable): A #GCancellable or %NULL
779  * @error: Return location for error or %NULL.
780  *
781  * Like g_dbus_object_manager_client_new_sync() but takes a #GBusType instead
782  * of a #GDBusConnection.
783  *
784  * This is a synchronous failable constructor - the calling thread is
785  * blocked until a reply is received. See g_dbus_object_manager_client_new_for_bus()
786  * for the asynchronous version.
787  *
788  * Returns: (transfer full) (type GDBusObjectManagerClient): A
789  *   #GDBusObjectManagerClient object or %NULL if @error is set. Free
790  *   with g_object_unref().
791  *
792  * Since: 2.30
793  */
794 GDBusObjectManager *
795 g_dbus_object_manager_client_new_for_bus_sync (GBusType                       bus_type,
796                                                GDBusObjectManagerClientFlags  flags,
797                                                const gchar                   *name,
798                                                const gchar                   *object_path,
799                                                GDBusProxyTypeFunc             get_proxy_type_func,
800                                                gpointer                       get_proxy_type_user_data,
801                                                GDestroyNotify                 get_proxy_type_destroy_notify,
802                                                GCancellable                  *cancellable,
803                                                GError                       **error)
804 {
805   GInitable *initable;
806
807   g_return_val_if_fail (bus_type != G_BUS_TYPE_NONE, NULL);
808   g_return_val_if_fail (g_dbus_is_name (name), NULL);
809   g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
810   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
811
812   initable = g_initable_new (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
813                              cancellable,
814                              error,
815                              "bus-type", bus_type,
816                              "flags", flags,
817                              "name", name,
818                              "object-path", object_path,
819                              "get-proxy-type-func", get_proxy_type_func,
820                              "get-proxy-type-user-data", get_proxy_type_user_data,
821                              "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
822                              NULL);
823   if (initable != NULL)
824     return G_DBUS_OBJECT_MANAGER (initable);
825   else
826     return NULL;
827 }
828
829 /**
830  * g_dbus_object_manager_client_new_for_bus:
831  * @bus_type: A #GBusType.
832  * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
833  * @name: The owner of the control object (unique or well-known name).
834  * @object_path: The object path of the control object.
835  * @get_proxy_type_func: (nullable): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
836  * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
837  * @get_proxy_type_destroy_notify: (nullable): Free function for @get_proxy_type_user_data or %NULL.
838  * @cancellable: (nullable): A #GCancellable or %NULL
839  * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
840  * @user_data: The data to pass to @callback.
841  *
842  * Like g_dbus_object_manager_client_new() but takes a #GBusType instead of a
843  * #GDBusConnection.
844  *
845  * This is an asynchronous failable constructor. When the result is
846  * ready, @callback will be invoked in the
847  * [thread-default main loop][g-main-context-push-thread-default]
848  * of the thread you are calling this method from. You can
849  * then call g_dbus_object_manager_client_new_for_bus_finish() to get the result. See
850  * g_dbus_object_manager_client_new_for_bus_sync() for the synchronous version.
851  *
852  * Since: 2.30
853  */
854 void
855 g_dbus_object_manager_client_new_for_bus (GBusType                       bus_type,
856                                           GDBusObjectManagerClientFlags  flags,
857                                           const gchar                   *name,
858                                           const gchar                   *object_path,
859                                           GDBusProxyTypeFunc             get_proxy_type_func,
860                                           gpointer                       get_proxy_type_user_data,
861                                           GDestroyNotify                 get_proxy_type_destroy_notify,
862                                           GCancellable                  *cancellable,
863                                           GAsyncReadyCallback            callback,
864                                           gpointer                       user_data)
865 {
866   g_return_if_fail (bus_type != G_BUS_TYPE_NONE);
867   g_return_if_fail (g_dbus_is_name (name));
868   g_return_if_fail (g_variant_is_object_path (object_path));
869
870   g_async_initable_new_async (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
871                               G_PRIORITY_DEFAULT,
872                               cancellable,
873                               callback,
874                               user_data,
875                               "bus-type", bus_type,
876                               "flags", flags,
877                               "name", name,
878                               "object-path", object_path,
879                               "get-proxy-type-func", get_proxy_type_func,
880                               "get-proxy-type-user-data", get_proxy_type_user_data,
881                               "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
882                               NULL);
883 }
884
885 /**
886  * g_dbus_object_manager_client_new_for_bus_finish:
887  * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_object_manager_client_new_for_bus().
888  * @error: Return location for error or %NULL.
889  *
890  * Finishes an operation started with g_dbus_object_manager_client_new_for_bus().
891  *
892  * Returns: (transfer full) (type GDBusObjectManagerClient): A
893  *   #GDBusObjectManagerClient object or %NULL if @error is set. Free
894  *   with g_object_unref().
895  *
896  * Since: 2.30
897  */
898 GDBusObjectManager *
899 g_dbus_object_manager_client_new_for_bus_finish (GAsyncResult   *res,
900                                                  GError        **error)
901 {
902   GObject *object;
903   GObject *source_object;
904
905   source_object = g_async_result_get_source_object (res);
906   g_assert (source_object != NULL);
907
908   object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
909                                         res,
910                                         error);
911   g_object_unref (source_object);
912
913   if (object != NULL)
914     return G_DBUS_OBJECT_MANAGER (object);
915   else
916     return NULL;
917 }
918
919 /* ---------------------------------------------------------------------------------------------------- */
920
921 /**
922  * g_dbus_object_manager_client_get_connection:
923  * @manager: A #GDBusObjectManagerClient
924  *
925  * Gets the #GDBusConnection used by @manager.
926  *
927  * Returns: (transfer none): A #GDBusConnection object. Do not free,
928  *   the object belongs to @manager.
929  *
930  * Since: 2.30
931  */
932 GDBusConnection *
933 g_dbus_object_manager_client_get_connection (GDBusObjectManagerClient *manager)
934 {
935   GDBusConnection *ret;
936   g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
937   g_mutex_lock (&manager->priv->lock);
938   ret = manager->priv->connection;
939   g_mutex_unlock (&manager->priv->lock);
940   return ret;
941 }
942
943 /**
944  * g_dbus_object_manager_client_get_name:
945  * @manager: A #GDBusObjectManagerClient
946  *
947  * Gets the name that @manager is for, or %NULL if not a message bus
948  * connection.
949  *
950  * Returns: A unique or well-known name. Do not free, the string
951  * belongs to @manager.
952  *
953  * Since: 2.30
954  */
955 const gchar *
956 g_dbus_object_manager_client_get_name (GDBusObjectManagerClient *manager)
957 {
958   const gchar *ret;
959   g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
960   g_mutex_lock (&manager->priv->lock);
961   ret = manager->priv->name;
962   g_mutex_unlock (&manager->priv->lock);
963   return ret;
964 }
965
966 /**
967  * g_dbus_object_manager_client_get_flags:
968  * @manager: A #GDBusObjectManagerClient
969  *
970  * Gets the flags that @manager was constructed with.
971  *
972  * Returns: Zero of more flags from the #GDBusObjectManagerClientFlags
973  * enumeration.
974  *
975  * Since: 2.30
976  */
977 GDBusObjectManagerClientFlags
978 g_dbus_object_manager_client_get_flags (GDBusObjectManagerClient *manager)
979 {
980   GDBusObjectManagerClientFlags ret;
981   g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE);
982   g_mutex_lock (&manager->priv->lock);
983   ret = manager->priv->flags;
984   g_mutex_unlock (&manager->priv->lock);
985   return ret;
986 }
987
988 /**
989  * g_dbus_object_manager_client_get_name_owner:
990  * @manager: A #GDBusObjectManagerClient.
991  *
992  * The unique name that owns the name that @manager is for or %NULL if
993  * no-one currently owns that name. You can connect to the
994  * #GObject::notify signal to track changes to the
995  * #GDBusObjectManagerClient:name-owner property.
996  *
997  * Returns: (nullable): The name owner or %NULL if no name owner
998  * exists. Free with g_free().
999  *
1000  * Since: 2.30
1001  */
1002 gchar *
1003 g_dbus_object_manager_client_get_name_owner (GDBusObjectManagerClient *manager)
1004 {
1005   gchar *ret;
1006   g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
1007   g_mutex_lock (&manager->priv->lock);
1008   ret = g_strdup (manager->priv->name_owner);
1009   g_mutex_unlock (&manager->priv->lock);
1010   return ret;
1011 }
1012
1013 /* ---------------------------------------------------------------------------------------------------- */
1014
1015 /* signal handler for all objects we manage - we dispatch signals
1016  * from here to the objects
1017  */
1018 static void
1019 signal_cb (GDBusConnection *connection,
1020            const gchar     *sender_name,
1021            const gchar     *object_path,
1022            const gchar     *interface_name,
1023            const gchar     *signal_name,
1024            GVariant        *parameters,
1025            gpointer         user_data)
1026 {
1027   GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (user_data);
1028   GDBusObjectProxy *object_proxy;
1029   GDBusInterface *interface;
1030
1031   g_mutex_lock (&manager->priv->lock);
1032   object_proxy = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1033   if (object_proxy == NULL)
1034     {
1035       g_mutex_unlock (&manager->priv->lock);
1036       goto out;
1037     }
1038   g_object_ref (object_proxy);
1039   g_mutex_unlock (&manager->priv->lock);
1040
1041   //g_debug ("yay, signal_cb %s %s: %s\n", signal_name, object_path, g_variant_print (parameters, TRUE));
1042
1043   g_object_ref (manager);
1044   if (g_strcmp0 (interface_name, "org.freedesktop.DBus.Properties") == 0)
1045     {
1046       if (g_strcmp0 (signal_name, "PropertiesChanged") == 0)
1047         {
1048           const gchar *properties_interface_name;
1049           GVariant *changed_properties;
1050           const gchar **invalidated_properties;
1051
1052           g_variant_get (parameters,
1053                          "(&s@a{sv}^a&s)",
1054                          &properties_interface_name,
1055                          &changed_properties,
1056                          &invalidated_properties);
1057
1058           interface = g_dbus_object_get_interface (G_DBUS_OBJECT (object_proxy), properties_interface_name);
1059           if (interface != NULL)
1060             {
1061               GVariantIter property_iter;
1062               const gchar *property_name;
1063               GVariant *property_value;
1064               guint n;
1065
1066               /* update caches... */
1067               g_variant_iter_init (&property_iter, changed_properties);
1068               while (g_variant_iter_next (&property_iter,
1069                                           "{&sv}",
1070                                           &property_name,
1071                                           &property_value))
1072                 {
1073                   g_dbus_proxy_set_cached_property (G_DBUS_PROXY (interface),
1074                                                     property_name,
1075                                                     property_value);
1076                   g_variant_unref (property_value);
1077                 }
1078
1079               for (n = 0; invalidated_properties[n] != NULL; n++)
1080                 {
1081                   g_dbus_proxy_set_cached_property (G_DBUS_PROXY (interface),
1082                                                     invalidated_properties[n],
1083                                                     NULL);
1084                 }
1085               /* ... and then synthesize the signal */
1086               g_signal_emit_by_name (interface,
1087                                      "g-properties-changed",
1088                                      changed_properties,
1089                                      invalidated_properties);
1090               g_signal_emit (manager,
1091                              signals[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL],
1092                              0,
1093                              object_proxy,
1094                              interface,
1095                              changed_properties,
1096                              invalidated_properties);
1097               g_object_unref (interface);
1098             }
1099           g_variant_unref (changed_properties);
1100           g_free (invalidated_properties);
1101         }
1102     }
1103   else
1104     {
1105       /* regular signal - just dispatch it */
1106       interface = g_dbus_object_get_interface (G_DBUS_OBJECT (object_proxy), interface_name);
1107       if (interface != NULL)
1108         {
1109           g_signal_emit_by_name (interface,
1110                                  "g-signal",
1111                                  sender_name,
1112                                  signal_name,
1113                                  parameters);
1114           g_signal_emit (manager,
1115                          signals[INTERFACE_PROXY_SIGNAL_SIGNAL],
1116                          0,
1117                          object_proxy,
1118                          interface,
1119                          sender_name,
1120                          signal_name,
1121                          parameters);
1122           g_object_unref (interface);
1123         }
1124     }
1125   g_object_unref (manager);
1126
1127  out:
1128   g_clear_object (&object_proxy);
1129 }
1130
1131 static void
1132 subscribe_signals (GDBusObjectManagerClient *manager,
1133                    const gchar *name_owner)
1134 {
1135   GError *error = NULL;
1136   GVariant *ret;
1137
1138   g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager));
1139   g_return_if_fail (manager->priv->signal_subscription_id == 0);
1140   g_return_if_fail (name_owner == NULL || g_dbus_is_unique_name (name_owner));
1141
1142   if (name_owner != NULL)
1143     {
1144       /* Only add path_namespace if it's non-'/'. This removes a no-op key from
1145        * the match rule, and also works around a D-Bus bug where
1146        * path_namespace='/' matches nothing in D-Bus versions < 1.6.18.
1147        *
1148        * See: https://bugs.freedesktop.org/show_bug.cgi?id=70799 */
1149       if (g_str_equal (manager->priv->object_path, "/"))
1150         {
1151           manager->priv->match_rule = g_strdup_printf ("type='signal',sender='%s'",
1152                                                        name_owner);
1153         }
1154       else
1155         {
1156           manager->priv->match_rule = g_strdup_printf ("type='signal',sender='%s',path_namespace='%s'",
1157                                                        name_owner, manager->priv->object_path);
1158         }
1159
1160       /* The bus daemon may not implement path_namespace so gracefully
1161        * handle this by using a fallback triggered if @error is set. */
1162       ret = g_dbus_connection_call_sync (manager->priv->connection,
1163                                          "org.freedesktop.DBus",
1164                                          "/org/freedesktop/DBus",
1165                                          "org.freedesktop.DBus",
1166                                          "AddMatch",
1167                                          g_variant_new ("(s)",
1168                                                         manager->priv->match_rule),
1169                                          NULL, /* reply_type */
1170                                          G_DBUS_CALL_FLAGS_NONE,
1171                                          -1, /* default timeout */
1172                                          NULL, /* TODO: Cancellable */
1173                                          &error);
1174
1175       /* yay, bus daemon supports path_namespace */
1176       if (ret != NULL)
1177         g_variant_unref (ret);
1178     }
1179
1180   if (error == NULL)
1181     {
1182       /* still need to ask GDBusConnection for the callbacks */
1183       manager->priv->signal_subscription_id =
1184         g_dbus_connection_signal_subscribe (manager->priv->connection,
1185                                             name_owner,
1186                                             NULL, /* interface */
1187                                             NULL, /* member */
1188                                             NULL, /* path - TODO: really want wildcard support here */
1189                                             NULL, /* arg0 */
1190                                             G_DBUS_SIGNAL_FLAGS_NONE |
1191                                             G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
1192                                             signal_cb,
1193                                             manager,
1194                                             NULL); /* user_data_free_func */
1195
1196     }
1197   else
1198     {
1199       /* TODO: we could report this to the user
1200       g_warning ("Message bus daemon does not support path_namespace: %s (%s %d)",
1201                  error->message,
1202                  g_quark_to_string (error->domain),
1203                  error->code);
1204       */
1205
1206       g_error_free (error);
1207
1208       /* no need to call RemoveMatch when done since it didn't work */
1209       g_free (manager->priv->match_rule);
1210       manager->priv->match_rule = NULL;
1211
1212       /* Fallback is to subscribe to *all* signals from the name owner which
1213        * is rather wasteful. It's probably not a big practical problem because
1214        * users typically want all objects that the name owner supplies.
1215        */
1216       manager->priv->signal_subscription_id =
1217         g_dbus_connection_signal_subscribe (manager->priv->connection,
1218                                             name_owner,
1219                                             NULL, /* interface */
1220                                             NULL, /* member */
1221                                             NULL, /* path - TODO: really want wildcard support here */
1222                                             NULL, /* arg0 */
1223                                             G_DBUS_SIGNAL_FLAGS_NONE,
1224                                             signal_cb,
1225                                             manager,
1226                                             NULL); /* user_data_free_func */
1227     }
1228 }
1229
1230 static void
1231 maybe_unsubscribe_signals (GDBusObjectManagerClient *manager)
1232 {
1233   g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager));
1234
1235   if (manager->priv->signal_subscription_id > 0)
1236     {
1237       g_dbus_connection_signal_unsubscribe (manager->priv->connection,
1238                                             manager->priv->signal_subscription_id);
1239       manager->priv->signal_subscription_id = 0;
1240     }
1241
1242   if (manager->priv->match_rule != NULL)
1243     {
1244       /* Since the AddMatch call succeeded this is guaranteed to not
1245        * fail - therefore, don't bother checking the return value
1246        */
1247       g_dbus_connection_call (manager->priv->connection,
1248                               "org.freedesktop.DBus",
1249                               "/org/freedesktop/DBus",
1250                               "org.freedesktop.DBus",
1251                               "RemoveMatch",
1252                               g_variant_new ("(s)",
1253                                              manager->priv->match_rule),
1254                               NULL, /* reply_type */
1255                               G_DBUS_CALL_FLAGS_NONE,
1256                               -1, /* default timeout */
1257                               NULL, /* GCancellable */
1258                               NULL, /* GAsyncReadyCallback */
1259                               NULL); /* user data */
1260       g_free (manager->priv->match_rule);
1261       manager->priv->match_rule = NULL;
1262     }
1263
1264 }
1265
1266 /* ---------------------------------------------------------------------------------------------------- */
1267
1268 static GWeakRef *
1269 weak_ref_new (GObject *object)
1270 {
1271   GWeakRef *weak_ref = g_new0 (GWeakRef, 1);
1272   g_weak_ref_init (weak_ref, object);
1273   return g_steal_pointer (&weak_ref);
1274 }
1275
1276 static void
1277 weak_ref_free (GWeakRef *weak_ref)
1278 {
1279   g_weak_ref_clear (weak_ref);
1280   g_free (weak_ref);
1281 }
1282
1283 static void
1284 on_get_managed_objects_finish (GObject      *source,
1285                                GAsyncResult *result,
1286                                gpointer      user_data)
1287 {
1288
1289   GDBusProxy *proxy = G_DBUS_PROXY (source);
1290   GWeakRef *manager_weak = user_data;
1291   GDBusObjectManagerClient *manager;
1292   GError *error = NULL;
1293   GVariant *value = NULL;
1294   gchar *new_name_owner = NULL;
1295
1296   value = g_dbus_proxy_call_finish (proxy, result, &error);
1297
1298   manager = G_DBUS_OBJECT_MANAGER_CLIENT (g_weak_ref_get (manager_weak));
1299   /* Manager got disposed, nothing to do */
1300   if (manager == NULL)
1301     {
1302       goto out;
1303     }
1304
1305   new_name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy);
1306   if (value == NULL)
1307     {
1308       maybe_unsubscribe_signals (manager);
1309       if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
1310         {
1311           g_warning ("Error calling GetManagedObjects() when name owner %s for name %s came back: %s",
1312                      new_name_owner,
1313                      manager->priv->name,
1314                      error->message);
1315         }
1316     }
1317   else
1318     {
1319       process_get_all_result (manager, value, new_name_owner);
1320     }
1321
1322   /* do the :name-owner notify *AFTER* emitting ::object-proxy-added signals - this
1323    * way the user knows that the signals were emitted because the name owner came back
1324    */
1325   g_mutex_lock (&manager->priv->lock);
1326   manager->priv->name_owner = g_steal_pointer (&new_name_owner);
1327   g_mutex_unlock (&manager->priv->lock);
1328   g_object_notify (G_OBJECT (manager), "name-owner");
1329
1330   g_object_unref (manager);
1331  out:
1332   g_clear_error (&error);
1333   g_clear_pointer (&value, g_variant_unref);
1334   weak_ref_free (manager_weak);
1335 }
1336
1337 static void
1338 on_notify_g_name_owner (GObject    *object,
1339                         GParamSpec *pspec,
1340                         gpointer    user_data)
1341 {
1342   GWeakRef *manager_weak = user_data;
1343   GDBusObjectManagerClient *manager = NULL;
1344   gchar *old_name_owner;
1345   gchar *new_name_owner;
1346
1347   manager = G_DBUS_OBJECT_MANAGER_CLIENT (g_weak_ref_get (manager_weak));
1348   if (manager == NULL)
1349     return;
1350
1351   g_mutex_lock (&manager->priv->lock);
1352   old_name_owner = manager->priv->name_owner;
1353   new_name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy);
1354   manager->priv->name_owner = NULL;
1355
1356   if (g_strcmp0 (old_name_owner, new_name_owner) != 0)
1357     {
1358       GPtrArray *proxies;
1359
1360       /* remote manager changed; nuke all local proxies  */
1361       proxies = g_hash_table_steal_all_values (
1362         manager->priv->map_object_path_to_object_proxy);
1363
1364       g_mutex_unlock (&manager->priv->lock);
1365
1366       /* do the :name-owner notify with a NULL name - this way the user knows
1367        * the ::object-proxy-removed following is because the name owner went
1368        * away
1369        */
1370       g_object_notify (G_OBJECT (manager), "name-owner");
1371
1372       for (guint i = 0; i < proxies->len; ++i)
1373         {
1374           GDBusObjectProxy *object_proxy =
1375             G_DBUS_OBJECT_PROXY (g_ptr_array_index (proxies, i));
1376           g_signal_emit_by_name (manager, "object-removed", object_proxy);
1377         }
1378       g_clear_pointer (&proxies, g_ptr_array_unref);
1379
1380       /* nuke local filter */
1381       maybe_unsubscribe_signals (manager);
1382     }
1383   else
1384     {
1385       g_mutex_unlock (&manager->priv->lock);
1386     }
1387
1388   if (new_name_owner != NULL)
1389     {
1390       //g_debug ("repopulating for %s", new_name_owner);
1391
1392       subscribe_signals (manager,
1393                          new_name_owner);
1394       g_dbus_proxy_call (manager->priv->control_proxy,
1395                          "GetManagedObjects",
1396                          NULL, /* parameters */
1397                          G_DBUS_CALL_FLAGS_NONE,
1398                          -1,
1399                          manager->priv->cancel,
1400                          on_get_managed_objects_finish,
1401                          weak_ref_new (G_OBJECT (manager)));
1402     }
1403   g_free (new_name_owner);
1404   g_free (old_name_owner);
1405   g_object_unref (manager);
1406 }
1407
1408 static gboolean
1409 initable_init (GInitable     *initable,
1410                GCancellable  *cancellable,
1411                GError       **error)
1412 {
1413   GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (initable);
1414   gboolean ret;
1415   GVariant *value;
1416   GDBusProxyFlags proxy_flags;
1417
1418   ret = FALSE;
1419
1420   if (manager->priv->bus_type != G_BUS_TYPE_NONE)
1421     {
1422       g_assert (manager->priv->connection == NULL);
1423       manager->priv->connection = g_bus_get_sync (manager->priv->bus_type, cancellable, error);
1424       if (manager->priv->connection == NULL)
1425         goto out;
1426     }
1427
1428   proxy_flags = G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES;
1429   if (manager->priv->flags & G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START)
1430     proxy_flags |= G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START;
1431
1432   manager->priv->control_proxy = g_dbus_proxy_new_sync (manager->priv->connection,
1433                                                         proxy_flags,
1434                                                         NULL, /* GDBusInterfaceInfo* */
1435                                                         manager->priv->name,
1436                                                         manager->priv->object_path,
1437                                                         "org.freedesktop.DBus.ObjectManager",
1438                                                         cancellable,
1439                                                         error);
1440   if (manager->priv->control_proxy == NULL)
1441     goto out;
1442
1443   /* Use weak refs here. The @control_proxy will emit its signals in the current
1444    * #GMainContext (since we constructed it just above). However, the user may
1445    * drop the last external reference to this #GDBusObjectManagerClient in
1446    * another thread between a signal being emitted and scheduled in an idle
1447    * callback in this #GMainContext, and that idle callback being invoked. We
1448    * can’t use a strong reference here, as there’s no
1449    * g_dbus_object_manager_client_disconnect() (or similar) method to tell us
1450    * when the last external reference to this object has been dropped, so we
1451    * can’t break a strong reference count cycle. So use weak refs. */
1452   manager->priv->name_owner_signal_id =
1453       g_signal_connect_data (G_OBJECT (manager->priv->control_proxy),
1454                             "notify::g-name-owner",
1455                             G_CALLBACK (on_notify_g_name_owner),
1456                             weak_ref_new (G_OBJECT (manager)),
1457                             (GClosureNotify) weak_ref_free,
1458                             G_CONNECT_DEFAULT);
1459
1460   manager->priv->signal_signal_id =
1461       g_signal_connect_data (manager->priv->control_proxy,
1462                             "g-signal",
1463                             G_CALLBACK (on_control_proxy_g_signal),
1464                             weak_ref_new (G_OBJECT (manager)),
1465                             (GClosureNotify) weak_ref_free,
1466                             G_CONNECT_DEFAULT);
1467
1468   manager->priv->name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy);
1469   if (manager->priv->name_owner == NULL && manager->priv->name != NULL)
1470     {
1471       /* it's perfectly fine if there's no name owner.. we're just going to
1472        * wait until one is ready
1473        */
1474     }
1475   else
1476     {
1477       /* yay, we can get the objects */
1478       subscribe_signals (manager,
1479                          manager->priv->name_owner);
1480       value = g_dbus_proxy_call_sync (manager->priv->control_proxy,
1481                                       "GetManagedObjects",
1482                                       NULL, /* parameters */
1483                                       G_DBUS_CALL_FLAGS_NONE,
1484                                       -1,
1485                                       cancellable,
1486                                       error);
1487       if (value == NULL)
1488         {
1489           maybe_unsubscribe_signals (manager);
1490
1491           g_warn_if_fail (manager->priv->signal_signal_id != 0);
1492           g_signal_handler_disconnect (manager->priv->control_proxy,
1493                                        manager->priv->signal_signal_id);
1494           manager->priv->signal_signal_id = 0;
1495
1496           g_warn_if_fail (manager->priv->name_owner_signal_id != 0);
1497           g_signal_handler_disconnect (manager->priv->control_proxy,
1498                                        manager->priv->name_owner_signal_id);
1499           manager->priv->name_owner_signal_id = 0;
1500
1501           g_object_unref (manager->priv->control_proxy);
1502           manager->priv->control_proxy = NULL;
1503
1504           goto out;
1505         }
1506
1507       process_get_all_result (manager, value, manager->priv->name_owner);
1508       g_variant_unref (value);
1509     }
1510
1511   ret = TRUE;
1512
1513  out:
1514   return ret;
1515 }
1516
1517 static void
1518 initable_iface_init (GInitableIface *initable_iface)
1519 {
1520   initable_iface->init = initable_init;
1521 }
1522
1523 static void
1524 async_initable_iface_init (GAsyncInitableIface *async_initable_iface)
1525 {
1526   /* for now, just use default: run GInitable code in thread */
1527 }
1528
1529 /* ---------------------------------------------------------------------------------------------------- */
1530
1531 static void
1532 add_interfaces (GDBusObjectManagerClient *manager,
1533                 const gchar       *object_path,
1534                 GVariant          *ifaces_and_properties,
1535                 const gchar       *name_owner)
1536 {
1537   GDBusObjectProxy *op;
1538   gboolean added;
1539   GVariantIter iter;
1540   const gchar *interface_name;
1541   GVariant *properties;
1542   GList *interface_added_signals, *l;
1543   GDBusProxy *interface_proxy;
1544
1545   g_return_if_fail (name_owner == NULL || g_dbus_is_unique_name (name_owner));
1546
1547   g_mutex_lock (&manager->priv->lock);
1548
1549   interface_added_signals = NULL;
1550   added = FALSE;
1551
1552   op = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1553   if (op == NULL)
1554     {
1555       GType object_proxy_type;
1556       if (manager->priv->get_proxy_type_func != NULL)
1557         {
1558           object_proxy_type = manager->priv->get_proxy_type_func (manager,
1559                                                                   object_path,
1560                                                                   NULL,
1561                                                                   manager->priv->get_proxy_type_user_data);
1562           g_warn_if_fail (g_type_is_a (object_proxy_type, G_TYPE_DBUS_OBJECT_PROXY));
1563         }
1564       else
1565         {
1566           object_proxy_type = G_TYPE_DBUS_OBJECT_PROXY;
1567         }
1568       op = g_object_new (object_proxy_type,
1569                          "g-connection", manager->priv->connection,
1570                          "g-object-path", object_path,
1571                          NULL);
1572       added = TRUE;
1573     }
1574   g_object_ref (op);
1575
1576   g_variant_iter_init (&iter, ifaces_and_properties);
1577   while (g_variant_iter_next (&iter,
1578                               "{&s@a{sv}}",
1579                               &interface_name,
1580                               &properties))
1581     {
1582       GError *error;
1583       GType interface_proxy_type;
1584
1585       if (manager->priv->get_proxy_type_func != NULL)
1586         {
1587           interface_proxy_type = manager->priv->get_proxy_type_func (manager,
1588                                                                      object_path,
1589                                                                      interface_name,
1590                                                                      manager->priv->get_proxy_type_user_data);
1591           g_warn_if_fail (g_type_is_a (interface_proxy_type, G_TYPE_DBUS_PROXY));
1592         }
1593       else
1594         {
1595           interface_proxy_type = G_TYPE_DBUS_PROXY;
1596         }
1597
1598       /* this is fine - there is no blocking IO because we pass DO_NOT_LOAD_PROPERTIES and
1599        * DO_NOT_CONNECT_SIGNALS and use a unique name
1600        */
1601       error = NULL;
1602       interface_proxy = g_initable_new (interface_proxy_type,
1603                                         NULL, /* GCancellable */
1604                                         &error,
1605                                         "g-connection", manager->priv->connection,
1606                                         "g-flags", G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
1607                                                    G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
1608                                         "g-name", name_owner,
1609                                         "g-object-path", object_path,
1610                                         "g-interface-name", interface_name,
1611                                         NULL);
1612       if (interface_proxy == NULL)
1613         {
1614           g_warning ("%s: Error constructing proxy for path %s and interface %s: %s",
1615                      G_STRLOC,
1616                      object_path,
1617                      interface_name,
1618                      error->message);
1619           g_error_free (error);
1620         }
1621       else
1622         {
1623           GVariantIter property_iter;
1624           const gchar *property_name;
1625           GVariant *property_value;
1626
1627           /* associate the interface proxy with the object */
1628           g_dbus_interface_set_object (G_DBUS_INTERFACE (interface_proxy),
1629                                        G_DBUS_OBJECT (op));
1630
1631           g_variant_iter_init (&property_iter, properties);
1632           while (g_variant_iter_next (&property_iter,
1633                                       "{&sv}",
1634                                       &property_name,
1635                                       &property_value))
1636             {
1637               g_dbus_proxy_set_cached_property (interface_proxy,
1638                                                 property_name,
1639                                                 property_value);
1640               g_variant_unref (property_value);
1641             }
1642
1643           _g_dbus_object_proxy_add_interface (op, interface_proxy);
1644           if (!added)
1645             interface_added_signals = g_list_append (interface_added_signals, g_object_ref (interface_proxy));
1646           g_object_unref (interface_proxy);
1647         }
1648       g_variant_unref (properties);
1649     }
1650
1651   if (added)
1652     {
1653       g_hash_table_insert (manager->priv->map_object_path_to_object_proxy,
1654                            g_strdup (object_path),
1655                            op);
1656     }
1657
1658   g_mutex_unlock (&manager->priv->lock);
1659
1660   /* now that we don't hold the lock any more, emit signals */
1661   g_object_ref (manager);
1662   for (l = interface_added_signals; l != NULL; l = l->next)
1663     {
1664       interface_proxy = G_DBUS_PROXY (l->data);
1665       g_signal_emit_by_name (manager, "interface-added", op, interface_proxy);
1666       g_object_unref (interface_proxy);
1667     }
1668   g_list_free (interface_added_signals);
1669
1670   if (added)
1671     g_signal_emit_by_name (manager, "object-added", op);
1672
1673   g_object_unref (manager);
1674   g_object_unref (op);
1675 }
1676
1677 static void
1678 remove_interfaces (GDBusObjectManagerClient   *manager,
1679                    const gchar         *object_path,
1680                    const gchar *const  *interface_names)
1681 {
1682   GDBusObjectProxy *op;
1683   GList *interfaces;
1684   guint n;
1685   guint num_interfaces;
1686   guint num_interfaces_to_remove;
1687
1688   g_mutex_lock (&manager->priv->lock);
1689
1690   op = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1691   if (op == NULL)
1692     {
1693       g_debug ("%s: Processing InterfaceRemoved signal for path %s but no object proxy exists",
1694                G_STRLOC,
1695                object_path);
1696       g_mutex_unlock (&manager->priv->lock);
1697       return;
1698     }
1699
1700   interfaces = g_dbus_object_get_interfaces (G_DBUS_OBJECT (op));
1701   num_interfaces = g_list_length (interfaces);
1702   g_list_free_full (interfaces, g_object_unref);
1703
1704   num_interfaces_to_remove = g_strv_length ((gchar **) interface_names);
1705
1706   /* see if we are going to completety remove the object */
1707   g_object_ref (manager);
1708   if (num_interfaces_to_remove == num_interfaces)
1709     {
1710       g_object_ref (op);
1711       g_warn_if_fail (g_hash_table_remove (manager->priv->map_object_path_to_object_proxy, object_path));
1712       g_mutex_unlock (&manager->priv->lock);
1713       g_signal_emit_by_name (manager, "object-removed", op);
1714       g_object_unref (op);
1715     }
1716   else
1717     {
1718       g_object_ref (op);
1719       g_mutex_unlock (&manager->priv->lock);
1720       for (n = 0; interface_names != NULL && interface_names[n] != NULL; n++)
1721         {
1722           GDBusInterface *interface;
1723           interface = g_dbus_object_get_interface (G_DBUS_OBJECT (op), interface_names[n]);
1724           _g_dbus_object_proxy_remove_interface (op, interface_names[n]);
1725           if (interface != NULL)
1726             {
1727               g_signal_emit_by_name (manager, "interface-removed", op, interface);
1728               g_object_unref (interface);
1729             }
1730         }
1731       g_object_unref (op);
1732     }
1733   g_object_unref (manager);
1734 }
1735
1736 static void
1737 process_get_all_result (GDBusObjectManagerClient *manager,
1738                         GVariant          *value,
1739                         const gchar       *name_owner)
1740 {
1741   GVariant *arg0;
1742   const gchar *object_path;
1743   GVariant *ifaces_and_properties;
1744   GVariantIter iter;
1745
1746   g_return_if_fail (name_owner == NULL || g_dbus_is_unique_name (name_owner));
1747
1748   arg0 = g_variant_get_child_value (value, 0);
1749   g_variant_iter_init (&iter, arg0);
1750   while (g_variant_iter_next (&iter,
1751                               "{&o@a{sa{sv}}}",
1752                               &object_path,
1753                               &ifaces_and_properties))
1754     {
1755       add_interfaces (manager, object_path, ifaces_and_properties, name_owner);
1756       g_variant_unref (ifaces_and_properties);
1757     }
1758   g_variant_unref (arg0);
1759 }
1760
1761 static void
1762 on_control_proxy_g_signal (GDBusProxy   *proxy,
1763                            const gchar  *sender_name,
1764                            const gchar  *signal_name,
1765                            GVariant     *parameters,
1766                            gpointer      user_data)
1767 {
1768   GWeakRef *manager_weak = user_data;
1769   GDBusObjectManagerClient *manager = NULL;
1770   const gchar *object_path;
1771
1772   manager = G_DBUS_OBJECT_MANAGER_CLIENT (g_weak_ref_get (manager_weak));
1773   if (manager == NULL)
1774     return;
1775
1776   //g_debug ("yay, g_signal %s: %s\n", signal_name, g_variant_print (parameters, TRUE));
1777
1778   if (g_strcmp0 (signal_name, "InterfacesAdded") == 0)
1779     {
1780       GVariant *ifaces_and_properties;
1781       g_variant_get (parameters,
1782                      "(&o@a{sa{sv}})",
1783                      &object_path,
1784                      &ifaces_and_properties);
1785       add_interfaces (manager, object_path, ifaces_and_properties, manager->priv->name_owner);
1786       g_variant_unref (ifaces_and_properties);
1787     }
1788   else if (g_strcmp0 (signal_name, "InterfacesRemoved") == 0)
1789     {
1790       const gchar **ifaces;
1791       g_variant_get (parameters,
1792                      "(&o^a&s)",
1793                      &object_path,
1794                      &ifaces);
1795       remove_interfaces (manager, object_path, ifaces);
1796       g_free (ifaces);
1797     }
1798
1799   g_object_unref (manager);
1800 }
1801
1802 /* ---------------------------------------------------------------------------------------------------- */
1803
1804 static const gchar *
1805 g_dbus_object_manager_client_get_object_path (GDBusObjectManager *_manager)
1806 {
1807   GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
1808   return manager->priv->object_path;
1809 }
1810
1811 static GDBusObject *
1812 g_dbus_object_manager_client_get_object (GDBusObjectManager *_manager,
1813                                          const gchar        *object_path)
1814 {
1815   GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
1816   GDBusObject *ret;
1817
1818   g_mutex_lock (&manager->priv->lock);
1819   ret = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1820   if (ret != NULL)
1821     g_object_ref (ret);
1822   g_mutex_unlock (&manager->priv->lock);
1823   return ret;
1824 }
1825
1826 static GDBusInterface *
1827 g_dbus_object_manager_client_get_interface  (GDBusObjectManager  *_manager,
1828                                              const gchar         *object_path,
1829                                              const gchar         *interface_name)
1830 {
1831   GDBusInterface *ret;
1832   GDBusObject *object;
1833
1834   ret = NULL;
1835
1836   object = g_dbus_object_manager_get_object (_manager, object_path);
1837   if (object == NULL)
1838     goto out;
1839
1840   ret = g_dbus_object_get_interface (object, interface_name);
1841   g_object_unref (object);
1842
1843  out:
1844   return ret;
1845 }
1846
1847 static GList *
1848 g_dbus_object_manager_client_get_objects (GDBusObjectManager *_manager)
1849 {
1850   GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
1851   GList *ret;
1852
1853   g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
1854
1855   g_mutex_lock (&manager->priv->lock);
1856   ret = g_hash_table_get_values (manager->priv->map_object_path_to_object_proxy);
1857   g_list_foreach (ret, (GFunc) g_object_ref, NULL);
1858   g_mutex_unlock (&manager->priv->lock);
1859
1860   return ret;
1861 }
1862
1863
1864 static void
1865 dbus_object_manager_interface_init (GDBusObjectManagerIface *iface)
1866 {
1867   iface->get_object_path = g_dbus_object_manager_client_get_object_path;
1868   iface->get_objects     = g_dbus_object_manager_client_get_objects;
1869   iface->get_object      = g_dbus_object_manager_client_get_object;
1870   iface->get_interface   = g_dbus_object_manager_client_get_interface;
1871 }
1872
1873 /* ---------------------------------------------------------------------------------------------------- */