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