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