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