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