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