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