GDBusProxy: Improve struct packing
[platform/upstream/glib.git] / gio / gdbusproxy.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 <stdlib.h>
26 #include <string.h>
27
28 #include "gdbusutils.h"
29 #include "gdbusproxy.h"
30 #include "gioenumtypes.h"
31 #include "gdbusconnection.h"
32 #include "gdbuserror.h"
33 #include "gdbusprivate.h"
34 #include "gio-marshal.h"
35 #include "ginitable.h"
36 #include "gasyncinitable.h"
37 #include "gioerror.h"
38 #include "gasyncresult.h"
39 #include "gsimpleasyncresult.h"
40 #include "gcancellable.h"
41
42 #include "glibintl.h"
43
44 /**
45  * SECTION:gdbusproxy
46  * @short_description: Client-side proxies
47  * @include: gio/gio.h
48  *
49  * #GDBusProxy is a base class used for proxies to access a D-Bus
50  * interface on a remote object. A #GDBusProxy can be constructed for
51  * both well-known and unique names.
52  *
53  * By default, #GDBusProxy will cache all properties (and listen to
54  * changes) of the remote object, and proxy all signals that gets
55  * emitted. This behaviour can be changed by passing suitable
56  * #GDBusProxyFlags when the proxy is created. If the proxy is for a
57  * well-known name, the property cache is flushed when the name owner
58  * vanishes and reloaded when a name owner appears.
59  *
60  * If a #GDBusProxy is used for a well-known name, the owner of the
61  * name is tracked and can be read from
62  * #GDBusProxy:g-name-owner. Connect to the #GObject::notify signal to
63  * get notified of changes. Additionally, only signals and property
64  * changes emitted from the current name owner are considered and
65  * calls are always sent to the current name owner. This avoids a
66  * number of race conditions when the name is lost by one owner and
67  * claimed by another. However, if no name owner currently exists,
68  * then calls will be sent to the well-known name which may result in
69  * the message bus launching an owner (unless
70  * %G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START is set).
71  *
72  * The generic #GDBusProxy::g-properties-changed and #GDBusProxy::g-signal
73  * signals are not very convenient to work with. Therefore, the recommended
74  * way of working with proxies is to subclass #GDBusProxy, and have
75  * more natural properties and signals in your derived class.
76  *
77  * See <xref linkend="gdbus-example-proxy-subclass"/> for an example.
78  *
79  * <example id="gdbus-wellknown-proxy"><title>GDBusProxy for a well-known-name</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gdbus-example-watch-proxy.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting></example>
80  */
81
82 struct _GDBusProxyPrivate
83 {
84   GBusType bus_type;
85   GDBusProxyFlags flags;
86   GDBusConnection *connection;
87
88   gchar *name;
89   gchar *name_owner;
90   gchar *object_path;
91   gchar *interface_name;
92   gint timeout_msec;
93
94   guint name_owner_changed_subscription_id;
95
96   GCancellable *get_all_cancellable;
97
98   /* gchar* -> GVariant* */
99   GHashTable *properties;
100
101   GDBusInterfaceInfo *expected_interface;
102
103   guint properties_changed_subscriber_id;
104   guint signals_subscriber_id;
105
106   gboolean initialized;
107 };
108
109 enum
110 {
111   PROP_0,
112   PROP_G_CONNECTION,
113   PROP_G_BUS_TYPE,
114   PROP_G_NAME,
115   PROP_G_NAME_OWNER,
116   PROP_G_FLAGS,
117   PROP_G_OBJECT_PATH,
118   PROP_G_INTERFACE_NAME,
119   PROP_G_DEFAULT_TIMEOUT,
120   PROP_G_INTERFACE_INFO
121 };
122
123 enum
124 {
125   PROPERTIES_CHANGED_SIGNAL,
126   SIGNAL_SIGNAL,
127   LAST_SIGNAL,
128 };
129
130 guint signals[LAST_SIGNAL] = {0};
131
132 static void initable_iface_init       (GInitableIface *initable_iface);
133 static void async_initable_iface_init (GAsyncInitableIface *async_initable_iface);
134
135 G_DEFINE_TYPE_WITH_CODE (GDBusProxy, g_dbus_proxy, G_TYPE_OBJECT,
136                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)
137                          G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init)
138                          );
139
140 static void
141 g_dbus_proxy_finalize (GObject *object)
142 {
143   GDBusProxy *proxy = G_DBUS_PROXY (object);
144
145   g_warn_if_fail (proxy->priv->get_all_cancellable == NULL);
146
147   if (proxy->priv->name_owner_changed_subscription_id > 0)
148     g_dbus_connection_signal_unsubscribe (proxy->priv->connection,
149                                           proxy->priv->name_owner_changed_subscription_id);
150
151   if (proxy->priv->properties_changed_subscriber_id > 0)
152     g_dbus_connection_signal_unsubscribe (proxy->priv->connection,
153                                           proxy->priv->properties_changed_subscriber_id);
154
155   if (proxy->priv->signals_subscriber_id > 0)
156     g_dbus_connection_signal_unsubscribe (proxy->priv->connection,
157                                           proxy->priv->signals_subscriber_id);
158
159   if (proxy->priv->connection != NULL)
160     g_object_unref (proxy->priv->connection);
161   g_free (proxy->priv->name);
162   g_free (proxy->priv->name_owner);
163   g_free (proxy->priv->object_path);
164   g_free (proxy->priv->interface_name);
165   if (proxy->priv->properties != NULL)
166     g_hash_table_unref (proxy->priv->properties);
167
168   if (proxy->priv->expected_interface != NULL)
169     {
170       g_dbus_interface_info_cache_release (proxy->priv->expected_interface);
171       g_dbus_interface_info_unref (proxy->priv->expected_interface);
172     }
173
174   G_OBJECT_CLASS (g_dbus_proxy_parent_class)->finalize (object);
175 }
176
177 static void
178 g_dbus_proxy_get_property (GObject    *object,
179                            guint       prop_id,
180                            GValue     *value,
181                            GParamSpec *pspec)
182 {
183   GDBusProxy *proxy = G_DBUS_PROXY (object);
184
185   switch (prop_id)
186     {
187     case PROP_G_CONNECTION:
188       g_value_set_object (value, proxy->priv->connection);
189       break;
190
191     case PROP_G_FLAGS:
192       g_value_set_flags (value, proxy->priv->flags);
193       break;
194
195     case PROP_G_NAME:
196       g_value_set_string (value, proxy->priv->name);
197       break;
198
199     case PROP_G_NAME_OWNER:
200       g_value_set_string (value, proxy->priv->name_owner);
201       break;
202
203     case PROP_G_OBJECT_PATH:
204       g_value_set_string (value, proxy->priv->object_path);
205       break;
206
207     case PROP_G_INTERFACE_NAME:
208       g_value_set_string (value, proxy->priv->interface_name);
209       break;
210
211     case PROP_G_DEFAULT_TIMEOUT:
212       g_value_set_int (value, proxy->priv->timeout_msec);
213       break;
214
215     case PROP_G_INTERFACE_INFO:
216       g_value_set_boxed (value, g_dbus_proxy_get_interface_info (proxy));
217       break;
218
219     default:
220       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
221       break;
222     }
223 }
224
225 static void
226 g_dbus_proxy_set_property (GObject      *object,
227                            guint         prop_id,
228                            const GValue *value,
229                            GParamSpec   *pspec)
230 {
231   GDBusProxy *proxy = G_DBUS_PROXY (object);
232
233   switch (prop_id)
234     {
235     case PROP_G_CONNECTION:
236       proxy->priv->connection = g_value_dup_object (value);
237       break;
238
239     case PROP_G_FLAGS:
240       proxy->priv->flags = g_value_get_flags (value);
241       break;
242
243     case PROP_G_NAME:
244       proxy->priv->name = g_value_dup_string (value);
245       break;
246
247     case PROP_G_OBJECT_PATH:
248       proxy->priv->object_path = g_value_dup_string (value);
249       break;
250
251     case PROP_G_INTERFACE_NAME:
252       proxy->priv->interface_name = g_value_dup_string (value);
253       break;
254
255     case PROP_G_DEFAULT_TIMEOUT:
256       g_dbus_proxy_set_default_timeout (proxy, g_value_get_int (value));
257       break;
258
259     case PROP_G_INTERFACE_INFO:
260       g_dbus_proxy_set_interface_info (proxy, g_value_get_boxed (value));
261       break;
262
263     case PROP_G_BUS_TYPE:
264       proxy->priv->bus_type = g_value_get_enum (value);
265       break;
266
267     default:
268       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
269       break;
270     }
271 }
272
273 static void
274 g_dbus_proxy_class_init (GDBusProxyClass *klass)
275 {
276   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
277
278   gobject_class->finalize     = g_dbus_proxy_finalize;
279   gobject_class->set_property = g_dbus_proxy_set_property;
280   gobject_class->get_property = g_dbus_proxy_get_property;
281
282   /* Note that all property names are prefixed to avoid collisions with D-Bus property names
283    * in derived classes */
284
285   /**
286    * GDBusProxy:g-interface-info:
287    *
288    * Ensure that interactions with this proxy conform to the given
289    * interface.  For example, when completing a method call, if the
290    * type signature of the message isn't what's expected, the given
291    * #GError is set.  Signals that have a type signature mismatch are
292    * simply dropped.
293    *
294    * Since: 2.26
295    */
296   g_object_class_install_property (gobject_class,
297                                    PROP_G_INTERFACE_INFO,
298                                    g_param_spec_boxed ("g-interface-info",
299                                                        P_("Interface Information"),
300                                                        P_("Interface Information"),
301                                                        G_TYPE_DBUS_INTERFACE_INFO,
302                                                        G_PARAM_READABLE |
303                                                        G_PARAM_WRITABLE |
304                                                        G_PARAM_STATIC_NAME |
305                                                        G_PARAM_STATIC_BLURB |
306                                                        G_PARAM_STATIC_NICK));
307
308   /**
309    * GDBusProxy:g-connection:
310    *
311    * The #GDBusConnection the proxy is for.
312    *
313    * Since: 2.26
314    */
315   g_object_class_install_property (gobject_class,
316                                    PROP_G_CONNECTION,
317                                    g_param_spec_object ("g-connection",
318                                                         P_("g-connection"),
319                                                         P_("The connection the proxy is for"),
320                                                         G_TYPE_DBUS_CONNECTION,
321                                                         G_PARAM_READABLE |
322                                                         G_PARAM_WRITABLE |
323                                                         G_PARAM_CONSTRUCT_ONLY |
324                                                         G_PARAM_STATIC_NAME |
325                                                         G_PARAM_STATIC_BLURB |
326                                                         G_PARAM_STATIC_NICK));
327
328   /**
329    * GDBusProxy:g-bus-type:
330    *
331    * If this property is not %G_BUS_TYPE_NONE, then
332    * #GDBusProxy:g-connection must be %NULL and will be set to the
333    * #GDBusConnection obtained by calling g_bus_get() with the value
334    * of this property.
335    *
336    * Since: 2.26
337    */
338   g_object_class_install_property (gobject_class,
339                                    PROP_G_BUS_TYPE,
340                                    g_param_spec_enum ("g-bus-type",
341                                                       P_("Bus Type"),
342                                                       P_("The bus to connect to, if any"),
343                                                       G_TYPE_BUS_TYPE,
344                                                       G_BUS_TYPE_NONE,
345                                                       G_PARAM_WRITABLE |
346                                                       G_PARAM_CONSTRUCT_ONLY |
347                                                       G_PARAM_STATIC_NAME |
348                                                       G_PARAM_STATIC_BLURB |
349                                                       G_PARAM_STATIC_NICK));
350
351   /**
352    * GDBusProxy:g-flags:
353    *
354    * Flags from the #GDBusProxyFlags enumeration.
355    *
356    * Since: 2.26
357    */
358   g_object_class_install_property (gobject_class,
359                                    PROP_G_FLAGS,
360                                    g_param_spec_flags ("g-flags",
361                                                        P_("g-flags"),
362                                                        P_("Flags for the proxy"),
363                                                        G_TYPE_DBUS_PROXY_FLAGS,
364                                                        G_DBUS_PROXY_FLAGS_NONE,
365                                                        G_PARAM_READABLE |
366                                                        G_PARAM_WRITABLE |
367                                                        G_PARAM_CONSTRUCT_ONLY |
368                                                        G_PARAM_STATIC_NAME |
369                                                        G_PARAM_STATIC_BLURB |
370                                                        G_PARAM_STATIC_NICK));
371
372   /**
373    * GDBusProxy:g-name:
374    *
375    * The well-known or unique name that the proxy is for.
376    *
377    * Since: 2.26
378    */
379   g_object_class_install_property (gobject_class,
380                                    PROP_G_NAME,
381                                    g_param_spec_string ("g-name",
382                                                         P_("g-name"),
383                                                         P_("The well-known or unique name that the proxy is for"),
384                                                         NULL,
385                                                         G_PARAM_READABLE |
386                                                         G_PARAM_WRITABLE |
387                                                         G_PARAM_CONSTRUCT_ONLY |
388                                                         G_PARAM_STATIC_NAME |
389                                                         G_PARAM_STATIC_BLURB |
390                                                         G_PARAM_STATIC_NICK));
391
392   /**
393    * GDBusProxy:g-name-owner:
394    *
395    * The unique name that owns #GDBusProxy:name or %NULL if no-one
396    * currently owns that name. You may connect to #GObject::notify signal to
397    * track changes to this property.
398    *
399    * Since: 2.26
400    */
401   g_object_class_install_property (gobject_class,
402                                    PROP_G_NAME_OWNER,
403                                    g_param_spec_string ("g-name-owner",
404                                                         P_("g-name-owner"),
405                                                         P_("The unique name for the owner"),
406                                                         NULL,
407                                                         G_PARAM_READABLE |
408                                                         G_PARAM_STATIC_NAME |
409                                                         G_PARAM_STATIC_BLURB |
410                                                         G_PARAM_STATIC_NICK));
411
412   /**
413    * GDBusProxy:g-object-path:
414    *
415    * The object path the proxy is for.
416    *
417    * Since: 2.26
418    */
419   g_object_class_install_property (gobject_class,
420                                    PROP_G_OBJECT_PATH,
421                                    g_param_spec_string ("g-object-path",
422                                                         P_("g-object-path"),
423                                                         P_("The object path the proxy is for"),
424                                                         NULL,
425                                                         G_PARAM_READABLE |
426                                                         G_PARAM_WRITABLE |
427                                                         G_PARAM_CONSTRUCT_ONLY |
428                                                         G_PARAM_STATIC_NAME |
429                                                         G_PARAM_STATIC_BLURB |
430                                                         G_PARAM_STATIC_NICK));
431
432   /**
433    * GDBusProxy:g-interface-name:
434    *
435    * The D-Bus interface name the proxy is for.
436    *
437    * Since: 2.26
438    */
439   g_object_class_install_property (gobject_class,
440                                    PROP_G_INTERFACE_NAME,
441                                    g_param_spec_string ("g-interface-name",
442                                                         P_("g-interface-name"),
443                                                         P_("The D-Bus interface name the proxy is for"),
444                                                         NULL,
445                                                         G_PARAM_READABLE |
446                                                         G_PARAM_WRITABLE |
447                                                         G_PARAM_CONSTRUCT_ONLY |
448                                                         G_PARAM_STATIC_NAME |
449                                                         G_PARAM_STATIC_BLURB |
450                                                         G_PARAM_STATIC_NICK));
451
452   /**
453    * GDBusProxy:g-default-timeout:
454    *
455    * The timeout to use if -1 (specifying default timeout) is passed
456    * as @timeout_msec in the g_dbus_proxy_call() and
457    * g_dbus_proxy_call_sync() functions.
458    *
459    * This allows applications to set a proxy-wide timeout for all
460    * remote method invocations on the proxy. If this property is -1,
461    * the default timeout (typically 25 seconds) is used. If set to
462    * %G_MAXINT, then no timeout is used.
463    *
464    * Since: 2.26
465    */
466   g_object_class_install_property (gobject_class,
467                                    PROP_G_DEFAULT_TIMEOUT,
468                                    g_param_spec_int ("g-default-timeout",
469                                                      P_("Default Timeout"),
470                                                      P_("Timeout for remote method invocation"),
471                                                      -1,
472                                                      G_MAXINT,
473                                                      -1,
474                                                      G_PARAM_READABLE |
475                                                      G_PARAM_WRITABLE |
476                                                      G_PARAM_CONSTRUCT |
477                                                      G_PARAM_STATIC_NAME |
478                                                      G_PARAM_STATIC_BLURB |
479                                                      G_PARAM_STATIC_NICK));
480
481   /**
482    * GDBusProxy::g-properties-changed:
483    * @proxy: The #GDBusProxy emitting the signal.
484    * @changed_properties: A #GVariant containing the properties that changed
485    * @invalidated_properties: A %NULL terminated array of properties that was invalidated
486    *
487    * Emitted when one or more D-Bus properties on @proxy changes. The
488    * local cache has already been updated when this signal fires. Note
489    * that both @changed_properties and @invalidated_properties are
490    * guaranteed to never be %NULL (either may be empty though).
491    *
492    * This signal corresponds to the
493    * <literal>PropertiesChanged</literal> D-Bus signal on the
494    * <literal>org.freedesktop.DBus.Properties</literal> interface.
495    *
496    * Since: 2.26
497    */
498   signals[PROPERTIES_CHANGED_SIGNAL] = g_signal_new ("g-properties-changed",
499                                                      G_TYPE_DBUS_PROXY,
500                                                      G_SIGNAL_RUN_LAST,
501                                                      G_STRUCT_OFFSET (GDBusProxyClass, g_properties_changed),
502                                                      NULL,
503                                                      NULL,
504                                                      _gio_marshal_VOID__VARIANT_BOXED,
505                                                      G_TYPE_NONE,
506                                                      2,
507                                                      G_TYPE_VARIANT,
508                                                      G_TYPE_STRV | G_SIGNAL_TYPE_STATIC_SCOPE);
509
510   /**
511    * GDBusProxy::g-signal:
512    * @proxy: The #GDBusProxy emitting the signal.
513    * @sender_name: The sender of the signal or %NULL if the connection is not a bus connection.
514    * @signal_name: The name of the signal.
515    * @parameters: A #GVariant tuple with parameters for the signal.
516    *
517    * Emitted when a signal from the remote object and interface that @proxy is for, has been received.
518    *
519    * Since: 2.26
520    */
521   signals[SIGNAL_SIGNAL] = g_signal_new ("g-signal",
522                                          G_TYPE_DBUS_PROXY,
523                                          G_SIGNAL_RUN_LAST,
524                                          G_STRUCT_OFFSET (GDBusProxyClass, g_signal),
525                                          NULL,
526                                          NULL,
527                                          _gio_marshal_VOID__STRING_STRING_VARIANT,
528                                          G_TYPE_NONE,
529                                          3,
530                                          G_TYPE_STRING,
531                                          G_TYPE_STRING,
532                                          G_TYPE_VARIANT);
533
534
535   g_type_class_add_private (klass, sizeof (GDBusProxyPrivate));
536 }
537
538 static void
539 g_dbus_proxy_init (GDBusProxy *proxy)
540 {
541   proxy->priv = G_TYPE_INSTANCE_GET_PRIVATE (proxy, G_TYPE_DBUS_PROXY, GDBusProxyPrivate);
542   proxy->priv->properties = g_hash_table_new_full (g_str_hash,
543                                                    g_str_equal,
544                                                    g_free,
545                                                    (GDestroyNotify) g_variant_unref);
546 }
547
548 /* ---------------------------------------------------------------------------------------------------- */
549
550 static gint
551 property_name_sort_func (const gchar **a,
552                          const gchar **b)
553 {
554   return g_strcmp0 (*a, *b);
555 }
556
557 /**
558  * g_dbus_proxy_get_cached_property_names:
559  * @proxy: A #GDBusProxy.
560  *
561  * Gets the names of all cached properties on @proxy.
562  *
563  * Returns: A %NULL-terminated array of strings or %NULL if @proxy has
564  * no cached properties. Free the returned array with g_strfreev().
565  *
566  * Since: 2.26
567  */
568 gchar **
569 g_dbus_proxy_get_cached_property_names (GDBusProxy  *proxy)
570 {
571   gchar **names;
572   GPtrArray *p;
573   GHashTableIter iter;
574   const gchar *key;
575
576   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
577
578   names = NULL;
579   if (g_hash_table_size (proxy->priv->properties) == 0)
580     goto out;
581
582   p = g_ptr_array_new ();
583
584   g_hash_table_iter_init (&iter, proxy->priv->properties);
585   while (g_hash_table_iter_next (&iter, (gpointer) &key, NULL))
586     g_ptr_array_add (p, g_strdup (key));
587   g_ptr_array_sort (p, (GCompareFunc) property_name_sort_func);
588   g_ptr_array_add (p, NULL);
589
590   names = (gchar **) g_ptr_array_free (p, FALSE);
591
592  out:
593   return names;
594 }
595
596 static const GDBusPropertyInfo *
597 lookup_property_info_or_warn (GDBusProxy  *proxy,
598                               const gchar *property_name)
599 {
600   const GDBusPropertyInfo *info;
601
602   if (proxy->priv->expected_interface == NULL)
603     return NULL;
604
605   info = g_dbus_interface_info_lookup_property (proxy->priv->expected_interface, property_name);
606   if (info == NULL)
607     {
608       g_warning ("Trying to lookup property %s which isn't in expected interface %s",
609                  property_name,
610                  proxy->priv->expected_interface->name);
611     }
612
613   return info;
614 }
615
616 /**
617  * g_dbus_proxy_get_cached_property:
618  * @proxy: A #GDBusProxy.
619  * @property_name: Property name.
620  *
621  * Looks up the value for a property from the cache. This call does no
622  * blocking IO.
623  *
624  * If @proxy has an expected interface (see
625  * #GDBusProxy:g-interface-info), then @property_name (for existence)
626  * is checked against it.
627  *
628  * Returns: A reference to the #GVariant instance that holds the value
629  * for @property_name or %NULL if the value is not in the cache. The
630  * returned reference must be freed with g_variant_unref().
631  *
632  * Since: 2.26
633  */
634 GVariant *
635 g_dbus_proxy_get_cached_property (GDBusProxy   *proxy,
636                                   const gchar  *property_name)
637 {
638   GVariant *value;
639
640   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
641   g_return_val_if_fail (property_name != NULL, NULL);
642
643   value = g_hash_table_lookup (proxy->priv->properties, property_name);
644   if (value == NULL)
645     {
646       lookup_property_info_or_warn (proxy, property_name);
647       /* no difference */
648       goto out;
649     }
650
651   g_variant_ref (value);
652
653  out:
654   return value;
655 }
656
657 /**
658  * g_dbus_proxy_set_cached_property:
659  * @proxy: A #GDBusProxy
660  * @property_name: Property name.
661  * @value: (allow-none): Value for the property or %NULL to remove it from the cache.
662  *
663  * If @value is not %NULL, sets the cached value for the property with
664  * name @property_name to the value in @value.
665  *
666  * If @value is %NULL, then the cached value is removed from the
667  * property cache.
668  *
669  * If @proxy has an expected interface (see
670  * #GDBusProxy:g-interface-info), then @property_name (for existence)
671  * and @value (for the type) is checked against it.
672  *
673  * If the @value #GVariant is floating, it is consumed. This allows
674  * convenient 'inline' use of g_variant_new(), e.g.
675  * |[
676  *  g_dbus_proxy_set_cached_property (proxy,
677  *                                    "SomeProperty",
678  *                                    g_variant_new ("(si)",
679  *                                                  "A String",
680  *                                                  42));
681  * ]|
682  *
683  * Normally you will not need to use this method since @proxy is
684  * tracking changes using the
685  * <literal>org.freedesktop.DBus.Properties.PropertiesChanged</literal>
686  * D-Bus signal. However, for performance reasons an object may decide
687  * to not use this signal for some properties and instead use a
688  * proprietary out-of-band mechanism to transmit changes.
689  *
690  * As a concrete example, consider an object with a property
691  * <literal>ChatroomParticipants</literal> which is an array of
692  * strings. Instead of transmitting the same (long) array every time
693  * the property changes, it is more efficient to only transmit the
694  * delta using e.g. signals <literal>ChatroomParticipantJoined(String
695  * name)</literal> and <literal>ChatroomParticipantParted(String
696  * name)</literal>.
697  *
698  * Since: 2.26
699  */
700 void
701 g_dbus_proxy_set_cached_property (GDBusProxy   *proxy,
702                                   const gchar  *property_name,
703                                   GVariant     *value)
704 {
705   const GDBusPropertyInfo *info;
706
707   g_return_if_fail (G_IS_DBUS_PROXY (proxy));
708   g_return_if_fail (property_name != NULL);
709
710   if (value != NULL)
711     {
712       info = lookup_property_info_or_warn (proxy, property_name);
713       if (info != NULL)
714         {
715           if (g_strcmp0 (info->signature, g_variant_get_type_string (value)) != 0)
716             {
717               g_warning (_("Trying to set property %s of type %s but according to the expected "
718                            "interface the type is %s"),
719                          property_name,
720                          g_variant_get_type_string (value),
721                          info->signature);
722               goto out;
723             }
724         }
725       g_hash_table_insert (proxy->priv->properties,
726                            g_strdup (property_name),
727                            g_variant_ref_sink (value));
728     }
729   else
730     {
731       g_hash_table_remove (proxy->priv->properties, property_name);
732     }
733
734  out:
735   ;
736 }
737
738 /* ---------------------------------------------------------------------------------------------------- */
739
740 static void
741 on_signal_received (GDBusConnection *connection,
742                     const gchar     *sender_name,
743                     const gchar     *object_path,
744                     const gchar     *interface_name,
745                     const gchar     *signal_name,
746                     GVariant        *parameters,
747                     gpointer         user_data)
748 {
749   GDBusProxy *proxy = G_DBUS_PROXY (user_data);
750
751   if (!proxy->priv->initialized)
752     goto out;
753
754   if (proxy->priv->name_owner != NULL && g_strcmp0 (sender_name, proxy->priv->name_owner) != 0)
755     goto out;
756
757   if (proxy->priv->expected_interface != NULL)
758     {
759       const GDBusSignalInfo *info;
760       GVariantType *expected_type;
761       info = g_dbus_interface_info_lookup_signal (proxy->priv->expected_interface, signal_name);
762       if (info == NULL)
763         goto out;
764       expected_type = _g_dbus_compute_complete_signature (info->args);
765       if (!g_variant_type_equal (expected_type, g_variant_get_type (parameters)))
766         {
767           g_variant_type_free (expected_type);
768           goto out;
769         }
770       g_variant_type_free (expected_type);
771     }
772
773   g_signal_emit (proxy,
774                  signals[SIGNAL_SIGNAL],
775                  0,
776                  sender_name,
777                  signal_name,
778                  parameters);
779  out:
780   ;
781 }
782
783 /* ---------------------------------------------------------------------------------------------------- */
784
785 static void
786 insert_property_checked (GDBusProxy  *proxy,
787                          gchar *property_name,
788                          GVariant *value)
789 {
790   if (proxy->priv->expected_interface != NULL)
791     {
792       const GDBusPropertyInfo *info;
793
794       info = g_dbus_interface_info_lookup_property (proxy->priv->expected_interface, property_name);
795       /* Ignore unknown properties */
796       if (info == NULL)
797         goto invalid;
798
799       /* Ignore properties with the wrong type */
800       if (g_strcmp0 (info->signature, g_variant_get_type_string (value)) != 0)
801         goto invalid;
802     }
803
804   g_hash_table_insert (proxy->priv->properties,
805                        property_name, /* adopts string */
806                        value); /* adopts value */
807
808   return;
809
810  invalid:
811   g_variant_unref (value);
812   g_free (property_name);
813 }
814
815 static void
816 on_properties_changed (GDBusConnection *connection,
817                        const gchar     *sender_name,
818                        const gchar     *object_path,
819                        const gchar     *interface_name,
820                        const gchar     *signal_name,
821                        GVariant        *parameters,
822                        gpointer         user_data)
823 {
824   GDBusProxy *proxy = G_DBUS_PROXY (user_data);
825   const gchar *interface_name_for_signal;
826   GVariant *changed_properties;
827   gchar **invalidated_properties;
828   GVariantIter iter;
829   gchar *key;
830   GVariant *value;
831   guint n;
832
833   changed_properties = NULL;
834   invalidated_properties = NULL;
835
836   if (!proxy->priv->initialized)
837     goto out;
838
839   if (proxy->priv->name_owner != NULL && g_strcmp0 (sender_name, proxy->priv->name_owner) != 0)
840     goto out;
841
842   if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sa{sv}as)")))
843     {
844       g_warning ("Value for PropertiesChanged signal with type `%s' does not match `(sa{sv}as)'",
845                  g_variant_get_type_string (parameters));
846       goto out;
847     }
848
849   g_variant_get (parameters,
850                  "(&s@a{sv}^a&s)",
851                  &interface_name_for_signal,
852                  &changed_properties,
853                  &invalidated_properties);
854
855   if (g_strcmp0 (interface_name_for_signal, proxy->priv->interface_name) != 0)
856     goto out;
857
858   g_variant_iter_init (&iter, changed_properties);
859   while (g_variant_iter_next (&iter, "{sv}", &key, &value))
860     {
861       insert_property_checked (proxy,
862                                key, /* adopts string */
863                                value); /* adopts value */
864     }
865
866   for (n = 0; invalidated_properties[n] != NULL; n++)
867     {
868       g_hash_table_remove (proxy->priv->properties, invalidated_properties[n]);
869     }
870
871   /* emit signal */
872   g_signal_emit (proxy, signals[PROPERTIES_CHANGED_SIGNAL],
873                  0,
874                  changed_properties,
875                  invalidated_properties);
876
877  out:
878   if (changed_properties != NULL)
879     g_variant_unref (changed_properties);
880   g_free (invalidated_properties);
881 }
882
883 /* ---------------------------------------------------------------------------------------------------- */
884
885 static void
886 process_get_all_reply (GDBusProxy *proxy,
887                        GVariant   *result)
888 {
889   GVariantIter *iter;
890   gchar *key;
891   GVariant *value;
892
893   if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(a{sv})")))
894     {
895       g_warning ("Value for GetAll reply with type `%s' does not match `(a{sv})'",
896                  g_variant_get_type_string (result));
897       goto out;
898     }
899
900   g_variant_get (result, "(a{sv})", &iter);
901   while (g_variant_iter_next (iter, "{sv}", &key, &value))
902     {
903       insert_property_checked (proxy,
904                                key, /* adopts string */
905                                value); /* adopts value */
906     }
907   g_variant_iter_free (iter);
908
909   /* Synthesize ::g-properties-changed changed */
910   if (g_hash_table_size (proxy->priv->properties) > 0)
911     {
912       GVariant *changed_properties;
913       const gchar *invalidated_properties[1] = {NULL};
914
915       g_variant_get (result,
916                      "(@a{sv})",
917                      &changed_properties);
918       g_signal_emit (proxy, signals[PROPERTIES_CHANGED_SIGNAL],
919                      0,
920                      changed_properties,
921                      invalidated_properties);
922       g_variant_unref (changed_properties);
923     }
924
925  out:
926   ;
927 }
928
929 typedef struct
930 {
931   GDBusProxy *proxy;
932   GCancellable *cancellable;
933   gchar *name_owner;
934 } LoadPropertiesOnNameOwnerChangedData;
935
936 static void
937 on_name_owner_changed_get_all_cb (GDBusConnection *connection,
938                                   GAsyncResult    *res,
939                                   gpointer         user_data)
940 {
941   LoadPropertiesOnNameOwnerChangedData *data = user_data;
942   GVariant *result;
943   GError *error;
944   gboolean cancelled;
945
946   cancelled = FALSE;
947
948   error = NULL;
949   result = g_dbus_connection_call_finish (connection,
950                                           res,
951                                           &error);
952   if (result == NULL)
953     {
954       if (error->domain == G_IO_ERROR && error->code == G_IO_ERROR_CANCELLED)
955         cancelled = TRUE;
956       /* We just ignore if GetAll() is failing. Because this might happen
957        * if the object has no properties at all. Or if the caller is
958        * not authorized to see the properties.
959        *
960        * Either way, apps can know about this by using
961        * get_cached_property_names() or get_cached_property().
962        *
963        * TODO: handle G_DBUS_DEBUG flag 'proxy' and, if enabled, log the
964        * fact that GetAll() failed
965        */
966       //g_debug ("error: %d %d %s", error->domain, error->code, error->message);
967       g_error_free (error);
968     }
969
970   /* and finally we can notify */
971   if (!cancelled)
972     {
973       g_free (data->proxy->priv->name_owner);
974       data->proxy->priv->name_owner = data->name_owner;
975       data->name_owner = NULL; /* to avoid an extra copy, we steal the string */
976
977       g_hash_table_remove_all (data->proxy->priv->properties);
978       if (result != NULL)
979         {
980           process_get_all_reply (data->proxy, result);
981           g_variant_unref (result);
982         }
983
984       g_object_notify (G_OBJECT (data->proxy), "g-name-owner");
985     }
986
987   if (data->cancellable == data->proxy->priv->get_all_cancellable)
988     data->proxy->priv->get_all_cancellable = NULL;
989
990   g_object_unref (data->proxy);
991   g_object_unref (data->cancellable);
992   g_free (data->name_owner);
993   g_free (data);
994 }
995
996 static void
997 on_name_owner_changed (GDBusConnection *connection,
998                        const gchar      *sender_name,
999                        const gchar      *object_path,
1000                        const gchar      *interface_name,
1001                        const gchar      *signal_name,
1002                        GVariant         *parameters,
1003                        gpointer          user_data)
1004 {
1005   GDBusProxy *proxy = G_DBUS_PROXY (user_data);
1006   const gchar *old_owner;
1007   const gchar *new_owner;
1008
1009   /* if we are already trying to load properties, cancel that */
1010   if (proxy->priv->get_all_cancellable != NULL)
1011     {
1012       g_cancellable_cancel (proxy->priv->get_all_cancellable);
1013       proxy->priv->get_all_cancellable = NULL;
1014     }
1015
1016   g_variant_get (parameters,
1017                  "(&s&s&s)",
1018                  NULL,
1019                  &old_owner,
1020                  &new_owner);
1021
1022   if (strlen (new_owner) == 0)
1023     {
1024       g_free (proxy->priv->name_owner);
1025       proxy->priv->name_owner = NULL;
1026
1027       /* Synthesize ::g-properties-changed changed */
1028       if (!(proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES) &&
1029           g_hash_table_size (proxy->priv->properties) > 0)
1030         {
1031           GVariantBuilder builder;
1032           GVariant *changed_properties;
1033           GPtrArray *invalidated_properties;
1034           GHashTableIter iter;
1035           const gchar *key;
1036
1037           /* Build changed_properties (always empty) and invalidated_properties ... */
1038           g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
1039           changed_properties = g_variant_builder_end (&builder);
1040           invalidated_properties = g_ptr_array_new_with_free_func (g_free);
1041           g_hash_table_iter_init (&iter, proxy->priv->properties);
1042           while (g_hash_table_iter_next (&iter, (gpointer) &key, NULL))
1043             g_ptr_array_add (invalidated_properties, g_strdup (key));
1044           g_ptr_array_add (invalidated_properties, NULL);
1045
1046           /* ... throw out the properties ... */
1047           g_hash_table_remove_all (proxy->priv->properties);
1048
1049           /* ... and finally emit the ::g-properties-changed signal */
1050           g_signal_emit (proxy, signals[PROPERTIES_CHANGED_SIGNAL],
1051                          0,
1052                          changed_properties,
1053                          (const gchar* const *) invalidated_properties->pdata);
1054           g_variant_unref (changed_properties);
1055           g_ptr_array_unref (invalidated_properties);
1056         }
1057       g_object_notify (G_OBJECT (proxy), "g-name-owner");
1058     }
1059   else
1060     {
1061       /* ignore duplicates - this can happen when activating the service */
1062       if (g_strcmp0 (new_owner, proxy->priv->name_owner) == 0)
1063         goto out;
1064
1065       if (proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES)
1066         {
1067           g_free (proxy->priv->name_owner);
1068           proxy->priv->name_owner = g_strdup (new_owner);
1069           g_hash_table_remove_all (proxy->priv->properties);
1070           g_object_notify (G_OBJECT (proxy), "g-name-owner");
1071         }
1072       else
1073         {
1074           LoadPropertiesOnNameOwnerChangedData *data;
1075
1076           /* start loading properties.. only then emit notify::g-name-owner .. we
1077            * need to be able to cancel this in the event another NameOwnerChanged
1078            * signal suddenly happens
1079            */
1080
1081           g_assert (proxy->priv->get_all_cancellable == NULL);
1082           proxy->priv->get_all_cancellable = g_cancellable_new ();
1083           data = g_new0 (LoadPropertiesOnNameOwnerChangedData, 1);
1084           data->proxy = g_object_ref (proxy);
1085           data->cancellable = proxy->priv->get_all_cancellable;
1086           data->name_owner = g_strdup (new_owner);
1087           g_dbus_connection_call (proxy->priv->connection,
1088                                   data->name_owner,
1089                                   proxy->priv->object_path,
1090                                   "org.freedesktop.DBus.Properties",
1091                                   "GetAll",
1092                                   g_variant_new ("(s)", proxy->priv->interface_name),
1093                                   G_VARIANT_TYPE ("(a{sv})"),
1094                                   G_DBUS_CALL_FLAGS_NONE,
1095                                   -1,           /* timeout */
1096                                   proxy->priv->get_all_cancellable,
1097                                   (GAsyncReadyCallback) on_name_owner_changed_get_all_cb,
1098                                   data);
1099         }
1100     }
1101
1102  out:
1103   ;
1104 }
1105
1106 /* ---------------------------------------------------------------------------------------------------- */
1107
1108 typedef struct
1109 {
1110   GDBusProxy *proxy;
1111   GCancellable *cancellable;
1112   GSimpleAsyncResult *simple;
1113 } AsyncInitData;
1114
1115 static void
1116 async_init_data_free (AsyncInitData *data)
1117 {
1118   g_object_unref (data->proxy);
1119   if (data->cancellable != NULL)
1120     g_object_unref (data->cancellable);
1121   g_object_unref (data->simple);
1122   g_free (data);
1123 }
1124
1125 static void
1126 async_init_get_all_cb (GDBusConnection *connection,
1127                        GAsyncResult    *res,
1128                        gpointer         user_data)
1129 {
1130   AsyncInitData *data = user_data;
1131   GVariant *result;
1132   GError *error;
1133
1134   error = NULL;
1135   result = g_dbus_connection_call_finish (connection,
1136                                           res,
1137                                           &error);
1138   if (result == NULL)
1139     {
1140       /* We just ignore if GetAll() is failing. Because this might happen
1141        * if the object has no properties at all. Or if the caller is
1142        * not authorized to see the properties.
1143        *
1144        * Either way, apps can know about this by using
1145        * get_cached_property_names() or get_cached_property().
1146        *
1147        * TODO: handle G_DBUS_DEBUG flag 'proxy' and, if enabled, log the
1148        * fact that GetAll() failed
1149        */
1150       //g_debug ("error: %d %d %s", error->domain, error->code, error->message);
1151       g_error_free (error);
1152     }
1153   else
1154     {
1155       g_simple_async_result_set_op_res_gpointer (data->simple,
1156                                                  result,
1157                                                  (GDestroyNotify) g_variant_unref);
1158     }
1159
1160   g_simple_async_result_complete_in_idle (data->simple);
1161   async_init_data_free (data);
1162 }
1163
1164
1165 static void
1166 async_init_get_name_owner_cb (GDBusConnection *connection,
1167                               GAsyncResult    *res,
1168                               gpointer         user_data)
1169 {
1170   AsyncInitData *data = user_data;
1171
1172   if (res != NULL)
1173     {
1174       GError *error;
1175       GVariant *result;
1176
1177       error = NULL;
1178       result = g_dbus_connection_call_finish (connection,
1179                                               res,
1180                                               &error);
1181       if (result == NULL)
1182         {
1183           if (error->domain == G_DBUS_ERROR &&
1184               error->code == G_DBUS_ERROR_NAME_HAS_NO_OWNER)
1185             {
1186               g_error_free (error);
1187             }
1188           else
1189             {
1190               g_simple_async_result_take_error (data->simple, error);
1191               g_simple_async_result_complete_in_idle (data->simple);
1192               async_init_data_free (data);
1193               goto out;
1194             }
1195         }
1196       else
1197         {
1198           g_variant_get (result,
1199                          "(s)",
1200                          &data->proxy->priv->name_owner);
1201           g_variant_unref (result);
1202         }
1203     }
1204
1205   if (!(data->proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES))
1206     {
1207       /* load all properties asynchronously */
1208       g_dbus_connection_call (data->proxy->priv->connection,
1209                               data->proxy->priv->name_owner,
1210                               data->proxy->priv->object_path,
1211                               "org.freedesktop.DBus.Properties",
1212                               "GetAll",
1213                               g_variant_new ("(s)", data->proxy->priv->interface_name),
1214                               G_VARIANT_TYPE ("(a{sv})"),
1215                               G_DBUS_CALL_FLAGS_NONE,
1216                               -1,           /* timeout */
1217                               data->cancellable,
1218                               (GAsyncReadyCallback) async_init_get_all_cb,
1219                               data);
1220     }
1221   else
1222     {
1223       g_simple_async_result_complete_in_idle (data->simple);
1224       async_init_data_free (data);
1225     }
1226
1227  out:
1228   ;
1229 }
1230
1231 static void
1232 async_init_call_get_name_owner (AsyncInitData *data)
1233 {
1234   g_dbus_connection_call (data->proxy->priv->connection,
1235                           "org.freedesktop.DBus",  /* name */
1236                           "/org/freedesktop/DBus", /* object path */
1237                           "org.freedesktop.DBus",  /* interface */
1238                           "GetNameOwner",
1239                           g_variant_new ("(s)",
1240                                          data->proxy->priv->name),
1241                           G_VARIANT_TYPE ("(s)"),
1242                           G_DBUS_CALL_FLAGS_NONE,
1243                           -1,           /* timeout */
1244                           data->cancellable,
1245                           (GAsyncReadyCallback) async_init_get_name_owner_cb,
1246                           data);
1247 }
1248
1249 static void
1250 async_init_start_service_by_name_cb (GDBusConnection *connection,
1251                                      GAsyncResult    *res,
1252                                      gpointer         user_data)
1253 {
1254   AsyncInitData *data = user_data;
1255   GError *error;
1256   GVariant *result;
1257
1258   error = NULL;
1259   result = g_dbus_connection_call_finish (connection,
1260                                           res,
1261                                           &error);
1262   if (result == NULL)
1263     {
1264       /* Errors are not unexpected; the bus will reply e.g.
1265        *
1266        *   org.freedesktop.DBus.Error.ServiceUnknown: The name org.gnome.Epiphany2
1267        *   was not provided by any .service files
1268        *
1269        * This doesn't mean that the name doesn't have an owner, just
1270        * that it's not provided by a .service file. So just proceed to
1271        * invoke GetNameOwner() if dealing with that error.
1272        */
1273       if (error->domain == G_DBUS_ERROR &&
1274           error->code == G_DBUS_ERROR_SERVICE_UNKNOWN)
1275         {
1276           g_error_free (error);
1277         }
1278       else
1279         {
1280           g_prefix_error (&error,
1281                           _("Error calling StartServiceByName for %s: "),
1282                           data->proxy->priv->name);
1283           goto failed;
1284         }
1285     }
1286   else
1287     {
1288       guint32 start_service_result;
1289       g_variant_get (result,
1290                      "(u)",
1291                      &start_service_result);
1292       g_variant_unref (result);
1293       if (start_service_result == 1 ||  /* DBUS_START_REPLY_SUCCESS */
1294           start_service_result == 2)    /* DBUS_START_REPLY_ALREADY_RUNNING */
1295         {
1296           /* continue to invoke GetNameOwner() */
1297         }
1298       else
1299         {
1300           error = g_error_new (G_IO_ERROR,
1301                                G_IO_ERROR_FAILED,
1302                                _("Unexpected reply %d from StartServiceByName(\"%s\") method"),
1303                                start_service_result,
1304                                data->proxy->priv->name);
1305           goto failed;
1306         }
1307     }
1308
1309   async_init_call_get_name_owner (data);
1310   return;
1311
1312  failed:
1313   g_warn_if_fail (error != NULL);
1314   g_simple_async_result_take_error (data->simple, error);
1315   g_simple_async_result_complete_in_idle (data->simple);
1316   async_init_data_free (data);
1317 }
1318
1319 static void
1320 async_init_call_start_service_by_name (AsyncInitData *data)
1321 {
1322   g_dbus_connection_call (data->proxy->priv->connection,
1323                           "org.freedesktop.DBus",  /* name */
1324                           "/org/freedesktop/DBus", /* object path */
1325                           "org.freedesktop.DBus",  /* interface */
1326                           "StartServiceByName",
1327                           g_variant_new ("(su)",
1328                                          data->proxy->priv->name,
1329                                          0),
1330                           G_VARIANT_TYPE ("(u)"),
1331                           G_DBUS_CALL_FLAGS_NONE,
1332                           -1,           /* timeout */
1333                           data->cancellable,
1334                           (GAsyncReadyCallback) async_init_start_service_by_name_cb,
1335                           data);
1336 }
1337
1338 static void
1339 async_initable_init_second_async (GAsyncInitable      *initable,
1340                                   gint                 io_priority,
1341                                   GCancellable        *cancellable,
1342                                   GAsyncReadyCallback  callback,
1343                                   gpointer             user_data)
1344 {
1345   GDBusProxy *proxy = G_DBUS_PROXY (initable);
1346   AsyncInitData *data;
1347
1348   data = g_new0 (AsyncInitData, 1);
1349   data->proxy = g_object_ref (proxy);
1350   data->cancellable = cancellable != NULL ? g_object_ref (cancellable) : NULL;
1351   data->simple = g_simple_async_result_new (G_OBJECT (proxy),
1352                                             callback,
1353                                             user_data,
1354                                             NULL);
1355
1356   /* Check name ownership asynchronously - possibly also start the service */
1357   if (proxy->priv->name == NULL)
1358     {
1359       /* Do nothing */
1360       async_init_get_name_owner_cb (proxy->priv->connection, NULL, data);
1361     }
1362   else if (g_dbus_is_unique_name (proxy->priv->name))
1363     {
1364       proxy->priv->name_owner = g_strdup (proxy->priv->name);
1365       async_init_get_name_owner_cb (proxy->priv->connection, NULL, data);
1366     }
1367   else
1368     {
1369       if (proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START)
1370         {
1371           async_init_call_get_name_owner (data);
1372         }
1373       else
1374         {
1375           async_init_call_start_service_by_name (data);
1376         }
1377     }
1378 }
1379
1380 static gboolean
1381 async_initable_init_second_finish (GAsyncInitable  *initable,
1382                                    GAsyncResult    *res,
1383                                    GError         **error)
1384 {
1385   GDBusProxy *proxy = G_DBUS_PROXY (initable);
1386   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
1387   GVariant *result;
1388   gboolean ret;
1389
1390   ret = FALSE;
1391
1392   if (g_simple_async_result_propagate_error (simple, error))
1393     goto out;
1394
1395   result = g_simple_async_result_get_op_res_gpointer (simple);
1396   if (result != NULL)
1397     {
1398       process_get_all_reply (proxy, result);
1399     }
1400
1401   ret = TRUE;
1402
1403  out:
1404   proxy->priv->initialized = TRUE;
1405   return ret;
1406 }
1407
1408 /* ---------------------------------------------------------------------------------------------------- */
1409
1410 static void
1411 async_initable_init_first (GAsyncInitable *initable)
1412 {
1413   GDBusProxy *proxy = G_DBUS_PROXY (initable);
1414
1415   if (!(proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES))
1416     {
1417       /* subscribe to PropertiesChanged() */
1418       proxy->priv->properties_changed_subscriber_id =
1419         g_dbus_connection_signal_subscribe (proxy->priv->connection,
1420                                             proxy->priv->name,
1421                                             "org.freedesktop.DBus.Properties",
1422                                             "PropertiesChanged",
1423                                             proxy->priv->object_path,
1424                                             proxy->priv->interface_name,
1425                                             G_DBUS_SIGNAL_FLAGS_NONE,
1426                                             on_properties_changed,
1427                                             proxy,
1428                                             NULL);
1429     }
1430
1431   if (!(proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS))
1432     {
1433       /* subscribe to all signals for the object */
1434       proxy->priv->signals_subscriber_id =
1435         g_dbus_connection_signal_subscribe (proxy->priv->connection,
1436                                             proxy->priv->name,
1437                                             proxy->priv->interface_name,
1438                                             NULL,                        /* member */
1439                                             proxy->priv->object_path,
1440                                             NULL,                        /* arg0 */
1441                                             G_DBUS_SIGNAL_FLAGS_NONE,
1442                                             on_signal_received,
1443                                             proxy,
1444                                             NULL);
1445     }
1446
1447   if (proxy->priv->name != NULL && !g_dbus_is_unique_name (proxy->priv->name))
1448     {
1449       proxy->priv->name_owner_changed_subscription_id =
1450         g_dbus_connection_signal_subscribe (proxy->priv->connection,
1451                                             "org.freedesktop.DBus",  /* name */
1452                                             "org.freedesktop.DBus",  /* interface */
1453                                             "NameOwnerChanged",      /* signal name */
1454                                             "/org/freedesktop/DBus", /* path */
1455                                             proxy->priv->name,       /* arg0 */
1456                                             G_DBUS_SIGNAL_FLAGS_NONE,
1457                                             on_name_owner_changed,
1458                                             proxy,
1459                                             NULL);
1460     }
1461 }
1462
1463 /* ---------------------------------------------------------------------------------------------------- */
1464
1465 /* initialization is split into two parts - the first is the
1466  * non-blocing part that requires the callers GMainContext - the
1467  * second is a blocking part async part that doesn't require the
1468  * callers GMainContext.. we do this split so the code can be reused
1469  * in the GInitable implementation below.
1470  *
1471  * Note that obtaining a GDBusConnection is not shared between the two
1472  * paths.
1473  */
1474
1475 typedef struct
1476 {
1477   GDBusProxy          *proxy;
1478   gint                 io_priority;
1479   GCancellable        *cancellable;
1480   GAsyncReadyCallback  callback;
1481   gpointer             user_data;
1482 } GetConnectionData;
1483
1484 static void
1485 get_connection_cb (GObject       *source_object,
1486                    GAsyncResult  *res,
1487                    gpointer       user_data)
1488 {
1489   GetConnectionData *data = user_data;
1490   GError *error;
1491
1492   error = NULL;
1493   data->proxy->priv->connection = g_bus_get_finish (res, &error);
1494   if (data->proxy->priv->connection == NULL)
1495     {
1496       GSimpleAsyncResult *simple;
1497       simple = g_simple_async_result_new (G_OBJECT (data->proxy),
1498                                           data->callback,
1499                                           data->user_data,
1500                                           NULL);
1501       g_simple_async_result_take_error (simple, error);
1502       g_simple_async_result_complete_in_idle (simple);
1503       g_object_unref (simple);
1504     }
1505   else
1506     {
1507       async_initable_init_first (G_ASYNC_INITABLE (data->proxy));
1508       async_initable_init_second_async (G_ASYNC_INITABLE (data->proxy),
1509                                         data->io_priority,
1510                                         data->cancellable,
1511                                         data->callback,
1512                                         data->user_data);
1513     }
1514
1515   if (data->cancellable != NULL)
1516     g_object_unref (data->cancellable);
1517   if (data->proxy != NULL)
1518     g_object_unref (data->proxy);
1519   g_free (data);
1520 }
1521
1522 static void
1523 async_initable_init_async (GAsyncInitable      *initable,
1524                            gint                 io_priority,
1525                            GCancellable        *cancellable,
1526                            GAsyncReadyCallback  callback,
1527                            gpointer             user_data)
1528 {
1529   GDBusProxy *proxy = G_DBUS_PROXY (initable);
1530
1531   if (proxy->priv->bus_type != G_BUS_TYPE_NONE)
1532     {
1533       GetConnectionData *data;
1534
1535       g_assert (proxy->priv->connection == NULL);
1536
1537       data = g_new0 (GetConnectionData, 1);
1538       data->proxy = g_object_ref (proxy);
1539       data->io_priority = io_priority;
1540       data->cancellable = cancellable != NULL ? g_object_ref (cancellable) : NULL;
1541       data->callback = callback;
1542       data->user_data = user_data;
1543       g_bus_get (proxy->priv->bus_type,
1544                  cancellable,
1545                  get_connection_cb,
1546                  data);
1547     }
1548   else
1549     {
1550       async_initable_init_first (initable);
1551       async_initable_init_second_async (initable, io_priority, cancellable, callback, user_data);
1552     }
1553 }
1554
1555 static gboolean
1556 async_initable_init_finish (GAsyncInitable  *initable,
1557                             GAsyncResult    *res,
1558                             GError         **error)
1559 {
1560   return async_initable_init_second_finish (initable, res, error);
1561 }
1562
1563 static void
1564 async_initable_iface_init (GAsyncInitableIface *async_initable_iface)
1565 {
1566   async_initable_iface->init_async = async_initable_init_async;
1567   async_initable_iface->init_finish = async_initable_init_finish;
1568 }
1569
1570 /* ---------------------------------------------------------------------------------------------------- */
1571
1572 typedef struct
1573 {
1574   GMainContext *context;
1575   GMainLoop *loop;
1576   GAsyncResult *res;
1577 } InitableAsyncInitableData;
1578
1579 static void
1580 async_initable_init_async_cb (GObject      *source_object,
1581                               GAsyncResult *res,
1582                               gpointer      user_data)
1583 {
1584   InitableAsyncInitableData *data = user_data;
1585   data->res = g_object_ref (res);
1586   g_main_loop_quit (data->loop);
1587 }
1588
1589 /* Simply reuse the GAsyncInitable implementation but run the first
1590  * part (that is non-blocking and requires the callers GMainContext)
1591  * with the callers GMainContext.. and the second with a private
1592  * GMainContext (bug 621310 is slightly related).
1593  *
1594  * Note that obtaining a GDBusConnection is not shared between the two
1595  * paths.
1596  */
1597 static gboolean
1598 initable_init (GInitable     *initable,
1599                GCancellable  *cancellable,
1600                GError       **error)
1601 {
1602   GDBusProxy *proxy = G_DBUS_PROXY (initable);
1603   InitableAsyncInitableData *data;
1604   gboolean ret;
1605
1606   ret = FALSE;
1607
1608   if (proxy->priv->bus_type != G_BUS_TYPE_NONE)
1609     {
1610       g_assert (proxy->priv->connection == NULL);
1611       proxy->priv->connection = g_bus_get_sync (proxy->priv->bus_type,
1612                                                 cancellable,
1613                                                 error);
1614       if (proxy->priv->connection == NULL)
1615         goto out;
1616     }
1617
1618   async_initable_init_first (G_ASYNC_INITABLE (initable));
1619
1620   data = g_new0 (InitableAsyncInitableData, 1);
1621   data->context = g_main_context_new ();
1622   data->loop = g_main_loop_new (data->context, FALSE);
1623
1624   g_main_context_push_thread_default (data->context);
1625
1626   async_initable_init_second_async (G_ASYNC_INITABLE (initable),
1627                                     G_PRIORITY_DEFAULT,
1628                                     cancellable,
1629                                     async_initable_init_async_cb,
1630                                     data);
1631
1632   g_main_loop_run (data->loop);
1633
1634   ret = async_initable_init_second_finish (G_ASYNC_INITABLE (initable),
1635                                            data->res,
1636                                            error);
1637
1638   g_main_context_pop_thread_default (data->context);
1639
1640   g_main_context_unref (data->context);
1641   g_main_loop_unref (data->loop);
1642   g_object_unref (data->res);
1643   g_free (data);
1644
1645  out:
1646
1647   return ret;
1648 }
1649
1650 static void
1651 initable_iface_init (GInitableIface *initable_iface)
1652 {
1653   initable_iface->init = initable_init;
1654 }
1655
1656 /* ---------------------------------------------------------------------------------------------------- */
1657
1658 /**
1659  * g_dbus_proxy_new:
1660  * @connection: A #GDBusConnection.
1661  * @flags: Flags used when constructing the proxy.
1662  * @info: (allow-none): A #GDBusInterfaceInfo specifying the minimal interface that @proxy conforms to or %NULL.
1663  * @name: (allow-none): A bus name (well-known or unique) or %NULL if @connection is not a message bus connection.
1664  * @object_path: An object path.
1665  * @interface_name: A D-Bus interface name.
1666  * @cancellable: A #GCancellable or %NULL.
1667  * @callback: Callback function to invoke when the proxy is ready.
1668  * @user_data: User data to pass to @callback.
1669  *
1670  * Creates a proxy for accessing @interface_name on the remote object
1671  * at @object_path owned by @name at @connection and asynchronously
1672  * loads D-Bus properties unless the
1673  * %G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES flag is used. Connect to
1674  * the #GDBusProxy::g-properties-changed signal to get notified about
1675  * property changes.
1676  *
1677  * If the %G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS flag is not set, also sets up
1678  * match rules for signals. Connect to the #GDBusProxy::g-signal signal
1679  * to handle signals from the remote object.
1680  *
1681  * If @name is a well-known name and the
1682  * %G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START flag isn't set and no name
1683  * owner currently exists, the message bus will be requested to launch
1684  * a name owner for the name.
1685  *
1686  * This is a failable asynchronous constructor - when the proxy is
1687  * ready, @callback will be invoked and you can use
1688  * g_dbus_proxy_new_finish() to get the result.
1689  *
1690  * See g_dbus_proxy_new_sync() and for a synchronous version of this constructor.
1691  *
1692  * See <xref linkend="gdbus-wellknown-proxy"/> for an example of how #GDBusProxy can be used.
1693  *
1694  * Since: 2.26
1695  */
1696 void
1697 g_dbus_proxy_new (GDBusConnection     *connection,
1698                   GDBusProxyFlags      flags,
1699                   GDBusInterfaceInfo  *info,
1700                   const gchar         *name,
1701                   const gchar         *object_path,
1702                   const gchar         *interface_name,
1703                   GCancellable        *cancellable,
1704                   GAsyncReadyCallback  callback,
1705                   gpointer             user_data)
1706 {
1707   g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
1708   g_return_if_fail ((name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) || g_dbus_is_name (name));
1709   g_return_if_fail (g_variant_is_object_path (object_path));
1710   g_return_if_fail (g_dbus_is_interface_name (interface_name));
1711
1712   g_async_initable_new_async (G_TYPE_DBUS_PROXY,
1713                               G_PRIORITY_DEFAULT,
1714                               cancellable,
1715                               callback,
1716                               user_data,
1717                               "g-flags", flags,
1718                               "g-interface-info", info,
1719                               "g-name", name,
1720                               "g-connection", connection,
1721                               "g-object-path", object_path,
1722                               "g-interface-name", interface_name,
1723                               NULL);
1724 }
1725
1726 /**
1727  * g_dbus_proxy_new_finish:
1728  * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to g_dbus_proxy_new().
1729  * @error: Return location for error or %NULL.
1730  *
1731  * Finishes creating a #GDBusProxy.
1732  *
1733  * Returns: A #GDBusProxy or %NULL if @error is set. Free with g_object_unref().
1734  *
1735  * Since: 2.26
1736  */
1737 GDBusProxy *
1738 g_dbus_proxy_new_finish (GAsyncResult  *res,
1739                          GError       **error)
1740 {
1741   GObject *object;
1742   GObject *source_object;
1743
1744   source_object = g_async_result_get_source_object (res);
1745   g_assert (source_object != NULL);
1746
1747   object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
1748                                         res,
1749                                         error);
1750   g_object_unref (source_object);
1751
1752   if (object != NULL)
1753     return G_DBUS_PROXY (object);
1754   else
1755     return NULL;
1756 }
1757
1758 /**
1759  * g_dbus_proxy_new_sync:
1760  * @connection: A #GDBusConnection.
1761  * @flags: Flags used when constructing the proxy.
1762  * @info: (allow-none): A #GDBusInterfaceInfo specifying the minimal interface that @proxy conforms to or %NULL.
1763  * @name: (allow-none): A bus name (well-known or unique) or %NULL if @connection is not a message bus connection.
1764  * @object_path: An object path.
1765  * @interface_name: A D-Bus interface name.
1766  * @cancellable: (allow-none): A #GCancellable or %NULL.
1767  * @error: (allow-none): Return location for error or %NULL.
1768  *
1769  * Creates a proxy for accessing @interface_name on the remote object
1770  * at @object_path owned by @name at @connection and synchronously
1771  * loads D-Bus properties unless the
1772  * %G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES flag is used.
1773  *
1774  * If the %G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS flag is not set, also sets up
1775  * match rules for signals. Connect to the #GDBusProxy::g-signal signal
1776  * to handle signals from the remote object.
1777  *
1778  * If @name is a well-known name and the
1779  * %G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START flag isn't set and no name
1780  * owner currently exists, the message bus will be requested to launch
1781  * a name owner for the name.
1782  *
1783  * This is a synchronous failable constructor. See g_dbus_proxy_new()
1784  * and g_dbus_proxy_new_finish() for the asynchronous version.
1785  *
1786  * See <xref linkend="gdbus-wellknown-proxy"/> for an example of how #GDBusProxy can be used.
1787  *
1788  * Returns: A #GDBusProxy or %NULL if error is set. Free with g_object_unref().
1789  *
1790  * Since: 2.26
1791  */
1792 GDBusProxy *
1793 g_dbus_proxy_new_sync (GDBusConnection     *connection,
1794                        GDBusProxyFlags      flags,
1795                        GDBusInterfaceInfo  *info,
1796                        const gchar         *name,
1797                        const gchar         *object_path,
1798                        const gchar         *interface_name,
1799                        GCancellable        *cancellable,
1800                        GError             **error)
1801 {
1802   GInitable *initable;
1803
1804   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
1805   g_return_val_if_fail ((name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) ||
1806                         g_dbus_is_name (name), NULL);
1807   g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
1808   g_return_val_if_fail (g_dbus_is_interface_name (interface_name), NULL);
1809
1810   initable = g_initable_new (G_TYPE_DBUS_PROXY,
1811                              cancellable,
1812                              error,
1813                              "g-flags", flags,
1814                              "g-interface-info", info,
1815                              "g-name", name,
1816                              "g-connection", connection,
1817                              "g-object-path", object_path,
1818                              "g-interface-name", interface_name,
1819                              NULL);
1820   if (initable != NULL)
1821     return G_DBUS_PROXY (initable);
1822   else
1823     return NULL;
1824 }
1825
1826 /* ---------------------------------------------------------------------------------------------------- */
1827
1828 /**
1829  * g_dbus_proxy_new_for_bus:
1830  * @bus_type: A #GBusType.
1831  * @flags: Flags used when constructing the proxy.
1832  * @info: (allow-none): A #GDBusInterfaceInfo specifying the minimal interface that @proxy conforms to or %NULL.
1833  * @name: A bus name (well-known or unique).
1834  * @object_path: An object path.
1835  * @interface_name: A D-Bus interface name.
1836  * @cancellable: A #GCancellable or %NULL.
1837  * @callback: Callback function to invoke when the proxy is ready.
1838  * @user_data: User data to pass to @callback.
1839  *
1840  * Like g_dbus_proxy_new() but takes a #GBusType instead of a #GDBusConnection.
1841  *
1842  * See <xref linkend="gdbus-wellknown-proxy"/> for an example of how #GDBusProxy can be used.
1843  *
1844  * Since: 2.26
1845  */
1846 void
1847 g_dbus_proxy_new_for_bus (GBusType             bus_type,
1848                           GDBusProxyFlags      flags,
1849                           GDBusInterfaceInfo  *info,
1850                           const gchar         *name,
1851                           const gchar         *object_path,
1852                           const gchar         *interface_name,
1853                           GCancellable        *cancellable,
1854                           GAsyncReadyCallback  callback,
1855                           gpointer             user_data)
1856 {
1857   g_return_if_fail (g_dbus_is_name (name));
1858   g_return_if_fail (g_variant_is_object_path (object_path));
1859   g_return_if_fail (g_dbus_is_interface_name (interface_name));
1860
1861   g_async_initable_new_async (G_TYPE_DBUS_PROXY,
1862                               G_PRIORITY_DEFAULT,
1863                               cancellable,
1864                               callback,
1865                               user_data,
1866                               "g-flags", flags,
1867                               "g-interface-info", info,
1868                               "g-name", name,
1869                               "g-bus-type", bus_type,
1870                               "g-object-path", object_path,
1871                               "g-interface-name", interface_name,
1872                               NULL);
1873 }
1874
1875 /**
1876  * g_dbus_proxy_new_for_bus_finish:
1877  * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to g_dbus_proxy_new_for_bus().
1878  * @error: Return location for error or %NULL.
1879  *
1880  * Finishes creating a #GDBusProxy.
1881  *
1882  * Returns: A #GDBusProxy or %NULL if @error is set. Free with g_object_unref().
1883  *
1884  * Since: 2.26
1885  */
1886 GDBusProxy *
1887 g_dbus_proxy_new_for_bus_finish (GAsyncResult  *res,
1888                                  GError       **error)
1889 {
1890   return g_dbus_proxy_new_finish (res, error);
1891 }
1892
1893 /**
1894  * g_dbus_proxy_new_for_bus_sync:
1895  * @bus_type: A #GBusType.
1896  * @flags: Flags used when constructing the proxy.
1897  * @info: (allow-none): A #GDBusInterfaceInfo specifying the minimal interface
1898  *        that @proxy conforms to or %NULL.
1899  * @name: A bus name (well-known or unique).
1900  * @object_path: An object path.
1901  * @interface_name: A D-Bus interface name.
1902  * @cancellable: A #GCancellable or %NULL.
1903  * @error: Return location for error or %NULL.
1904  *
1905  * Like g_dbus_proxy_new_sync() but takes a #GBusType instead of a #GDBusConnection.
1906  *
1907  * See <xref linkend="gdbus-wellknown-proxy"/> for an example of how #GDBusProxy can be used.
1908  *
1909  * Returns: A #GDBusProxy or %NULL if error is set. Free with g_object_unref().
1910  *
1911  * Since: 2.26
1912  */
1913 GDBusProxy *
1914 g_dbus_proxy_new_for_bus_sync (GBusType             bus_type,
1915                                GDBusProxyFlags      flags,
1916                                GDBusInterfaceInfo  *info,
1917                                const gchar         *name,
1918                                const gchar         *object_path,
1919                                const gchar         *interface_name,
1920                                GCancellable        *cancellable,
1921                                GError             **error)
1922 {
1923   GInitable *initable;
1924
1925   g_return_val_if_fail (g_dbus_is_name (name), NULL);
1926   g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
1927   g_return_val_if_fail (g_dbus_is_interface_name (interface_name), NULL);
1928
1929   initable = g_initable_new (G_TYPE_DBUS_PROXY,
1930                              cancellable,
1931                              error,
1932                              "g-flags", flags,
1933                              "g-interface-info", info,
1934                              "g-name", name,
1935                              "g-bus-type", bus_type,
1936                              "g-object-path", object_path,
1937                              "g-interface-name", interface_name,
1938                              NULL);
1939   if (initable != NULL)
1940     return G_DBUS_PROXY (initable);
1941   else
1942     return NULL;
1943 }
1944
1945 /* ---------------------------------------------------------------------------------------------------- */
1946
1947 /**
1948  * g_dbus_proxy_get_connection:
1949  * @proxy: A #GDBusProxy.
1950  *
1951  * Gets the connection @proxy is for.
1952  *
1953  * Returns: (transfer none): A #GDBusConnection owned by @proxy. Do not free.
1954  *
1955  * Since: 2.26
1956  */
1957 GDBusConnection *
1958 g_dbus_proxy_get_connection (GDBusProxy *proxy)
1959 {
1960   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
1961   return proxy->priv->connection;
1962 }
1963
1964 /**
1965  * g_dbus_proxy_get_flags:
1966  * @proxy: A #GDBusProxy.
1967  *
1968  * Gets the flags that @proxy was constructed with.
1969  *
1970  * Returns: Flags from the #GDBusProxyFlags enumeration.
1971  *
1972  * Since: 2.26
1973  */
1974 GDBusProxyFlags
1975 g_dbus_proxy_get_flags (GDBusProxy *proxy)
1976 {
1977   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), 0);
1978   return proxy->priv->flags;
1979 }
1980
1981 /**
1982  * g_dbus_proxy_get_name:
1983  * @proxy: A #GDBusProxy.
1984  *
1985  * Gets the name that @proxy was constructed for.
1986  *
1987  * Returns: A string owned by @proxy. Do not free.
1988  *
1989  * Since: 2.26
1990  */
1991 const gchar *
1992 g_dbus_proxy_get_name (GDBusProxy *proxy)
1993 {
1994   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
1995   return proxy->priv->name;
1996 }
1997
1998 /**
1999  * g_dbus_proxy_get_name_owner:
2000  * @proxy: A #GDBusProxy.
2001  *
2002  * The unique name that owns the name that @proxy is for or %NULL if
2003  * no-one currently owns that name. You may connect to the
2004  * #GObject::notify signal to track changes to the
2005  * #GDBusProxy:g-name-owner property.
2006  *
2007  * Returns: The name owner or %NULL if no name owner exists. Free with g_free().
2008  *
2009  * Since: 2.26
2010  */
2011 gchar *
2012 g_dbus_proxy_get_name_owner (GDBusProxy *proxy)
2013 {
2014   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
2015   return g_strdup (proxy->priv->name_owner);
2016 }
2017
2018 /**
2019  * g_dbus_proxy_get_object_path:
2020  * @proxy: A #GDBusProxy.
2021  *
2022  * Gets the object path @proxy is for.
2023  *
2024  * Returns: A string owned by @proxy. Do not free.
2025  *
2026  * Since: 2.26
2027  */
2028 const gchar *
2029 g_dbus_proxy_get_object_path (GDBusProxy *proxy)
2030 {
2031   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
2032   return proxy->priv->object_path;
2033 }
2034
2035 /**
2036  * g_dbus_proxy_get_interface_name:
2037  * @proxy: A #GDBusProxy.
2038  *
2039  * Gets the D-Bus interface name @proxy is for.
2040  *
2041  * Returns: A string owned by @proxy. Do not free.
2042  *
2043  * Since: 2.26
2044  */
2045 const gchar *
2046 g_dbus_proxy_get_interface_name (GDBusProxy *proxy)
2047 {
2048   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
2049   return proxy->priv->interface_name;
2050 }
2051
2052 /**
2053  * g_dbus_proxy_get_default_timeout:
2054  * @proxy: A #GDBusProxy.
2055  *
2056  * Gets the timeout to use if -1 (specifying default timeout) is
2057  * passed as @timeout_msec in the g_dbus_proxy_call() and
2058  * g_dbus_proxy_call_sync() functions.
2059  *
2060  * See the #GDBusProxy:g-default-timeout property for more details.
2061  *
2062  * Returns: Timeout to use for @proxy.
2063  *
2064  * Since: 2.26
2065  */
2066 gint
2067 g_dbus_proxy_get_default_timeout (GDBusProxy *proxy)
2068 {
2069   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), -1);
2070   return proxy->priv->timeout_msec;
2071 }
2072
2073 /**
2074  * g_dbus_proxy_set_default_timeout:
2075  * @proxy: A #GDBusProxy.
2076  * @timeout_msec: Timeout in milliseconds.
2077  *
2078  * Sets the timeout to use if -1 (specifying default timeout) is
2079  * passed as @timeout_msec in the g_dbus_proxy_call() and
2080  * g_dbus_proxy_call_sync() functions.
2081  *
2082  * See the #GDBusProxy:g-default-timeout property for more details.
2083  *
2084  * Since: 2.26
2085  */
2086 void
2087 g_dbus_proxy_set_default_timeout (GDBusProxy *proxy,
2088                                   gint        timeout_msec)
2089 {
2090   g_return_if_fail (G_IS_DBUS_PROXY (proxy));
2091   g_return_if_fail (timeout_msec == -1 || timeout_msec >= 0);
2092
2093   /* TODO: locking? */
2094   if (proxy->priv->timeout_msec != timeout_msec)
2095     {
2096       proxy->priv->timeout_msec = timeout_msec;
2097       g_object_notify (G_OBJECT (proxy), "g-default-timeout");
2098     }
2099 }
2100
2101 /**
2102  * g_dbus_proxy_get_interface_info:
2103  * @proxy: A #GDBusProxy
2104  *
2105  * Returns the #GDBusInterfaceInfo, if any, specifying the minimal
2106  * interface that @proxy conforms to.
2107  *
2108  * See the #GDBusProxy:g-interface-info property for more details.
2109  *
2110  * Returns: A #GDBusInterfaceInfo or %NULL. Do not unref the returned
2111  * object, it is owned by @proxy.
2112  *
2113  * Since: 2.26
2114  */
2115 GDBusInterfaceInfo *
2116 g_dbus_proxy_get_interface_info (GDBusProxy *proxy)
2117 {
2118   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
2119   return proxy->priv->expected_interface;
2120 }
2121
2122 /**
2123  * g_dbus_proxy_set_interface_info:
2124  * @proxy: A #GDBusProxy
2125  * @info: (allow-none): Minimum interface this proxy conforms to or %NULL to unset.
2126  *
2127  * Ensure that interactions with @proxy conform to the given
2128  * interface.  For example, when completing a method call, if the type
2129  * signature of the message isn't what's expected, the given #GError
2130  * is set.  Signals that have a type signature mismatch are simply
2131  * dropped.
2132  *
2133  * See the #GDBusProxy:g-interface-info property for more details.
2134  *
2135  * Since: 2.26
2136  */
2137 void
2138 g_dbus_proxy_set_interface_info (GDBusProxy         *proxy,
2139                                  GDBusInterfaceInfo *info)
2140 {
2141   g_return_if_fail (G_IS_DBUS_PROXY (proxy));
2142   if (proxy->priv->expected_interface != NULL)
2143     {
2144       g_dbus_interface_info_cache_release (proxy->priv->expected_interface);
2145       g_dbus_interface_info_unref (proxy->priv->expected_interface);
2146     }
2147   proxy->priv->expected_interface = info != NULL ? g_dbus_interface_info_ref (info) : NULL;
2148   if (proxy->priv->expected_interface != NULL)
2149     g_dbus_interface_info_cache_build (proxy->priv->expected_interface);
2150 }
2151
2152 /* ---------------------------------------------------------------------------------------------------- */
2153
2154 static gboolean
2155 maybe_split_method_name (const gchar  *method_name,
2156                          gchar       **out_interface_name,
2157                          const gchar **out_method_name)
2158 {
2159   gboolean was_split;
2160
2161   was_split = FALSE;
2162   g_assert (out_interface_name != NULL);
2163   g_assert (out_method_name != NULL);
2164   *out_interface_name = NULL;
2165   *out_method_name = NULL;
2166
2167   if (strchr (method_name, '.') != NULL)
2168     {
2169       gchar *p;
2170       gchar *last_dot;
2171
2172       p = g_strdup (method_name);
2173       last_dot = strrchr (p, '.');
2174       *last_dot = '\0';
2175
2176       *out_interface_name = p;
2177       *out_method_name = last_dot + 1;
2178
2179       was_split = TRUE;
2180     }
2181
2182   return was_split;
2183 }
2184
2185
2186 static void
2187 reply_cb (GDBusConnection *connection,
2188           GAsyncResult    *res,
2189           gpointer         user_data)
2190 {
2191   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
2192   GVariant *value;
2193   GError *error;
2194
2195   error = NULL;
2196   value = g_dbus_connection_call_finish (connection,
2197                                          res,
2198                                          &error);
2199   if (error != NULL)
2200     {
2201       g_simple_async_result_take_error (simple, error);
2202     }
2203   else
2204     {
2205       g_simple_async_result_set_op_res_gpointer (simple,
2206                                                  value,
2207                                                  (GDestroyNotify) g_variant_unref);
2208     }
2209
2210   /* no need to complete in idle since the method GDBusConnection already does */
2211   g_simple_async_result_complete (simple);
2212   g_object_unref (simple);
2213 }
2214
2215 static const GDBusMethodInfo *
2216 lookup_method_info_or_warn (GDBusProxy  *proxy,
2217                             const gchar *method_name)
2218 {
2219   const GDBusMethodInfo *info;
2220
2221   if (proxy->priv->expected_interface == NULL)
2222     return NULL;
2223
2224   info = g_dbus_interface_info_lookup_method (proxy->priv->expected_interface, method_name);
2225   if (info == NULL)
2226     {
2227       g_warning ("Trying to invoke method %s which isn't in expected interface %s",
2228                  method_name, proxy->priv->expected_interface->name);
2229     }
2230
2231   return info;
2232 }
2233
2234 static const gchar *
2235 get_destination_for_call (GDBusProxy *proxy)
2236 {
2237   const gchar *ret;
2238
2239   ret = NULL;
2240
2241   /* If proxy->priv->name is a unique name, then proxy->priv->name_owner
2242    * is never NULL and always the same as proxy->priv->name. We use this
2243    * knowledge to avoid checking if proxy->priv->name is a unique or
2244    * well-known name.
2245    */
2246   ret = proxy->priv->name_owner;
2247   if (ret != NULL)
2248     goto out;
2249
2250   if (proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START)
2251     goto out;
2252
2253   ret = proxy->priv->name;
2254
2255  out:
2256   return ret;
2257 }
2258
2259 /**
2260  * g_dbus_proxy_call:
2261  * @proxy: A #GDBusProxy.
2262  * @method_name: Name of method to invoke.
2263  * @parameters: (allow-none): A #GVariant tuple with parameters for the signal or %NULL if not passing parameters.
2264  * @flags: Flags from the #GDBusCallFlags enumeration.
2265  * @timeout_msec: The timeout in milliseconds (with %G_MAXINT meaning
2266  *                "infinite") or -1 to use the proxy default timeout.
2267  * @cancellable: A #GCancellable or %NULL.
2268  * @callback: A #GAsyncReadyCallback to call when the request is satisfied or %NULL if you don't
2269  * care about the result of the method invocation.
2270  * @user_data: The data to pass to @callback.
2271  *
2272  * Asynchronously invokes the @method_name method on @proxy.
2273  *
2274  * If @method_name contains any dots, then @name is split into interface and
2275  * method name parts. This allows using @proxy for invoking methods on
2276  * other interfaces.
2277  *
2278  * If the #GDBusConnection associated with @proxy is closed then
2279  * the operation will fail with %G_IO_ERROR_CLOSED. If
2280  * @cancellable is canceled, the operation will fail with
2281  * %G_IO_ERROR_CANCELLED. If @parameters contains a value not
2282  * compatible with the D-Bus protocol, the operation fails with
2283  * %G_IO_ERROR_INVALID_ARGUMENT.
2284  *
2285  * If the @parameters #GVariant is floating, it is consumed. This allows
2286  * convenient 'inline' use of g_variant_new(), e.g.:
2287  * |[
2288  *  g_dbus_proxy_call (proxy,
2289  *                     "TwoStrings",
2290  *                     g_variant_new ("(ss)",
2291  *                                    "Thing One",
2292  *                                    "Thing Two"),
2293  *                     G_DBUS_CALL_FLAGS_NONE,
2294  *                     -1,
2295  *                     NULL,
2296  *                     (GAsyncReadyCallback) two_strings_done,
2297  *                     &amp;data);
2298  * ]|
2299  *
2300  * This is an asynchronous method. When the operation is finished,
2301  * @callback will be invoked in the
2302  * <link linkend="g-main-context-push-thread-default">thread-default
2303  * main loop</link> of the thread you are calling this method from.
2304  * You can then call g_dbus_proxy_call_finish() to get the result of
2305  * the operation. See g_dbus_proxy_call_sync() for the synchronous
2306  * version of this method.
2307  *
2308  * Since: 2.26
2309  */
2310 void
2311 g_dbus_proxy_call (GDBusProxy          *proxy,
2312                    const gchar         *method_name,
2313                    GVariant            *parameters,
2314                    GDBusCallFlags       flags,
2315                    gint                 timeout_msec,
2316                    GCancellable        *cancellable,
2317                    GAsyncReadyCallback  callback,
2318                    gpointer             user_data)
2319 {
2320   GSimpleAsyncResult *simple;
2321   gboolean was_split;
2322   gchar *split_interface_name;
2323   const gchar *split_method_name;
2324   const gchar *target_method_name;
2325   const gchar *target_interface_name;
2326   const gchar *destination;
2327   GVariantType *reply_type;
2328
2329   g_return_if_fail (G_IS_DBUS_PROXY (proxy));
2330   g_return_if_fail (g_dbus_is_member_name (method_name) || g_dbus_is_interface_name (method_name));
2331   g_return_if_fail (parameters == NULL || g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE));
2332   g_return_if_fail (timeout_msec == -1 || timeout_msec >= 0);
2333
2334   reply_type = NULL;
2335   split_interface_name = NULL;
2336
2337   simple = g_simple_async_result_new (G_OBJECT (proxy),
2338                                       callback,
2339                                       user_data,
2340                                       g_dbus_proxy_call);
2341
2342   was_split = maybe_split_method_name (method_name, &split_interface_name, &split_method_name);
2343   target_method_name = was_split ? split_method_name : method_name;
2344   target_interface_name = was_split ? split_interface_name : proxy->priv->interface_name;
2345
2346   /* Warn if method is unexpected (cf. :g-interface-info) */
2347   if (!was_split)
2348     {
2349       const GDBusMethodInfo *expected_method_info;
2350       expected_method_info = lookup_method_info_or_warn (proxy, target_method_name);
2351       if (expected_method_info != NULL)
2352         reply_type = _g_dbus_compute_complete_signature (expected_method_info->out_args);
2353     }
2354
2355   destination = NULL;
2356   if (proxy->priv->name != NULL)
2357     {
2358       destination = get_destination_for_call (proxy);
2359       if (destination == NULL)
2360         {
2361           g_simple_async_result_set_error (simple,
2362                                            G_IO_ERROR,
2363                                            G_IO_ERROR_FAILED,
2364                                            _("Cannot invoke method; proxy is for a well-known name without an owner and proxy was constructed with the G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START flag"));
2365           goto out;
2366         }
2367     }
2368
2369   g_dbus_connection_call (proxy->priv->connection,
2370                           destination,
2371                           proxy->priv->object_path,
2372                           target_interface_name,
2373                           target_method_name,
2374                           parameters,
2375                           reply_type,
2376                           flags,
2377                           timeout_msec == -1 ? proxy->priv->timeout_msec : timeout_msec,
2378                           cancellable,
2379                           (GAsyncReadyCallback) reply_cb,
2380                           simple);
2381
2382  out:
2383   if (reply_type != NULL)
2384     g_variant_type_free (reply_type);
2385
2386   g_free (split_interface_name);
2387 }
2388
2389 /**
2390  * g_dbus_proxy_call_finish:
2391  * @proxy: A #GDBusProxy.
2392  * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_proxy_call().
2393  * @error: Return location for error or %NULL.
2394  *
2395  * Finishes an operation started with g_dbus_proxy_call().
2396  *
2397  * Returns: %NULL if @error is set. Otherwise a #GVariant tuple with
2398  * return values. Free with g_variant_unref().
2399  *
2400  * Since: 2.26
2401  */
2402 GVariant *
2403 g_dbus_proxy_call_finish (GDBusProxy    *proxy,
2404                           GAsyncResult  *res,
2405                           GError       **error)
2406 {
2407   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
2408   GVariant *value;
2409
2410   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
2411   g_return_val_if_fail (G_IS_ASYNC_RESULT (res), NULL);
2412   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2413
2414   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_dbus_proxy_call);
2415
2416   value = NULL;
2417
2418   if (g_simple_async_result_propagate_error (simple, error))
2419     goto out;
2420
2421   value = g_variant_ref (g_simple_async_result_get_op_res_gpointer (simple));
2422
2423  out:
2424   return value;
2425 }
2426
2427 /**
2428  * g_dbus_proxy_call_sync:
2429  * @proxy: A #GDBusProxy.
2430  * @method_name: Name of method to invoke.
2431  * @parameters: (allow-none): A #GVariant tuple with parameters for the signal
2432  *              or %NULL if not passing parameters.
2433  * @flags: Flags from the #GDBusCallFlags enumeration.
2434  * @timeout_msec: The timeout in milliseconds (with %G_MAXINT meaning
2435  *                "infinite") or -1 to use the proxy default timeout.
2436  * @cancellable: A #GCancellable or %NULL.
2437  * @error: Return location for error or %NULL.
2438  *
2439  * Synchronously invokes the @method_name method on @proxy.
2440  *
2441  * If @method_name contains any dots, then @name is split into interface and
2442  * method name parts. This allows using @proxy for invoking methods on
2443  * other interfaces.
2444  *
2445  * If the #GDBusConnection associated with @proxy is disconnected then
2446  * the operation will fail with %G_IO_ERROR_CLOSED. If
2447  * @cancellable is canceled, the operation will fail with
2448  * %G_IO_ERROR_CANCELLED. If @parameters contains a value not
2449  * compatible with the D-Bus protocol, the operation fails with
2450  * %G_IO_ERROR_INVALID_ARGUMENT.
2451  *
2452  * If the @parameters #GVariant is floating, it is consumed. This allows
2453  * convenient 'inline' use of g_variant_new(), e.g.:
2454  * |[
2455  *  g_dbus_proxy_call_sync (proxy,
2456  *                          "TwoStrings",
2457  *                          g_variant_new ("(ss)",
2458  *                                         "Thing One",
2459  *                                         "Thing Two"),
2460  *                          G_DBUS_CALL_FLAGS_NONE,
2461  *                          -1,
2462  *                          NULL,
2463  *                          &amp;error);
2464  * ]|
2465  *
2466  * The calling thread is blocked until a reply is received. See
2467  * g_dbus_proxy_call() for the asynchronous version of this
2468  * method.
2469  *
2470  * Returns: %NULL if @error is set. Otherwise a #GVariant tuple with
2471  * return values. Free with g_variant_unref().
2472  *
2473  * Since: 2.26
2474  */
2475 GVariant *
2476 g_dbus_proxy_call_sync (GDBusProxy      *proxy,
2477                         const gchar     *method_name,
2478                         GVariant        *parameters,
2479                         GDBusCallFlags   flags,
2480                         gint             timeout_msec,
2481                         GCancellable    *cancellable,
2482                         GError         **error)
2483 {
2484   GVariant *ret;
2485   gboolean was_split;
2486   gchar *split_interface_name;
2487   const gchar *split_method_name;
2488   const gchar *target_method_name;
2489   const gchar *target_interface_name;
2490   const gchar *destination;
2491   GVariantType *reply_type;
2492
2493   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
2494   g_return_val_if_fail (g_dbus_is_member_name (method_name) || g_dbus_is_interface_name (method_name), NULL);
2495   g_return_val_if_fail (parameters == NULL || g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE), NULL);
2496   g_return_val_if_fail (timeout_msec == -1 || timeout_msec >= 0, NULL);
2497   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2498
2499   reply_type = NULL;
2500
2501   was_split = maybe_split_method_name (method_name, &split_interface_name, &split_method_name);
2502   target_method_name = was_split ? split_method_name : method_name;
2503   target_interface_name = was_split ? split_interface_name : proxy->priv->interface_name;
2504
2505   /* Warn if method is unexpected (cf. :g-interface-info) */
2506   if (!was_split)
2507     {
2508       const GDBusMethodInfo *expected_method_info;
2509       expected_method_info = lookup_method_info_or_warn (proxy, target_method_name);
2510       if (expected_method_info != NULL)
2511         reply_type = _g_dbus_compute_complete_signature (expected_method_info->out_args);
2512     }
2513
2514   destination = NULL;
2515   if (proxy->priv->name != NULL)
2516     {
2517       destination = get_destination_for_call (proxy);
2518       if (destination == NULL)
2519         {
2520           g_set_error_literal (error,
2521                                G_IO_ERROR,
2522                                G_IO_ERROR_FAILED,
2523                                _("Cannot invoke method; proxy is for a well-known name without an owner and proxy was constructed with the G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START flag"));
2524           ret = NULL;
2525           goto out;
2526         }
2527     }
2528
2529   ret = g_dbus_connection_call_sync (proxy->priv->connection,
2530                                      destination,
2531                                      proxy->priv->object_path,
2532                                      target_interface_name,
2533                                      target_method_name,
2534                                      parameters,
2535                                      reply_type,
2536                                      flags,
2537                                      timeout_msec == -1 ? proxy->priv->timeout_msec : timeout_msec,
2538                                      cancellable,
2539                                      error);
2540
2541  out:
2542   if (reply_type != NULL)
2543     g_variant_type_free (reply_type);
2544
2545   g_free (split_interface_name);
2546
2547   return ret;
2548 }
2549
2550 /* ---------------------------------------------------------------------------------------------------- */