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