GDBus: Remove cached value if a property is invalidated
[platform/upstream/glib.git] / gio / gdbusproxy.c
1 /* GDBus - GLib D-Bus Library
2  *
3  * Copyright (C) 2008-2010 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: David Zeuthen <davidz@redhat.com>
21  */
22
23 #include "config.h"
24
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include <gobject/gvaluecollector.h>
29
30 #include "gdbusutils.h"
31 #include "gdbusproxy.h"
32 #include "gioenumtypes.h"
33 #include "gdbusconnection.h"
34 #include "gdbuserror.h"
35 #include "gdbusprivate.h"
36 #include "gio-marshal.h"
37 #include "ginitable.h"
38 #include "gasyncinitable.h"
39 #include "gioerror.h"
40 #include "gasyncresult.h"
41 #include "gsimpleasyncresult.h"
42
43 #include "glibintl.h"
44 #include "gioalias.h"
45
46 /**
47  * SECTION:gdbusproxy
48  * @short_description: Base class for proxies
49  * @include: gio/gio.h
50  *
51  * #GDBusProxy is a base class used for proxies to access a D-Bus
52  * interface on a remote object. A #GDBusProxy can only be constructed
53  * for unique name bus and does not track whether the name
54  * vanishes. Use g_bus_watch_proxy() to construct #GDBusProxy proxies
55  * for owners of a well-known names.
56  *
57  * By default, #GDBusProxy will cache all properties (and listen for
58  * their changes) of the remote object, and proxy all signals that gets
59  * emitted. This behaviour can be changed by passing suitable
60  * #GDBusProxyFlags when the proxy is created.
61  *
62  * The generic #GDBusProxy::g-properties-changed and #GDBusProxy::g-signal
63  * signals are not very convenient to work with. Therefore, the recommended
64  * way of working with proxies is to subclass #GDBusProxy, and have
65  * more natural properties and signals in your derived class. The
66  * @interface_type argument of g_bus_watch_proxy() lets you obtain
67  * instances of your derived class when using the high-level API.
68  *
69  * See <xref linkend="gdbus-example-proxy-subclass"/> for an example.
70  */
71
72 struct _GDBusProxyPrivate
73 {
74   GDBusConnection *connection;
75   GDBusProxyFlags flags;
76   gchar *unique_bus_name;
77   gchar *object_path;
78   gchar *interface_name;
79   gint timeout_msec;
80
81   /* gchar* -> GVariant* */
82   GHashTable *properties;
83
84   GDBusInterfaceInfo *expected_interface;
85
86   guint properties_changed_subscriber_id;
87   guint signals_subscriber_id;
88
89   gboolean initialized;
90 };
91
92 enum
93 {
94   PROP_0,
95   PROP_G_CONNECTION,
96   PROP_G_UNIQUE_BUS_NAME,
97   PROP_G_FLAGS,
98   PROP_G_OBJECT_PATH,
99   PROP_G_INTERFACE_NAME,
100   PROP_G_DEFAULT_TIMEOUT,
101   PROP_G_INTERFACE_INFO
102 };
103
104 enum
105 {
106   PROPERTIES_CHANGED_SIGNAL,
107   SIGNAL_SIGNAL,
108   LAST_SIGNAL,
109 };
110
111 static void g_dbus_proxy_constructed (GObject *object);
112
113 guint signals[LAST_SIGNAL] = {0};
114
115 static void initable_iface_init       (GInitableIface *initable_iface);
116 static void async_initable_iface_init (GAsyncInitableIface *async_initable_iface);
117
118 G_DEFINE_TYPE_WITH_CODE (GDBusProxy, g_dbus_proxy, G_TYPE_OBJECT,
119                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)
120                          G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init)
121                          );
122
123 static void
124 g_dbus_proxy_finalize (GObject *object)
125 {
126   GDBusProxy *proxy = G_DBUS_PROXY (object);
127
128   if (proxy->priv->properties_changed_subscriber_id > 0)
129     g_dbus_connection_signal_unsubscribe (proxy->priv->connection,
130                                           proxy->priv->properties_changed_subscriber_id);
131
132   if (proxy->priv->signals_subscriber_id > 0)
133     g_dbus_connection_signal_unsubscribe (proxy->priv->connection,
134                                           proxy->priv->signals_subscriber_id);
135
136   g_object_unref (proxy->priv->connection);
137   g_free (proxy->priv->unique_bus_name);
138   g_free (proxy->priv->object_path);
139   g_free (proxy->priv->interface_name);
140   if (proxy->priv->properties != NULL)
141     g_hash_table_unref (proxy->priv->properties);
142
143   if (proxy->priv->expected_interface != NULL)
144     g_dbus_interface_info_unref (proxy->priv->expected_interface);
145
146   G_OBJECT_CLASS (g_dbus_proxy_parent_class)->finalize (object);
147 }
148
149 static void
150 g_dbus_proxy_get_property (GObject    *object,
151                            guint       prop_id,
152                            GValue     *value,
153                            GParamSpec *pspec)
154 {
155   GDBusProxy *proxy = G_DBUS_PROXY (object);
156
157   switch (prop_id)
158     {
159     case PROP_G_CONNECTION:
160       g_value_set_object (value, proxy->priv->connection);
161       break;
162
163     case PROP_G_FLAGS:
164       g_value_set_flags (value, proxy->priv->flags);
165       break;
166
167     case PROP_G_UNIQUE_BUS_NAME:
168       g_value_set_string (value, proxy->priv->unique_bus_name);
169       break;
170
171     case PROP_G_OBJECT_PATH:
172       g_value_set_string (value, proxy->priv->object_path);
173       break;
174
175     case PROP_G_INTERFACE_NAME:
176       g_value_set_string (value, proxy->priv->interface_name);
177       break;
178
179     case PROP_G_DEFAULT_TIMEOUT:
180       g_value_set_int (value, proxy->priv->timeout_msec);
181       break;
182
183     case PROP_G_INTERFACE_INFO:
184       g_value_set_boxed (value, g_dbus_proxy_get_interface_info (proxy));
185       break;
186
187     default:
188       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
189       break;
190     }
191 }
192
193 static void
194 g_dbus_proxy_set_property (GObject      *object,
195                            guint         prop_id,
196                            const GValue *value,
197                            GParamSpec   *pspec)
198 {
199   GDBusProxy *proxy = G_DBUS_PROXY (object);
200
201   switch (prop_id)
202     {
203     case PROP_G_CONNECTION:
204       proxy->priv->connection = g_value_dup_object (value);
205       break;
206
207     case PROP_G_FLAGS:
208       proxy->priv->flags = g_value_get_flags (value);
209       break;
210
211     case PROP_G_UNIQUE_BUS_NAME:
212       proxy->priv->unique_bus_name = g_value_dup_string (value);
213       break;
214
215     case PROP_G_OBJECT_PATH:
216       proxy->priv->object_path = g_value_dup_string (value);
217       break;
218
219     case PROP_G_INTERFACE_NAME:
220       proxy->priv->interface_name = g_value_dup_string (value);
221       break;
222
223     case PROP_G_DEFAULT_TIMEOUT:
224       g_dbus_proxy_set_default_timeout (proxy, g_value_get_int (value));
225       break;
226
227     case PROP_G_INTERFACE_INFO:
228       g_dbus_proxy_set_interface_info (proxy, g_value_get_boxed (value));
229       break;
230
231     default:
232       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
233       break;
234     }
235 }
236
237 static void
238 g_dbus_proxy_class_init (GDBusProxyClass *klass)
239 {
240   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
241
242   gobject_class->finalize     = g_dbus_proxy_finalize;
243   gobject_class->set_property = g_dbus_proxy_set_property;
244   gobject_class->get_property = g_dbus_proxy_get_property;
245   gobject_class->constructed  = g_dbus_proxy_constructed;
246
247   /* Note that all property names are prefixed to avoid collisions with D-Bus property names
248    * in derived classes */
249
250   /**
251    * GDBusProxy:g-interface-info:
252    *
253    * Ensure that interactions with this proxy conform to the given
254    * interface.  For example, when completing a method call, if the
255    * type signature of the message isn't what's expected, the given
256    * #GError is set.  Signals that have a type signature mismatch are
257    * simply dropped.
258    *
259    * Since: 2.26
260    */
261   g_object_class_install_property (gobject_class,
262                                    PROP_G_INTERFACE_INFO,
263                                    g_param_spec_boxed ("g-interface-info",
264                                                        P_("Interface Information"),
265                                                        P_("Interface Information"),
266                                                        G_TYPE_DBUS_INTERFACE_INFO,
267                                                        G_PARAM_READABLE |
268                                                        G_PARAM_WRITABLE |
269                                                        G_PARAM_STATIC_NAME |
270                                                        G_PARAM_STATIC_BLURB |
271                                                        G_PARAM_STATIC_NICK));
272
273   /**
274    * GDBusProxy:g-connection:
275    *
276    * The #GDBusConnection the proxy is for.
277    *
278    * Since: 2.26
279    */
280   g_object_class_install_property (gobject_class,
281                                    PROP_G_CONNECTION,
282                                    g_param_spec_object ("g-connection",
283                                                         P_("g-connection"),
284                                                         P_("The connection the proxy is for"),
285                                                         G_TYPE_DBUS_CONNECTION,
286                                                         G_PARAM_READABLE |
287                                                         G_PARAM_WRITABLE |
288                                                         G_PARAM_CONSTRUCT_ONLY |
289                                                         G_PARAM_STATIC_NAME |
290                                                         G_PARAM_STATIC_BLURB |
291                                                         G_PARAM_STATIC_NICK));
292
293   /**
294    * GDBusProxy:g-flags:
295    *
296    * Flags from the #GDBusProxyFlags enumeration.
297    *
298    * Since: 2.26
299    */
300   g_object_class_install_property (gobject_class,
301                                    PROP_G_FLAGS,
302                                    g_param_spec_flags ("g-flags",
303                                                        P_("g-flags"),
304                                                        P_("Flags for the proxy"),
305                                                        G_TYPE_DBUS_PROXY_FLAGS,
306                                                        G_DBUS_PROXY_FLAGS_NONE,
307                                                        G_PARAM_READABLE |
308                                                        G_PARAM_WRITABLE |
309                                                        G_PARAM_CONSTRUCT_ONLY |
310                                                        G_PARAM_STATIC_NAME |
311                                                        G_PARAM_STATIC_BLURB |
312                                                        G_PARAM_STATIC_NICK));
313
314   /**
315    * GDBusProxy:g-unique-bus-name:
316    *
317    * The unique bus name the proxy is for.
318    *
319    * Since: 2.26
320    */
321   g_object_class_install_property (gobject_class,
322                                    PROP_G_UNIQUE_BUS_NAME,
323                                    g_param_spec_string ("g-unique-bus-name",
324                                                         P_("g-unique-bus-name"),
325                                                         P_("The unique bus name the proxy is for"),
326                                                         NULL,
327                                                         G_PARAM_READABLE |
328                                                         G_PARAM_WRITABLE |
329                                                         G_PARAM_CONSTRUCT_ONLY |
330                                                         G_PARAM_STATIC_NAME |
331                                                         G_PARAM_STATIC_BLURB |
332                                                         G_PARAM_STATIC_NICK));
333
334   /**
335    * GDBusProxy:g-object-path:
336    *
337    * The object path the proxy is for.
338    *
339    * Since: 2.26
340    */
341   g_object_class_install_property (gobject_class,
342                                    PROP_G_OBJECT_PATH,
343                                    g_param_spec_string ("g-object-path",
344                                                         P_("g-object-path"),
345                                                         P_("The object path the proxy is for"),
346                                                         NULL,
347                                                         G_PARAM_READABLE |
348                                                         G_PARAM_WRITABLE |
349                                                         G_PARAM_CONSTRUCT_ONLY |
350                                                         G_PARAM_STATIC_NAME |
351                                                         G_PARAM_STATIC_BLURB |
352                                                         G_PARAM_STATIC_NICK));
353
354   /**
355    * GDBusProxy:g-interface-name:
356    *
357    * The D-Bus interface name the proxy is for.
358    *
359    * Since: 2.26
360    */
361   g_object_class_install_property (gobject_class,
362                                    PROP_G_INTERFACE_NAME,
363                                    g_param_spec_string ("g-interface-name",
364                                                         P_("g-interface-name"),
365                                                         P_("The D-Bus interface name the proxy is for"),
366                                                         NULL,
367                                                         G_PARAM_READABLE |
368                                                         G_PARAM_WRITABLE |
369                                                         G_PARAM_CONSTRUCT_ONLY |
370                                                         G_PARAM_STATIC_NAME |
371                                                         G_PARAM_STATIC_BLURB |
372                                                         G_PARAM_STATIC_NICK));
373
374   /**
375    * GDBusProxy:g-default-timeout:
376    *
377    * The timeout to use if -1 (specifying default timeout) is passed
378    * as @timeout_msec in the g_dbus_proxy_call() and
379    * g_dbus_proxy_call_sync() functions.
380    *
381    * This allows applications to set a proxy-wide timeout for all
382    * remote method invocations on the proxy. If this property is -1,
383    * the default timeout (typically 25 seconds) is used. If set to
384    * %G_MAXINT, then no timeout is used.
385    *
386    * Since: 2.26
387    */
388   g_object_class_install_property (gobject_class,
389                                    PROP_G_DEFAULT_TIMEOUT,
390                                    g_param_spec_int ("g-default-timeout",
391                                                      P_("Default Timeout"),
392                                                      P_("Timeout for remote method invocation"),
393                                                      -1,
394                                                      G_MAXINT,
395                                                      -1,
396                                                      G_PARAM_READABLE |
397                                                      G_PARAM_WRITABLE |
398                                                      G_PARAM_CONSTRUCT |
399                                                      G_PARAM_STATIC_NAME |
400                                                      G_PARAM_STATIC_BLURB |
401                                                      G_PARAM_STATIC_NICK));
402
403   /**
404    * GDBusProxy::g-properties-changed:
405    * @proxy: The #GDBusProxy emitting the signal.
406    * @changed_properties: A #GVariant containing the properties that changed
407    * @invalidated_properties: A %NULL terminated array of properties that was invalidated
408    *
409    * Emitted when one or more D-Bus properties on @proxy changes. The
410    * local cache has already been updated when this signal fires. Note
411    * that both @changed_properties and @invalidated_properties are
412    * guaranteed to never be %NULL (either may be empty though).
413    *
414    * This signal corresponds to the
415    * <literal>PropertiesChanged</literal> D-Bus signal on the
416    * <literal>org.freedesktop.DBus.Properties</literal> interface.
417    *
418    * Since: 2.26
419    */
420   signals[PROPERTIES_CHANGED_SIGNAL] = g_signal_new ("g-properties-changed",
421                                                      G_TYPE_DBUS_PROXY,
422                                                      G_SIGNAL_RUN_LAST,
423                                                      G_STRUCT_OFFSET (GDBusProxyClass, g_properties_changed),
424                                                      NULL,
425                                                      NULL,
426                                                      _gio_marshal_VOID__BOXED_BOXED,
427                                                      G_TYPE_NONE,
428                                                      2,
429                                                      G_TYPE_VARIANT,
430                                                      G_TYPE_STRV | G_SIGNAL_TYPE_STATIC_SCOPE);
431
432   /**
433    * GDBusProxy::g-signal:
434    * @proxy: The #GDBusProxy emitting the signal.
435    * @sender_name: The sender of the signal or %NULL if the connection is not a bus connection.
436    * @signal_name: The name of the signal.
437    * @parameters: A #GVariant tuple with parameters for the signal.
438    *
439    * Emitted when a signal from the remote object and interface that @proxy is for, has been received.
440    *
441    * Since: 2.26
442    */
443   signals[SIGNAL_SIGNAL] = g_signal_new ("g-signal",
444                                          G_TYPE_DBUS_PROXY,
445                                          G_SIGNAL_RUN_LAST,
446                                          G_STRUCT_OFFSET (GDBusProxyClass, g_signal),
447                                          NULL,
448                                          NULL,
449                                          _gio_marshal_VOID__STRING_STRING_BOXED,
450                                          G_TYPE_NONE,
451                                          3,
452                                          G_TYPE_STRING,
453                                          G_TYPE_STRING,
454                                          G_TYPE_VARIANT);
455
456
457   g_type_class_add_private (klass, sizeof (GDBusProxyPrivate));
458 }
459
460 static void
461 g_dbus_proxy_init (GDBusProxy *proxy)
462 {
463   proxy->priv = G_TYPE_INSTANCE_GET_PRIVATE (proxy, G_TYPE_DBUS_PROXY, GDBusProxyPrivate);
464   proxy->priv->properties = g_hash_table_new_full (g_str_hash,
465                                                    g_str_equal,
466                                                    g_free,
467                                                    (GDestroyNotify) g_variant_unref);
468 }
469
470 /* ---------------------------------------------------------------------------------------------------- */
471
472 /**
473  * g_dbus_proxy_get_cached_property_names:
474  * @proxy: A #GDBusProxy.
475  *
476  * Gets the names of all cached properties on @proxy.
477  *
478  * Returns: A %NULL-terminated array of strings or %NULL if @proxy has
479  * no cached properties. Free the returned array with g_strfreev().
480  *
481  * Since: 2.26
482  */
483 gchar **
484 g_dbus_proxy_get_cached_property_names (GDBusProxy  *proxy)
485 {
486   gchar **names;
487   GPtrArray *p;
488   GHashTableIter iter;
489   const gchar *key;
490
491   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
492
493   names = NULL;
494   if (g_hash_table_size (proxy->priv->properties) == 0)
495     goto out;
496
497   p = g_ptr_array_new ();
498
499   g_hash_table_iter_init (&iter, proxy->priv->properties);
500   while (g_hash_table_iter_next (&iter, (gpointer) &key, NULL))
501     g_ptr_array_add (p, g_strdup (key));
502   g_ptr_array_sort (p, (GCompareFunc) g_strcmp0);
503   g_ptr_array_add (p, NULL);
504
505   names = (gchar **) g_ptr_array_free (p, FALSE);
506
507  out:
508   return names;
509 }
510
511 static const GDBusPropertyInfo *
512 lookup_property_info_or_warn (GDBusProxy  *proxy,
513                               const gchar *property_name)
514 {
515   const GDBusPropertyInfo *info;
516
517   if (proxy->priv->expected_interface == NULL)
518     return NULL;
519
520   info = g_dbus_interface_info_lookup_property (proxy->priv->expected_interface, property_name);
521   if (info == NULL)
522     {
523       g_warning ("Trying to lookup property %s which isn't in expected interface %s",
524                  property_name,
525                  proxy->priv->expected_interface->name);
526     }
527
528   return info;
529 }
530
531 /**
532  * g_dbus_proxy_get_cached_property:
533  * @proxy: A #GDBusProxy.
534  * @property_name: Property name.
535  *
536  * Looks up the value for a property from the cache. This call does no
537  * blocking IO.
538  *
539  * If @proxy has an expected interface (see
540  * #GDBusProxy:g-interface-info), then @property_name (for existence)
541  * is checked against it.
542  *
543  * Returns: A reference to the #GVariant instance that holds the value
544  * for @property_name or %NULL if the value is not in the cache. The
545  * returned reference must be freed with g_variant_unref().
546  *
547  * Since: 2.26
548  */
549 GVariant *
550 g_dbus_proxy_get_cached_property (GDBusProxy   *proxy,
551                                   const gchar  *property_name)
552 {
553   GVariant *value;
554
555   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
556   g_return_val_if_fail (property_name != NULL, NULL);
557
558   value = g_hash_table_lookup (proxy->priv->properties, property_name);
559   if (value == NULL)
560     {
561       const GDBusPropertyInfo *info;
562       info = lookup_property_info_or_warn (proxy, property_name);
563       /* no difference */
564       goto out;
565     }
566
567   g_variant_ref (value);
568
569  out:
570   return value;
571 }
572
573 /**
574  * g_dbus_proxy_set_cached_property:
575  * @proxy: A #GDBusProxy
576  * @property_name: Property name.
577  * @value: Value for the property or %NULL to remove it from the cache.
578  *
579  * If @value is not %NULL, sets the cached value for the property with
580  * name @property_name to the value in @value.
581  *
582  * If @value is %NULL, then the cached value is removed from the
583  * property cache.
584  *
585  * If @proxy has an expected interface (see
586  * #GDBusProxy:g-interface-info), then @property_name (for existence)
587  * and @value (for the type) is checked against it.
588  *
589  * If the @value #GVariant is floating, it is consumed. This allows
590  * convenient 'inline' use of g_variant_new(), e.g.
591  * |[
592  *  g_dbus_proxy_set_cached_property (proxy,
593  *                                    "SomeProperty",
594  *                                    g_variant_new ("(si)",
595  *                                                  "A String",
596  *                                                  42));
597  * ]|
598  *
599  * Normally you will not need to use this method since @proxy is
600  * tracking changes using the
601  * <literal>org.freedesktop.DBus.Properties.PropertiesChanged</literal>
602  * D-Bus signal. However, for performance reasons an object may decide
603  * to not use this signal for some properties and instead use a
604  * proprietary out-of-band mechanism to transmit changes.
605  *
606  * As a concrete example, consider an object with a property
607  * <literal>ChatroomParticipants</literal> which is an array of
608  * strings. Instead of transmitting the same (long) array every time
609  * the property changes, it is more efficient to only transmit the
610  * delta using e.g. signals <literal>ChatroomParticipantJoined(String
611  * name)</literal> and <literal>ChatroomParticipantParted(String
612  * name)</literal>.
613  *
614  * Since: 2.26
615  */
616 void
617 g_dbus_proxy_set_cached_property (GDBusProxy   *proxy,
618                                   const gchar  *property_name,
619                                   GVariant     *value)
620 {
621   const GDBusPropertyInfo *info;
622
623   g_return_if_fail (G_IS_DBUS_PROXY (proxy));
624   g_return_if_fail (property_name != NULL);
625
626   if (value != NULL)
627     {
628       info = lookup_property_info_or_warn (proxy, property_name);
629       if (info != NULL)
630         {
631           if (g_strcmp0 (info->signature, g_variant_get_type_string (value)) != 0)
632             {
633               g_warning (_("Trying to set property %s of type %s but according to the expected "
634                            "interface the type is %s"),
635                          property_name,
636                          g_variant_get_type_string (value),
637                          info->signature);
638               goto out;
639             }
640         }
641       g_hash_table_insert (proxy->priv->properties,
642                            g_strdup (property_name),
643                            g_variant_ref_sink (value));
644     }
645   else
646     {
647       g_hash_table_remove (proxy->priv->properties, property_name);
648     }
649
650  out:
651   ;
652 }
653
654 /* ---------------------------------------------------------------------------------------------------- */
655
656 static void
657 on_signal_received (GDBusConnection *connection,
658                     const gchar     *sender_name,
659                     const gchar     *object_path,
660                     const gchar     *interface_name,
661                     const gchar     *signal_name,
662                     GVariant        *parameters,
663                     gpointer         user_data)
664 {
665   GDBusProxy *proxy = G_DBUS_PROXY (user_data);
666
667   if (!proxy->priv->initialized)
668     goto out;
669
670   g_signal_emit (proxy,
671                  signals[SIGNAL_SIGNAL],
672                  0,
673                  sender_name,
674                  signal_name,
675                  parameters);
676  out:
677   ;
678 }
679
680 /* ---------------------------------------------------------------------------------------------------- */
681
682 static void
683 on_properties_changed (GDBusConnection *connection,
684                        const gchar     *sender_name,
685                        const gchar     *object_path,
686                        const gchar     *interface_name,
687                        const gchar     *signal_name,
688                        GVariant        *parameters,
689                        gpointer         user_data)
690 {
691   GDBusProxy *proxy = G_DBUS_PROXY (user_data);
692   GError *error;
693   const gchar *interface_name_for_signal;
694   GVariant *changed_properties;
695   gchar **invalidated_properties;
696   GVariantIter iter;
697   gchar *key;
698   GVariant *value;
699   guint n;
700
701   error = NULL;
702   changed_properties = NULL;
703   invalidated_properties = NULL;
704
705   if (!proxy->priv->initialized)
706     goto out;
707
708   if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sa{sv}as)")))
709     {
710       g_warning ("Value for PropertiesChanged signal with type `%s' does not match `(sa{sv}as)'",
711                  g_variant_get_type_string (parameters));
712       goto out;
713     }
714
715   g_variant_get (parameters,
716                  "(&s@a{sv}^a&s)",
717                  &interface_name_for_signal,
718                  &changed_properties,
719                  &invalidated_properties);
720
721   if (g_strcmp0 (interface_name_for_signal, proxy->priv->interface_name) != 0)
722     goto out;
723
724   g_variant_iter_init (&iter, changed_properties);
725   while (g_variant_iter_next (&iter, "{sv}", &key, &value))
726     {
727       g_hash_table_insert (proxy->priv->properties,
728                            key, /* adopts string */
729                            value); /* adopts value */
730     }
731
732   for (n = 0; invalidated_properties[n] != NULL; n++)
733     {
734       g_hash_table_remove (proxy->priv->properties, invalidated_properties[n]);
735     }
736
737   /* emit signal */
738   g_signal_emit (proxy, signals[PROPERTIES_CHANGED_SIGNAL],
739                  0,
740                  changed_properties,
741                  invalidated_properties);
742
743  out:
744   if (changed_properties != NULL)
745     g_variant_unref (changed_properties);
746   g_free (invalidated_properties);
747 }
748
749 /* ---------------------------------------------------------------------------------------------------- */
750
751 static void
752 g_dbus_proxy_constructed (GObject *object)
753 {
754   if (G_OBJECT_CLASS (g_dbus_proxy_parent_class)->constructed != NULL)
755     G_OBJECT_CLASS (g_dbus_proxy_parent_class)->constructed (object);
756 }
757
758 /* ---------------------------------------------------------------------------------------------------- */
759
760 static void
761 subscribe_to_signals (GDBusProxy *proxy)
762 {
763   if (!(proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES))
764     {
765       /* subscribe to PropertiesChanged() */
766       proxy->priv->properties_changed_subscriber_id =
767         g_dbus_connection_signal_subscribe (proxy->priv->connection,
768                                             proxy->priv->unique_bus_name,
769                                             "org.freedesktop.DBus.Properties",
770                                             "PropertiesChanged",
771                                             proxy->priv->object_path,
772                                             proxy->priv->interface_name,
773                                             on_properties_changed,
774                                             proxy,
775                                             NULL);
776     }
777
778   if (!(proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS))
779     {
780       /* subscribe to all signals for the object */
781       proxy->priv->signals_subscriber_id =
782         g_dbus_connection_signal_subscribe (proxy->priv->connection,
783                                             proxy->priv->unique_bus_name,
784                                             proxy->priv->interface_name,
785                                             NULL,                        /* member */
786                                             proxy->priv->object_path,
787                                             NULL,                        /* arg0 */
788                                             on_signal_received,
789                                             proxy,
790                                             NULL);
791     }
792 }
793
794 /* ---------------------------------------------------------------------------------------------------- */
795
796 static void
797 process_get_all_reply (GDBusProxy *proxy,
798                        GVariant   *result)
799 {
800   GVariantIter iter;
801   GVariant *item;
802
803   if (strcmp (g_variant_get_type_string (result), "(a{sv})") != 0)
804     {
805       g_warning ("Value for GetAll reply with type `%s' does not match `(a{sv})'",
806                  g_variant_get_type_string (result));
807       goto out;
808     }
809
810   g_variant_iter_init (&iter, g_variant_get_child_value (result, 0));
811   while ((item = g_variant_iter_next_value (&iter)) != NULL)
812     {
813       gchar *key;
814       GVariant *value;
815
816       g_variant_get (item,
817                      "{sv}",
818                      &key,
819                      &value);
820       //g_print ("got %s -> %s\n", key, g_variant_markup_print (value, FALSE, 0, 0));
821
822       g_hash_table_insert (proxy->priv->properties,
823                            key,
824                            value); /* steals value */
825     }
826  out:
827   ;
828 }
829
830 static gboolean
831 initable_init (GInitable     *initable,
832                GCancellable  *cancellable,
833                GError       **error)
834 {
835   GDBusProxy *proxy = G_DBUS_PROXY (initable);
836   GVariant *result;
837   gboolean ret;
838
839   ret = FALSE;
840
841   subscribe_to_signals (proxy);
842
843   if (!(proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES))
844     {
845       /* load all properties synchronously */
846       result = g_dbus_connection_call_sync (proxy->priv->connection,
847                                             proxy->priv->unique_bus_name,
848                                             proxy->priv->object_path,
849                                             "org.freedesktop.DBus.Properties",
850                                             "GetAll",
851                                             g_variant_new ("(s)", proxy->priv->interface_name),
852                                             G_DBUS_CALL_FLAGS_NONE,
853                                             -1,           /* timeout */
854                                             cancellable,
855                                             error);
856       if (result == NULL)
857         goto out;
858
859       process_get_all_reply (proxy, result);
860
861       g_variant_unref (result);
862     }
863
864   ret = TRUE;
865
866  out:
867   proxy->priv->initialized = TRUE;
868   return ret;
869 }
870
871 static void
872 initable_iface_init (GInitableIface *initable_iface)
873 {
874   initable_iface->init = initable_init;
875 }
876
877 /* ---------------------------------------------------------------------------------------------------- */
878
879 static void
880 get_all_cb (GDBusConnection *connection,
881             GAsyncResult    *res,
882             gpointer         user_data)
883 {
884   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
885   GVariant *result;
886   GError *error;
887
888   error = NULL;
889   result = g_dbus_connection_call_finish (connection,
890                                           res,
891                                           &error);
892   if (result == NULL)
893     {
894       g_simple_async_result_set_from_error (simple, error);
895       g_error_free (error);
896     }
897   else
898     {
899       g_simple_async_result_set_op_res_gpointer (simple,
900                                                  result,
901                                                  (GDestroyNotify) g_variant_unref);
902     }
903
904   g_simple_async_result_complete_in_idle (simple);
905   g_object_unref (simple);
906 }
907
908 static void
909 async_initable_init_async (GAsyncInitable      *initable,
910                            gint                 io_priority,
911                            GCancellable        *cancellable,
912                            GAsyncReadyCallback  callback,
913                            gpointer             user_data)
914 {
915   GDBusProxy *proxy = G_DBUS_PROXY (initable);
916   GSimpleAsyncResult *simple;
917
918   simple = g_simple_async_result_new (G_OBJECT (proxy),
919                                       callback,
920                                       user_data,
921                                       NULL);
922
923   subscribe_to_signals (proxy);
924
925   if (!(proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES))
926     {
927       /* load all properties asynchronously */
928       g_dbus_connection_call (proxy->priv->connection,
929                               proxy->priv->unique_bus_name,
930                               proxy->priv->object_path,
931                               "org.freedesktop.DBus.Properties",
932                               "GetAll",
933                               g_variant_new ("(s)", proxy->priv->interface_name),
934                               G_DBUS_CALL_FLAGS_NONE,
935                               -1,           /* timeout */
936                               cancellable,
937                               (GAsyncReadyCallback) get_all_cb,
938                               simple);
939     }
940   else
941     {
942       g_simple_async_result_complete_in_idle (simple);
943       g_object_unref (simple);
944     }
945 }
946
947 static gboolean
948 async_initable_init_finish (GAsyncInitable  *initable,
949                             GAsyncResult    *res,
950                             GError         **error)
951 {
952   GDBusProxy *proxy = G_DBUS_PROXY (initable);
953   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
954   GVariant *result;
955   gboolean ret;
956
957   ret = FALSE;
958
959   result = g_simple_async_result_get_op_res_gpointer (simple);
960   if (result == NULL)
961     {
962       if (!(proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES))
963         {
964           g_simple_async_result_propagate_error (simple, error);
965           goto out;
966         }
967     }
968   else
969     {
970       process_get_all_reply (proxy, result);
971     }
972
973   ret = TRUE;
974
975  out:
976   proxy->priv->initialized = TRUE;
977   return ret;
978 }
979
980 static void
981 async_initable_iface_init (GAsyncInitableIface *async_initable_iface)
982 {
983   async_initable_iface->init_async = async_initable_init_async;
984   async_initable_iface->init_finish = async_initable_init_finish;
985 }
986
987 /* ---------------------------------------------------------------------------------------------------- */
988
989 /**
990  * g_dbus_proxy_new:
991  * @connection: A #GDBusConnection.
992  * @object_type: Either #G_TYPE_DBUS_PROXY or the #GType for the #GDBusProxy<!-- -->-derived type of proxy to create.
993  * @flags: Flags used when constructing the proxy.
994  * @info: A #GDBusInterfaceInfo specifying the minimal interface that @proxy conforms to or %NULL.
995  * @unique_bus_name: A unique bus name or %NULL if @connection is not a message bus connection.
996  * @object_path: An object path.
997  * @interface_name: A D-Bus interface name.
998  * @cancellable: A #GCancellable or %NULL.
999  * @callback: Callback function to invoke when the proxy is ready.
1000  * @user_data: User data to pass to @callback.
1001  *
1002  * Creates a proxy for accessing @interface_name on the remote object at @object_path
1003  * owned by @unique_bus_name at @connection and asynchronously loads D-Bus properties unless the
1004  * #G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES flag is used. Connect to the
1005  * #GDBusProxy::g-properties-changed signal to get notified about property changes.
1006  *
1007  * If the #G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS flag is not set, also sets up
1008  * match rules for signals. Connect to the #GDBusProxy::g-signal signal
1009  * to handle signals from the remote object.
1010  *
1011  * This is a failable asynchronous constructor - when the proxy is
1012  * ready, @callback will be invoked and you can use
1013  * g_dbus_proxy_new_finish() to get the result.
1014  *
1015  * See g_dbus_proxy_new_sync() and for a synchronous version of this constructor.
1016  *
1017  * Since: 2.26
1018  */
1019 void
1020 g_dbus_proxy_new (GDBusConnection     *connection,
1021                   GType                object_type,
1022                   GDBusProxyFlags      flags,
1023                   GDBusInterfaceInfo  *info,
1024                   const gchar         *unique_bus_name,
1025                   const gchar         *object_path,
1026                   const gchar         *interface_name,
1027                   GCancellable        *cancellable,
1028                   GAsyncReadyCallback  callback,
1029                   gpointer             user_data)
1030 {
1031   g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
1032   g_return_if_fail (g_type_is_a (object_type, G_TYPE_DBUS_PROXY));
1033   g_return_if_fail ((unique_bus_name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) ||
1034                     g_dbus_is_unique_name (unique_bus_name));
1035   g_return_if_fail (g_variant_is_object_path (object_path));
1036   g_return_if_fail (g_dbus_is_interface_name (interface_name));
1037
1038   g_async_initable_new_async (object_type,
1039                               G_PRIORITY_DEFAULT,
1040                               cancellable,
1041                               callback,
1042                               user_data,
1043                               "g-flags", flags,
1044                               "g-interface-info", info,
1045                               "g-unique-bus-name", unique_bus_name,
1046                               "g-connection", connection,
1047                               "g-object-path", object_path,
1048                               "g-interface-name", interface_name,
1049                               NULL);
1050 }
1051
1052 /**
1053  * g_dbus_proxy_new_finish:
1054  * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to g_dbus_proxy_new().
1055  * @error: Return location for error or %NULL.
1056  *
1057  * Finishes creating a #GDBusProxy.
1058  *
1059  * Returns: A #GDBusProxy or %NULL if @error is set. Free with g_object_unref().
1060  *
1061  * Since: 2.26
1062  */
1063 GDBusProxy *
1064 g_dbus_proxy_new_finish (GAsyncResult  *res,
1065                          GError       **error)
1066 {
1067   GObject *object;
1068   GObject *source_object;
1069
1070   source_object = g_async_result_get_source_object (res);
1071   g_assert (source_object != NULL);
1072
1073   object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
1074                                         res,
1075                                         error);
1076   g_object_unref (source_object);
1077
1078   if (object != NULL)
1079     return G_DBUS_PROXY (object);
1080   else
1081     return NULL;
1082 }
1083
1084
1085 /* ---------------------------------------------------------------------------------------------------- */
1086
1087 /**
1088  * g_dbus_proxy_new_sync:
1089  * @connection: A #GDBusConnection.
1090  * @object_type: Either #G_TYPE_DBUS_PROXY or the #GType for the #GDBusProxy<!-- -->-derived type of proxy to create.
1091  * @flags: Flags used when constructing the proxy.
1092  * @info: A #GDBusInterfaceInfo specifying the minimal interface that @proxy conforms to or %NULL.
1093  * @unique_bus_name: A unique bus name or %NULL if @connection is not a message bus connection.
1094  * @object_path: An object path.
1095  * @interface_name: A D-Bus interface name.
1096  * @cancellable: A #GCancellable or %NULL.
1097  * @error: Return location for error or %NULL.
1098  *
1099  * Creates a proxy for accessing @interface_name on the remote object at @object_path
1100  * owned by @unique_bus_name at @connection and synchronously loads D-Bus properties unless the
1101  * #G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES flag is used.
1102  *
1103  * If the #G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS flag is not set, also sets up
1104  * match rules for signals. Connect to the #GDBusProxy::g-signal signal
1105  * to handle signals from the remote object.
1106  *
1107  * This is a synchronous failable constructor. See g_dbus_proxy_new()
1108  * and g_dbus_proxy_new_finish() for the asynchronous version.
1109  *
1110  * Returns: A #GDBusProxy or %NULL if error is set. Free with g_object_unref().
1111  *
1112  * Since: 2.26
1113  */
1114 GDBusProxy *
1115 g_dbus_proxy_new_sync (GDBusConnection     *connection,
1116                        GType                object_type,
1117                        GDBusProxyFlags      flags,
1118                        GDBusInterfaceInfo  *info,
1119                        const gchar         *unique_bus_name,
1120                        const gchar         *object_path,
1121                        const gchar         *interface_name,
1122                        GCancellable        *cancellable,
1123                        GError             **error)
1124 {
1125   GInitable *initable;
1126
1127   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
1128   g_return_val_if_fail (g_type_is_a (object_type, G_TYPE_DBUS_PROXY), NULL);
1129   g_return_val_if_fail ((unique_bus_name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) ||
1130                         g_dbus_is_unique_name (unique_bus_name), NULL);
1131   g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
1132   g_return_val_if_fail (g_dbus_is_interface_name (interface_name), NULL);
1133
1134   initable = g_initable_new (object_type,
1135                              cancellable,
1136                              error,
1137                              "g-flags", flags,
1138                              "g-interface-info", info,
1139                              "g-unique-bus-name", unique_bus_name,
1140                              "g-connection", connection,
1141                              "g-object-path", object_path,
1142                              "g-interface-name", interface_name,
1143                              NULL);
1144   if (initable != NULL)
1145     return G_DBUS_PROXY (initable);
1146   else
1147     return NULL;
1148 }
1149
1150 /* ---------------------------------------------------------------------------------------------------- */
1151
1152 /**
1153  * g_dbus_proxy_get_connection:
1154  * @proxy: A #GDBusProxy.
1155  *
1156  * Gets the connection @proxy is for.
1157  *
1158  * Returns: A #GDBusConnection owned by @proxy. Do not free.
1159  *
1160  * Since: 2.26
1161  */
1162 GDBusConnection *
1163 g_dbus_proxy_get_connection (GDBusProxy *proxy)
1164 {
1165   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
1166   return proxy->priv->connection;
1167 }
1168
1169 /**
1170  * g_dbus_proxy_get_flags:
1171  * @proxy: A #GDBusProxy.
1172  *
1173  * Gets the flags that @proxy was constructed with.
1174  *
1175  * Returns: Flags from the #GDBusProxyFlags enumeration.
1176  *
1177  * Since: 2.26
1178  */
1179 GDBusProxyFlags
1180 g_dbus_proxy_get_flags (GDBusProxy *proxy)
1181 {
1182   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), 0);
1183   return proxy->priv->flags;
1184 }
1185
1186 /**
1187  * g_dbus_proxy_get_unique_bus_name:
1188  * @proxy: A #GDBusProxy.
1189  *
1190  * Gets the unique bus name @proxy is for.
1191  *
1192  * Returns: A string owned by @proxy. Do not free.
1193  *
1194  * Since: 2.26
1195  */
1196 const gchar *
1197 g_dbus_proxy_get_unique_bus_name (GDBusProxy *proxy)
1198 {
1199   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
1200   return proxy->priv->unique_bus_name;
1201 }
1202
1203 /**
1204  * g_dbus_proxy_get_object_path:
1205  * @proxy: A #GDBusProxy.
1206  *
1207  * Gets the object path @proxy is for.
1208  *
1209  * Returns: A string owned by @proxy. Do not free.
1210  *
1211  * Since: 2.26
1212  */
1213 const gchar *
1214 g_dbus_proxy_get_object_path (GDBusProxy *proxy)
1215 {
1216   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
1217   return proxy->priv->object_path;
1218 }
1219
1220 /**
1221  * g_dbus_proxy_get_interface_name:
1222  * @proxy: A #GDBusProxy.
1223  *
1224  * Gets the D-Bus interface name @proxy is for.
1225  *
1226  * Returns: A string owned by @proxy. Do not free.
1227  *
1228  * Since: 2.26
1229  */
1230 const gchar *
1231 g_dbus_proxy_get_interface_name (GDBusProxy *proxy)
1232 {
1233   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
1234   return proxy->priv->interface_name;
1235 }
1236
1237 /**
1238  * g_dbus_proxy_get_default_timeout:
1239  * @proxy: A #GDBusProxy.
1240  *
1241  * Gets the timeout to use if -1 (specifying default timeout) is
1242  * passed as @timeout_msec in the g_dbus_proxy_call() and
1243  * g_dbus_proxy_call_sync() functions.
1244  *
1245  * See the #GDBusProxy:g-default-timeout property for more details.
1246  *
1247  * Returns: Timeout to use for @proxy.
1248  *
1249  * Since: 2.26
1250  */
1251 gint
1252 g_dbus_proxy_get_default_timeout (GDBusProxy *proxy)
1253 {
1254   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), -1);
1255   return proxy->priv->timeout_msec;
1256 }
1257
1258 /**
1259  * g_dbus_proxy_set_default_timeout:
1260  * @proxy: A #GDBusProxy.
1261  * @timeout_msec: Timeout in milliseconds.
1262  *
1263  * Sets the timeout to use if -1 (specifying default timeout) is
1264  * passed as @timeout_msec in the g_dbus_proxy_call() and
1265  * g_dbus_proxy_call_sync() functions.
1266  *
1267  * See the #GDBusProxy:g-default-timeout property for more details.
1268  *
1269  * Since: 2.26
1270  */
1271 void
1272 g_dbus_proxy_set_default_timeout (GDBusProxy *proxy,
1273                                   gint        timeout_msec)
1274 {
1275   g_return_if_fail (G_IS_DBUS_PROXY (proxy));
1276   g_return_if_fail (timeout_msec == -1 || timeout_msec >= 0);
1277
1278   /* TODO: locking? */
1279   if (proxy->priv->timeout_msec != timeout_msec)
1280     {
1281       proxy->priv->timeout_msec = timeout_msec;
1282       g_object_notify (G_OBJECT (proxy), "g-default-timeout");
1283     }
1284 }
1285
1286 /**
1287  * g_dbus_proxy_get_interface_info:
1288  * @proxy: A #GDBusProxy
1289  *
1290  * Returns the #GDBusInterfaceInfo, if any, specifying the minimal
1291  * interface that @proxy conforms to.
1292  *
1293  * See the #GDBusProxy:g-interface-info property for more details.
1294  *
1295  * Returns: A #GDBusInterfaceInfo or %NULL. Do not unref the returned
1296  * object, it is owned by @proxy.
1297  *
1298  * Since: 2.26
1299  */
1300 GDBusInterfaceInfo *
1301 g_dbus_proxy_get_interface_info (GDBusProxy *proxy)
1302 {
1303   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
1304   return proxy->priv->expected_interface;
1305 }
1306
1307 /**
1308  * g_dbus_proxy_set_interface_info:
1309  * @proxy: A #GDBusProxy
1310  * @info: Minimum interface this proxy conforms to or %NULL to unset.
1311  *
1312  * Ensure that interactions with @proxy conform to the given
1313  * interface.  For example, when completing a method call, if the type
1314  * signature of the message isn't what's expected, the given #GError
1315  * is set.  Signals that have a type signature mismatch are simply
1316  * dropped.
1317  *
1318  * See the #GDBusProxy:g-interface-info property for more details.
1319  *
1320  * Since: 2.26
1321  */
1322 void
1323 g_dbus_proxy_set_interface_info (GDBusProxy         *proxy,
1324                                  GDBusInterfaceInfo *info)
1325 {
1326   g_return_if_fail (G_IS_DBUS_PROXY (proxy));
1327   if (proxy->priv->expected_interface != NULL)
1328     g_dbus_interface_info_unref (proxy->priv->expected_interface);
1329   proxy->priv->expected_interface = info != NULL ? g_dbus_interface_info_ref (info) : NULL;
1330 }
1331
1332 /* ---------------------------------------------------------------------------------------------------- */
1333
1334 static gboolean
1335 maybe_split_method_name (const gchar  *method_name,
1336                          gchar       **out_interface_name,
1337                          const gchar **out_method_name)
1338 {
1339   gboolean was_split;
1340
1341   was_split = FALSE;
1342   g_assert (out_interface_name != NULL);
1343   g_assert (out_method_name != NULL);
1344   *out_interface_name = NULL;
1345   *out_method_name = NULL;
1346
1347   if (strchr (method_name, '.') != NULL)
1348     {
1349       gchar *p;
1350       gchar *last_dot;
1351
1352       p = g_strdup (method_name);
1353       last_dot = strrchr (p, '.');
1354       *last_dot = '\0';
1355
1356       *out_interface_name = p;
1357       *out_method_name = last_dot + 1;
1358
1359       was_split = TRUE;
1360     }
1361
1362   return was_split;
1363 }
1364
1365
1366 static void
1367 reply_cb (GDBusConnection *connection,
1368           GAsyncResult    *res,
1369           gpointer         user_data)
1370 {
1371   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
1372   GVariant *value;
1373   GError *error;
1374
1375   error = NULL;
1376   value = g_dbus_connection_call_finish (connection,
1377                                          res,
1378                                          &error);
1379   if (error != NULL)
1380     {
1381       g_simple_async_result_set_from_error (simple,
1382                                             error);
1383       g_error_free (error);
1384     }
1385   else
1386     {
1387       g_simple_async_result_set_op_res_gpointer (simple,
1388                                                  value,
1389                                                  (GDestroyNotify) g_variant_unref);
1390     }
1391
1392   /* no need to complete in idle since the method GDBusConnection already does */
1393   g_simple_async_result_complete (simple);
1394 }
1395
1396 static const GDBusMethodInfo *
1397 lookup_method_info_or_warn (GDBusProxy  *proxy,
1398                             const gchar *method_name)
1399 {
1400   const GDBusMethodInfo *info;
1401
1402   if (proxy->priv->expected_interface == NULL)
1403     return NULL;
1404
1405   info = g_dbus_interface_info_lookup_method (proxy->priv->expected_interface, method_name);
1406   if (info == NULL)
1407     {
1408       g_warning ("Trying to invoke method %s which isn't in expected interface %s",
1409                  method_name, proxy->priv->expected_interface->name);
1410     }
1411
1412   return info;
1413 }
1414
1415 static gboolean
1416 validate_method_return (const char             *method_name,
1417                         GVariant               *value,
1418                         const GDBusMethodInfo  *expected_method_info,
1419                         GError                **error)
1420 {
1421   const gchar *type_string;
1422   gchar *signature;
1423   gboolean ret;
1424
1425   ret = TRUE;
1426   signature = NULL;
1427
1428   if (value == NULL || expected_method_info == NULL)
1429     goto out;
1430
1431   /* Shouldn't happen... */
1432   if (g_variant_classify (value) != G_VARIANT_CLASS_TUPLE)
1433     goto out;
1434
1435   type_string = g_variant_get_type_string (value);
1436   signature = _g_dbus_compute_complete_signature (expected_method_info->out_args, TRUE);
1437   if (g_strcmp0 (type_string, signature) != 0)
1438     {
1439       g_set_error (error,
1440                    G_IO_ERROR,
1441                    G_IO_ERROR_INVALID_ARGUMENT,
1442                    _("Method `%s' returned signature `%s', but expected `%s'"),
1443                    method_name,
1444                    type_string,
1445                    signature);
1446       ret = FALSE;
1447     }
1448
1449  out:
1450   g_free (signature);
1451   return ret;
1452 }
1453
1454 /**
1455  * g_dbus_proxy_call:
1456  * @proxy: A #GDBusProxy.
1457  * @method_name: Name of method to invoke.
1458  * @parameters: A #GVariant tuple with parameters for the signal or %NULL if not passing parameters.
1459  * @flags: Flags from the #GDBusCallFlags enumeration.
1460  * @timeout_msec: The timeout in milliseconds or -1 to use the proxy default timeout.
1461  * @cancellable: A #GCancellable or %NULL.
1462  * @callback: A #GAsyncReadyCallback to call when the request is satisfied or %NULL if you don't
1463  * care about the result of the method invocation.
1464  * @user_data: The data to pass to @callback.
1465  *
1466  * Asynchronously invokes the @method_name method on @proxy.
1467  *
1468  * If @method_name contains any dots, then @name is split into interface and
1469  * method name parts. This allows using @proxy for invoking methods on
1470  * other interfaces.
1471  *
1472  * If the #GDBusConnection associated with @proxy is closed then
1473  * the operation will fail with %G_IO_ERROR_CLOSED. If
1474  * @cancellable is canceled, the operation will fail with
1475  * %G_IO_ERROR_CANCELLED. If @parameters contains a value not
1476  * compatible with the D-Bus protocol, the operation fails with
1477  * %G_IO_ERROR_INVALID_ARGUMENT.
1478  *
1479  * If the @parameters #GVariant is floating, it is consumed. This allows
1480  * convenient 'inline' use of g_variant_new(), e.g.:
1481  * |[
1482  *  g_dbus_proxy_call (proxy,
1483  *                     "TwoStrings",
1484  *                     g_variant_new ("(ss)",
1485  *                                    "Thing One",
1486  *                                    "Thing Two"),
1487  *                     G_DBUS_CALL_FLAGS_NONE,
1488  *                     -1,
1489  *                     NULL,
1490  *                     (GAsyncReadyCallback) two_strings_done,
1491  *                     &amp;data);
1492  * ]|
1493  *
1494  * This is an asynchronous method. When the operation is finished,
1495  * @callback will be invoked in the
1496  * <link linkend="g-main-context-push-thread-default">thread-default
1497  * main loop</link> of the thread you are calling this method from.
1498  * You can then call g_dbus_proxy_call_finish() to get the result of
1499  * the operation. See g_dbus_proxy_call_sync() for the synchronous
1500  * version of this method.
1501  *
1502  * Since: 2.26
1503  */
1504 void
1505 g_dbus_proxy_call (GDBusProxy          *proxy,
1506                    const gchar         *method_name,
1507                    GVariant            *parameters,
1508                    GDBusCallFlags       flags,
1509                    gint                 timeout_msec,
1510                    GCancellable        *cancellable,
1511                    GAsyncReadyCallback  callback,
1512                    gpointer             user_data)
1513 {
1514   GSimpleAsyncResult *simple;
1515   gboolean was_split;
1516   gchar *split_interface_name;
1517   const gchar *split_method_name;
1518   const GDBusMethodInfo *expected_method_info;
1519   const gchar *target_method_name;
1520   const gchar *target_interface_name;
1521
1522   g_return_if_fail (G_IS_DBUS_PROXY (proxy));
1523   g_return_if_fail (g_dbus_is_member_name (method_name) || g_dbus_is_interface_name (method_name));
1524   g_return_if_fail (parameters == NULL || g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE));
1525   g_return_if_fail (timeout_msec == -1 || timeout_msec >= 0);
1526
1527   simple = g_simple_async_result_new (G_OBJECT (proxy),
1528                                       callback,
1529                                       user_data,
1530                                       g_dbus_proxy_call);
1531
1532   was_split = maybe_split_method_name (method_name, &split_interface_name, &split_method_name);
1533   target_method_name = was_split ? split_method_name : method_name;
1534   target_interface_name = was_split ? split_interface_name : proxy->priv->interface_name;
1535
1536   g_object_set_data_full (G_OBJECT (simple), "-gdbus-proxy-method-name", g_strdup (target_method_name), g_free);
1537
1538   /* Just warn here */
1539   expected_method_info = lookup_method_info_or_warn (proxy, target_method_name);
1540
1541   g_dbus_connection_call (proxy->priv->connection,
1542                           proxy->priv->unique_bus_name,
1543                           proxy->priv->object_path,
1544                           target_interface_name,
1545                           target_method_name,
1546                           parameters,
1547                           flags,
1548                           timeout_msec == -1 ? proxy->priv->timeout_msec : timeout_msec,
1549                           cancellable,
1550                           (GAsyncReadyCallback) reply_cb,
1551                           simple);
1552
1553   g_free (split_interface_name);
1554 }
1555
1556 /**
1557  * g_dbus_proxy_call_finish:
1558  * @proxy: A #GDBusProxy.
1559  * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_proxy_call().
1560  * @error: Return location for error or %NULL.
1561  *
1562  * Finishes an operation started with g_dbus_proxy_call().
1563  *
1564  * Returns: %NULL if @error is set. Otherwise a #GVariant tuple with
1565  * return values. Free with g_variant_unref().
1566  *
1567  * Since: 2.26
1568  */
1569 GVariant *
1570 g_dbus_proxy_call_finish (GDBusProxy    *proxy,
1571                           GAsyncResult  *res,
1572                           GError       **error)
1573 {
1574   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
1575   GVariant *value;
1576   const char *method_name;
1577   const GDBusMethodInfo *expected_method_info;
1578
1579   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
1580   g_return_val_if_fail (G_IS_ASYNC_RESULT (res), NULL);
1581   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1582
1583   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_dbus_proxy_call);
1584
1585   value = NULL;
1586
1587   if (g_simple_async_result_propagate_error (simple, error))
1588     goto out;
1589
1590   value = g_simple_async_result_get_op_res_gpointer (simple);
1591   method_name = g_object_get_data (G_OBJECT (simple), "-gdbus-proxy-method-name");
1592
1593   /* We may not have a method name for internally-generated proxy calls like GetAll */
1594   if (value && method_name && proxy->priv->expected_interface)
1595     {
1596       expected_method_info = g_dbus_interface_info_lookup_method (proxy->priv->expected_interface, method_name);
1597       if (!validate_method_return (method_name, value, expected_method_info, error))
1598         {
1599           g_variant_unref (value);
1600           value = NULL;
1601         }
1602     }
1603
1604  out:
1605   return value;
1606 }
1607
1608 /**
1609  * g_dbus_proxy_call_sync:
1610  * @proxy: A #GDBusProxy.
1611  * @method_name: Name of method to invoke.
1612  * @parameters: A #GVariant tuple with parameters for the signal or %NULL if not passing parameters.
1613  * @flags: Flags from the #GDBusCallFlags enumeration.
1614  * @timeout_msec: The timeout in milliseconds or -1 to use the proxy default timeout.
1615  * @cancellable: A #GCancellable or %NULL.
1616  * @error: Return location for error or %NULL.
1617  *
1618  * Synchronously invokes the @method_name method on @proxy.
1619  *
1620  * If @method_name contains any dots, then @name is split into interface and
1621  * method name parts. This allows using @proxy for invoking methods on
1622  * other interfaces.
1623  *
1624  * If the #GDBusConnection associated with @proxy is disconnected then
1625  * the operation will fail with %G_IO_ERROR_CLOSED. If
1626  * @cancellable is canceled, the operation will fail with
1627  * %G_IO_ERROR_CANCELLED. If @parameters contains a value not
1628  * compatible with the D-Bus protocol, the operation fails with
1629  * %G_IO_ERROR_INVALID_ARGUMENT.
1630  *
1631  * If the @parameters #GVariant is floating, it is consumed. This allows
1632  * convenient 'inline' use of g_variant_new(), e.g.:
1633  * |[
1634  *  g_dbus_proxy_call_sync (proxy,
1635  *                          "TwoStrings",
1636  *                          g_variant_new ("(ss)",
1637  *                                         "Thing One",
1638  *                                         "Thing Two"),
1639  *                          G_DBUS_CALL_FLAGS_NONE,
1640  *                          -1,
1641  *                          NULL,
1642  *                          &amp;error);
1643  * ]|
1644  *
1645  * The calling thread is blocked until a reply is received. See
1646  * g_dbus_proxy_call() for the asynchronous version of this
1647  * method.
1648  *
1649  * Returns: %NULL if @error is set. Otherwise a #GVariant tuple with
1650  * return values. Free with g_variant_unref().
1651  *
1652  * Since: 2.26
1653  */
1654 GVariant *
1655 g_dbus_proxy_call_sync (GDBusProxy      *proxy,
1656                         const gchar     *method_name,
1657                         GVariant        *parameters,
1658                         GDBusCallFlags   flags,
1659                         gint             timeout_msec,
1660                         GCancellable    *cancellable,
1661                         GError         **error)
1662 {
1663   GVariant *ret;
1664   gboolean was_split;
1665   gchar *split_interface_name;
1666   const gchar *split_method_name;
1667   const GDBusMethodInfo *expected_method_info;
1668   const gchar *target_method_name;
1669   const gchar *target_interface_name;
1670
1671   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
1672   g_return_val_if_fail (g_dbus_is_member_name (method_name) || g_dbus_is_interface_name (method_name), NULL);
1673   g_return_val_if_fail (parameters == NULL || g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE), NULL);
1674   g_return_val_if_fail (timeout_msec == -1 || timeout_msec >= 0, NULL);
1675   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1676
1677   was_split = maybe_split_method_name (method_name, &split_interface_name, &split_method_name);
1678   target_method_name = was_split ? split_method_name : method_name;
1679   target_interface_name = was_split ? split_interface_name : proxy->priv->interface_name;
1680
1681   if (proxy->priv->expected_interface)
1682     {
1683       expected_method_info = g_dbus_interface_info_lookup_method (proxy->priv->expected_interface, target_method_name);
1684       if (expected_method_info == NULL)
1685         {
1686           g_warning ("Trying to invoke method `%s' which isn't in expected interface `%s'",
1687                      target_method_name,
1688                      target_interface_name);
1689         }
1690     }
1691   else
1692     {
1693       expected_method_info = NULL;
1694     }
1695
1696   ret = g_dbus_connection_call_sync (proxy->priv->connection,
1697                                      proxy->priv->unique_bus_name,
1698                                      proxy->priv->object_path,
1699                                      target_interface_name,
1700                                      target_method_name,
1701                                      parameters,
1702                                      flags,
1703                                      timeout_msec == -1 ? proxy->priv->timeout_msec : timeout_msec,
1704                                      cancellable,
1705                                      error);
1706   if (!validate_method_return (target_method_name, ret, expected_method_info, error))
1707     {
1708       g_variant_unref (ret);
1709       ret = NULL;
1710     }
1711
1712   g_free (split_interface_name);
1713
1714   return ret;
1715 }
1716
1717 /* ---------------------------------------------------------------------------------------------------- */
1718
1719 #define __G_DBUS_PROXY_C__
1720 #include "gioaliasdef.c"