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