Change LGPL-2.1+ to LGPL-2.1-or-later
[platform/upstream/glib.git] / gio / gdbusproxy.c
1 /* GDBus - GLib D-Bus Library
2  *
3  * Copyright (C) 2008-2010 Red Hat, Inc.
4  *
5  * SPDX-License-Identifier: LGPL-2.1-or-later
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General
18  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
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 "ginitable.h"
35 #include "gasyncinitable.h"
36 #include "gioerror.h"
37 #include "gtask.h"
38 #include "gcancellable.h"
39 #include "gdbusinterface.h"
40 #include "gasyncresult.h"
41
42 #ifdef G_OS_UNIX
43 #include "gunixfdlist.h"
44 #endif
45
46 #include "glibintl.h"
47 #include "gmarshal-internal.h"
48
49 /**
50  * SECTION:gdbusproxy
51  * @short_description: Client-side D-Bus interface proxy
52  * @include: gio/gio.h
53  *
54  * #GDBusProxy is a base class used for proxies to access a D-Bus
55  * interface on a remote object. A #GDBusProxy can be constructed for
56  * both well-known and unique names.
57  *
58  * By default, #GDBusProxy will cache all properties (and listen to
59  * changes) of the remote object, and proxy all signals that get
60  * emitted. This behaviour can be changed by passing suitable
61  * #GDBusProxyFlags when the proxy is created. If the proxy is for a
62  * well-known name, the property cache is flushed when the name owner
63  * vanishes and reloaded when a name owner appears.
64  *
65  * The unique name owner of the proxy's name is tracked and can be read from
66  * #GDBusProxy:g-name-owner. Connect to the #GObject::notify signal to
67  * get notified of changes. Additionally, only signals and property
68  * changes emitted from the current name owner are considered and
69  * calls are always sent to the current name owner. This avoids a
70  * number of race conditions when the name is lost by one owner and
71  * claimed by another. However, if no name owner currently exists,
72  * then calls will be sent to the well-known name which may result in
73  * the message bus launching an owner (unless
74  * %G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START is set).
75  *
76  * If the proxy is for a stateless D-Bus service, where the name owner may
77  * be started and stopped between calls, the #GDBusProxy:g-name-owner tracking
78  * of #GDBusProxy will cause the proxy to drop signal and property changes from
79  * the service after it has restarted for the first time. When interacting
80  * with a stateless D-Bus service, do not use #GDBusProxy — use direct D-Bus
81  * method calls and signal connections.
82  *
83  * The generic #GDBusProxy::g-properties-changed and
84  * #GDBusProxy::g-signal signals are not very convenient to work with.
85  * Therefore, the recommended way of working with proxies is to subclass
86  * #GDBusProxy, and have more natural properties and signals in your derived
87  * class. This [example][gdbus-example-gdbus-codegen] shows how this can
88  * easily be done using the [gdbus-codegen][gdbus-codegen] tool.
89  *
90  * A #GDBusProxy instance can be used from multiple threads but note
91  * that all signals (e.g. #GDBusProxy::g-signal, #GDBusProxy::g-properties-changed
92  * and #GObject::notify) are emitted in the
93  * [thread-default main context][g-main-context-push-thread-default]
94  * of the thread where the instance was constructed.
95  *
96  * An example using a proxy for a well-known name can be found in
97  * [gdbus-example-watch-proxy.c](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/gio/tests/gdbus-example-watch-proxy.c)
98  */
99
100 /* lock protecting the mutable properties: name_owner, timeout_msec,
101  * expected_interface, and the properties hash table
102  */
103 G_LOCK_DEFINE_STATIC (properties_lock);
104
105 /* ---------------------------------------------------------------------------------------------------- */
106
107 static GWeakRef *
108 weak_ref_new (GObject *object)
109 {
110   GWeakRef *weak_ref = g_new0 (GWeakRef, 1);
111   g_weak_ref_init (weak_ref, object);
112   return g_steal_pointer (&weak_ref);
113 }
114
115 static void
116 weak_ref_free (GWeakRef *weak_ref)
117 {
118   g_weak_ref_clear (weak_ref);
119   g_free (weak_ref);
120 }
121
122 /* ---------------------------------------------------------------------------------------------------- */
123
124 struct _GDBusProxyPrivate
125 {
126   GBusType bus_type;
127   GDBusProxyFlags flags;
128   GDBusConnection *connection;
129
130   gchar *name;
131   /* mutable, protected by properties_lock */
132   gchar *name_owner;
133   gchar *object_path;
134   gchar *interface_name;
135   /* mutable, protected by properties_lock */
136   gint timeout_msec;
137
138   guint name_owner_changed_subscription_id;
139
140   GCancellable *get_all_cancellable;
141
142   /* gchar* -> GVariant*, protected by properties_lock */
143   GHashTable *properties;
144
145   /* mutable, protected by properties_lock */
146   GDBusInterfaceInfo *expected_interface;
147
148   guint properties_changed_subscription_id;
149   guint signals_subscription_id;
150
151   gboolean initialized;
152
153   /* mutable, protected by properties_lock */
154   GDBusObject *object;
155 };
156
157 enum
158 {
159   PROP_0,
160   PROP_G_CONNECTION,
161   PROP_G_BUS_TYPE,
162   PROP_G_NAME,
163   PROP_G_NAME_OWNER,
164   PROP_G_FLAGS,
165   PROP_G_OBJECT_PATH,
166   PROP_G_INTERFACE_NAME,
167   PROP_G_DEFAULT_TIMEOUT,
168   PROP_G_INTERFACE_INFO
169 };
170
171 enum
172 {
173   PROPERTIES_CHANGED_SIGNAL,
174   SIGNAL_SIGNAL,
175   LAST_SIGNAL,
176 };
177
178 static guint signals[LAST_SIGNAL] = {0};
179
180 static void dbus_interface_iface_init (GDBusInterfaceIface *dbus_interface_iface);
181 static void initable_iface_init       (GInitableIface *initable_iface);
182 static void async_initable_iface_init (GAsyncInitableIface *async_initable_iface);
183
184 G_DEFINE_TYPE_WITH_CODE (GDBusProxy, g_dbus_proxy, G_TYPE_OBJECT,
185                          G_ADD_PRIVATE (GDBusProxy)
186                          G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_INTERFACE, dbus_interface_iface_init)
187                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)
188                          G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init))
189
190 static void
191 g_dbus_proxy_finalize (GObject *object)
192 {
193   GDBusProxy *proxy = G_DBUS_PROXY (object);
194
195   g_warn_if_fail (proxy->priv->get_all_cancellable == NULL);
196
197   if (proxy->priv->name_owner_changed_subscription_id > 0)
198     g_dbus_connection_signal_unsubscribe (proxy->priv->connection,
199                                           proxy->priv->name_owner_changed_subscription_id);
200
201   if (proxy->priv->properties_changed_subscription_id > 0)
202     g_dbus_connection_signal_unsubscribe (proxy->priv->connection,
203                                           proxy->priv->properties_changed_subscription_id);
204
205   if (proxy->priv->signals_subscription_id > 0)
206     g_dbus_connection_signal_unsubscribe (proxy->priv->connection,
207                                           proxy->priv->signals_subscription_id);
208
209   if (proxy->priv->connection != NULL)
210     g_object_unref (proxy->priv->connection);
211   g_free (proxy->priv->name);
212   g_free (proxy->priv->name_owner);
213   g_free (proxy->priv->object_path);
214   g_free (proxy->priv->interface_name);
215   if (proxy->priv->properties != NULL)
216     g_hash_table_unref (proxy->priv->properties);
217
218   if (proxy->priv->expected_interface != NULL)
219     {
220       g_dbus_interface_info_cache_release (proxy->priv->expected_interface);
221       g_dbus_interface_info_unref (proxy->priv->expected_interface);
222     }
223
224   if (proxy->priv->object != NULL)
225     g_object_remove_weak_pointer (G_OBJECT (proxy->priv->object), (gpointer *) &proxy->priv->object);
226
227   G_OBJECT_CLASS (g_dbus_proxy_parent_class)->finalize (object);
228 }
229
230 static void
231 g_dbus_proxy_get_property (GObject    *object,
232                            guint       prop_id,
233                            GValue     *value,
234                            GParamSpec *pspec)
235 {
236   GDBusProxy *proxy = G_DBUS_PROXY (object);
237
238   switch (prop_id)
239     {
240     case PROP_G_CONNECTION:
241       g_value_set_object (value, proxy->priv->connection);
242       break;
243
244     case PROP_G_FLAGS:
245       g_value_set_flags (value, proxy->priv->flags);
246       break;
247
248     case PROP_G_NAME:
249       g_value_set_string (value, proxy->priv->name);
250       break;
251
252     case PROP_G_NAME_OWNER:
253       g_value_take_string (value, g_dbus_proxy_get_name_owner (proxy));
254       break;
255
256     case PROP_G_OBJECT_PATH:
257       g_value_set_string (value, proxy->priv->object_path);
258       break;
259
260     case PROP_G_INTERFACE_NAME:
261       g_value_set_string (value, proxy->priv->interface_name);
262       break;
263
264     case PROP_G_DEFAULT_TIMEOUT:
265       g_value_set_int (value, g_dbus_proxy_get_default_timeout (proxy));
266       break;
267
268     case PROP_G_INTERFACE_INFO:
269       g_value_set_boxed (value, g_dbus_proxy_get_interface_info (proxy));
270       break;
271
272     default:
273       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
274       break;
275     }
276 }
277
278 static void
279 g_dbus_proxy_set_property (GObject      *object,
280                            guint         prop_id,
281                            const GValue *value,
282                            GParamSpec   *pspec)
283 {
284   GDBusProxy *proxy = G_DBUS_PROXY (object);
285
286   switch (prop_id)
287     {
288     case PROP_G_CONNECTION:
289       proxy->priv->connection = g_value_dup_object (value);
290       break;
291
292     case PROP_G_FLAGS:
293       proxy->priv->flags = g_value_get_flags (value);
294       break;
295
296     case PROP_G_NAME:
297       proxy->priv->name = g_value_dup_string (value);
298       break;
299
300     case PROP_G_OBJECT_PATH:
301       proxy->priv->object_path = g_value_dup_string (value);
302       break;
303
304     case PROP_G_INTERFACE_NAME:
305       proxy->priv->interface_name = g_value_dup_string (value);
306       break;
307
308     case PROP_G_DEFAULT_TIMEOUT:
309       g_dbus_proxy_set_default_timeout (proxy, g_value_get_int (value));
310       break;
311
312     case PROP_G_INTERFACE_INFO:
313       g_dbus_proxy_set_interface_info (proxy, g_value_get_boxed (value));
314       break;
315
316     case PROP_G_BUS_TYPE:
317       proxy->priv->bus_type = g_value_get_enum (value);
318       break;
319
320     default:
321       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
322       break;
323     }
324 }
325
326 static void
327 g_dbus_proxy_class_init (GDBusProxyClass *klass)
328 {
329   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
330
331   gobject_class->finalize     = g_dbus_proxy_finalize;
332   gobject_class->set_property = g_dbus_proxy_set_property;
333   gobject_class->get_property = g_dbus_proxy_get_property;
334
335   /* Note that all property names are prefixed to avoid collisions with D-Bus property names
336    * in derived classes */
337
338   /**
339    * GDBusProxy:g-interface-info:
340    *
341    * Ensure that interactions with this proxy conform to the given
342    * interface. This is mainly to ensure that malformed data received
343    * from the other peer is ignored. The given #GDBusInterfaceInfo is
344    * said to be the "expected interface".
345    *
346    * The checks performed are:
347    * - When completing a method call, if the type signature of
348    *   the reply message isn't what's expected, the reply is
349    *   discarded and the #GError is set to %G_IO_ERROR_INVALID_ARGUMENT.
350    *
351    * - Received signals that have a type signature mismatch are dropped and
352    *   a warning is logged via g_warning().
353    *
354    * - Properties received via the initial `GetAll()` call or via the 
355    *   `::PropertiesChanged` signal (on the
356    *   [org.freedesktop.DBus.Properties](http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties)
357    *   interface) or set using g_dbus_proxy_set_cached_property()
358    *   with a type signature mismatch are ignored and a warning is
359    *   logged via g_warning().
360    *
361    * Note that these checks are never done on methods, signals and
362    * properties that are not referenced in the given
363    * #GDBusInterfaceInfo, since extending a D-Bus interface on the
364    * service-side is not considered an ABI break.
365    *
366    * Since: 2.26
367    */
368   g_object_class_install_property (gobject_class,
369                                    PROP_G_INTERFACE_INFO,
370                                    g_param_spec_boxed ("g-interface-info",
371                                                        P_("Interface Information"),
372                                                        P_("Interface Information"),
373                                                        G_TYPE_DBUS_INTERFACE_INFO,
374                                                        G_PARAM_READABLE |
375                                                        G_PARAM_WRITABLE |
376                                                        G_PARAM_STATIC_NAME |
377                                                        G_PARAM_STATIC_BLURB |
378                                                        G_PARAM_STATIC_NICK));
379
380   /**
381    * GDBusProxy:g-connection:
382    *
383    * The #GDBusConnection the proxy is for.
384    *
385    * Since: 2.26
386    */
387   g_object_class_install_property (gobject_class,
388                                    PROP_G_CONNECTION,
389                                    g_param_spec_object ("g-connection",
390                                                         P_("g-connection"),
391                                                         P_("The connection the proxy is for"),
392                                                         G_TYPE_DBUS_CONNECTION,
393                                                         G_PARAM_READABLE |
394                                                         G_PARAM_WRITABLE |
395                                                         G_PARAM_CONSTRUCT_ONLY |
396                                                         G_PARAM_STATIC_NAME |
397                                                         G_PARAM_STATIC_BLURB |
398                                                         G_PARAM_STATIC_NICK));
399
400   /**
401    * GDBusProxy:g-bus-type:
402    *
403    * If this property is not %G_BUS_TYPE_NONE, then
404    * #GDBusProxy:g-connection must be %NULL and will be set to the
405    * #GDBusConnection obtained by calling g_bus_get() with the value
406    * of this property.
407    *
408    * Since: 2.26
409    */
410   g_object_class_install_property (gobject_class,
411                                    PROP_G_BUS_TYPE,
412                                    g_param_spec_enum ("g-bus-type",
413                                                       P_("Bus Type"),
414                                                       P_("The bus to connect to, if any"),
415                                                       G_TYPE_BUS_TYPE,
416                                                       G_BUS_TYPE_NONE,
417                                                       G_PARAM_WRITABLE |
418                                                       G_PARAM_CONSTRUCT_ONLY |
419                                                       G_PARAM_STATIC_NAME |
420                                                       G_PARAM_STATIC_BLURB |
421                                                       G_PARAM_STATIC_NICK));
422
423   /**
424    * GDBusProxy:g-flags:
425    *
426    * Flags from the #GDBusProxyFlags enumeration.
427    *
428    * Since: 2.26
429    */
430   g_object_class_install_property (gobject_class,
431                                    PROP_G_FLAGS,
432                                    g_param_spec_flags ("g-flags",
433                                                        P_("g-flags"),
434                                                        P_("Flags for the proxy"),
435                                                        G_TYPE_DBUS_PROXY_FLAGS,
436                                                        G_DBUS_PROXY_FLAGS_NONE,
437                                                        G_PARAM_READABLE |
438                                                        G_PARAM_WRITABLE |
439                                                        G_PARAM_CONSTRUCT_ONLY |
440                                                        G_PARAM_STATIC_NAME |
441                                                        G_PARAM_STATIC_BLURB |
442                                                        G_PARAM_STATIC_NICK));
443
444   /**
445    * GDBusProxy:g-name:
446    *
447    * The well-known or unique name that the proxy is for.
448    *
449    * Since: 2.26
450    */
451   g_object_class_install_property (gobject_class,
452                                    PROP_G_NAME,
453                                    g_param_spec_string ("g-name",
454                                                         P_("g-name"),
455                                                         P_("The well-known or unique name that the proxy is for"),
456                                                         NULL,
457                                                         G_PARAM_READABLE |
458                                                         G_PARAM_WRITABLE |
459                                                         G_PARAM_CONSTRUCT_ONLY |
460                                                         G_PARAM_STATIC_NAME |
461                                                         G_PARAM_STATIC_BLURB |
462                                                         G_PARAM_STATIC_NICK));
463
464   /**
465    * GDBusProxy:g-name-owner:
466    *
467    * The unique name that owns #GDBusProxy:g-name or %NULL if no-one
468    * currently owns that name. You may connect to #GObject::notify signal to
469    * track changes to this property.
470    *
471    * Since: 2.26
472    */
473   g_object_class_install_property (gobject_class,
474                                    PROP_G_NAME_OWNER,
475                                    g_param_spec_string ("g-name-owner",
476                                                         P_("g-name-owner"),
477                                                         P_("The unique name for the owner"),
478                                                         NULL,
479                                                         G_PARAM_READABLE |
480                                                         G_PARAM_STATIC_NAME |
481                                                         G_PARAM_STATIC_BLURB |
482                                                         G_PARAM_STATIC_NICK));
483
484   /**
485    * GDBusProxy:g-object-path:
486    *
487    * The object path the proxy is for.
488    *
489    * Since: 2.26
490    */
491   g_object_class_install_property (gobject_class,
492                                    PROP_G_OBJECT_PATH,
493                                    g_param_spec_string ("g-object-path",
494                                                         P_("g-object-path"),
495                                                         P_("The object path the proxy is for"),
496                                                         NULL,
497                                                         G_PARAM_READABLE |
498                                                         G_PARAM_WRITABLE |
499                                                         G_PARAM_CONSTRUCT_ONLY |
500                                                         G_PARAM_STATIC_NAME |
501                                                         G_PARAM_STATIC_BLURB |
502                                                         G_PARAM_STATIC_NICK));
503
504   /**
505    * GDBusProxy:g-interface-name:
506    *
507    * The D-Bus interface name the proxy is for.
508    *
509    * Since: 2.26
510    */
511   g_object_class_install_property (gobject_class,
512                                    PROP_G_INTERFACE_NAME,
513                                    g_param_spec_string ("g-interface-name",
514                                                         P_("g-interface-name"),
515                                                         P_("The D-Bus interface name the proxy is for"),
516                                                         NULL,
517                                                         G_PARAM_READABLE |
518                                                         G_PARAM_WRITABLE |
519                                                         G_PARAM_CONSTRUCT_ONLY |
520                                                         G_PARAM_STATIC_NAME |
521                                                         G_PARAM_STATIC_BLURB |
522                                                         G_PARAM_STATIC_NICK));
523
524   /**
525    * GDBusProxy:g-default-timeout:
526    *
527    * The timeout to use if -1 (specifying default timeout) is passed
528    * as @timeout_msec in the g_dbus_proxy_call() and
529    * g_dbus_proxy_call_sync() functions.
530    *
531    * This allows applications to set a proxy-wide timeout for all
532    * remote method invocations on the proxy. If this property is -1,
533    * the default timeout (typically 25 seconds) is used. If set to
534    * %G_MAXINT, then no timeout is used.
535    *
536    * Since: 2.26
537    */
538   g_object_class_install_property (gobject_class,
539                                    PROP_G_DEFAULT_TIMEOUT,
540                                    g_param_spec_int ("g-default-timeout",
541                                                      P_("Default Timeout"),
542                                                      P_("Timeout for remote method invocation"),
543                                                      -1,
544                                                      G_MAXINT,
545                                                      -1,
546                                                      G_PARAM_READABLE |
547                                                      G_PARAM_WRITABLE |
548                                                      G_PARAM_CONSTRUCT |
549                                                      G_PARAM_STATIC_NAME |
550                                                      G_PARAM_STATIC_BLURB |
551                                                      G_PARAM_STATIC_NICK));
552
553   /**
554    * GDBusProxy::g-properties-changed:
555    * @proxy: The #GDBusProxy emitting the signal.
556    * @changed_properties: A #GVariant containing the properties that changed (type: `a{sv}`)
557    * @invalidated_properties: A %NULL terminated array of properties that was invalidated
558    *
559    * Emitted when one or more D-Bus properties on @proxy changes. The
560    * local cache has already been updated when this signal fires. Note
561    * that both @changed_properties and @invalidated_properties are
562    * guaranteed to never be %NULL (either may be empty though).
563    *
564    * If the proxy has the flag
565    * %G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES set, then
566    * @invalidated_properties will always be empty.
567    *
568    * This signal corresponds to the
569    * `PropertiesChanged` D-Bus signal on the
570    * `org.freedesktop.DBus.Properties` interface.
571    *
572    * Since: 2.26
573    */
574   signals[PROPERTIES_CHANGED_SIGNAL] = g_signal_new (I_("g-properties-changed"),
575                                                      G_TYPE_DBUS_PROXY,
576                                                      G_SIGNAL_RUN_LAST | G_SIGNAL_MUST_COLLECT,
577                                                      G_STRUCT_OFFSET (GDBusProxyClass, g_properties_changed),
578                                                      NULL,
579                                                      NULL,
580                                                      _g_cclosure_marshal_VOID__VARIANT_BOXED,
581                                                      G_TYPE_NONE,
582                                                      2,
583                                                      G_TYPE_VARIANT,
584                                                      G_TYPE_STRV | G_SIGNAL_TYPE_STATIC_SCOPE);
585   g_signal_set_va_marshaller (signals[PROPERTIES_CHANGED_SIGNAL],
586                               G_TYPE_FROM_CLASS (klass),
587                               _g_cclosure_marshal_VOID__VARIANT_BOXEDv);
588
589   /**
590    * GDBusProxy::g-signal:
591    * @proxy: The #GDBusProxy emitting the signal.
592    * @sender_name: (nullable): The sender of the signal or %NULL if the connection is not a bus connection.
593    * @signal_name: The name of the signal.
594    * @parameters: A #GVariant tuple with parameters for the signal.
595    *
596    * Emitted when a signal from the remote object and interface that @proxy is for, has been received.
597    *
598    * Since 2.72 this signal supports detailed connections. You can connect to
599    * the detailed signal `g-signal::x` in order to receive callbacks only when
600    * signal `x` is received from the remote object.
601    *
602    * Since: 2.26
603    */
604   signals[SIGNAL_SIGNAL] = g_signal_new (I_("g-signal"),
605                                          G_TYPE_DBUS_PROXY,
606                                          G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED | G_SIGNAL_MUST_COLLECT,
607                                          G_STRUCT_OFFSET (GDBusProxyClass, g_signal),
608                                          NULL,
609                                          NULL,
610                                          _g_cclosure_marshal_VOID__STRING_STRING_VARIANT,
611                                          G_TYPE_NONE,
612                                          3,
613                                          G_TYPE_STRING,
614                                          G_TYPE_STRING,
615                                          G_TYPE_VARIANT);
616   g_signal_set_va_marshaller (signals[SIGNAL_SIGNAL],
617                               G_TYPE_FROM_CLASS (klass),
618                               _g_cclosure_marshal_VOID__STRING_STRING_VARIANTv);
619
620 }
621
622 static void
623 g_dbus_proxy_init (GDBusProxy *proxy)
624 {
625   proxy->priv = g_dbus_proxy_get_instance_private (proxy);
626   proxy->priv->properties = g_hash_table_new_full (g_str_hash,
627                                                    g_str_equal,
628                                                    g_free,
629                                                    (GDestroyNotify) g_variant_unref);
630 }
631
632 /* ---------------------------------------------------------------------------------------------------- */
633
634 /**
635  * g_dbus_proxy_get_cached_property_names:
636  * @proxy: A #GDBusProxy.
637  *
638  * Gets the names of all cached properties on @proxy.
639  *
640  * Returns: (transfer full) (nullable) (array zero-terminated=1): A
641  *          %NULL-terminated array of strings or %NULL if
642  *          @proxy has no cached properties. Free the returned array with
643  *          g_strfreev().
644  *
645  * Since: 2.26
646  */
647 gchar **
648 g_dbus_proxy_get_cached_property_names (GDBusProxy  *proxy)
649 {
650   gchar **names;
651   GPtrArray *p;
652   GHashTableIter iter;
653   const gchar *key;
654
655   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
656
657   G_LOCK (properties_lock);
658
659   names = NULL;
660   if (g_hash_table_size (proxy->priv->properties) == 0)
661     goto out;
662
663   p = g_ptr_array_new ();
664
665   g_hash_table_iter_init (&iter, proxy->priv->properties);
666   while (g_hash_table_iter_next (&iter, (gpointer) &key, NULL))
667     g_ptr_array_add (p, g_strdup (key));
668   g_ptr_array_sort_values (p, (GCompareFunc) g_strcmp0);
669   g_ptr_array_add (p, NULL);
670
671   names = (gchar **) g_ptr_array_free (p, FALSE);
672
673  out:
674   G_UNLOCK (properties_lock);
675   return names;
676 }
677
678 /* properties_lock must be held for as long as you will keep the
679  * returned value
680  */
681 static const GDBusPropertyInfo *
682 lookup_property_info (GDBusProxy  *proxy,
683                       const gchar *property_name)
684 {
685   const GDBusPropertyInfo *info = NULL;
686
687   if (proxy->priv->expected_interface == NULL)
688     goto out;
689
690   info = g_dbus_interface_info_lookup_property (proxy->priv->expected_interface, property_name);
691
692  out:
693   return info;
694 }
695
696 /**
697  * g_dbus_proxy_get_cached_property:
698  * @proxy: A #GDBusProxy.
699  * @property_name: Property name.
700  *
701  * Looks up the value for a property from the cache. This call does no
702  * blocking IO.
703  *
704  * If @proxy has an expected interface (see
705  * #GDBusProxy:g-interface-info) and @property_name is referenced by
706  * it, then @value is checked against the type of the property.
707  *
708  * Returns: (transfer full) (nullable): A reference to the #GVariant instance
709  *    that holds the value for @property_name or %NULL if the value is not in
710  *    the cache. The returned reference must be freed with g_variant_unref().
711  *
712  * Since: 2.26
713  */
714 GVariant *
715 g_dbus_proxy_get_cached_property (GDBusProxy   *proxy,
716                                   const gchar  *property_name)
717 {
718   const GDBusPropertyInfo *info;
719   GVariant *value;
720
721   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
722   g_return_val_if_fail (property_name != NULL, NULL);
723
724   G_LOCK (properties_lock);
725
726   value = g_hash_table_lookup (proxy->priv->properties, property_name);
727   if (value == NULL)
728     goto out;
729
730   info = lookup_property_info (proxy, property_name);
731   if (info != NULL)
732     {
733       const gchar *type_string = g_variant_get_type_string (value);
734       if (g_strcmp0 (type_string, info->signature) != 0)
735         {
736           g_warning ("Trying to get property %s with type %s but according to the expected "
737                      "interface the type is %s",
738                      property_name,
739                      type_string,
740                      info->signature);
741           value = NULL;
742           goto out;
743         }
744     }
745
746   g_variant_ref (value);
747
748  out:
749   G_UNLOCK (properties_lock);
750   return value;
751 }
752
753 /**
754  * g_dbus_proxy_set_cached_property:
755  * @proxy: A #GDBusProxy
756  * @property_name: Property name.
757  * @value: (nullable): Value for the property or %NULL to remove it from the cache.
758  *
759  * If @value is not %NULL, sets the cached value for the property with
760  * name @property_name to the value in @value.
761  *
762  * If @value is %NULL, then the cached value is removed from the
763  * property cache.
764  *
765  * If @proxy has an expected interface (see
766  * #GDBusProxy:g-interface-info) and @property_name is referenced by
767  * it, then @value is checked against the type of the property.
768  *
769  * If the @value #GVariant is floating, it is consumed. This allows
770  * convenient 'inline' use of g_variant_new(), e.g.
771  * |[<!-- language="C" -->
772  *  g_dbus_proxy_set_cached_property (proxy,
773  *                                    "SomeProperty",
774  *                                    g_variant_new ("(si)",
775  *                                                  "A String",
776  *                                                  42));
777  * ]|
778  *
779  * Normally you will not need to use this method since @proxy
780  * is tracking changes using the
781  * `org.freedesktop.DBus.Properties.PropertiesChanged`
782  * D-Bus signal. However, for performance reasons an object may
783  * decide to not use this signal for some properties and instead
784  * use a proprietary out-of-band mechanism to transmit changes.
785  *
786  * As a concrete example, consider an object with a property
787  * `ChatroomParticipants` which is an array of strings. Instead of
788  * transmitting the same (long) array every time the property changes,
789  * it is more efficient to only transmit the delta using e.g. signals
790  * `ChatroomParticipantJoined(String name)` and
791  * `ChatroomParticipantParted(String name)`.
792  *
793  * Since: 2.26
794  */
795 void
796 g_dbus_proxy_set_cached_property (GDBusProxy   *proxy,
797                                   const gchar  *property_name,
798                                   GVariant     *value)
799 {
800   const GDBusPropertyInfo *info;
801
802   g_return_if_fail (G_IS_DBUS_PROXY (proxy));
803   g_return_if_fail (property_name != NULL);
804
805   G_LOCK (properties_lock);
806
807   if (value != NULL)
808     {
809       info = lookup_property_info (proxy, property_name);
810       if (info != NULL)
811         {
812           if (g_strcmp0 (info->signature, g_variant_get_type_string (value)) != 0)
813             {
814               g_warning ("Trying to set property %s of type %s but according to the expected "
815                          "interface the type is %s",
816                          property_name,
817                          g_variant_get_type_string (value),
818                          info->signature);
819               goto out;
820             }
821         }
822       g_hash_table_insert (proxy->priv->properties,
823                            g_strdup (property_name),
824                            g_variant_ref_sink (value));
825     }
826   else
827     {
828       g_hash_table_remove (proxy->priv->properties, property_name);
829     }
830
831  out:
832   G_UNLOCK (properties_lock);
833 }
834
835 /* ---------------------------------------------------------------------------------------------------- */
836
837 static void
838 on_signal_received (GDBusConnection *connection,
839                     const gchar     *sender_name,
840                     const gchar     *object_path,
841                     const gchar     *interface_name,
842                     const gchar     *signal_name,
843                     GVariant        *parameters,
844                     gpointer         user_data)
845 {
846   GWeakRef *proxy_weak = user_data;
847   GDBusProxy *proxy;
848
849   proxy = G_DBUS_PROXY (g_weak_ref_get (proxy_weak));
850   if (proxy == NULL)
851     return;
852
853   if (!proxy->priv->initialized)
854     goto out;
855
856   G_LOCK (properties_lock);
857
858   if (proxy->priv->name_owner != NULL && g_strcmp0 (sender_name, proxy->priv->name_owner) != 0)
859     {
860       G_UNLOCK (properties_lock);
861       goto out;
862     }
863
864   if (proxy->priv->expected_interface != NULL)
865     {
866       const GDBusSignalInfo *info;
867       info = g_dbus_interface_info_lookup_signal (proxy->priv->expected_interface, signal_name);
868       if (info != NULL)
869         {
870           GVariantType *expected_type;
871           expected_type = _g_dbus_compute_complete_signature (info->args);
872           if (!g_variant_type_equal (expected_type, g_variant_get_type (parameters)))
873             {
874               gchar *expected_type_string = g_variant_type_dup_string (expected_type);
875               g_warning ("Dropping signal %s of type %s since the type from the expected interface is %s",
876                          info->name,
877                          g_variant_get_type_string (parameters),
878                          expected_type_string);
879               g_free (expected_type_string);
880               g_variant_type_free (expected_type);
881               G_UNLOCK (properties_lock);
882               goto out;
883             }
884           g_variant_type_free (expected_type);
885         }
886     }
887
888   G_UNLOCK (properties_lock);
889
890   g_signal_emit (proxy,
891                  signals[SIGNAL_SIGNAL],
892                  g_quark_try_string (signal_name),
893                  sender_name,
894                  signal_name,
895                  parameters);
896
897  out:
898   g_clear_object (&proxy);
899 }
900
901 /* ---------------------------------------------------------------------------------------------------- */
902
903 /* must hold properties_lock */
904 static void
905 insert_property_checked (GDBusProxy  *proxy,
906                          gchar *property_name,
907                          GVariant *value)
908 {
909   if (proxy->priv->expected_interface != NULL)
910     {
911       const GDBusPropertyInfo *info;
912       info = g_dbus_interface_info_lookup_property (proxy->priv->expected_interface, property_name);
913       /* Only check known properties */
914       if (info != NULL)
915         {
916           /* Warn about properties with the wrong type */
917           if (g_strcmp0 (info->signature, g_variant_get_type_string (value)) != 0)
918             {
919               g_warning ("Received property %s with type %s does not match expected type "
920                          "%s in the expected interface",
921                          property_name,
922                          g_variant_get_type_string (value),
923                          info->signature);
924               goto invalid;
925             }
926         }
927     }
928
929   g_hash_table_insert (proxy->priv->properties,
930                        property_name, /* adopts string */
931                        value); /* adopts value */
932
933   return;
934
935  invalid:
936   g_variant_unref (value);
937   g_free (property_name);
938 }
939
940 typedef struct
941 {
942   GDBusProxy *proxy;
943   gchar *prop_name;
944 } InvalidatedPropGetData;
945
946 static void
947 invalidated_property_get_cb (GDBusConnection *connection,
948                              GAsyncResult    *res,
949                              gpointer         user_data)
950 {
951   InvalidatedPropGetData *data = user_data;
952   const gchar *invalidated_properties[] = {NULL};
953   GVariantBuilder builder;
954   GVariant *value = NULL;
955   GVariant *unpacked_value = NULL;
956
957   /* errors are fine, the other end could have disconnected */
958   value = g_dbus_connection_call_finish (connection, res, NULL);
959   if (value == NULL)
960     {
961       goto out;
962     }
963
964   if (!g_variant_is_of_type (value, G_VARIANT_TYPE ("(v)")))
965     {
966       g_warning ("Expected type '(v)' for Get() reply, got '%s'", g_variant_get_type_string (value));
967       goto out;
968     }
969
970   g_variant_get (value, "(v)", &unpacked_value);
971
972   /* synthesize the a{sv} in the PropertiesChanged signal */
973   g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
974   g_variant_builder_add (&builder, "{sv}", data->prop_name, unpacked_value);
975
976   G_LOCK (properties_lock);
977   insert_property_checked (data->proxy,
978                            data->prop_name,  /* adopts string */
979                            unpacked_value);  /* adopts value */
980   data->prop_name = NULL;
981   G_UNLOCK (properties_lock);
982
983   g_signal_emit (data->proxy,
984                  signals[PROPERTIES_CHANGED_SIGNAL], 0,
985                  g_variant_builder_end (&builder), /* consumed */
986                  invalidated_properties);
987
988
989  out:
990   if (value != NULL)
991     g_variant_unref (value);
992   g_object_unref (data->proxy);
993   g_free (data->prop_name);
994   g_slice_free (InvalidatedPropGetData, data);
995 }
996
997 static void
998 on_properties_changed (GDBusConnection *connection,
999                        const gchar     *sender_name,
1000                        const gchar     *object_path,
1001                        const gchar     *interface_name,
1002                        const gchar     *signal_name,
1003                        GVariant        *parameters,
1004                        gpointer         user_data)
1005 {
1006   GWeakRef *proxy_weak = user_data;
1007   gboolean emit_g_signal = FALSE;
1008   GDBusProxy *proxy;
1009   const gchar *interface_name_for_signal;
1010   GVariant *changed_properties;
1011   gchar **invalidated_properties;
1012   GVariantIter iter;
1013   gchar *key;
1014   GVariant *value;
1015   guint n;
1016
1017   changed_properties = NULL;
1018   invalidated_properties = NULL;
1019
1020   proxy = G_DBUS_PROXY (g_weak_ref_get (proxy_weak));
1021   if (proxy == NULL)
1022     return;
1023
1024   if (!proxy->priv->initialized)
1025     goto out;
1026
1027   G_LOCK (properties_lock);
1028
1029   if (proxy->priv->name_owner != NULL && g_strcmp0 (sender_name, proxy->priv->name_owner) != 0)
1030     {
1031       G_UNLOCK (properties_lock);
1032       goto out;
1033     }
1034
1035   if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sa{sv}as)")))
1036     {
1037       g_warning ("Value for PropertiesChanged signal with type '%s' does not match '(sa{sv}as)'",
1038                  g_variant_get_type_string (parameters));
1039       G_UNLOCK (properties_lock);
1040       goto out;
1041     }
1042
1043   g_variant_get (parameters,
1044                  "(&s@a{sv}^a&s)",
1045                  &interface_name_for_signal,
1046                  &changed_properties,
1047                  &invalidated_properties);
1048
1049   if (g_strcmp0 (interface_name_for_signal, proxy->priv->interface_name) != 0)
1050     {
1051       G_UNLOCK (properties_lock);
1052       goto out;
1053     }
1054
1055   g_variant_iter_init (&iter, changed_properties);
1056   while (g_variant_iter_next (&iter, "{sv}", &key, &value))
1057     {
1058       insert_property_checked (proxy,
1059                                key, /* adopts string */
1060                                value); /* adopts value */
1061       emit_g_signal = TRUE;
1062     }
1063
1064   if (proxy->priv->flags & G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES)
1065     {
1066       if (proxy->priv->name_owner != NULL)
1067         {
1068           for (n = 0; invalidated_properties[n] != NULL; n++)
1069             {
1070               InvalidatedPropGetData *data;
1071               data = g_slice_new0 (InvalidatedPropGetData);
1072               data->proxy = g_object_ref (proxy);
1073               data->prop_name = g_strdup (invalidated_properties[n]);
1074               g_dbus_connection_call (proxy->priv->connection,
1075                                       proxy->priv->name_owner,
1076                                       proxy->priv->object_path,
1077                                       "org.freedesktop.DBus.Properties",
1078                                       "Get",
1079                                       g_variant_new ("(ss)", proxy->priv->interface_name, data->prop_name),
1080                                       G_VARIANT_TYPE ("(v)"),
1081                                       G_DBUS_CALL_FLAGS_NONE,
1082                                       -1,           /* timeout */
1083                                       NULL,         /* GCancellable */
1084                                       (GAsyncReadyCallback) invalidated_property_get_cb,
1085                                       data);
1086             }
1087         }
1088     }
1089   else
1090     {
1091       emit_g_signal = TRUE;
1092       for (n = 0; invalidated_properties[n] != NULL; n++)
1093         {
1094           g_hash_table_remove (proxy->priv->properties, invalidated_properties[n]);
1095         }
1096     }
1097
1098   G_UNLOCK (properties_lock);
1099
1100   if (emit_g_signal)
1101     {
1102       g_signal_emit (proxy, signals[PROPERTIES_CHANGED_SIGNAL],
1103                      0,
1104                      changed_properties,
1105                      invalidated_properties);
1106     }
1107
1108  out:
1109   g_clear_pointer (&changed_properties, g_variant_unref);
1110   g_free (invalidated_properties);
1111   g_clear_object (&proxy);
1112 }
1113
1114 /* ---------------------------------------------------------------------------------------------------- */
1115
1116 static void
1117 process_get_all_reply (GDBusProxy *proxy,
1118                        GVariant   *result)
1119 {
1120   GVariantIter *iter;
1121   gchar *key;
1122   GVariant *value;
1123   guint num_properties;
1124
1125   if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(a{sv})")))
1126     {
1127       g_warning ("Value for GetAll reply with type '%s' does not match '(a{sv})'",
1128                  g_variant_get_type_string (result));
1129       goto out;
1130     }
1131
1132   G_LOCK (properties_lock);
1133
1134   g_variant_get (result, "(a{sv})", &iter);
1135   while (g_variant_iter_next (iter, "{sv}", &key, &value))
1136     {
1137       insert_property_checked (proxy,
1138                                key, /* adopts string */
1139                                value); /* adopts value */
1140     }
1141   g_variant_iter_free (iter);
1142
1143   num_properties = g_hash_table_size (proxy->priv->properties);
1144   G_UNLOCK (properties_lock);
1145
1146   /* Synthesize ::g-properties-changed changed */
1147   if (num_properties > 0)
1148     {
1149       GVariant *changed_properties;
1150       const gchar *invalidated_properties[1] = {NULL};
1151
1152       g_variant_get (result,
1153                      "(@a{sv})",
1154                      &changed_properties);
1155       g_signal_emit (proxy, signals[PROPERTIES_CHANGED_SIGNAL],
1156                      0,
1157                      changed_properties,
1158                      invalidated_properties);
1159       g_variant_unref (changed_properties);
1160     }
1161
1162  out:
1163   ;
1164 }
1165
1166 typedef struct
1167 {
1168   GDBusProxy *proxy;
1169   GCancellable *cancellable;
1170   gchar *name_owner;
1171 } LoadPropertiesOnNameOwnerChangedData;
1172
1173 static void
1174 on_name_owner_changed_get_all_cb (GDBusConnection *connection,
1175                                   GAsyncResult    *res,
1176                                   gpointer         user_data)
1177 {
1178   LoadPropertiesOnNameOwnerChangedData *data = user_data;
1179   GVariant *result;
1180   GError *error;
1181   gboolean cancelled;
1182
1183   cancelled = FALSE;
1184
1185   error = NULL;
1186   result = g_dbus_connection_call_finish (connection,
1187                                           res,
1188                                           &error);
1189   if (result == NULL)
1190     {
1191       if (error->domain == G_IO_ERROR && error->code == G_IO_ERROR_CANCELLED)
1192         cancelled = TRUE;
1193       /* We just ignore if GetAll() is failing. Because this might happen
1194        * if the object has no properties at all. Or if the caller is
1195        * not authorized to see the properties.
1196        *
1197        * Either way, apps can know about this by using
1198        * get_cached_property_names() or get_cached_property().
1199        */
1200       if (G_UNLIKELY (_g_dbus_debug_proxy ()))
1201         {
1202           g_debug ("error: %d %d %s",
1203                    error->domain,
1204                    error->code,
1205                    error->message);
1206         }
1207       g_error_free (error);
1208     }
1209
1210   /* and finally we can notify */
1211   if (!cancelled)
1212     {
1213       G_LOCK (properties_lock);
1214       g_free (data->proxy->priv->name_owner);
1215       data->proxy->priv->name_owner = g_steal_pointer (&data->name_owner);
1216       g_hash_table_remove_all (data->proxy->priv->properties);
1217       G_UNLOCK (properties_lock);
1218       if (result != NULL)
1219         {
1220           process_get_all_reply (data->proxy, result);
1221           g_variant_unref (result);
1222         }
1223
1224       g_object_notify (G_OBJECT (data->proxy), "g-name-owner");
1225     }
1226
1227   if (data->cancellable == data->proxy->priv->get_all_cancellable)
1228     data->proxy->priv->get_all_cancellable = NULL;
1229
1230   g_object_unref (data->proxy);
1231   g_object_unref (data->cancellable);
1232   g_free (data->name_owner);
1233   g_free (data);
1234 }
1235
1236 static void
1237 on_name_owner_changed (GDBusConnection *connection,
1238                        const gchar      *sender_name,
1239                        const gchar      *object_path,
1240                        const gchar      *interface_name,
1241                        const gchar      *signal_name,
1242                        GVariant         *parameters,
1243                        gpointer          user_data)
1244 {
1245   GWeakRef *proxy_weak = user_data;
1246   GDBusProxy *proxy;
1247   const gchar *old_owner;
1248   const gchar *new_owner;
1249
1250   proxy = G_DBUS_PROXY (g_weak_ref_get (proxy_weak));
1251   if (proxy == NULL)
1252     return;
1253
1254   /* if we are already trying to load properties, cancel that */
1255   if (proxy->priv->get_all_cancellable != NULL)
1256     {
1257       g_cancellable_cancel (proxy->priv->get_all_cancellable);
1258       proxy->priv->get_all_cancellable = NULL;
1259     }
1260
1261   g_variant_get (parameters,
1262                  "(&s&s&s)",
1263                  NULL,
1264                  &old_owner,
1265                  &new_owner);
1266
1267   if (strlen (new_owner) == 0)
1268     {
1269       G_LOCK (properties_lock);
1270       g_free (proxy->priv->name_owner);
1271       proxy->priv->name_owner = NULL;
1272
1273       /* Synthesize ::g-properties-changed changed */
1274       if (!(proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES) &&
1275           g_hash_table_size (proxy->priv->properties) > 0)
1276         {
1277           GVariantBuilder builder;
1278           GPtrArray *invalidated_properties;
1279           GHashTableIter iter;
1280           const gchar *key;
1281
1282           /* Build changed_properties (always empty) and invalidated_properties ... */
1283           g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
1284
1285           invalidated_properties = g_ptr_array_new_with_free_func (g_free);
1286           g_hash_table_iter_init (&iter, proxy->priv->properties);
1287           while (g_hash_table_iter_next (&iter, (gpointer) &key, NULL))
1288             g_ptr_array_add (invalidated_properties, g_strdup (key));
1289           g_ptr_array_add (invalidated_properties, NULL);
1290
1291           /* ... throw out the properties ... */
1292           g_hash_table_remove_all (proxy->priv->properties);
1293
1294           G_UNLOCK (properties_lock);
1295
1296           /* ... and finally emit the ::g-properties-changed signal */
1297           g_signal_emit (proxy, signals[PROPERTIES_CHANGED_SIGNAL],
1298                          0,
1299                          g_variant_builder_end (&builder) /* consumed */,
1300                          (const gchar* const *) invalidated_properties->pdata);
1301           g_ptr_array_unref (invalidated_properties);
1302         }
1303       else
1304         {
1305           G_UNLOCK (properties_lock);
1306         }
1307       g_object_notify (G_OBJECT (proxy), "g-name-owner");
1308     }
1309   else
1310     {
1311       G_LOCK (properties_lock);
1312
1313       /* ignore duplicates - this can happen when activating the service */
1314       if (g_strcmp0 (new_owner, proxy->priv->name_owner) == 0)
1315         {
1316           G_UNLOCK (properties_lock);
1317           goto out;
1318         }
1319
1320       if (proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES)
1321         {
1322           g_free (proxy->priv->name_owner);
1323           proxy->priv->name_owner = g_strdup (new_owner);
1324
1325           g_hash_table_remove_all (proxy->priv->properties);
1326           G_UNLOCK (properties_lock);
1327           g_object_notify (G_OBJECT (proxy), "g-name-owner");
1328         }
1329       else
1330         {
1331           LoadPropertiesOnNameOwnerChangedData *data;
1332
1333           G_UNLOCK (properties_lock);
1334
1335           /* start loading properties.. only then emit notify::g-name-owner .. we
1336            * need to be able to cancel this in the event another NameOwnerChanged
1337            * signal suddenly happens
1338            */
1339
1340           g_assert (proxy->priv->get_all_cancellable == NULL);
1341           proxy->priv->get_all_cancellable = g_cancellable_new ();
1342           data = g_new0 (LoadPropertiesOnNameOwnerChangedData, 1);
1343           data->proxy = g_object_ref (proxy);
1344           data->cancellable = proxy->priv->get_all_cancellable;
1345           data->name_owner = g_strdup (new_owner);
1346           g_dbus_connection_call (proxy->priv->connection,
1347                                   data->name_owner,
1348                                   proxy->priv->object_path,
1349                                   "org.freedesktop.DBus.Properties",
1350                                   "GetAll",
1351                                   g_variant_new ("(s)", proxy->priv->interface_name),
1352                                   G_VARIANT_TYPE ("(a{sv})"),
1353                                   G_DBUS_CALL_FLAGS_NONE,
1354                                   -1,           /* timeout */
1355                                   proxy->priv->get_all_cancellable,
1356                                   (GAsyncReadyCallback) on_name_owner_changed_get_all_cb,
1357                                   data);
1358         }
1359     }
1360
1361  out:
1362   g_clear_object (&proxy);
1363 }
1364
1365 /* ---------------------------------------------------------------------------------------------------- */
1366
1367 static void
1368 async_init_get_all_cb (GDBusConnection *connection,
1369                        GAsyncResult    *res,
1370                        gpointer         user_data)
1371 {
1372   GTask *task = user_data;
1373   GVariant *result;
1374   GError *error;
1375
1376   error = NULL;
1377   result = g_dbus_connection_call_finish (connection,
1378                                           res,
1379                                           &error);
1380   if (result == NULL)
1381     {
1382       /* We just ignore if GetAll() is failing. Because this might happen
1383        * if the object has no properties at all. Or if the caller is
1384        * not authorized to see the properties.
1385        *
1386        * Either way, apps can know about this by using
1387        * get_cached_property_names() or get_cached_property().
1388        */
1389       if (G_UNLIKELY (_g_dbus_debug_proxy ()))
1390         {
1391           g_debug ("error: %d %d %s",
1392                    error->domain,
1393                    error->code,
1394                    error->message);
1395         }
1396       g_error_free (error);
1397     }
1398
1399   g_task_return_pointer (task, result,
1400                          (GDestroyNotify) g_variant_unref);
1401   g_object_unref (task);
1402 }
1403
1404 static void
1405 async_init_data_set_name_owner (GTask       *task,
1406                                 const gchar *name_owner)
1407 {
1408   GDBusProxy *proxy = g_task_get_source_object (task);
1409   gboolean get_all;
1410
1411   if (name_owner != NULL)
1412     {
1413       G_LOCK (properties_lock);
1414       /* Must free first, since on_name_owner_changed() could run before us */
1415       g_free (proxy->priv->name_owner);
1416       proxy->priv->name_owner = g_strdup (name_owner);
1417       G_UNLOCK (properties_lock);
1418     }
1419
1420   get_all = TRUE;
1421
1422   if (proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES)
1423     {
1424       /* Don't load properties if the API user doesn't want them */
1425       get_all = FALSE;
1426     }
1427   else if (name_owner == NULL && proxy->priv->name != NULL)
1428     {
1429       /* Don't attempt to load properties if the name_owner is NULL (which
1430        * usually means the name isn't owned), unless name is also NULL (which
1431        * means we actually wanted to talk to the directly-connected process -
1432        * either dbus-daemon or a peer - instead of going via dbus-daemon)
1433        */
1434         get_all = FALSE;
1435     }
1436
1437   if (get_all)
1438     {
1439       /* load all properties asynchronously */
1440       g_dbus_connection_call (proxy->priv->connection,
1441                               name_owner,
1442                               proxy->priv->object_path,
1443                               "org.freedesktop.DBus.Properties",
1444                               "GetAll",
1445                               g_variant_new ("(s)", proxy->priv->interface_name),
1446                               G_VARIANT_TYPE ("(a{sv})"),
1447                               G_DBUS_CALL_FLAGS_NONE,
1448                               -1,           /* timeout */
1449                               g_task_get_cancellable (task),
1450                               (GAsyncReadyCallback) async_init_get_all_cb,
1451                               task);
1452     }
1453   else
1454     {
1455       g_task_return_pointer (task, NULL, NULL);
1456       g_object_unref (task);
1457     }
1458 }
1459
1460 static void
1461 async_init_get_name_owner_cb (GDBusConnection *connection,
1462                               GAsyncResult    *res,
1463                               gpointer         user_data)
1464 {
1465   GTask *task = user_data;
1466   GError *error;
1467   GVariant *result;
1468
1469   error = NULL;
1470   result = g_dbus_connection_call_finish (connection,
1471                                           res,
1472                                           &error);
1473   if (result == NULL)
1474     {
1475       if (error->domain == G_DBUS_ERROR &&
1476           error->code == G_DBUS_ERROR_NAME_HAS_NO_OWNER)
1477         {
1478           g_error_free (error);
1479           async_init_data_set_name_owner (task, NULL);
1480         }
1481       else
1482         {
1483           g_task_return_error (task, error);
1484           g_object_unref (task);
1485         }
1486     }
1487   else
1488     {
1489       /* borrowed from result to avoid an extra copy */
1490       const gchar *name_owner;
1491
1492       g_variant_get (result, "(&s)", &name_owner);
1493       async_init_data_set_name_owner (task, name_owner);
1494       g_variant_unref (result);
1495     }
1496 }
1497
1498 static void
1499 async_init_call_get_name_owner (GTask *task)
1500 {
1501   GDBusProxy *proxy = g_task_get_source_object (task);
1502
1503   g_dbus_connection_call (proxy->priv->connection,
1504                           "org.freedesktop.DBus",  /* name */
1505                           "/org/freedesktop/DBus", /* object path */
1506                           "org.freedesktop.DBus",  /* interface */
1507                           "GetNameOwner",
1508                           g_variant_new ("(s)",
1509                                          proxy->priv->name),
1510                           G_VARIANT_TYPE ("(s)"),
1511                           G_DBUS_CALL_FLAGS_NONE,
1512                           -1,           /* timeout */
1513                           g_task_get_cancellable (task),
1514                           (GAsyncReadyCallback) async_init_get_name_owner_cb,
1515                           task);
1516 }
1517
1518 static void
1519 async_init_start_service_by_name_cb (GDBusConnection *connection,
1520                                      GAsyncResult    *res,
1521                                      gpointer         user_data)
1522 {
1523   GTask *task = user_data;
1524   GDBusProxy *proxy = g_task_get_source_object (task);
1525   GError *error;
1526   GVariant *result;
1527
1528   error = NULL;
1529   result = g_dbus_connection_call_finish (connection,
1530                                           res,
1531                                           &error);
1532   if (result == NULL)
1533     {
1534       /* Errors are not unexpected; the bus will reply e.g.
1535        *
1536        *   org.freedesktop.DBus.Error.ServiceUnknown: The name org.gnome.Epiphany2
1537        *   was not provided by any .service files
1538        *
1539        * or (see #677718)
1540        *
1541        *   org.freedesktop.systemd1.Masked: Unit polkit.service is masked.
1542        *
1543        * This doesn't mean that the name doesn't have an owner, just
1544        * that it's not provided by a .service file or can't currently
1545        * be started.
1546        *
1547        * In particular, in both cases, it could be that a service
1548        * owner will actually appear later. So instead of erroring out,
1549        * we just proceed to invoke GetNameOwner() if dealing with the
1550        * kind of errors above.
1551        */
1552       if (error->domain == G_DBUS_ERROR && error->code == G_DBUS_ERROR_SERVICE_UNKNOWN)
1553         {
1554           g_error_free (error);
1555         }
1556       else
1557         {
1558           gchar *remote_error = g_dbus_error_get_remote_error (error);
1559           if (g_strcmp0 (remote_error, "org.freedesktop.systemd1.Masked") == 0)
1560             {
1561               g_error_free (error);
1562               g_free (remote_error);
1563             }
1564           else
1565             {
1566               g_dbus_error_strip_remote_error (error);
1567               g_prefix_error (&error,
1568                               _("Error calling StartServiceByName for %s: "),
1569                               proxy->priv->name);
1570               g_free (remote_error);
1571               goto failed;
1572             }
1573         }
1574     }
1575   else
1576     {
1577       guint32 start_service_result;
1578       g_variant_get (result,
1579                      "(u)",
1580                      &start_service_result);
1581       g_variant_unref (result);
1582       if (start_service_result == 1 ||  /* DBUS_START_REPLY_SUCCESS */
1583           start_service_result == 2)    /* DBUS_START_REPLY_ALREADY_RUNNING */
1584         {
1585           /* continue to invoke GetNameOwner() */
1586         }
1587       else
1588         {
1589           error = g_error_new (G_IO_ERROR,
1590                                G_IO_ERROR_FAILED,
1591                                _("Unexpected reply %d from StartServiceByName(\"%s\") method"),
1592                                start_service_result,
1593                                proxy->priv->name);
1594           goto failed;
1595         }
1596     }
1597
1598   async_init_call_get_name_owner (task);
1599   return;
1600
1601  failed:
1602   g_warn_if_fail (error != NULL);
1603   g_task_return_error (task, error);
1604   g_object_unref (task);
1605 }
1606
1607 static void
1608 async_init_call_start_service_by_name (GTask *task)
1609 {
1610   GDBusProxy *proxy = g_task_get_source_object (task);
1611
1612   g_dbus_connection_call (proxy->priv->connection,
1613                           "org.freedesktop.DBus",  /* name */
1614                           "/org/freedesktop/DBus", /* object path */
1615                           "org.freedesktop.DBus",  /* interface */
1616                           "StartServiceByName",
1617                           g_variant_new ("(su)",
1618                                          proxy->priv->name,
1619                                          0),
1620                           G_VARIANT_TYPE ("(u)"),
1621                           G_DBUS_CALL_FLAGS_NONE,
1622                           -1,           /* timeout */
1623                           g_task_get_cancellable (task),
1624                           (GAsyncReadyCallback) async_init_start_service_by_name_cb,
1625                           task);
1626 }
1627
1628 static void
1629 async_initable_init_second_async (GAsyncInitable      *initable,
1630                                   gint                 io_priority,
1631                                   GCancellable        *cancellable,
1632                                   GAsyncReadyCallback  callback,
1633                                   gpointer             user_data)
1634 {
1635   GDBusProxy *proxy = G_DBUS_PROXY (initable);
1636   GTask *task;
1637
1638   task = g_task_new (proxy, cancellable, callback, user_data);
1639   g_task_set_source_tag (task, async_initable_init_second_async);
1640   g_task_set_name (task, "[gio] D-Bus proxy init");
1641   g_task_set_priority (task, io_priority);
1642
1643   /* Check name ownership asynchronously - possibly also start the service */
1644   if (proxy->priv->name == NULL)
1645     {
1646       /* Do nothing */
1647       async_init_data_set_name_owner (task, NULL);
1648     }
1649   else if (g_dbus_is_unique_name (proxy->priv->name))
1650     {
1651       async_init_data_set_name_owner (task, proxy->priv->name);
1652     }
1653   else
1654     {
1655       if ((proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START) ||
1656           (proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START_AT_CONSTRUCTION))
1657         {
1658           async_init_call_get_name_owner (task);
1659         }
1660       else
1661         {
1662           async_init_call_start_service_by_name (task);
1663         }
1664     }
1665 }
1666
1667 static gboolean
1668 async_initable_init_second_finish (GAsyncInitable  *initable,
1669                                    GAsyncResult    *res,
1670                                    GError         **error)
1671 {
1672   GDBusProxy *proxy = G_DBUS_PROXY (initable);
1673   GTask *task = G_TASK (res);
1674   GVariant *result;
1675   gboolean ret;
1676
1677   ret = !g_task_had_error (task);
1678
1679   result = g_task_propagate_pointer (task, error);
1680   if (result != NULL)
1681     {
1682       process_get_all_reply (proxy, result);
1683       g_variant_unref (result);
1684     }
1685
1686   proxy->priv->initialized = TRUE;
1687   return ret;
1688 }
1689
1690 /* ---------------------------------------------------------------------------------------------------- */
1691
1692 static void
1693 async_initable_init_first (GAsyncInitable *initable)
1694 {
1695   GDBusProxy *proxy = G_DBUS_PROXY (initable);
1696   GDBusSignalFlags signal_flags = G_DBUS_SIGNAL_FLAGS_NONE;
1697
1698   if (proxy->priv->flags & G_DBUS_PROXY_FLAGS_NO_MATCH_RULE)
1699     signal_flags |= G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE;
1700
1701   if (!(proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES))
1702     {
1703       /* subscribe to PropertiesChanged() */
1704       proxy->priv->properties_changed_subscription_id =
1705         g_dbus_connection_signal_subscribe (proxy->priv->connection,
1706                                             proxy->priv->name,
1707                                             "org.freedesktop.DBus.Properties",
1708                                             "PropertiesChanged",
1709                                             proxy->priv->object_path,
1710                                             proxy->priv->interface_name,
1711                                             signal_flags,
1712                                             on_properties_changed,
1713                                             weak_ref_new (G_OBJECT (proxy)),
1714                                             (GDestroyNotify) weak_ref_free);
1715     }
1716
1717   if (!(proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS))
1718     {
1719       /* subscribe to all signals for the object */
1720       proxy->priv->signals_subscription_id =
1721         g_dbus_connection_signal_subscribe (proxy->priv->connection,
1722                                             proxy->priv->name,
1723                                             proxy->priv->interface_name,
1724                                             NULL,                        /* member */
1725                                             proxy->priv->object_path,
1726                                             NULL,                        /* arg0 */
1727                                             signal_flags,
1728                                             on_signal_received,
1729                                             weak_ref_new (G_OBJECT (proxy)),
1730                                             (GDestroyNotify) weak_ref_free);
1731     }
1732
1733   if (proxy->priv->name != NULL &&
1734       (g_dbus_connection_get_flags (proxy->priv->connection) & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION))
1735     {
1736       proxy->priv->name_owner_changed_subscription_id =
1737         g_dbus_connection_signal_subscribe (proxy->priv->connection,
1738                                             "org.freedesktop.DBus",  /* name */
1739                                             "org.freedesktop.DBus",  /* interface */
1740                                             "NameOwnerChanged",      /* signal name */
1741                                             "/org/freedesktop/DBus", /* path */
1742                                             proxy->priv->name,       /* arg0 */
1743                                             signal_flags,
1744                                             on_name_owner_changed,
1745                                             weak_ref_new (G_OBJECT (proxy)),
1746                                             (GDestroyNotify) weak_ref_free);
1747     }
1748 }
1749
1750 /* ---------------------------------------------------------------------------------------------------- */
1751
1752 /* initialization is split into two parts - the first is the
1753  * non-blocking part that requires the callers GMainContext - the
1754  * second is a blocking part async part that doesn't require the
1755  * callers GMainContext.. we do this split so the code can be reused
1756  * in the GInitable implementation below.
1757  *
1758  * Note that obtaining a GDBusConnection is not shared between the two
1759  * paths.
1760  */
1761
1762 static void
1763 init_second_async_cb (GObject       *source_object,
1764                       GAsyncResult  *res,
1765                       gpointer       user_data)
1766 {
1767   GTask *task = user_data;
1768   GError *error = NULL;
1769
1770   if (async_initable_init_second_finish (G_ASYNC_INITABLE (source_object), res, &error))
1771     g_task_return_boolean (task, TRUE);
1772   else
1773     g_task_return_error (task, error);
1774   g_object_unref (task);
1775 }
1776
1777 static void
1778 get_connection_cb (GObject       *source_object,
1779                    GAsyncResult  *res,
1780                    gpointer       user_data)
1781 {
1782   GTask *task = user_data;
1783   GDBusProxy *proxy = g_task_get_source_object (task);
1784   GError *error;
1785
1786   error = NULL;
1787   proxy->priv->connection = g_bus_get_finish (res, &error);
1788   if (proxy->priv->connection == NULL)
1789     {
1790       g_task_return_error (task, error);
1791       g_object_unref (task);
1792     }
1793   else
1794     {
1795       async_initable_init_first (G_ASYNC_INITABLE (proxy));
1796       async_initable_init_second_async (G_ASYNC_INITABLE (proxy),
1797                                         g_task_get_priority (task),
1798                                         g_task_get_cancellable (task),
1799                                         init_second_async_cb,
1800                                         task);
1801     }
1802 }
1803
1804 static void
1805 async_initable_init_async (GAsyncInitable      *initable,
1806                            gint                 io_priority,
1807                            GCancellable        *cancellable,
1808                            GAsyncReadyCallback  callback,
1809                            gpointer             user_data)
1810 {
1811   GDBusProxy *proxy = G_DBUS_PROXY (initable);
1812   GTask *task;
1813
1814   task = g_task_new (proxy, cancellable, callback, user_data);
1815   g_task_set_source_tag (task, async_initable_init_async);
1816   g_task_set_name (task, "[gio] D-Bus proxy init");
1817   g_task_set_priority (task, io_priority);
1818
1819   if (proxy->priv->bus_type != G_BUS_TYPE_NONE)
1820     {
1821       g_assert (proxy->priv->connection == NULL);
1822
1823       g_bus_get (proxy->priv->bus_type,
1824                  cancellable,
1825                  get_connection_cb,
1826                  task);
1827     }
1828   else
1829     {
1830       async_initable_init_first (initable);
1831       async_initable_init_second_async (initable, io_priority, cancellable,
1832                                         init_second_async_cb, task);
1833     }
1834 }
1835
1836 static gboolean
1837 async_initable_init_finish (GAsyncInitable  *initable,
1838                             GAsyncResult    *res,
1839                             GError         **error)
1840 {
1841   return g_task_propagate_boolean (G_TASK (res), error);
1842 }
1843
1844 static void
1845 async_initable_iface_init (GAsyncInitableIface *async_initable_iface)
1846 {
1847   async_initable_iface->init_async = async_initable_init_async;
1848   async_initable_iface->init_finish = async_initable_init_finish;
1849 }
1850
1851 /* ---------------------------------------------------------------------------------------------------- */
1852
1853 typedef struct
1854 {
1855   GMainContext *context;
1856   GMainLoop *loop;
1857   GAsyncResult *res;
1858 } InitableAsyncInitableData;
1859
1860 static void
1861 async_initable_init_async_cb (GObject      *source_object,
1862                               GAsyncResult *res,
1863                               gpointer      user_data)
1864 {
1865   InitableAsyncInitableData *data = user_data;
1866   data->res = g_object_ref (res);
1867   g_main_loop_quit (data->loop);
1868 }
1869
1870 /* Simply reuse the GAsyncInitable implementation but run the first
1871  * part (that is non-blocking and requires the callers GMainContext)
1872  * with the callers GMainContext.. and the second with a private
1873  * GMainContext (bug 621310 is slightly related).
1874  *
1875  * Note that obtaining a GDBusConnection is not shared between the two
1876  * paths.
1877  */
1878 static gboolean
1879 initable_init (GInitable     *initable,
1880                GCancellable  *cancellable,
1881                GError       **error)
1882 {
1883   GDBusProxy *proxy = G_DBUS_PROXY (initable);
1884   InitableAsyncInitableData *data;
1885   gboolean ret;
1886
1887   ret = FALSE;
1888
1889   if (proxy->priv->bus_type != G_BUS_TYPE_NONE)
1890     {
1891       g_assert (proxy->priv->connection == NULL);
1892       proxy->priv->connection = g_bus_get_sync (proxy->priv->bus_type,
1893                                                 cancellable,
1894                                                 error);
1895       if (proxy->priv->connection == NULL)
1896         goto out;
1897     }
1898
1899   async_initable_init_first (G_ASYNC_INITABLE (initable));
1900
1901   data = g_new0 (InitableAsyncInitableData, 1);
1902   data->context = g_main_context_new ();
1903   data->loop = g_main_loop_new (data->context, FALSE);
1904
1905   g_main_context_push_thread_default (data->context);
1906
1907   async_initable_init_second_async (G_ASYNC_INITABLE (initable),
1908                                     G_PRIORITY_DEFAULT,
1909                                     cancellable,
1910                                     async_initable_init_async_cb,
1911                                     data);
1912
1913   g_main_loop_run (data->loop);
1914
1915   ret = async_initable_init_second_finish (G_ASYNC_INITABLE (initable),
1916                                            data->res,
1917                                            error);
1918
1919   g_main_context_pop_thread_default (data->context);
1920
1921   g_main_context_unref (data->context);
1922   g_main_loop_unref (data->loop);
1923   g_object_unref (data->res);
1924   g_free (data);
1925
1926  out:
1927
1928   return ret;
1929 }
1930
1931 static void
1932 initable_iface_init (GInitableIface *initable_iface)
1933 {
1934   initable_iface->init = initable_init;
1935 }
1936
1937 /* ---------------------------------------------------------------------------------------------------- */
1938
1939 /**
1940  * g_dbus_proxy_new:
1941  * @connection: A #GDBusConnection.
1942  * @flags: Flags used when constructing the proxy.
1943  * @info: (nullable): A #GDBusInterfaceInfo specifying the minimal interface that @proxy conforms to or %NULL.
1944  * @name: (nullable): A bus name (well-known or unique) or %NULL if @connection is not a message bus connection.
1945  * @object_path: An object path.
1946  * @interface_name: A D-Bus interface name.
1947  * @cancellable: (nullable): A #GCancellable or %NULL.
1948  * @callback: Callback function to invoke when the proxy is ready.
1949  * @user_data: User data to pass to @callback.
1950  *
1951  * Creates a proxy for accessing @interface_name on the remote object
1952  * at @object_path owned by @name at @connection and asynchronously
1953  * loads D-Bus properties unless the
1954  * %G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES flag is used. Connect to
1955  * the #GDBusProxy::g-properties-changed signal to get notified about
1956  * property changes.
1957  *
1958  * If the %G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS flag is not set, also sets up
1959  * match rules for signals. Connect to the #GDBusProxy::g-signal signal
1960  * to handle signals from the remote object.
1961  *
1962  * If both %G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES and
1963  * %G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS are set, this constructor is
1964  * guaranteed to complete immediately without blocking.
1965  *
1966  * If @name is a well-known name and the
1967  * %G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START and %G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START_AT_CONSTRUCTION
1968  * flags aren't set and no name owner currently exists, the message bus
1969  * will be requested to launch a name owner for the name.
1970  *
1971  * This is a failable asynchronous constructor - when the proxy is
1972  * ready, @callback will be invoked and you can use
1973  * g_dbus_proxy_new_finish() to get the result.
1974  *
1975  * See g_dbus_proxy_new_sync() and for a synchronous version of this constructor.
1976  *
1977  * #GDBusProxy is used in this [example][gdbus-wellknown-proxy].
1978  *
1979  * Since: 2.26
1980  */
1981 void
1982 g_dbus_proxy_new (GDBusConnection     *connection,
1983                   GDBusProxyFlags      flags,
1984                   GDBusInterfaceInfo  *info,
1985                   const gchar         *name,
1986                   const gchar         *object_path,
1987                   const gchar         *interface_name,
1988                   GCancellable        *cancellable,
1989                   GAsyncReadyCallback  callback,
1990                   gpointer             user_data)
1991 {
1992   _g_dbus_initialize ();
1993
1994   g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
1995   g_return_if_fail ((name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) || g_dbus_is_name (name));
1996   g_return_if_fail (g_variant_is_object_path (object_path));
1997   g_return_if_fail (g_dbus_is_interface_name (interface_name));
1998
1999   g_async_initable_new_async (G_TYPE_DBUS_PROXY,
2000                               G_PRIORITY_DEFAULT,
2001                               cancellable,
2002                               callback,
2003                               user_data,
2004                               "g-flags", flags,
2005                               "g-interface-info", info,
2006                               "g-name", name,
2007                               "g-connection", connection,
2008                               "g-object-path", object_path,
2009                               "g-interface-name", interface_name,
2010                               NULL);
2011 }
2012
2013 /**
2014  * g_dbus_proxy_new_finish:
2015  * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to g_dbus_proxy_new().
2016  * @error: Return location for error or %NULL.
2017  *
2018  * Finishes creating a #GDBusProxy.
2019  *
2020  * Returns: (transfer full): A #GDBusProxy or %NULL if @error is set.
2021  *    Free with g_object_unref().
2022  *
2023  * Since: 2.26
2024  */
2025 GDBusProxy *
2026 g_dbus_proxy_new_finish (GAsyncResult  *res,
2027                          GError       **error)
2028 {
2029   GObject *object;
2030   GObject *source_object;
2031
2032   source_object = g_async_result_get_source_object (res);
2033   g_assert (source_object != NULL);
2034
2035   object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
2036                                         res,
2037                                         error);
2038   g_object_unref (source_object);
2039
2040   if (object != NULL)
2041     return G_DBUS_PROXY (object);
2042   else
2043     return NULL;
2044 }
2045
2046 /**
2047  * g_dbus_proxy_new_sync:
2048  * @connection: A #GDBusConnection.
2049  * @flags: Flags used when constructing the proxy.
2050  * @info: (nullable): A #GDBusInterfaceInfo specifying the minimal interface that @proxy conforms to or %NULL.
2051  * @name: (nullable): A bus name (well-known or unique) or %NULL if @connection is not a message bus connection.
2052  * @object_path: An object path.
2053  * @interface_name: A D-Bus interface name.
2054  * @cancellable: (nullable): A #GCancellable or %NULL.
2055  * @error: (nullable): Return location for error or %NULL.
2056  *
2057  * Creates a proxy for accessing @interface_name on the remote object
2058  * at @object_path owned by @name at @connection and synchronously
2059  * loads D-Bus properties unless the
2060  * %G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES flag is used.
2061  *
2062  * If the %G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS flag is not set, also sets up
2063  * match rules for signals. Connect to the #GDBusProxy::g-signal signal
2064  * to handle signals from the remote object.
2065  *
2066  * If both %G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES and
2067  * %G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS are set, this constructor is
2068  * guaranteed to return immediately without blocking.
2069  *
2070  * If @name is a well-known name and the
2071  * %G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START and %G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START_AT_CONSTRUCTION
2072  * flags aren't set and no name owner currently exists, the message bus
2073  * will be requested to launch a name owner for the name.
2074  *
2075  * This is a synchronous failable constructor. See g_dbus_proxy_new()
2076  * and g_dbus_proxy_new_finish() for the asynchronous version.
2077  *
2078  * #GDBusProxy is used in this [example][gdbus-wellknown-proxy].
2079  *
2080  * Returns: (transfer full): A #GDBusProxy or %NULL if error is set.
2081  *    Free with g_object_unref().
2082  *
2083  * Since: 2.26
2084  */
2085 GDBusProxy *
2086 g_dbus_proxy_new_sync (GDBusConnection     *connection,
2087                        GDBusProxyFlags      flags,
2088                        GDBusInterfaceInfo  *info,
2089                        const gchar         *name,
2090                        const gchar         *object_path,
2091                        const gchar         *interface_name,
2092                        GCancellable        *cancellable,
2093                        GError             **error)
2094 {
2095   GInitable *initable;
2096
2097   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
2098   g_return_val_if_fail ((name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) ||
2099                         g_dbus_is_name (name), NULL);
2100   g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
2101   g_return_val_if_fail (g_dbus_is_interface_name (interface_name), NULL);
2102
2103   initable = g_initable_new (G_TYPE_DBUS_PROXY,
2104                              cancellable,
2105                              error,
2106                              "g-flags", flags,
2107                              "g-interface-info", info,
2108                              "g-name", name,
2109                              "g-connection", connection,
2110                              "g-object-path", object_path,
2111                              "g-interface-name", interface_name,
2112                              NULL);
2113   if (initable != NULL)
2114     return G_DBUS_PROXY (initable);
2115   else
2116     return NULL;
2117 }
2118
2119 /* ---------------------------------------------------------------------------------------------------- */
2120
2121 /**
2122  * g_dbus_proxy_new_for_bus:
2123  * @bus_type: A #GBusType.
2124  * @flags: Flags used when constructing the proxy.
2125  * @info: (nullable): A #GDBusInterfaceInfo specifying the minimal interface that @proxy conforms to or %NULL.
2126  * @name: A bus name (well-known or unique).
2127  * @object_path: An object path.
2128  * @interface_name: A D-Bus interface name.
2129  * @cancellable: (nullable): A #GCancellable or %NULL.
2130  * @callback: Callback function to invoke when the proxy is ready.
2131  * @user_data: User data to pass to @callback.
2132  *
2133  * Like g_dbus_proxy_new() but takes a #GBusType instead of a #GDBusConnection.
2134  *
2135  * #GDBusProxy is used in this [example][gdbus-wellknown-proxy].
2136  *
2137  * Since: 2.26
2138  */
2139 void
2140 g_dbus_proxy_new_for_bus (GBusType             bus_type,
2141                           GDBusProxyFlags      flags,
2142                           GDBusInterfaceInfo  *info,
2143                           const gchar         *name,
2144                           const gchar         *object_path,
2145                           const gchar         *interface_name,
2146                           GCancellable        *cancellable,
2147                           GAsyncReadyCallback  callback,
2148                           gpointer             user_data)
2149 {
2150   _g_dbus_initialize ();
2151
2152   g_return_if_fail (g_dbus_is_name (name));
2153   g_return_if_fail (g_variant_is_object_path (object_path));
2154   g_return_if_fail (g_dbus_is_interface_name (interface_name));
2155
2156   g_async_initable_new_async (G_TYPE_DBUS_PROXY,
2157                               G_PRIORITY_DEFAULT,
2158                               cancellable,
2159                               callback,
2160                               user_data,
2161                               "g-flags", flags,
2162                               "g-interface-info", info,
2163                               "g-name", name,
2164                               "g-bus-type", bus_type,
2165                               "g-object-path", object_path,
2166                               "g-interface-name", interface_name,
2167                               NULL);
2168 }
2169
2170 /**
2171  * g_dbus_proxy_new_for_bus_finish:
2172  * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to g_dbus_proxy_new_for_bus().
2173  * @error: Return location for error or %NULL.
2174  *
2175  * Finishes creating a #GDBusProxy.
2176  *
2177  * Returns: (transfer full): A #GDBusProxy or %NULL if @error is set.
2178  *    Free with g_object_unref().
2179  *
2180  * Since: 2.26
2181  */
2182 GDBusProxy *
2183 g_dbus_proxy_new_for_bus_finish (GAsyncResult  *res,
2184                                  GError       **error)
2185 {
2186   return g_dbus_proxy_new_finish (res, error);
2187 }
2188
2189 /**
2190  * g_dbus_proxy_new_for_bus_sync:
2191  * @bus_type: A #GBusType.
2192  * @flags: Flags used when constructing the proxy.
2193  * @info: (nullable): A #GDBusInterfaceInfo specifying the minimal interface
2194  *        that @proxy conforms to or %NULL.
2195  * @name: A bus name (well-known or unique).
2196  * @object_path: An object path.
2197  * @interface_name: A D-Bus interface name.
2198  * @cancellable: (nullable): A #GCancellable or %NULL.
2199  * @error: Return location for error or %NULL.
2200  *
2201  * Like g_dbus_proxy_new_sync() but takes a #GBusType instead of a #GDBusConnection.
2202  *
2203  * #GDBusProxy is used in this [example][gdbus-wellknown-proxy].
2204  *
2205  * Returns: (transfer full): A #GDBusProxy or %NULL if error is set.
2206  *    Free with g_object_unref().
2207  *
2208  * Since: 2.26
2209  */
2210 GDBusProxy *
2211 g_dbus_proxy_new_for_bus_sync (GBusType             bus_type,
2212                                GDBusProxyFlags      flags,
2213                                GDBusInterfaceInfo  *info,
2214                                const gchar         *name,
2215                                const gchar         *object_path,
2216                                const gchar         *interface_name,
2217                                GCancellable        *cancellable,
2218                                GError             **error)
2219 {
2220   GInitable *initable;
2221
2222   _g_dbus_initialize ();
2223
2224   g_return_val_if_fail (g_dbus_is_name (name), NULL);
2225   g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
2226   g_return_val_if_fail (g_dbus_is_interface_name (interface_name), NULL);
2227
2228   initable = g_initable_new (G_TYPE_DBUS_PROXY,
2229                              cancellable,
2230                              error,
2231                              "g-flags", flags,
2232                              "g-interface-info", info,
2233                              "g-name", name,
2234                              "g-bus-type", bus_type,
2235                              "g-object-path", object_path,
2236                              "g-interface-name", interface_name,
2237                              NULL);
2238   if (initable != NULL)
2239     return G_DBUS_PROXY (initable);
2240   else
2241     return NULL;
2242 }
2243
2244 /* ---------------------------------------------------------------------------------------------------- */
2245
2246 /**
2247  * g_dbus_proxy_get_connection:
2248  * @proxy: A #GDBusProxy.
2249  *
2250  * Gets the connection @proxy is for.
2251  *
2252  * Returns: (transfer none) (not nullable): A #GDBusConnection owned by @proxy. Do not free.
2253  *
2254  * Since: 2.26
2255  */
2256 GDBusConnection *
2257 g_dbus_proxy_get_connection (GDBusProxy *proxy)
2258 {
2259   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
2260   return proxy->priv->connection;
2261 }
2262
2263 /**
2264  * g_dbus_proxy_get_flags:
2265  * @proxy: A #GDBusProxy.
2266  *
2267  * Gets the flags that @proxy was constructed with.
2268  *
2269  * Returns: Flags from the #GDBusProxyFlags enumeration.
2270  *
2271  * Since: 2.26
2272  */
2273 GDBusProxyFlags
2274 g_dbus_proxy_get_flags (GDBusProxy *proxy)
2275 {
2276   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), 0);
2277   return proxy->priv->flags;
2278 }
2279
2280 /**
2281  * g_dbus_proxy_get_name:
2282  * @proxy: A #GDBusProxy.
2283  *
2284  * Gets the name that @proxy was constructed for.
2285  *
2286  * When connected to a message bus, this will usually be non-%NULL.
2287  * However, it may be %NULL for a proxy that communicates using a peer-to-peer
2288  * pattern.
2289  *
2290  * Returns: (nullable): A string owned by @proxy. Do not free.
2291  *
2292  * Since: 2.26
2293  */
2294 const gchar *
2295 g_dbus_proxy_get_name (GDBusProxy *proxy)
2296 {
2297   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
2298   return proxy->priv->name;
2299 }
2300
2301 /**
2302  * g_dbus_proxy_get_name_owner:
2303  * @proxy: A #GDBusProxy.
2304  *
2305  * The unique name that owns the name that @proxy is for or %NULL if
2306  * no-one currently owns that name. You may connect to the
2307  * #GObject::notify signal to track changes to the
2308  * #GDBusProxy:g-name-owner property.
2309  *
2310  * Returns: (transfer full) (nullable): The name owner or %NULL if no name
2311  *    owner exists. Free with g_free().
2312  *
2313  * Since: 2.26
2314  */
2315 gchar *
2316 g_dbus_proxy_get_name_owner (GDBusProxy *proxy)
2317 {
2318   gchar *ret;
2319
2320   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
2321
2322   G_LOCK (properties_lock);
2323   ret = g_strdup (proxy->priv->name_owner);
2324   G_UNLOCK (properties_lock);
2325   return ret;
2326 }
2327
2328 /**
2329  * g_dbus_proxy_get_object_path:
2330  * @proxy: A #GDBusProxy.
2331  *
2332  * Gets the object path @proxy is for.
2333  *
2334  * Returns: (not nullable): A string owned by @proxy. Do not free.
2335  *
2336  * Since: 2.26
2337  */
2338 const gchar *
2339 g_dbus_proxy_get_object_path (GDBusProxy *proxy)
2340 {
2341   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
2342   return proxy->priv->object_path;
2343 }
2344
2345 /**
2346  * g_dbus_proxy_get_interface_name:
2347  * @proxy: A #GDBusProxy.
2348  *
2349  * Gets the D-Bus interface name @proxy is for.
2350  *
2351  * Returns: (not nullable): A string owned by @proxy. Do not free.
2352  *
2353  * Since: 2.26
2354  */
2355 const gchar *
2356 g_dbus_proxy_get_interface_name (GDBusProxy *proxy)
2357 {
2358   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
2359   return proxy->priv->interface_name;
2360 }
2361
2362 /**
2363  * g_dbus_proxy_get_default_timeout:
2364  * @proxy: A #GDBusProxy.
2365  *
2366  * Gets the timeout to use if -1 (specifying default timeout) is
2367  * passed as @timeout_msec in the g_dbus_proxy_call() and
2368  * g_dbus_proxy_call_sync() functions.
2369  *
2370  * See the #GDBusProxy:g-default-timeout property for more details.
2371  *
2372  * Returns: Timeout to use for @proxy.
2373  *
2374  * Since: 2.26
2375  */
2376 gint
2377 g_dbus_proxy_get_default_timeout (GDBusProxy *proxy)
2378 {
2379   gint ret;
2380
2381   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), -1);
2382
2383   G_LOCK (properties_lock);
2384   ret = proxy->priv->timeout_msec;
2385   G_UNLOCK (properties_lock);
2386   return ret;
2387 }
2388
2389 /**
2390  * g_dbus_proxy_set_default_timeout:
2391  * @proxy: A #GDBusProxy.
2392  * @timeout_msec: Timeout in milliseconds.
2393  *
2394  * Sets the timeout to use if -1 (specifying default timeout) is
2395  * passed as @timeout_msec in the g_dbus_proxy_call() and
2396  * g_dbus_proxy_call_sync() functions.
2397  *
2398  * See the #GDBusProxy:g-default-timeout property for more details.
2399  *
2400  * Since: 2.26
2401  */
2402 void
2403 g_dbus_proxy_set_default_timeout (GDBusProxy *proxy,
2404                                   gint        timeout_msec)
2405 {
2406   g_return_if_fail (G_IS_DBUS_PROXY (proxy));
2407   g_return_if_fail (timeout_msec == -1 || timeout_msec >= 0);
2408
2409   G_LOCK (properties_lock);
2410
2411   if (proxy->priv->timeout_msec != timeout_msec)
2412     {
2413       proxy->priv->timeout_msec = timeout_msec;
2414       G_UNLOCK (properties_lock);
2415
2416       g_object_notify (G_OBJECT (proxy), "g-default-timeout");
2417     }
2418   else
2419     {
2420       G_UNLOCK (properties_lock);
2421     }
2422 }
2423
2424 /**
2425  * g_dbus_proxy_get_interface_info:
2426  * @proxy: A #GDBusProxy
2427  *
2428  * Returns the #GDBusInterfaceInfo, if any, specifying the interface
2429  * that @proxy conforms to. See the #GDBusProxy:g-interface-info
2430  * property for more details.
2431  *
2432  * Returns: (transfer none) (nullable): A #GDBusInterfaceInfo or %NULL.
2433  *    Do not unref the returned object, it is owned by @proxy.
2434  *
2435  * Since: 2.26
2436  */
2437 GDBusInterfaceInfo *
2438 g_dbus_proxy_get_interface_info (GDBusProxy *proxy)
2439 {
2440   GDBusInterfaceInfo *ret;
2441
2442   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
2443
2444   G_LOCK (properties_lock);
2445   ret = proxy->priv->expected_interface;
2446   G_UNLOCK (properties_lock);
2447   /* FIXME: returning a borrowed ref with no guarantee that nobody will
2448    * call g_dbus_proxy_set_interface_info() and make it invalid...
2449    */
2450   return ret;
2451 }
2452
2453 /**
2454  * g_dbus_proxy_set_interface_info:
2455  * @proxy: A #GDBusProxy
2456  * @info: (transfer none) (nullable): Minimum interface this proxy conforms to
2457  *    or %NULL to unset.
2458  *
2459  * Ensure that interactions with @proxy conform to the given
2460  * interface. See the #GDBusProxy:g-interface-info property for more
2461  * details.
2462  *
2463  * Since: 2.26
2464  */
2465 void
2466 g_dbus_proxy_set_interface_info (GDBusProxy         *proxy,
2467                                  GDBusInterfaceInfo *info)
2468 {
2469   g_return_if_fail (G_IS_DBUS_PROXY (proxy));
2470   G_LOCK (properties_lock);
2471
2472   if (proxy->priv->expected_interface != NULL)
2473     {
2474       g_dbus_interface_info_cache_release (proxy->priv->expected_interface);
2475       g_dbus_interface_info_unref (proxy->priv->expected_interface);
2476     }
2477   proxy->priv->expected_interface = info != NULL ? g_dbus_interface_info_ref (info) : NULL;
2478   if (proxy->priv->expected_interface != NULL)
2479     g_dbus_interface_info_cache_build (proxy->priv->expected_interface);
2480
2481   G_UNLOCK (properties_lock);
2482 }
2483
2484 /* ---------------------------------------------------------------------------------------------------- */
2485
2486 static gboolean
2487 maybe_split_method_name (const gchar  *method_name,
2488                          gchar       **out_interface_name,
2489                          const gchar **out_method_name)
2490 {
2491   gboolean was_split;
2492
2493   was_split = FALSE;
2494   g_assert (out_interface_name != NULL);
2495   g_assert (out_method_name != NULL);
2496   *out_interface_name = NULL;
2497   *out_method_name = NULL;
2498
2499   if (strchr (method_name, '.') != NULL)
2500     {
2501       gchar *p;
2502       gchar *last_dot;
2503
2504       p = g_strdup (method_name);
2505       last_dot = strrchr (p, '.');
2506       *last_dot = '\0';
2507
2508       *out_interface_name = p;
2509       *out_method_name = last_dot + 1;
2510
2511       was_split = TRUE;
2512     }
2513
2514   return was_split;
2515 }
2516
2517 typedef struct
2518 {
2519   GVariant *value;
2520 #ifdef G_OS_UNIX
2521   GUnixFDList *fd_list;
2522 #endif
2523 } ReplyData;
2524
2525 static void
2526 reply_data_free (ReplyData *data)
2527 {
2528   g_variant_unref (data->value);
2529 #ifdef G_OS_UNIX
2530   if (data->fd_list != NULL)
2531     g_object_unref (data->fd_list);
2532 #endif
2533   g_slice_free (ReplyData, data);
2534 }
2535
2536 static void
2537 reply_cb (GDBusConnection *connection,
2538           GAsyncResult    *res,
2539           gpointer         user_data)
2540 {
2541   GTask *task = user_data;
2542   GVariant *value;
2543   GError *error;
2544 #ifdef G_OS_UNIX
2545   GUnixFDList *fd_list;
2546 #endif
2547
2548   error = NULL;
2549 #ifdef G_OS_UNIX
2550   value = g_dbus_connection_call_with_unix_fd_list_finish (connection,
2551                                                            &fd_list,
2552                                                            res,
2553                                                            &error);
2554 #else
2555   value = g_dbus_connection_call_finish (connection,
2556                                          res,
2557                                          &error);
2558 #endif
2559   if (error != NULL)
2560     {
2561       g_task_return_error (task, error);
2562     }
2563   else
2564     {
2565       ReplyData *data;
2566       data = g_slice_new0 (ReplyData);
2567       data->value = value;
2568 #ifdef G_OS_UNIX
2569       data->fd_list = fd_list;
2570 #endif
2571       g_task_return_pointer (task, data, (GDestroyNotify) reply_data_free);
2572     }
2573
2574   g_object_unref (task);
2575 }
2576
2577 /* properties_lock must be held for as long as you will keep the
2578  * returned value
2579  */
2580 static const GDBusMethodInfo *
2581 lookup_method_info (GDBusProxy  *proxy,
2582                     const gchar *method_name)
2583 {
2584   const GDBusMethodInfo *info = NULL;
2585
2586   if (proxy->priv->expected_interface == NULL)
2587     goto out;
2588
2589   info = g_dbus_interface_info_lookup_method (proxy->priv->expected_interface, method_name);
2590
2591 out:
2592   return info;
2593 }
2594
2595 /* properties_lock must be held for as long as you will keep the
2596  * returned value
2597  */
2598 static const gchar *
2599 get_destination_for_call (GDBusProxy *proxy)
2600 {
2601   const gchar *ret;
2602
2603   ret = NULL;
2604
2605   /* If proxy->priv->name is a unique name, then proxy->priv->name_owner
2606    * is never NULL and always the same as proxy->priv->name. We use this
2607    * knowledge to avoid checking if proxy->priv->name is a unique or
2608    * well-known name.
2609    */
2610   ret = proxy->priv->name_owner;
2611   if (ret != NULL)
2612     goto out;
2613
2614   if (proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START)
2615     goto out;
2616
2617   ret = proxy->priv->name;
2618
2619  out:
2620   return ret;
2621 }
2622
2623 /* ---------------------------------------------------------------------------------------------------- */
2624
2625 static void
2626 g_dbus_proxy_call_internal (GDBusProxy          *proxy,
2627                             const gchar         *method_name,
2628                             GVariant            *parameters,
2629                             GDBusCallFlags       flags,
2630                             gint                 timeout_msec,
2631                             GUnixFDList         *fd_list,
2632                             GCancellable        *cancellable,
2633                             GAsyncReadyCallback  callback,
2634                             gpointer             user_data)
2635 {
2636   GTask *task;
2637   gboolean was_split;
2638   gchar *split_interface_name;
2639   const gchar *split_method_name;
2640   const gchar *target_method_name;
2641   const gchar *target_interface_name;
2642   gchar *destination;
2643   GVariantType *reply_type;
2644   GAsyncReadyCallback my_callback;
2645
2646   g_return_if_fail (G_IS_DBUS_PROXY (proxy));
2647   g_return_if_fail (g_dbus_is_member_name (method_name) || g_dbus_is_interface_name (method_name));
2648   g_return_if_fail (parameters == NULL || g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE));
2649   g_return_if_fail (timeout_msec == -1 || timeout_msec >= 0);
2650 #ifdef G_OS_UNIX
2651   g_return_if_fail (fd_list == NULL || G_IS_UNIX_FD_LIST (fd_list));
2652 #else
2653   g_return_if_fail (fd_list == NULL);
2654 #endif
2655
2656   reply_type = NULL;
2657   split_interface_name = NULL;
2658
2659   /* g_dbus_connection_call() is optimised for the case of a NULL
2660    * callback.  If we get a NULL callback from our user then make sure
2661    * we pass along a NULL callback for ourselves as well.
2662    */
2663   if (callback != NULL)
2664     {
2665       my_callback = (GAsyncReadyCallback) reply_cb;
2666       task = g_task_new (proxy, cancellable, callback, user_data);
2667       g_task_set_source_tag (task, g_dbus_proxy_call_internal);
2668       g_task_set_name (task, "[gio] D-Bus proxy call");
2669     }
2670   else
2671     {
2672       my_callback = NULL;
2673       task = NULL;
2674     }
2675
2676   G_LOCK (properties_lock);
2677
2678   was_split = maybe_split_method_name (method_name, &split_interface_name, &split_method_name);
2679   target_method_name = was_split ? split_method_name : method_name;
2680   target_interface_name = was_split ? split_interface_name : proxy->priv->interface_name;
2681
2682   /* Warn if method is unexpected (cf. :g-interface-info) */
2683   if (!was_split)
2684     {
2685       const GDBusMethodInfo *expected_method_info;
2686       expected_method_info = lookup_method_info (proxy, target_method_name);
2687       if (expected_method_info != NULL)
2688         reply_type = _g_dbus_compute_complete_signature (expected_method_info->out_args);
2689     }
2690
2691   destination = NULL;
2692   if (proxy->priv->name != NULL)
2693     {
2694       destination = g_strdup (get_destination_for_call (proxy));
2695       if (destination == NULL)
2696         {
2697           if (task != NULL)
2698             {
2699               g_task_return_new_error (task,
2700                                        G_IO_ERROR,
2701                                        G_IO_ERROR_FAILED,
2702                                        _("Cannot invoke method; proxy is for the well-known name %s without an owner, and proxy was constructed with the G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START flag"),
2703                                        proxy->priv->name);
2704               g_object_unref (task);
2705             }
2706           G_UNLOCK (properties_lock);
2707           goto out;
2708         }
2709     }
2710
2711   G_UNLOCK (properties_lock);
2712
2713 #ifdef G_OS_UNIX
2714   g_dbus_connection_call_with_unix_fd_list (proxy->priv->connection,
2715                                             destination,
2716                                             proxy->priv->object_path,
2717                                             target_interface_name,
2718                                             target_method_name,
2719                                             parameters,
2720                                             reply_type,
2721                                             flags,
2722                                             timeout_msec == -1 ? proxy->priv->timeout_msec : timeout_msec,
2723                                             fd_list,
2724                                             cancellable,
2725                                             my_callback,
2726                                             task);
2727 #else
2728   g_dbus_connection_call (proxy->priv->connection,
2729                           destination,
2730                           proxy->priv->object_path,
2731                           target_interface_name,
2732                           target_method_name,
2733                           parameters,
2734                           reply_type,
2735                           flags,
2736                           timeout_msec == -1 ? proxy->priv->timeout_msec : timeout_msec,
2737                           cancellable,
2738                           my_callback,
2739                           task);
2740 #endif
2741
2742  out:
2743   if (reply_type != NULL)
2744     g_variant_type_free (reply_type);
2745
2746   g_free (destination);
2747   g_free (split_interface_name);
2748 }
2749
2750 static GVariant *
2751 g_dbus_proxy_call_finish_internal (GDBusProxy    *proxy,
2752                                    GUnixFDList  **out_fd_list,
2753                                    GAsyncResult  *res,
2754                                    GError       **error)
2755 {
2756   GVariant *value;
2757   ReplyData *data;
2758
2759   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
2760   g_return_val_if_fail (g_task_is_valid (res, proxy), NULL);
2761   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2762
2763   value = NULL;
2764
2765   data = g_task_propagate_pointer (G_TASK (res), error);
2766   if (!data)
2767     goto out;
2768
2769   value = g_variant_ref (data->value);
2770 #ifdef G_OS_UNIX
2771   if (out_fd_list != NULL)
2772     *out_fd_list = data->fd_list != NULL ? g_object_ref (data->fd_list) : NULL;
2773 #endif
2774   reply_data_free (data);
2775
2776  out:
2777   return value;
2778 }
2779
2780 static GVariant *
2781 g_dbus_proxy_call_sync_internal (GDBusProxy      *proxy,
2782                                  const gchar     *method_name,
2783                                  GVariant        *parameters,
2784                                  GDBusCallFlags   flags,
2785                                  gint             timeout_msec,
2786                                  GUnixFDList     *fd_list,
2787                                  GUnixFDList    **out_fd_list,
2788                                  GCancellable    *cancellable,
2789                                  GError         **error)
2790 {
2791   GVariant *ret;
2792   gboolean was_split;
2793   gchar *split_interface_name;
2794   const gchar *split_method_name;
2795   const gchar *target_method_name;
2796   const gchar *target_interface_name;
2797   gchar *destination;
2798   GVariantType *reply_type;
2799
2800   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
2801   g_return_val_if_fail (g_dbus_is_member_name (method_name) || g_dbus_is_interface_name (method_name), NULL);
2802   g_return_val_if_fail (parameters == NULL || g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE), NULL);
2803   g_return_val_if_fail (timeout_msec == -1 || timeout_msec >= 0, NULL);
2804 #ifdef G_OS_UNIX
2805   g_return_val_if_fail (fd_list == NULL || G_IS_UNIX_FD_LIST (fd_list), NULL);
2806 #else
2807   g_return_val_if_fail (fd_list == NULL, NULL);
2808 #endif
2809   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2810
2811   reply_type = NULL;
2812
2813   G_LOCK (properties_lock);
2814
2815   was_split = maybe_split_method_name (method_name, &split_interface_name, &split_method_name);
2816   target_method_name = was_split ? split_method_name : method_name;
2817   target_interface_name = was_split ? split_interface_name : proxy->priv->interface_name;
2818
2819   /* Warn if method is unexpected (cf. :g-interface-info) */
2820   if (!was_split)
2821     {
2822       const GDBusMethodInfo *expected_method_info;
2823       expected_method_info = lookup_method_info (proxy, target_method_name);
2824       if (expected_method_info != NULL)
2825         reply_type = _g_dbus_compute_complete_signature (expected_method_info->out_args);
2826     }
2827
2828   destination = NULL;
2829   if (proxy->priv->name != NULL)
2830     {
2831       destination = g_strdup (get_destination_for_call (proxy));
2832       if (destination == NULL)
2833         {
2834           g_set_error (error,
2835                        G_IO_ERROR,
2836                        G_IO_ERROR_FAILED,
2837                        _("Cannot invoke method; proxy is for the well-known name %s without an owner, and proxy was constructed with the G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START flag"),
2838                        proxy->priv->name);
2839           ret = NULL;
2840           G_UNLOCK (properties_lock);
2841           goto out;
2842         }
2843     }
2844
2845   G_UNLOCK (properties_lock);
2846
2847 #ifdef G_OS_UNIX
2848   ret = g_dbus_connection_call_with_unix_fd_list_sync (proxy->priv->connection,
2849                                                        destination,
2850                                                        proxy->priv->object_path,
2851                                                        target_interface_name,
2852                                                        target_method_name,
2853                                                        parameters,
2854                                                        reply_type,
2855                                                        flags,
2856                                                        timeout_msec == -1 ? proxy->priv->timeout_msec : timeout_msec,
2857                                                        fd_list,
2858                                                        out_fd_list,
2859                                                        cancellable,
2860                                                        error);
2861 #else
2862   ret = g_dbus_connection_call_sync (proxy->priv->connection,
2863                                      destination,
2864                                      proxy->priv->object_path,
2865                                      target_interface_name,
2866                                      target_method_name,
2867                                      parameters,
2868                                      reply_type,
2869                                      flags,
2870                                      timeout_msec == -1 ? proxy->priv->timeout_msec : timeout_msec,
2871                                      cancellable,
2872                                      error);
2873 #endif
2874
2875  out:
2876   if (reply_type != NULL)
2877     g_variant_type_free (reply_type);
2878
2879   g_free (destination);
2880   g_free (split_interface_name);
2881
2882   return ret;
2883 }
2884
2885 /* ---------------------------------------------------------------------------------------------------- */
2886
2887 /**
2888  * g_dbus_proxy_call:
2889  * @proxy: A #GDBusProxy.
2890  * @method_name: Name of method to invoke.
2891  * @parameters: (nullable): A #GVariant tuple with parameters for the signal or %NULL if not passing parameters.
2892  * @flags: Flags from the #GDBusCallFlags enumeration.
2893  * @timeout_msec: The timeout in milliseconds (with %G_MAXINT meaning
2894  *                "infinite") or -1 to use the proxy default timeout.
2895  * @cancellable: (nullable): A #GCancellable or %NULL.
2896  * @callback: (nullable): A #GAsyncReadyCallback to call when the request is satisfied or %NULL if you don't
2897  * care about the result of the method invocation.
2898  * @user_data: The data to pass to @callback.
2899  *
2900  * Asynchronously invokes the @method_name method on @proxy.
2901  *
2902  * If @method_name contains any dots, then @name is split into interface and
2903  * method name parts. This allows using @proxy for invoking methods on
2904  * other interfaces.
2905  *
2906  * If the #GDBusConnection associated with @proxy is closed then
2907  * the operation will fail with %G_IO_ERROR_CLOSED. If
2908  * @cancellable is canceled, the operation will fail with
2909  * %G_IO_ERROR_CANCELLED. If @parameters contains a value not
2910  * compatible with the D-Bus protocol, the operation fails with
2911  * %G_IO_ERROR_INVALID_ARGUMENT.
2912  *
2913  * If the @parameters #GVariant is floating, it is consumed. This allows
2914  * convenient 'inline' use of g_variant_new(), e.g.:
2915  * |[<!-- language="C" -->
2916  *  g_dbus_proxy_call (proxy,
2917  *                     "TwoStrings",
2918  *                     g_variant_new ("(ss)",
2919  *                                    "Thing One",
2920  *                                    "Thing Two"),
2921  *                     G_DBUS_CALL_FLAGS_NONE,
2922  *                     -1,
2923  *                     NULL,
2924  *                     (GAsyncReadyCallback) two_strings_done,
2925  *                     &data);
2926  * ]|
2927  *
2928  * If @proxy has an expected interface (see
2929  * #GDBusProxy:g-interface-info) and @method_name is referenced by it,
2930  * then the return value is checked against the return type.
2931  *
2932  * This is an asynchronous method. When the operation is finished,
2933  * @callback will be invoked in the
2934  * [thread-default main context][g-main-context-push-thread-default]
2935  * of the thread you are calling this method from.
2936  * You can then call g_dbus_proxy_call_finish() to get the result of
2937  * the operation. See g_dbus_proxy_call_sync() for the synchronous
2938  * version of this method.
2939  *
2940  * If @callback is %NULL then the D-Bus method call message will be sent with
2941  * the %G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED flag set.
2942  *
2943  * Since: 2.26
2944  */
2945 void
2946 g_dbus_proxy_call (GDBusProxy          *proxy,
2947                    const gchar         *method_name,
2948                    GVariant            *parameters,
2949                    GDBusCallFlags       flags,
2950                    gint                 timeout_msec,
2951                    GCancellable        *cancellable,
2952                    GAsyncReadyCallback  callback,
2953                    gpointer             user_data)
2954 {
2955   g_dbus_proxy_call_internal (proxy, method_name, parameters, flags, timeout_msec, NULL, cancellable, callback, user_data);
2956 }
2957
2958 /**
2959  * g_dbus_proxy_call_finish:
2960  * @proxy: A #GDBusProxy.
2961  * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_proxy_call().
2962  * @error: Return location for error or %NULL.
2963  *
2964  * Finishes an operation started with g_dbus_proxy_call().
2965  *
2966  * Returns: %NULL if @error is set. Otherwise a #GVariant tuple with
2967  * return values. Free with g_variant_unref().
2968  *
2969  * Since: 2.26
2970  */
2971 GVariant *
2972 g_dbus_proxy_call_finish (GDBusProxy    *proxy,
2973                           GAsyncResult  *res,
2974                           GError       **error)
2975 {
2976   return g_dbus_proxy_call_finish_internal (proxy, NULL, res, error);
2977 }
2978
2979 /**
2980  * g_dbus_proxy_call_sync:
2981  * @proxy: A #GDBusProxy.
2982  * @method_name: Name of method to invoke.
2983  * @parameters: (nullable): A #GVariant tuple with parameters for the signal
2984  *              or %NULL if not passing parameters.
2985  * @flags: Flags from the #GDBusCallFlags enumeration.
2986  * @timeout_msec: The timeout in milliseconds (with %G_MAXINT meaning
2987  *                "infinite") or -1 to use the proxy default timeout.
2988  * @cancellable: (nullable): A #GCancellable or %NULL.
2989  * @error: Return location for error or %NULL.
2990  *
2991  * Synchronously invokes the @method_name method on @proxy.
2992  *
2993  * If @method_name contains any dots, then @name is split into interface and
2994  * method name parts. This allows using @proxy for invoking methods on
2995  * other interfaces.
2996  *
2997  * If the #GDBusConnection associated with @proxy is disconnected then
2998  * the operation will fail with %G_IO_ERROR_CLOSED. If
2999  * @cancellable is canceled, the operation will fail with
3000  * %G_IO_ERROR_CANCELLED. If @parameters contains a value not
3001  * compatible with the D-Bus protocol, the operation fails with
3002  * %G_IO_ERROR_INVALID_ARGUMENT.
3003  *
3004  * If the @parameters #GVariant is floating, it is consumed. This allows
3005  * convenient 'inline' use of g_variant_new(), e.g.:
3006  * |[<!-- language="C" -->
3007  *  g_dbus_proxy_call_sync (proxy,
3008  *                          "TwoStrings",
3009  *                          g_variant_new ("(ss)",
3010  *                                         "Thing One",
3011  *                                         "Thing Two"),
3012  *                          G_DBUS_CALL_FLAGS_NONE,
3013  *                          -1,
3014  *                          NULL,
3015  *                          &error);
3016  * ]|
3017  *
3018  * The calling thread is blocked until a reply is received. See
3019  * g_dbus_proxy_call() for the asynchronous version of this
3020  * method.
3021  *
3022  * If @proxy has an expected interface (see
3023  * #GDBusProxy:g-interface-info) and @method_name is referenced by it,
3024  * then the return value is checked against the return type.
3025  *
3026  * Returns: %NULL if @error is set. Otherwise a #GVariant tuple with
3027  * return values. Free with g_variant_unref().
3028  *
3029  * Since: 2.26
3030  */
3031 GVariant *
3032 g_dbus_proxy_call_sync (GDBusProxy      *proxy,
3033                         const gchar     *method_name,
3034                         GVariant        *parameters,
3035                         GDBusCallFlags   flags,
3036                         gint             timeout_msec,
3037                         GCancellable    *cancellable,
3038                         GError         **error)
3039 {
3040   return g_dbus_proxy_call_sync_internal (proxy, method_name, parameters, flags, timeout_msec, NULL, NULL, cancellable, error);
3041 }
3042
3043 /* ---------------------------------------------------------------------------------------------------- */
3044
3045 #ifdef G_OS_UNIX
3046
3047 /**
3048  * g_dbus_proxy_call_with_unix_fd_list:
3049  * @proxy: A #GDBusProxy.
3050  * @method_name: Name of method to invoke.
3051  * @parameters: (nullable): A #GVariant tuple with parameters for the signal or %NULL if not passing parameters.
3052  * @flags: Flags from the #GDBusCallFlags enumeration.
3053  * @timeout_msec: The timeout in milliseconds (with %G_MAXINT meaning
3054  *                "infinite") or -1 to use the proxy default timeout.
3055  * @fd_list: (nullable): A #GUnixFDList or %NULL.
3056  * @cancellable: (nullable): A #GCancellable or %NULL.
3057  * @callback: (nullable): A #GAsyncReadyCallback to call when the request is satisfied or %NULL if you don't
3058  * care about the result of the method invocation.
3059  * @user_data: The data to pass to @callback.
3060  *
3061  * Like g_dbus_proxy_call() but also takes a #GUnixFDList object.
3062  *
3063  * This method is only available on UNIX.
3064  *
3065  * Since: 2.30
3066  */
3067 void
3068 g_dbus_proxy_call_with_unix_fd_list (GDBusProxy          *proxy,
3069                                      const gchar         *method_name,
3070                                      GVariant            *parameters,
3071                                      GDBusCallFlags       flags,
3072                                      gint                 timeout_msec,
3073                                      GUnixFDList         *fd_list,
3074                                      GCancellable        *cancellable,
3075                                      GAsyncReadyCallback  callback,
3076                                      gpointer             user_data)
3077 {
3078   g_dbus_proxy_call_internal (proxy, method_name, parameters, flags, timeout_msec, fd_list, cancellable, callback, user_data);
3079 }
3080
3081 /**
3082  * g_dbus_proxy_call_with_unix_fd_list_finish:
3083  * @proxy: A #GDBusProxy.
3084  * @out_fd_list: (out) (optional): Return location for a #GUnixFDList or %NULL.
3085  * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_proxy_call_with_unix_fd_list().
3086  * @error: Return location for error or %NULL.
3087  *
3088  * Finishes an operation started with g_dbus_proxy_call_with_unix_fd_list().
3089  *
3090  * Returns: %NULL if @error is set. Otherwise a #GVariant tuple with
3091  * return values. Free with g_variant_unref().
3092  *
3093  * Since: 2.30
3094  */
3095 GVariant *
3096 g_dbus_proxy_call_with_unix_fd_list_finish (GDBusProxy    *proxy,
3097                                             GUnixFDList  **out_fd_list,
3098                                             GAsyncResult  *res,
3099                                             GError       **error)
3100 {
3101   return g_dbus_proxy_call_finish_internal (proxy, out_fd_list, res, error);
3102 }
3103
3104 /**
3105  * g_dbus_proxy_call_with_unix_fd_list_sync:
3106  * @proxy: A #GDBusProxy.
3107  * @method_name: Name of method to invoke.
3108  * @parameters: (nullable): A #GVariant tuple with parameters for the signal
3109  *              or %NULL if not passing parameters.
3110  * @flags: Flags from the #GDBusCallFlags enumeration.
3111  * @timeout_msec: The timeout in milliseconds (with %G_MAXINT meaning
3112  *                "infinite") or -1 to use the proxy default timeout.
3113  * @fd_list: (nullable): A #GUnixFDList or %NULL.
3114  * @out_fd_list: (out) (optional): Return location for a #GUnixFDList or %NULL.
3115  * @cancellable: (nullable): A #GCancellable or %NULL.
3116  * @error: Return location for error or %NULL.
3117  *
3118  * Like g_dbus_proxy_call_sync() but also takes and returns #GUnixFDList objects.
3119  *
3120  * This method is only available on UNIX.
3121  *
3122  * Returns: %NULL if @error is set. Otherwise a #GVariant tuple with
3123  * return values. Free with g_variant_unref().
3124  *
3125  * Since: 2.30
3126  */
3127 GVariant *
3128 g_dbus_proxy_call_with_unix_fd_list_sync (GDBusProxy      *proxy,
3129                                           const gchar     *method_name,
3130                                           GVariant        *parameters,
3131                                           GDBusCallFlags   flags,
3132                                           gint             timeout_msec,
3133                                           GUnixFDList     *fd_list,
3134                                           GUnixFDList    **out_fd_list,
3135                                           GCancellable    *cancellable,
3136                                           GError         **error)
3137 {
3138   return g_dbus_proxy_call_sync_internal (proxy, method_name, parameters, flags, timeout_msec, fd_list, out_fd_list, cancellable, error);
3139 }
3140
3141 #endif /* G_OS_UNIX */
3142
3143 /* ---------------------------------------------------------------------------------------------------- */
3144
3145 static GDBusInterfaceInfo *
3146 _g_dbus_proxy_get_info (GDBusInterface *interface)
3147 {
3148   GDBusProxy *proxy = G_DBUS_PROXY (interface);
3149   return g_dbus_proxy_get_interface_info (proxy);
3150 }
3151
3152 static GDBusObject *
3153 _g_dbus_proxy_get_object (GDBusInterface *interface)
3154 {
3155   GDBusProxy *proxy = G_DBUS_PROXY (interface);
3156   return proxy->priv->object;
3157 }
3158
3159 static GDBusObject *
3160 _g_dbus_proxy_dup_object (GDBusInterface *interface)
3161 {
3162   GDBusProxy *proxy = G_DBUS_PROXY (interface);
3163   GDBusObject *ret = NULL;
3164
3165   G_LOCK (properties_lock);
3166   if (proxy->priv->object != NULL)
3167     ret = g_object_ref (proxy->priv->object);
3168   G_UNLOCK (properties_lock);
3169   return ret;
3170 }
3171
3172 static void
3173 _g_dbus_proxy_set_object (GDBusInterface *interface,
3174                           GDBusObject    *object)
3175 {
3176   GDBusProxy *proxy = G_DBUS_PROXY (interface);
3177   G_LOCK (properties_lock);
3178   if (proxy->priv->object != NULL)
3179     g_object_remove_weak_pointer (G_OBJECT (proxy->priv->object), (gpointer *) &proxy->priv->object);
3180   proxy->priv->object = object;
3181   if (proxy->priv->object != NULL)
3182     g_object_add_weak_pointer (G_OBJECT (proxy->priv->object), (gpointer *) &proxy->priv->object);
3183   G_UNLOCK (properties_lock);
3184 }
3185
3186 static void
3187 dbus_interface_iface_init (GDBusInterfaceIface *dbus_interface_iface)
3188 {
3189   dbus_interface_iface->get_info   = _g_dbus_proxy_get_info;
3190   dbus_interface_iface->get_object = _g_dbus_proxy_get_object;
3191   dbus_interface_iface->dup_object = _g_dbus_proxy_dup_object;
3192   dbus_interface_iface->set_object = _g_dbus_proxy_set_object;
3193 }
3194
3195 /* ---------------------------------------------------------------------------------------------------- */