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