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