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