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