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