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.1 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, see <http://www.gnu.org/licenses/>.
17 *
18 * Author: David Zeuthen <davidz@redhat.com>
19 */
20
21 #include "config.h"
22
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "gdbusutils.h"
27 #include "gdbusproxy.h"
28 #include "gioenumtypes.h"
29 #include "gdbusconnection.h"
30 #include "gdbuserror.h"
31 #include "gdbusprivate.h"
32 #include "ginitable.h"
33 #include "gasyncinitable.h"
34 #include "gioerror.h"
35 #include "gtask.h"
36 #include "gcancellable.h"
37 #include "gdbusinterface.h"
38 #include "gasyncresult.h"
39
40 #ifdef G_OS_UNIX
41 #include "gunixfdlist.h"
42 #endif
43
44 #include "glibintl.h"
45 #include "gmarshal-internal.h"
46
47 /**
48 * SECTION:gdbusproxy
49 * @short_description: Client-side D-Bus interface proxy
50 * @include: gio/gio.h
51 *
52 * #GDBusProxy is a base class used for proxies to access a D-Bus
53 * interface on a remote object. A #GDBusProxy can be constructed for
54 * both well-known and unique names.
55 *
56 * By default, #GDBusProxy will cache all properties (and listen to
57 * changes) of the remote object, and proxy all signals that get
58 * emitted. This behaviour can be changed by passing suitable
59 * #GDBusProxyFlags when the proxy is created. If the proxy is for a
60 * well-known name, the property cache is flushed when the name owner
61 * vanishes and reloaded when a name owner appears.
62 *
63 * The unique name owner of the proxy's name is tracked and can be read from
64 * #GDBusProxy:g-name-owner. Connect to the #GObject::notify signal to
65 * get notified of changes. Additionally, only signals and property
66 * changes emitted from the current name owner are considered and
67 * calls are always sent to the current name owner. This avoids a
68 * number of race conditions when the name is lost by one owner and
69 * claimed by another. However, if no name owner currently exists,
70 * then calls will be sent to the well-known name which may result in
71 * the message bus launching an owner (unless
72 * %G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START is set).
73 *
74 * The generic #GDBusProxy::g-properties-changed and
75 * #GDBusProxy::g-signal signals are not very convenient to work with.
76 * Therefore, the recommended way of working with proxies is to subclass
77 * #GDBusProxy, and have more natural properties and signals in your derived
78 * class. This [example][gdbus-example-gdbus-codegen] shows how this can
79 * easily be done using the [gdbus-codegen][gdbus-codegen] tool.
80 *
81 * A #GDBusProxy instance can be used from multiple threads but note
82 * that all signals (e.g. #GDBusProxy::g-signal, #GDBusProxy::g-properties-changed
83 * and #GObject::notify) are emitted in the
84 * [thread-default main context][g-main-context-push-thread-default]
85 * of the thread where the instance was constructed.
86 *
87 * An example using a proxy for a well-known name can be found in
88 * [gdbus-example-watch-proxy.c](https://git.gnome.org/browse/glib/tree/gio/tests/gdbus-example-watch-proxy.c)
89 */
90
91 /* lock protecting the mutable properties: name_owner, timeout_msec,
92 * expected_interface, and the properties hash table
93 */
94 G_LOCK_DEFINE_STATIC (properties_lock);
95
96 /* ---------------------------------------------------------------------------------------------------- */
97
98 G_LOCK_DEFINE_STATIC (signal_subscription_lock);
99
100 typedef struct
101 {
102 volatile gint ref_count;
103 GDBusProxy *proxy;
104 } SignalSubscriptionData;
105
106 static SignalSubscriptionData *
signal_subscription_ref(SignalSubscriptionData * data)107 signal_subscription_ref (SignalSubscriptionData *data)
108 {
109 g_atomic_int_inc (&data->ref_count);
110 return data;
111 }
112
113 static void
signal_subscription_unref(SignalSubscriptionData * data)114 signal_subscription_unref (SignalSubscriptionData *data)
115 {
116 if (g_atomic_int_dec_and_test (&data->ref_count))
117 {
118 g_slice_free (SignalSubscriptionData, data);
119 }
120 }
121
122 /* ---------------------------------------------------------------------------------------------------- */
123
124 struct _GDBusProxyPrivate
125 {
126 GBusType bus_type;
127 GDBusProxyFlags flags;
128 GDBusConnection *connection;
129
130 gchar *name;
131 /* mutable, protected by properties_lock */
132 gchar *name_owner;
133 gchar *object_path;
134 gchar *interface_name;
135 /* mutable, protected by properties_lock */
136 gint timeout_msec;
137
138 guint name_owner_changed_subscription_id;
139
140 GCancellable *get_all_cancellable;
141
142 /* gchar* -> GVariant*, protected by properties_lock */
143 GHashTable *properties;
144
145 /* mutable, protected by properties_lock */
146 GDBusInterfaceInfo *expected_interface;
147
148 guint properties_changed_subscription_id;
149 guint signals_subscription_id;
150
151 gboolean initialized;
152
153 /* mutable, protected by properties_lock */
154 GDBusObject *object;
155
156 SignalSubscriptionData *signal_subscription_data;
157 };
158
159 enum
160 {
161 PROP_0,
162 PROP_G_CONNECTION,
163 PROP_G_BUS_TYPE,
164 PROP_G_NAME,
165 PROP_G_NAME_OWNER,
166 PROP_G_FLAGS,
167 PROP_G_OBJECT_PATH,
168 PROP_G_INTERFACE_NAME,
169 PROP_G_DEFAULT_TIMEOUT,
170 PROP_G_INTERFACE_INFO
171 };
172
173 enum
174 {
175 PROPERTIES_CHANGED_SIGNAL,
176 SIGNAL_SIGNAL,
177 LAST_SIGNAL,
178 };
179
180 static guint signals[LAST_SIGNAL] = {0};
181
182 static void dbus_interface_iface_init (GDBusInterfaceIface *dbus_interface_iface);
183 static void initable_iface_init (GInitableIface *initable_iface);
184 static void async_initable_iface_init (GAsyncInitableIface *async_initable_iface);
185
G_DEFINE_TYPE_WITH_CODE(GDBusProxy,g_dbus_proxy,G_TYPE_OBJECT,G_ADD_PRIVATE (GDBusProxy)G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_INTERFACE,dbus_interface_iface_init)G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,initable_iface_init)G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE,async_initable_iface_init))186 G_DEFINE_TYPE_WITH_CODE (GDBusProxy, g_dbus_proxy, G_TYPE_OBJECT,
187 G_ADD_PRIVATE (GDBusProxy)
188 G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_INTERFACE, dbus_interface_iface_init)
189 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)
190 G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init))
191
192 static void
193 g_dbus_proxy_dispose (GObject *object)
194 {
195 GDBusProxy *proxy = G_DBUS_PROXY (object);
196 G_LOCK (signal_subscription_lock);
197 if (proxy->priv->signal_subscription_data != NULL)
198 {
199 proxy->priv->signal_subscription_data->proxy = NULL;
200 signal_subscription_unref (proxy->priv->signal_subscription_data);
201 proxy->priv->signal_subscription_data = NULL;
202 }
203 G_UNLOCK (signal_subscription_lock);
204
205 G_OBJECT_CLASS (g_dbus_proxy_parent_class)->dispose (object);
206 }
207
208 static void
g_dbus_proxy_finalize(GObject * object)209 g_dbus_proxy_finalize (GObject *object)
210 {
211 GDBusProxy *proxy = G_DBUS_PROXY (object);
212
213 g_warn_if_fail (proxy->priv->get_all_cancellable == NULL);
214
215 if (proxy->priv->name_owner_changed_subscription_id > 0)
216 g_dbus_connection_signal_unsubscribe (proxy->priv->connection,
217 proxy->priv->name_owner_changed_subscription_id);
218
219 if (proxy->priv->properties_changed_subscription_id > 0)
220 g_dbus_connection_signal_unsubscribe (proxy->priv->connection,
221 proxy->priv->properties_changed_subscription_id);
222
223 if (proxy->priv->signals_subscription_id > 0)
224 g_dbus_connection_signal_unsubscribe (proxy->priv->connection,
225 proxy->priv->signals_subscription_id);
226
227 if (proxy->priv->connection != NULL)
228 g_object_unref (proxy->priv->connection);
229 g_free (proxy->priv->name);
230 g_free (proxy->priv->name_owner);
231 g_free (proxy->priv->object_path);
232 g_free (proxy->priv->interface_name);
233 if (proxy->priv->properties != NULL)
234 g_hash_table_unref (proxy->priv->properties);
235
236 if (proxy->priv->expected_interface != NULL)
237 {
238 g_dbus_interface_info_cache_release (proxy->priv->expected_interface);
239 g_dbus_interface_info_unref (proxy->priv->expected_interface);
240 }
241
242 if (proxy->priv->object != NULL)
243 g_object_remove_weak_pointer (G_OBJECT (proxy->priv->object), (gpointer *) &proxy->priv->object);
244
245 G_OBJECT_CLASS (g_dbus_proxy_parent_class)->finalize (object);
246 }
247
248 static void
g_dbus_proxy_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)249 g_dbus_proxy_get_property (GObject *object,
250 guint prop_id,
251 GValue *value,
252 GParamSpec *pspec)
253 {
254 GDBusProxy *proxy = G_DBUS_PROXY (object);
255
256 switch (prop_id)
257 {
258 case PROP_G_CONNECTION:
259 g_value_set_object (value, proxy->priv->connection);
260 break;
261
262 case PROP_G_FLAGS:
263 g_value_set_flags (value, proxy->priv->flags);
264 break;
265
266 case PROP_G_NAME:
267 g_value_set_string (value, proxy->priv->name);
268 break;
269
270 case PROP_G_NAME_OWNER:
271 g_value_take_string (value, g_dbus_proxy_get_name_owner (proxy));
272 break;
273
274 case PROP_G_OBJECT_PATH:
275 g_value_set_string (value, proxy->priv->object_path);
276 break;
277
278 case PROP_G_INTERFACE_NAME:
279 g_value_set_string (value, proxy->priv->interface_name);
280 break;
281
282 case PROP_G_DEFAULT_TIMEOUT:
283 g_value_set_int (value, g_dbus_proxy_get_default_timeout (proxy));
284 break;
285
286 case PROP_G_INTERFACE_INFO:
287 g_value_set_boxed (value, g_dbus_proxy_get_interface_info (proxy));
288 break;
289
290 default:
291 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
292 break;
293 }
294 }
295
296 static void
g_dbus_proxy_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)297 g_dbus_proxy_set_property (GObject *object,
298 guint prop_id,
299 const GValue *value,
300 GParamSpec *pspec)
301 {
302 GDBusProxy *proxy = G_DBUS_PROXY (object);
303
304 switch (prop_id)
305 {
306 case PROP_G_CONNECTION:
307 proxy->priv->connection = g_value_dup_object (value);
308 break;
309
310 case PROP_G_FLAGS:
311 proxy->priv->flags = g_value_get_flags (value);
312 break;
313
314 case PROP_G_NAME:
315 proxy->priv->name = g_value_dup_string (value);
316 break;
317
318 case PROP_G_OBJECT_PATH:
319 proxy->priv->object_path = g_value_dup_string (value);
320 break;
321
322 case PROP_G_INTERFACE_NAME:
323 proxy->priv->interface_name = g_value_dup_string (value);
324 break;
325
326 case PROP_G_DEFAULT_TIMEOUT:
327 g_dbus_proxy_set_default_timeout (proxy, g_value_get_int (value));
328 break;
329
330 case PROP_G_INTERFACE_INFO:
331 g_dbus_proxy_set_interface_info (proxy, g_value_get_boxed (value));
332 break;
333
334 case PROP_G_BUS_TYPE:
335 proxy->priv->bus_type = g_value_get_enum (value);
336 break;
337
338 default:
339 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
340 break;
341 }
342 }
343
344 static void
g_dbus_proxy_class_init(GDBusProxyClass * klass)345 g_dbus_proxy_class_init (GDBusProxyClass *klass)
346 {
347 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
348
349 gobject_class->dispose = g_dbus_proxy_dispose;
350 gobject_class->finalize = g_dbus_proxy_finalize;
351 gobject_class->set_property = g_dbus_proxy_set_property;
352 gobject_class->get_property = g_dbus_proxy_get_property;
353
354 /* Note that all property names are prefixed to avoid collisions with D-Bus property names
355 * in derived classes */
356
357 /**
358 * GDBusProxy:g-interface-info:
359 *
360 * Ensure that interactions with this proxy conform to the given
361 * interface. This is mainly to ensure that malformed data received
362 * from the other peer is ignored. The given #GDBusInterfaceInfo is
363 * said to be the "expected interface".
364 *
365 * The checks performed are:
366 * - When completing a method call, if the type signature of
367 * the reply message isn't what's expected, the reply is
368 * discarded and the #GError is set to %G_IO_ERROR_INVALID_ARGUMENT.
369 *
370 * - Received signals that have a type signature mismatch are dropped and
371 * a warning is logged via g_warning().
372 *
373 * - Properties received via the initial `GetAll()` call or via the
374 * `::PropertiesChanged` signal (on the
375 * [org.freedesktop.DBus.Properties](http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties)
376 * interface) or set using g_dbus_proxy_set_cached_property()
377 * with a type signature mismatch are ignored and a warning is
378 * logged via g_warning().
379 *
380 * Note that these checks are never done on methods, signals and
381 * properties that are not referenced in the given
382 * #GDBusInterfaceInfo, since extending a D-Bus interface on the
383 * service-side is not considered an ABI break.
384 *
385 * Since: 2.26
386 */
387 g_object_class_install_property (gobject_class,
388 PROP_G_INTERFACE_INFO,
389 g_param_spec_boxed ("g-interface-info",
390 P_("Interface Information"),
391 P_("Interface Information"),
392 G_TYPE_DBUS_INTERFACE_INFO,
393 G_PARAM_READABLE |
394 G_PARAM_WRITABLE |
395 G_PARAM_STATIC_NAME |
396 G_PARAM_STATIC_BLURB |
397 G_PARAM_STATIC_NICK));
398
399 /**
400 * GDBusProxy:g-connection:
401 *
402 * The #GDBusConnection the proxy is for.
403 *
404 * Since: 2.26
405 */
406 g_object_class_install_property (gobject_class,
407 PROP_G_CONNECTION,
408 g_param_spec_object ("g-connection",
409 P_("g-connection"),
410 P_("The connection the proxy is for"),
411 G_TYPE_DBUS_CONNECTION,
412 G_PARAM_READABLE |
413 G_PARAM_WRITABLE |
414 G_PARAM_CONSTRUCT_ONLY |
415 G_PARAM_STATIC_NAME |
416 G_PARAM_STATIC_BLURB |
417 G_PARAM_STATIC_NICK));
418
419 /**
420 * GDBusProxy:g-bus-type:
421 *
422 * If this property is not %G_BUS_TYPE_NONE, then
423 * #GDBusProxy:g-connection must be %NULL and will be set to the
424 * #GDBusConnection obtained by calling g_bus_get() with the value
425 * of this property.
426 *
427 * Since: 2.26
428 */
429 g_object_class_install_property (gobject_class,
430 PROP_G_BUS_TYPE,
431 g_param_spec_enum ("g-bus-type",
432 P_("Bus Type"),
433 P_("The bus to connect to, if any"),
434 G_TYPE_BUS_TYPE,
435 G_BUS_TYPE_NONE,
436 G_PARAM_WRITABLE |
437 G_PARAM_CONSTRUCT_ONLY |
438 G_PARAM_STATIC_NAME |
439 G_PARAM_STATIC_BLURB |
440 G_PARAM_STATIC_NICK));
441
442 /**
443 * GDBusProxy:g-flags:
444 *
445 * Flags from the #GDBusProxyFlags enumeration.
446 *
447 * Since: 2.26
448 */
449 g_object_class_install_property (gobject_class,
450 PROP_G_FLAGS,
451 g_param_spec_flags ("g-flags",
452 P_("g-flags"),
453 P_("Flags for the proxy"),
454 G_TYPE_DBUS_PROXY_FLAGS,
455 G_DBUS_PROXY_FLAGS_NONE,
456 G_PARAM_READABLE |
457 G_PARAM_WRITABLE |
458 G_PARAM_CONSTRUCT_ONLY |
459 G_PARAM_STATIC_NAME |
460 G_PARAM_STATIC_BLURB |
461 G_PARAM_STATIC_NICK));
462
463 /**
464 * GDBusProxy:g-name:
465 *
466 * The well-known or unique name that the proxy is for.
467 *
468 * Since: 2.26
469 */
470 g_object_class_install_property (gobject_class,
471 PROP_G_NAME,
472 g_param_spec_string ("g-name",
473 P_("g-name"),
474 P_("The well-known or unique name that the proxy is for"),
475 NULL,
476 G_PARAM_READABLE |
477 G_PARAM_WRITABLE |
478 G_PARAM_CONSTRUCT_ONLY |
479 G_PARAM_STATIC_NAME |
480 G_PARAM_STATIC_BLURB |
481 G_PARAM_STATIC_NICK));
482
483 /**
484 * GDBusProxy:g-name-owner:
485 *
486 * The unique name that owns #GDBusProxy:g-name or %NULL if no-one
487 * currently owns that name. You may connect to #GObject::notify signal to
488 * track changes to this property.
489 *
490 * Since: 2.26
491 */
492 g_object_class_install_property (gobject_class,
493 PROP_G_NAME_OWNER,
494 g_param_spec_string ("g-name-owner",
495 P_("g-name-owner"),
496 P_("The unique name for the owner"),
497 NULL,
498 G_PARAM_READABLE |
499 G_PARAM_STATIC_NAME |
500 G_PARAM_STATIC_BLURB |
501 G_PARAM_STATIC_NICK));
502
503 /**
504 * GDBusProxy:g-object-path:
505 *
506 * The object path the proxy is for.
507 *
508 * Since: 2.26
509 */
510 g_object_class_install_property (gobject_class,
511 PROP_G_OBJECT_PATH,
512 g_param_spec_string ("g-object-path",
513 P_("g-object-path"),
514 P_("The object path the proxy is for"),
515 NULL,
516 G_PARAM_READABLE |
517 G_PARAM_WRITABLE |
518 G_PARAM_CONSTRUCT_ONLY |
519 G_PARAM_STATIC_NAME |
520 G_PARAM_STATIC_BLURB |
521 G_PARAM_STATIC_NICK));
522
523 /**
524 * GDBusProxy:g-interface-name:
525 *
526 * The D-Bus interface name the proxy is for.
527 *
528 * Since: 2.26
529 */
530 g_object_class_install_property (gobject_class,
531 PROP_G_INTERFACE_NAME,
532 g_param_spec_string ("g-interface-name",
533 P_("g-interface-name"),
534 P_("The D-Bus interface name the proxy is for"),
535 NULL,
536 G_PARAM_READABLE |
537 G_PARAM_WRITABLE |
538 G_PARAM_CONSTRUCT_ONLY |
539 G_PARAM_STATIC_NAME |
540 G_PARAM_STATIC_BLURB |
541 G_PARAM_STATIC_NICK));
542
543 /**
544 * GDBusProxy:g-default-timeout:
545 *
546 * The timeout to use if -1 (specifying default timeout) is passed
547 * as @timeout_msec in the g_dbus_proxy_call() and
548 * g_dbus_proxy_call_sync() functions.
549 *
550 * This allows applications to set a proxy-wide timeout for all
551 * remote method invocations on the proxy. If this property is -1,
552 * the default timeout (typically 25 seconds) is used. If set to
553 * %G_MAXINT, then no timeout is used.
554 *
555 * Since: 2.26
556 */
557 g_object_class_install_property (gobject_class,
558 PROP_G_DEFAULT_TIMEOUT,
559 g_param_spec_int ("g-default-timeout",
560 P_("Default Timeout"),
561 P_("Timeout for remote method invocation"),
562 -1,
563 G_MAXINT,
564 -1,
565 G_PARAM_READABLE |
566 G_PARAM_WRITABLE |
567 G_PARAM_CONSTRUCT |
568 G_PARAM_STATIC_NAME |
569 G_PARAM_STATIC_BLURB |
570 G_PARAM_STATIC_NICK));
571
572 /**
573 * GDBusProxy::g-properties-changed:
574 * @proxy: The #GDBusProxy emitting the signal.
575 * @changed_properties: A #GVariant containing the properties that changed (type: `a{sv}`)
576 * @invalidated_properties: A %NULL terminated array of properties that was invalidated
577 *
578 * Emitted when one or more D-Bus properties on @proxy changes. The
579 * local cache has already been updated when this signal fires. Note
580 * that both @changed_properties and @invalidated_properties are
581 * guaranteed to never be %NULL (either may be empty though).
582 *
583 * If the proxy has the flag
584 * %G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES set, then
585 * @invalidated_properties will always be empty.
586 *
587 * This signal corresponds to the
588 * `PropertiesChanged` D-Bus signal on the
589 * `org.freedesktop.DBus.Properties` interface.
590 *
591 * Since: 2.26
592 */
593 signals[PROPERTIES_CHANGED_SIGNAL] = g_signal_new (I_("g-properties-changed"),
594 G_TYPE_DBUS_PROXY,
595 G_SIGNAL_RUN_LAST | G_SIGNAL_MUST_COLLECT,
596 G_STRUCT_OFFSET (GDBusProxyClass, g_properties_changed),
597 NULL,
598 NULL,
599 _g_cclosure_marshal_VOID__VARIANT_BOXED,
600 G_TYPE_NONE,
601 2,
602 G_TYPE_VARIANT,
603 G_TYPE_STRV | G_SIGNAL_TYPE_STATIC_SCOPE);
604 g_signal_set_va_marshaller (signals[PROPERTIES_CHANGED_SIGNAL],
605 G_TYPE_FROM_CLASS (klass),
606 _g_cclosure_marshal_VOID__VARIANT_BOXEDv);
607
608 /**
609 * GDBusProxy::g-signal:
610 * @proxy: The #GDBusProxy emitting the signal.
611 * @sender_name: (nullable): The sender of the signal or %NULL if the connection is not a bus connection.
612 * @signal_name: The name of the signal.
613 * @parameters: A #GVariant tuple with parameters for the signal.
614 *
615 * Emitted when a signal from the remote object and interface that @proxy is for, has been received.
616 *
617 * Since: 2.26
618 */
619 signals[SIGNAL_SIGNAL] = g_signal_new (I_("g-signal"),
620 G_TYPE_DBUS_PROXY,
621 G_SIGNAL_RUN_LAST | G_SIGNAL_MUST_COLLECT,
622 G_STRUCT_OFFSET (GDBusProxyClass, g_signal),
623 NULL,
624 NULL,
625 _g_cclosure_marshal_VOID__STRING_STRING_VARIANT,
626 G_TYPE_NONE,
627 3,
628 G_TYPE_STRING,
629 G_TYPE_STRING,
630 G_TYPE_VARIANT);
631 g_signal_set_va_marshaller (signals[SIGNAL_SIGNAL],
632 G_TYPE_FROM_CLASS (klass),
633 _g_cclosure_marshal_VOID__STRING_STRING_VARIANTv);
634
635 }
636
637 static void
g_dbus_proxy_init(GDBusProxy * proxy)638 g_dbus_proxy_init (GDBusProxy *proxy)
639 {
640 proxy->priv = g_dbus_proxy_get_instance_private (proxy);
641 proxy->priv->signal_subscription_data = g_slice_new0 (SignalSubscriptionData);
642 proxy->priv->signal_subscription_data->ref_count = 1;
643 proxy->priv->signal_subscription_data->proxy = proxy;
644 proxy->priv->properties = g_hash_table_new_full (g_str_hash,
645 g_str_equal,
646 g_free,
647 (GDestroyNotify) g_variant_unref);
648 }
649
650 /* ---------------------------------------------------------------------------------------------------- */
651
652 static gint
property_name_sort_func(const gchar ** a,const gchar ** b)653 property_name_sort_func (const gchar **a,
654 const gchar **b)
655 {
656 return g_strcmp0 (*a, *b);
657 }
658
659 /**
660 * g_dbus_proxy_get_cached_property_names:
661 * @proxy: A #GDBusProxy.
662 *
663 * Gets the names of all cached properties on @proxy.
664 *
665 * Returns: (transfer full) (nullable) (array zero-terminated=1): A
666 * %NULL-terminated array of strings or %NULL if
667 * @proxy has no cached properties. Free the returned array with
668 * g_strfreev().
669 *
670 * Since: 2.26
671 */
672 gchar **
g_dbus_proxy_get_cached_property_names(GDBusProxy * proxy)673 g_dbus_proxy_get_cached_property_names (GDBusProxy *proxy)
674 {
675 gchar **names;
676 GPtrArray *p;
677 GHashTableIter iter;
678 const gchar *key;
679
680 g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
681
682 G_LOCK (properties_lock);
683
684 names = NULL;
685 if (g_hash_table_size (proxy->priv->properties) == 0)
686 goto out;
687
688 p = g_ptr_array_new ();
689
690 g_hash_table_iter_init (&iter, proxy->priv->properties);
691 while (g_hash_table_iter_next (&iter, (gpointer) &key, NULL))
692 g_ptr_array_add (p, g_strdup (key));
693 g_ptr_array_sort (p, (GCompareFunc) property_name_sort_func);
694 g_ptr_array_add (p, NULL);
695
696 names = (gchar **) g_ptr_array_free (p, FALSE);
697
698 out:
699 G_UNLOCK (properties_lock);
700 return names;
701 }
702
703 /* properties_lock must be held for as long as you will keep the
704 * returned value
705 */
706 static const GDBusPropertyInfo *
lookup_property_info(GDBusProxy * proxy,const gchar * property_name)707 lookup_property_info (GDBusProxy *proxy,
708 const gchar *property_name)
709 {
710 const GDBusPropertyInfo *info = NULL;
711
712 if (proxy->priv->expected_interface == NULL)
713 goto out;
714
715 info = g_dbus_interface_info_lookup_property (proxy->priv->expected_interface, property_name);
716
717 out:
718 return info;
719 }
720
721 /**
722 * g_dbus_proxy_get_cached_property:
723 * @proxy: A #GDBusProxy.
724 * @property_name: Property name.
725 *
726 * Looks up the value for a property from the cache. This call does no
727 * blocking IO.
728 *
729 * If @proxy has an expected interface (see
730 * #GDBusProxy:g-interface-info) and @property_name is referenced by
731 * it, then @value is checked against the type of the property.
732 *
733 * Returns: (transfer full) (nullable): A reference to the #GVariant instance
734 * that holds the value for @property_name or %NULL if the value is not in
735 * the cache. The returned reference must be freed with g_variant_unref().
736 *
737 * Since: 2.26
738 */
739 GVariant *
g_dbus_proxy_get_cached_property(GDBusProxy * proxy,const gchar * property_name)740 g_dbus_proxy_get_cached_property (GDBusProxy *proxy,
741 const gchar *property_name)
742 {
743 const GDBusPropertyInfo *info;
744 GVariant *value;
745
746 g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
747 g_return_val_if_fail (property_name != NULL, NULL);
748
749 G_LOCK (properties_lock);
750
751 value = g_hash_table_lookup (proxy->priv->properties, property_name);
752 if (value == NULL)
753 goto out;
754
755 info = lookup_property_info (proxy, property_name);
756 if (info != NULL)
757 {
758 const gchar *type_string = g_variant_get_type_string (value);
759 if (g_strcmp0 (type_string, info->signature) != 0)
760 {
761 g_warning ("Trying to get property %s with type %s but according to the expected "
762 "interface the type is %s",
763 property_name,
764 type_string,
765 info->signature);
766 value = NULL;
767 goto out;
768 }
769 }
770
771 g_variant_ref (value);
772
773 out:
774 G_UNLOCK (properties_lock);
775 return value;
776 }
777
778 /**
779 * g_dbus_proxy_set_cached_property:
780 * @proxy: A #GDBusProxy
781 * @property_name: Property name.
782 * @value: (nullable): Value for the property or %NULL to remove it from the cache.
783 *
784 * If @value is not %NULL, sets the cached value for the property with
785 * name @property_name to the value in @value.
786 *
787 * If @value is %NULL, then the cached value is removed from the
788 * property cache.
789 *
790 * If @proxy has an expected interface (see
791 * #GDBusProxy:g-interface-info) and @property_name is referenced by
792 * it, then @value is checked against the type of the property.
793 *
794 * If the @value #GVariant is floating, it is consumed. This allows
795 * convenient 'inline' use of g_variant_new(), e.g.
796 * |[<!-- language="C" -->
797 * g_dbus_proxy_set_cached_property (proxy,
798 * "SomeProperty",
799 * g_variant_new ("(si)",
800 * "A String",
801 * 42));
802 * ]|
803 *
804 * Normally you will not need to use this method since @proxy
805 * is tracking changes using the
806 * `org.freedesktop.DBus.Properties.PropertiesChanged`
807 * D-Bus signal. However, for performance reasons an object may
808 * decide to not use this signal for some properties and instead
809 * use a proprietary out-of-band mechanism to transmit changes.
810 *
811 * As a concrete example, consider an object with a property
812 * `ChatroomParticipants` which is an array of strings. Instead of
813 * transmitting the same (long) array every time the property changes,
814 * it is more efficient to only transmit the delta using e.g. signals
815 * `ChatroomParticipantJoined(String name)` and
816 * `ChatroomParticipantParted(String name)`.
817 *
818 * Since: 2.26
819 */
820 void
g_dbus_proxy_set_cached_property(GDBusProxy * proxy,const gchar * property_name,GVariant * value)821 g_dbus_proxy_set_cached_property (GDBusProxy *proxy,
822 const gchar *property_name,
823 GVariant *value)
824 {
825 const GDBusPropertyInfo *info;
826
827 g_return_if_fail (G_IS_DBUS_PROXY (proxy));
828 g_return_if_fail (property_name != NULL);
829
830 G_LOCK (properties_lock);
831
832 if (value != NULL)
833 {
834 info = lookup_property_info (proxy, property_name);
835 if (info != NULL)
836 {
837 if (g_strcmp0 (info->signature, g_variant_get_type_string (value)) != 0)
838 {
839 g_warning ("Trying to set property %s of type %s but according to the expected "
840 "interface the type is %s",
841 property_name,
842 g_variant_get_type_string (value),
843 info->signature);
844 goto out;
845 }
846 }
847 g_hash_table_insert (proxy->priv->properties,
848 g_strdup (property_name),
849 g_variant_ref_sink (value));
850 }
851 else
852 {
853 g_hash_table_remove (proxy->priv->properties, property_name);
854 }
855
856 out:
857 G_UNLOCK (properties_lock);
858 }
859
860 /* ---------------------------------------------------------------------------------------------------- */
861
862 static void
on_signal_received(GDBusConnection * connection,const gchar * sender_name,const gchar * object_path,const gchar * interface_name,const gchar * signal_name,GVariant * parameters,gpointer user_data)863 on_signal_received (GDBusConnection *connection,
864 const gchar *sender_name,
865 const gchar *object_path,
866 const gchar *interface_name,
867 const gchar *signal_name,
868 GVariant *parameters,
869 gpointer user_data)
870 {
871 SignalSubscriptionData *data = user_data;
872 GDBusProxy *proxy;
873
874 G_LOCK (signal_subscription_lock);
875 proxy = data->proxy;
876 if (proxy == NULL)
877 {
878 G_UNLOCK (signal_subscription_lock);
879 return;
880 }
881 else
882 {
883 g_object_ref (proxy);
884 G_UNLOCK (signal_subscription_lock);
885 }
886
887 if (!proxy->priv->initialized)
888 goto out;
889
890 G_LOCK (properties_lock);
891
892 if (proxy->priv->name_owner != NULL && g_strcmp0 (sender_name, proxy->priv->name_owner) != 0)
893 {
894 G_UNLOCK (properties_lock);
895 goto out;
896 }
897
898 if (proxy->priv->expected_interface != NULL)
899 {
900 const GDBusSignalInfo *info;
901 info = g_dbus_interface_info_lookup_signal (proxy->priv->expected_interface, signal_name);
902 if (info != NULL)
903 {
904 GVariantType *expected_type;
905 expected_type = _g_dbus_compute_complete_signature (info->args);
906 if (!g_variant_type_equal (expected_type, g_variant_get_type (parameters)))
907 {
908 gchar *expected_type_string = g_variant_type_dup_string (expected_type);
909 g_warning ("Dropping signal %s of type %s since the type from the expected interface is %s",
910 info->name,
911 g_variant_get_type_string (parameters),
912 expected_type_string);
913 g_free (expected_type_string);
914 g_variant_type_free (expected_type);
915 G_UNLOCK (properties_lock);
916 goto out;
917 }
918 g_variant_type_free (expected_type);
919 }
920 }
921
922 G_UNLOCK (properties_lock);
923
924 g_signal_emit (proxy,
925 signals[SIGNAL_SIGNAL],
926 0,
927 sender_name,
928 signal_name,
929 parameters);
930
931 out:
932 if (proxy != NULL)
933 g_object_unref (proxy);
934 }
935
936 /* ---------------------------------------------------------------------------------------------------- */
937
938 /* must hold properties_lock */
939 static void
insert_property_checked(GDBusProxy * proxy,gchar * property_name,GVariant * value)940 insert_property_checked (GDBusProxy *proxy,
941 gchar *property_name,
942 GVariant *value)
943 {
944 if (proxy->priv->expected_interface != NULL)
945 {
946 const GDBusPropertyInfo *info;
947 info = g_dbus_interface_info_lookup_property (proxy->priv->expected_interface, property_name);
948 /* Only check known properties */
949 if (info != NULL)
950 {
951 /* Warn about properties with the wrong type */
952 if (g_strcmp0 (info->signature, g_variant_get_type_string (value)) != 0)
953 {
954 g_warning ("Received property %s with type %s does not match expected type "
955 "%s in the expected interface",
956 property_name,
957 g_variant_get_type_string (value),
958 info->signature);
959 goto invalid;
960 }
961 }
962 }
963
964 g_hash_table_insert (proxy->priv->properties,
965 property_name, /* adopts string */
966 value); /* adopts value */
967
968 return;
969
970 invalid:
971 g_variant_unref (value);
972 g_free (property_name);
973 }
974
975 typedef struct
976 {
977 GDBusProxy *proxy;
978 gchar *prop_name;
979 } InvalidatedPropGetData;
980
981 static void
invalidated_property_get_cb(GDBusConnection * connection,GAsyncResult * res,gpointer user_data)982 invalidated_property_get_cb (GDBusConnection *connection,
983 GAsyncResult *res,
984 gpointer user_data)
985 {
986 InvalidatedPropGetData *data = user_data;
987 const gchar *invalidated_properties[] = {NULL};
988 GVariantBuilder builder;
989 GVariant *value = NULL;
990 GVariant *unpacked_value = NULL;
991
992 /* errors are fine, the other end could have disconnected */
993 value = g_dbus_connection_call_finish (connection, res, NULL);
994 if (value == NULL)
995 {
996 goto out;
997 }
998
999 if (!g_variant_is_of_type (value, G_VARIANT_TYPE ("(v)")))
1000 {
1001 g_warning ("Expected type '(v)' for Get() reply, got '%s'", g_variant_get_type_string (value));
1002 goto out;
1003 }
1004
1005 g_variant_get (value, "(v)", &unpacked_value);
1006
1007 /* synthesize the a{sv} in the PropertiesChanged signal */
1008 g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
1009 g_variant_builder_add (&builder, "{sv}", data->prop_name, unpacked_value);
1010
1011 G_LOCK (properties_lock);
1012 insert_property_checked (data->proxy,
1013 data->prop_name, /* adopts string */
1014 unpacked_value); /* adopts value */
1015 data->prop_name = NULL;
1016 G_UNLOCK (properties_lock);
1017
1018 g_signal_emit (data->proxy,
1019 signals[PROPERTIES_CHANGED_SIGNAL], 0,
1020 g_variant_builder_end (&builder), /* consumed */
1021 invalidated_properties);
1022
1023
1024 out:
1025 if (value != NULL)
1026 g_variant_unref (value);
1027 g_object_unref (data->proxy);
1028 g_free (data->prop_name);
1029 g_slice_free (InvalidatedPropGetData, data);
1030 }
1031
1032 static void
on_properties_changed(GDBusConnection * connection,const gchar * sender_name,const gchar * object_path,const gchar * interface_name,const gchar * signal_name,GVariant * parameters,gpointer user_data)1033 on_properties_changed (GDBusConnection *connection,
1034 const gchar *sender_name,
1035 const gchar *object_path,
1036 const gchar *interface_name,
1037 const gchar *signal_name,
1038 GVariant *parameters,
1039 gpointer user_data)
1040 {
1041 SignalSubscriptionData *data = user_data;
1042 gboolean emit_g_signal = FALSE;
1043 GDBusProxy *proxy;
1044 const gchar *interface_name_for_signal;
1045 GVariant *changed_properties;
1046 gchar **invalidated_properties;
1047 GVariantIter iter;
1048 gchar *key;
1049 GVariant *value;
1050 guint n;
1051
1052 changed_properties = NULL;
1053 invalidated_properties = NULL;
1054
1055 G_LOCK (signal_subscription_lock);
1056 proxy = data->proxy;
1057 if (proxy == NULL)
1058 {
1059 G_UNLOCK (signal_subscription_lock);
1060 goto out;
1061 }
1062 else
1063 {
1064 g_object_ref (proxy);
1065 G_UNLOCK (signal_subscription_lock);
1066 }
1067
1068 if (!proxy->priv->initialized)
1069 goto out;
1070
1071 G_LOCK (properties_lock);
1072
1073 if (proxy->priv->name_owner != NULL && g_strcmp0 (sender_name, proxy->priv->name_owner) != 0)
1074 {
1075 G_UNLOCK (properties_lock);
1076 goto out;
1077 }
1078
1079 if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sa{sv}as)")))
1080 {
1081 g_warning ("Value for PropertiesChanged signal with type '%s' does not match '(sa{sv}as)'",
1082 g_variant_get_type_string (parameters));
1083 G_UNLOCK (properties_lock);
1084 goto out;
1085 }
1086
1087 g_variant_get (parameters,
1088 "(&s@a{sv}^a&s)",
1089 &interface_name_for_signal,
1090 &changed_properties,
1091 &invalidated_properties);
1092
1093 if (g_strcmp0 (interface_name_for_signal, proxy->priv->interface_name) != 0)
1094 {
1095 G_UNLOCK (properties_lock);
1096 goto out;
1097 }
1098
1099 g_variant_iter_init (&iter, changed_properties);
1100 while (g_variant_iter_next (&iter, "{sv}", &key, &value))
1101 {
1102 insert_property_checked (proxy,
1103 key, /* adopts string */
1104 value); /* adopts value */
1105 emit_g_signal = TRUE;
1106 }
1107
1108 if (proxy->priv->flags & G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES)
1109 {
1110 if (proxy->priv->name_owner != NULL)
1111 {
1112 for (n = 0; invalidated_properties[n] != NULL; n++)
1113 {
1114 InvalidatedPropGetData *data;
1115 data = g_slice_new0 (InvalidatedPropGetData);
1116 data->proxy = g_object_ref (proxy);
1117 data->prop_name = g_strdup (invalidated_properties[n]);
1118 g_dbus_connection_call (proxy->priv->connection,
1119 proxy->priv->name_owner,
1120 proxy->priv->object_path,
1121 "org.freedesktop.DBus.Properties",
1122 "Get",
1123 g_variant_new ("(ss)", proxy->priv->interface_name, data->prop_name),
1124 G_VARIANT_TYPE ("(v)"),
1125 G_DBUS_CALL_FLAGS_NONE,
1126 -1, /* timeout */
1127 NULL, /* GCancellable */
1128 (GAsyncReadyCallback) invalidated_property_get_cb,
1129 data);
1130 }
1131 }
1132 }
1133 else
1134 {
1135 emit_g_signal = TRUE;
1136 for (n = 0; invalidated_properties[n] != NULL; n++)
1137 {
1138 g_hash_table_remove (proxy->priv->properties, invalidated_properties[n]);
1139 }
1140 }
1141
1142 G_UNLOCK (properties_lock);
1143
1144 if (emit_g_signal)
1145 {
1146 g_signal_emit (proxy, signals[PROPERTIES_CHANGED_SIGNAL],
1147 0,
1148 changed_properties,
1149 invalidated_properties);
1150 }
1151
1152 out:
1153 if (changed_properties != NULL)
1154 g_variant_unref (changed_properties);
1155 g_free (invalidated_properties);
1156 if (proxy != NULL)
1157 g_object_unref (proxy);
1158 }
1159
1160 /* ---------------------------------------------------------------------------------------------------- */
1161
1162 static void
process_get_all_reply(GDBusProxy * proxy,GVariant * result)1163 process_get_all_reply (GDBusProxy *proxy,
1164 GVariant *result)
1165 {
1166 GVariantIter *iter;
1167 gchar *key;
1168 GVariant *value;
1169 guint num_properties;
1170
1171 if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(a{sv})")))
1172 {
1173 g_warning ("Value for GetAll reply with type '%s' does not match '(a{sv})'",
1174 g_variant_get_type_string (result));
1175 goto out;
1176 }
1177
1178 G_LOCK (properties_lock);
1179
1180 g_variant_get (result, "(a{sv})", &iter);
1181 while (g_variant_iter_next (iter, "{sv}", &key, &value))
1182 {
1183 insert_property_checked (proxy,
1184 key, /* adopts string */
1185 value); /* adopts value */
1186 }
1187 g_variant_iter_free (iter);
1188
1189 num_properties = g_hash_table_size (proxy->priv->properties);
1190 G_UNLOCK (properties_lock);
1191
1192 /* Synthesize ::g-properties-changed changed */
1193 if (num_properties > 0)
1194 {
1195 GVariant *changed_properties;
1196 const gchar *invalidated_properties[1] = {NULL};
1197
1198 g_variant_get (result,
1199 "(@a{sv})",
1200 &changed_properties);
1201 g_signal_emit (proxy, signals[PROPERTIES_CHANGED_SIGNAL],
1202 0,
1203 changed_properties,
1204 invalidated_properties);
1205 g_variant_unref (changed_properties);
1206 }
1207
1208 out:
1209 ;
1210 }
1211
1212 typedef struct
1213 {
1214 GDBusProxy *proxy;
1215 GCancellable *cancellable;
1216 gchar *name_owner;
1217 } LoadPropertiesOnNameOwnerChangedData;
1218
1219 static void
on_name_owner_changed_get_all_cb(GDBusConnection * connection,GAsyncResult * res,gpointer user_data)1220 on_name_owner_changed_get_all_cb (GDBusConnection *connection,
1221 GAsyncResult *res,
1222 gpointer user_data)
1223 {
1224 LoadPropertiesOnNameOwnerChangedData *data = user_data;
1225 GVariant *result;
1226 GError *error;
1227 gboolean cancelled;
1228
1229 cancelled = FALSE;
1230
1231 error = NULL;
1232 result = g_dbus_connection_call_finish (connection,
1233 res,
1234 &error);
1235 if (result == NULL)
1236 {
1237 if (error->domain == G_IO_ERROR && error->code == G_IO_ERROR_CANCELLED)
1238 cancelled = TRUE;
1239 /* We just ignore if GetAll() is failing. Because this might happen
1240 * if the object has no properties at all. Or if the caller is
1241 * not authorized to see the properties.
1242 *
1243 * Either way, apps can know about this by using
1244 * get_cached_property_names() or get_cached_property().
1245 */
1246 if (G_UNLIKELY (_g_dbus_debug_proxy ()))
1247 {
1248 g_debug ("error: %d %d %s",
1249 error->domain,
1250 error->code,
1251 error->message);
1252 }
1253 g_error_free (error);
1254 }
1255
1256 /* and finally we can notify */
1257 if (!cancelled)
1258 {
1259 G_LOCK (properties_lock);
1260 g_free (data->proxy->priv->name_owner);
1261 data->proxy->priv->name_owner = data->name_owner;
1262 data->name_owner = NULL; /* to avoid an extra copy, we steal the string */
1263 g_hash_table_remove_all (data->proxy->priv->properties);
1264 G_UNLOCK (properties_lock);
1265 if (result != NULL)
1266 {
1267 process_get_all_reply (data->proxy, result);
1268 g_variant_unref (result);
1269 }
1270
1271 g_object_notify (G_OBJECT (data->proxy), "g-name-owner");
1272 }
1273
1274 if (data->cancellable == data->proxy->priv->get_all_cancellable)
1275 data->proxy->priv->get_all_cancellable = NULL;
1276
1277 g_object_unref (data->proxy);
1278 g_object_unref (data->cancellable);
1279 g_free (data->name_owner);
1280 g_free (data);
1281 }
1282
1283 static void
on_name_owner_changed(GDBusConnection * connection,const gchar * sender_name,const gchar * object_path,const gchar * interface_name,const gchar * signal_name,GVariant * parameters,gpointer user_data)1284 on_name_owner_changed (GDBusConnection *connection,
1285 const gchar *sender_name,
1286 const gchar *object_path,
1287 const gchar *interface_name,
1288 const gchar *signal_name,
1289 GVariant *parameters,
1290 gpointer user_data)
1291 {
1292 SignalSubscriptionData *data = user_data;
1293 GDBusProxy *proxy;
1294 const gchar *old_owner;
1295 const gchar *new_owner;
1296
1297 G_LOCK (signal_subscription_lock);
1298 proxy = data->proxy;
1299 if (proxy == NULL)
1300 {
1301 G_UNLOCK (signal_subscription_lock);
1302 goto out;
1303 }
1304 else
1305 {
1306 g_object_ref (proxy);
1307 G_UNLOCK (signal_subscription_lock);
1308 }
1309
1310 /* if we are already trying to load properties, cancel that */
1311 if (proxy->priv->get_all_cancellable != NULL)
1312 {
1313 g_cancellable_cancel (proxy->priv->get_all_cancellable);
1314 proxy->priv->get_all_cancellable = NULL;
1315 }
1316
1317 g_variant_get (parameters,
1318 "(&s&s&s)",
1319 NULL,
1320 &old_owner,
1321 &new_owner);
1322
1323 if (strlen (new_owner) == 0)
1324 {
1325 G_LOCK (properties_lock);
1326 g_free (proxy->priv->name_owner);
1327 proxy->priv->name_owner = NULL;
1328
1329 /* Synthesize ::g-properties-changed changed */
1330 if (!(proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES) &&
1331 g_hash_table_size (proxy->priv->properties) > 0)
1332 {
1333 GVariantBuilder builder;
1334 GPtrArray *invalidated_properties;
1335 GHashTableIter iter;
1336 const gchar *key;
1337
1338 /* Build changed_properties (always empty) and invalidated_properties ... */
1339 g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
1340
1341 invalidated_properties = g_ptr_array_new_with_free_func (g_free);
1342 g_hash_table_iter_init (&iter, proxy->priv->properties);
1343 while (g_hash_table_iter_next (&iter, (gpointer) &key, NULL))
1344 g_ptr_array_add (invalidated_properties, g_strdup (key));
1345 g_ptr_array_add (invalidated_properties, NULL);
1346
1347 /* ... throw out the properties ... */
1348 g_hash_table_remove_all (proxy->priv->properties);
1349
1350 G_UNLOCK (properties_lock);
1351
1352 /* ... and finally emit the ::g-properties-changed signal */
1353 g_signal_emit (proxy, signals[PROPERTIES_CHANGED_SIGNAL],
1354 0,
1355 g_variant_builder_end (&builder) /* consumed */,
1356 (const gchar* const *) invalidated_properties->pdata);
1357 g_ptr_array_unref (invalidated_properties);
1358 }
1359 else
1360 {
1361 G_UNLOCK (properties_lock);
1362 }
1363 g_object_notify (G_OBJECT (proxy), "g-name-owner");
1364 }
1365 else
1366 {
1367 G_LOCK (properties_lock);
1368
1369 /* ignore duplicates - this can happen when activating the service */
1370 if (g_strcmp0 (new_owner, proxy->priv->name_owner) == 0)
1371 {
1372 G_UNLOCK (properties_lock);
1373 goto out;
1374 }
1375
1376 if (proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES)
1377 {
1378 g_free (proxy->priv->name_owner);
1379 proxy->priv->name_owner = g_strdup (new_owner);
1380
1381 g_hash_table_remove_all (proxy->priv->properties);
1382 G_UNLOCK (properties_lock);
1383 g_object_notify (G_OBJECT (proxy), "g-name-owner");
1384 }
1385 else
1386 {
1387 LoadPropertiesOnNameOwnerChangedData *data;
1388
1389 G_UNLOCK (properties_lock);
1390
1391 /* start loading properties.. only then emit notify::g-name-owner .. we
1392 * need to be able to cancel this in the event another NameOwnerChanged
1393 * signal suddenly happens
1394 */
1395
1396 g_assert (proxy->priv->get_all_cancellable == NULL);
1397 proxy->priv->get_all_cancellable = g_cancellable_new ();
1398 data = g_new0 (LoadPropertiesOnNameOwnerChangedData, 1);
1399 data->proxy = g_object_ref (proxy);
1400 data->cancellable = proxy->priv->get_all_cancellable;
1401 data->name_owner = g_strdup (new_owner);
1402 g_dbus_connection_call (proxy->priv->connection,
1403 data->name_owner,
1404 proxy->priv->object_path,
1405 "org.freedesktop.DBus.Properties",
1406 "GetAll",
1407 g_variant_new ("(s)", proxy->priv->interface_name),
1408 G_VARIANT_TYPE ("(a{sv})"),
1409 G_DBUS_CALL_FLAGS_NONE,
1410 -1, /* timeout */
1411 proxy->priv->get_all_cancellable,
1412 (GAsyncReadyCallback) on_name_owner_changed_get_all_cb,
1413 data);
1414 }
1415 }
1416
1417 out:
1418 if (proxy != NULL)
1419 g_object_unref (proxy);
1420 }
1421
1422 /* ---------------------------------------------------------------------------------------------------- */
1423
1424 static void
async_init_get_all_cb(GDBusConnection * connection,GAsyncResult * res,gpointer user_data)1425 async_init_get_all_cb (GDBusConnection *connection,
1426 GAsyncResult *res,
1427 gpointer user_data)
1428 {
1429 GTask *task = user_data;
1430 GVariant *result;
1431 GError *error;
1432
1433 error = NULL;
1434 result = g_dbus_connection_call_finish (connection,
1435 res,
1436 &error);
1437 if (result == NULL)
1438 {
1439 /* We just ignore if GetAll() is failing. Because this might happen
1440 * if the object has no properties at all. Or if the caller is
1441 * not authorized to see the properties.
1442 *
1443 * Either way, apps can know about this by using
1444 * get_cached_property_names() or get_cached_property().
1445 */
1446 if (G_UNLIKELY (_g_dbus_debug_proxy ()))
1447 {
1448 g_debug ("error: %d %d %s",
1449 error->domain,
1450 error->code,
1451 error->message);
1452 }
1453 g_error_free (error);
1454 }
1455
1456 g_task_return_pointer (task, result,
1457 (GDestroyNotify) g_variant_unref);
1458 g_object_unref (task);
1459 }
1460
1461 static void
async_init_data_set_name_owner(GTask * task,const gchar * name_owner)1462 async_init_data_set_name_owner (GTask *task,
1463 const gchar *name_owner)
1464 {
1465 GDBusProxy *proxy = g_task_get_source_object (task);
1466 gboolean get_all;
1467
1468 if (name_owner != NULL)
1469 {
1470 G_LOCK (properties_lock);
1471 /* Must free first, since on_name_owner_changed() could run before us */
1472 g_free (proxy->priv->name_owner);
1473 proxy->priv->name_owner = g_strdup (name_owner);
1474 G_UNLOCK (properties_lock);
1475 }
1476
1477 get_all = TRUE;
1478
1479 if (proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES)
1480 {
1481 /* Don't load properties if the API user doesn't want them */
1482 get_all = FALSE;
1483 }
1484 else if (name_owner == NULL && proxy->priv->name != NULL)
1485 {
1486 /* Don't attempt to load properties if the name_owner is NULL (which
1487 * usually means the name isn't owned), unless name is also NULL (which
1488 * means we actually wanted to talk to the directly-connected process -
1489 * either dbus-daemon or a peer - instead of going via dbus-daemon)
1490 */
1491 get_all = FALSE;
1492 }
1493
1494 if (get_all)
1495 {
1496 /* load all properties asynchronously */
1497 g_dbus_connection_call (proxy->priv->connection,
1498 name_owner,
1499 proxy->priv->object_path,
1500 "org.freedesktop.DBus.Properties",
1501 "GetAll",
1502 g_variant_new ("(s)", proxy->priv->interface_name),
1503 G_VARIANT_TYPE ("(a{sv})"),
1504 G_DBUS_CALL_FLAGS_NONE,
1505 -1, /* timeout */
1506 g_task_get_cancellable (task),
1507 (GAsyncReadyCallback) async_init_get_all_cb,
1508 task);
1509 }
1510 else
1511 {
1512 g_task_return_pointer (task, NULL, NULL);
1513 g_object_unref (task);
1514 }
1515 }
1516
1517 static void
async_init_get_name_owner_cb(GDBusConnection * connection,GAsyncResult * res,gpointer user_data)1518 async_init_get_name_owner_cb (GDBusConnection *connection,
1519 GAsyncResult *res,
1520 gpointer user_data)
1521 {
1522 GTask *task = user_data;
1523 GError *error;
1524 GVariant *result;
1525
1526 error = NULL;
1527 result = g_dbus_connection_call_finish (connection,
1528 res,
1529 &error);
1530 if (result == NULL)
1531 {
1532 if (error->domain == G_DBUS_ERROR &&
1533 error->code == G_DBUS_ERROR_NAME_HAS_NO_OWNER)
1534 {
1535 g_error_free (error);
1536 async_init_data_set_name_owner (task, NULL);
1537 }
1538 else
1539 {
1540 g_task_return_error (task, error);
1541 g_object_unref (task);
1542 }
1543 }
1544 else
1545 {
1546 /* borrowed from result to avoid an extra copy */
1547 const gchar *name_owner;
1548
1549 g_variant_get (result, "(&s)", &name_owner);
1550 async_init_data_set_name_owner (task, name_owner);
1551 g_variant_unref (result);
1552 }
1553 }
1554
1555 static void
async_init_call_get_name_owner(GTask * task)1556 async_init_call_get_name_owner (GTask *task)
1557 {
1558 GDBusProxy *proxy = g_task_get_source_object (task);
1559
1560 g_dbus_connection_call (proxy->priv->connection,
1561 "org.freedesktop.DBus", /* name */
1562 "/org/freedesktop/DBus", /* object path */
1563 "org.freedesktop.DBus", /* interface */
1564 "GetNameOwner",
1565 g_variant_new ("(s)",
1566 proxy->priv->name),
1567 G_VARIANT_TYPE ("(s)"),
1568 G_DBUS_CALL_FLAGS_NONE,
1569 -1, /* timeout */
1570 g_task_get_cancellable (task),
1571 (GAsyncReadyCallback) async_init_get_name_owner_cb,
1572 task);
1573 }
1574
1575 static void
async_init_start_service_by_name_cb(GDBusConnection * connection,GAsyncResult * res,gpointer user_data)1576 async_init_start_service_by_name_cb (GDBusConnection *connection,
1577 GAsyncResult *res,
1578 gpointer user_data)
1579 {
1580 GTask *task = user_data;
1581 GDBusProxy *proxy = g_task_get_source_object (task);
1582 GError *error;
1583 GVariant *result;
1584
1585 error = NULL;
1586 result = g_dbus_connection_call_finish (connection,
1587 res,
1588 &error);
1589 if (result == NULL)
1590 {
1591 /* Errors are not unexpected; the bus will reply e.g.
1592 *
1593 * org.freedesktop.DBus.Error.ServiceUnknown: The name org.gnome.Epiphany2
1594 * was not provided by any .service files
1595 *
1596 * or (see #677718)
1597 *
1598 * org.freedesktop.systemd1.Masked: Unit polkit.service is masked.
1599 *
1600 * This doesn't mean that the name doesn't have an owner, just
1601 * that it's not provided by a .service file or can't currently
1602 * be started.
1603 *
1604 * In particular, in both cases, it could be that a service
1605 * owner will actually appear later. So instead of erroring out,
1606 * we just proceed to invoke GetNameOwner() if dealing with the
1607 * kind of errors above.
1608 */
1609 if (error->domain == G_DBUS_ERROR && error->code == G_DBUS_ERROR_SERVICE_UNKNOWN)
1610 {
1611 g_error_free (error);
1612 }
1613 else
1614 {
1615 gchar *remote_error = g_dbus_error_get_remote_error (error);
1616 if (g_strcmp0 (remote_error, "org.freedesktop.systemd1.Masked") == 0)
1617 {
1618 g_error_free (error);
1619 g_free (remote_error);
1620 }
1621 else
1622 {
1623 g_dbus_error_strip_remote_error (error);
1624 g_prefix_error (&error,
1625 _("Error calling StartServiceByName for %s: "),
1626 proxy->priv->name);
1627 g_free (remote_error);
1628 goto failed;
1629 }
1630 }
1631 }
1632 else
1633 {
1634 guint32 start_service_result;
1635 g_variant_get (result,
1636 "(u)",
1637 &start_service_result);
1638 g_variant_unref (result);
1639 if (start_service_result == 1 || /* DBUS_START_REPLY_SUCCESS */
1640 start_service_result == 2) /* DBUS_START_REPLY_ALREADY_RUNNING */
1641 {
1642 /* continue to invoke GetNameOwner() */
1643 }
1644 else
1645 {
1646 error = g_error_new (G_IO_ERROR,
1647 G_IO_ERROR_FAILED,
1648 _("Unexpected reply %d from StartServiceByName(\"%s\") method"),
1649 start_service_result,
1650 proxy->priv->name);
1651 goto failed;
1652 }
1653 }
1654
1655 async_init_call_get_name_owner (task);
1656 return;
1657
1658 failed:
1659 g_warn_if_fail (error != NULL);
1660 g_task_return_error (task, error);
1661 g_object_unref (task);
1662 }
1663
1664 static void
async_init_call_start_service_by_name(GTask * task)1665 async_init_call_start_service_by_name (GTask *task)
1666 {
1667 GDBusProxy *proxy = g_task_get_source_object (task);
1668
1669 g_dbus_connection_call (proxy->priv->connection,
1670 "org.freedesktop.DBus", /* name */
1671 "/org/freedesktop/DBus", /* object path */
1672 "org.freedesktop.DBus", /* interface */
1673 "StartServiceByName",
1674 g_variant_new ("(su)",
1675 proxy->priv->name,
1676 0),
1677 G_VARIANT_TYPE ("(u)"),
1678 G_DBUS_CALL_FLAGS_NONE,
1679 -1, /* timeout */
1680 g_task_get_cancellable (task),
1681 (GAsyncReadyCallback) async_init_start_service_by_name_cb,
1682 task);
1683 }
1684
1685 static void
async_initable_init_second_async(GAsyncInitable * initable,gint io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1686 async_initable_init_second_async (GAsyncInitable *initable,
1687 gint io_priority,
1688 GCancellable *cancellable,
1689 GAsyncReadyCallback callback,
1690 gpointer user_data)
1691 {
1692 GDBusProxy *proxy = G_DBUS_PROXY (initable);
1693 GTask *task;
1694
1695 task = g_task_new (proxy, cancellable, callback, user_data);
1696 g_task_set_source_tag (task, async_initable_init_second_async);
1697 g_task_set_priority (task, io_priority);
1698
1699 /* Check name ownership asynchronously - possibly also start the service */
1700 if (proxy->priv->name == NULL)
1701 {
1702 /* Do nothing */
1703 async_init_data_set_name_owner (task, NULL);
1704 }
1705 else if (g_dbus_is_unique_name (proxy->priv->name))
1706 {
1707 async_init_data_set_name_owner (task, proxy->priv->name);
1708 }
1709 else
1710 {
1711 if ((proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START) ||
1712 (proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START_AT_CONSTRUCTION))
1713 {
1714 async_init_call_get_name_owner (task);
1715 }
1716 else
1717 {
1718 async_init_call_start_service_by_name (task);
1719 }
1720 }
1721 }
1722
1723 static gboolean
async_initable_init_second_finish(GAsyncInitable * initable,GAsyncResult * res,GError ** error)1724 async_initable_init_second_finish (GAsyncInitable *initable,
1725 GAsyncResult *res,
1726 GError **error)
1727 {
1728 GDBusProxy *proxy = G_DBUS_PROXY (initable);
1729 GTask *task = G_TASK (res);
1730 GVariant *result;
1731 gboolean ret;
1732
1733 ret = !g_task_had_error (task);
1734
1735 result = g_task_propagate_pointer (task, error);
1736 if (result != NULL)
1737 {
1738 process_get_all_reply (proxy, result);
1739 g_variant_unref (result);
1740 }
1741
1742 proxy->priv->initialized = TRUE;
1743 return ret;
1744 }
1745
1746 /* ---------------------------------------------------------------------------------------------------- */
1747
1748 static void
async_initable_init_first(GAsyncInitable * initable)1749 async_initable_init_first (GAsyncInitable *initable)
1750 {
1751 GDBusProxy *proxy = G_DBUS_PROXY (initable);
1752
1753 if (!(proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES))
1754 {
1755 /* subscribe to PropertiesChanged() */
1756 proxy->priv->properties_changed_subscription_id =
1757 g_dbus_connection_signal_subscribe (proxy->priv->connection,
1758 proxy->priv->name,
1759 "org.freedesktop.DBus.Properties",
1760 "PropertiesChanged",
1761 proxy->priv->object_path,
1762 proxy->priv->interface_name,
1763 G_DBUS_SIGNAL_FLAGS_NONE,
1764 on_properties_changed,
1765 signal_subscription_ref (proxy->priv->signal_subscription_data),
1766 (GDestroyNotify) signal_subscription_unref);
1767 }
1768
1769 if (!(proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS))
1770 {
1771 /* subscribe to all signals for the object */
1772 proxy->priv->signals_subscription_id =
1773 g_dbus_connection_signal_subscribe (proxy->priv->connection,
1774 proxy->priv->name,
1775 proxy->priv->interface_name,
1776 NULL, /* member */
1777 proxy->priv->object_path,
1778 NULL, /* arg0 */
1779 G_DBUS_SIGNAL_FLAGS_NONE,
1780 on_signal_received,
1781 signal_subscription_ref (proxy->priv->signal_subscription_data),
1782 (GDestroyNotify) signal_subscription_unref);
1783 }
1784
1785 if (proxy->priv->name != NULL &&
1786 (g_dbus_connection_get_flags (proxy->priv->connection) & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION))
1787 {
1788 proxy->priv->name_owner_changed_subscription_id =
1789 g_dbus_connection_signal_subscribe (proxy->priv->connection,
1790 "org.freedesktop.DBus", /* name */
1791 "org.freedesktop.DBus", /* interface */
1792 "NameOwnerChanged", /* signal name */
1793 "/org/freedesktop/DBus", /* path */
1794 proxy->priv->name, /* arg0 */
1795 G_DBUS_SIGNAL_FLAGS_NONE,
1796 on_name_owner_changed,
1797 signal_subscription_ref (proxy->priv->signal_subscription_data),
1798 (GDestroyNotify) signal_subscription_unref);
1799 }
1800 }
1801
1802 /* ---------------------------------------------------------------------------------------------------- */
1803
1804 /* initialization is split into two parts - the first is the
1805 * non-blocking part that requires the callers GMainContext - the
1806 * second is a blocking part async part that doesn't require the
1807 * callers GMainContext.. we do this split so the code can be reused
1808 * in the GInitable implementation below.
1809 *
1810 * Note that obtaining a GDBusConnection is not shared between the two
1811 * paths.
1812 */
1813
1814 static void
init_second_async_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1815 init_second_async_cb (GObject *source_object,
1816 GAsyncResult *res,
1817 gpointer user_data)
1818 {
1819 GTask *task = user_data;
1820 GError *error = NULL;
1821
1822 if (async_initable_init_second_finish (G_ASYNC_INITABLE (source_object), res, &error))
1823 g_task_return_boolean (task, TRUE);
1824 else
1825 g_task_return_error (task, error);
1826 g_object_unref (task);
1827 }
1828
1829 static void
get_connection_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1830 get_connection_cb (GObject *source_object,
1831 GAsyncResult *res,
1832 gpointer user_data)
1833 {
1834 GTask *task = user_data;
1835 GDBusProxy *proxy = g_task_get_source_object (task);
1836 GError *error;
1837
1838 error = NULL;
1839 proxy->priv->connection = g_bus_get_finish (res, &error);
1840 if (proxy->priv->connection == NULL)
1841 {
1842 g_task_return_error (task, error);
1843 g_object_unref (task);
1844 }
1845 else
1846 {
1847 async_initable_init_first (G_ASYNC_INITABLE (proxy));
1848 async_initable_init_second_async (G_ASYNC_INITABLE (proxy),
1849 g_task_get_priority (task),
1850 g_task_get_cancellable (task),
1851 init_second_async_cb,
1852 task);
1853 }
1854 }
1855
1856 static void
async_initable_init_async(GAsyncInitable * initable,gint io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1857 async_initable_init_async (GAsyncInitable *initable,
1858 gint io_priority,
1859 GCancellable *cancellable,
1860 GAsyncReadyCallback callback,
1861 gpointer user_data)
1862 {
1863 GDBusProxy *proxy = G_DBUS_PROXY (initable);
1864 GTask *task;
1865
1866 task = g_task_new (proxy, cancellable, callback, user_data);
1867 g_task_set_source_tag (task, async_initable_init_async);
1868 g_task_set_priority (task, io_priority);
1869
1870 if (proxy->priv->bus_type != G_BUS_TYPE_NONE)
1871 {
1872 g_assert (proxy->priv->connection == NULL);
1873
1874 g_bus_get (proxy->priv->bus_type,
1875 cancellable,
1876 get_connection_cb,
1877 task);
1878 }
1879 else
1880 {
1881 async_initable_init_first (initable);
1882 async_initable_init_second_async (initable, io_priority, cancellable,
1883 init_second_async_cb, task);
1884 }
1885 }
1886
1887 static gboolean
async_initable_init_finish(GAsyncInitable * initable,GAsyncResult * res,GError ** error)1888 async_initable_init_finish (GAsyncInitable *initable,
1889 GAsyncResult *res,
1890 GError **error)
1891 {
1892 return g_task_propagate_boolean (G_TASK (res), error);
1893 }
1894
1895 static void
async_initable_iface_init(GAsyncInitableIface * async_initable_iface)1896 async_initable_iface_init (GAsyncInitableIface *async_initable_iface)
1897 {
1898 async_initable_iface->init_async = async_initable_init_async;
1899 async_initable_iface->init_finish = async_initable_init_finish;
1900 }
1901
1902 /* ---------------------------------------------------------------------------------------------------- */
1903
1904 typedef struct
1905 {
1906 GMainContext *context;
1907 GMainLoop *loop;
1908 GAsyncResult *res;
1909 } InitableAsyncInitableData;
1910
1911 static void
async_initable_init_async_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1912 async_initable_init_async_cb (GObject *source_object,
1913 GAsyncResult *res,
1914 gpointer user_data)
1915 {
1916 InitableAsyncInitableData *data = user_data;
1917 data->res = g_object_ref (res);
1918 g_main_loop_quit (data->loop);
1919 }
1920
1921 /* Simply reuse the GAsyncInitable implementation but run the first
1922 * part (that is non-blocking and requires the callers GMainContext)
1923 * with the callers GMainContext.. and the second with a private
1924 * GMainContext (bug 621310 is slightly related).
1925 *
1926 * Note that obtaining a GDBusConnection is not shared between the two
1927 * paths.
1928 */
1929 static gboolean
initable_init(GInitable * initable,GCancellable * cancellable,GError ** error)1930 initable_init (GInitable *initable,
1931 GCancellable *cancellable,
1932 GError **error)
1933 {
1934 GDBusProxy *proxy = G_DBUS_PROXY (initable);
1935 InitableAsyncInitableData *data;
1936 gboolean ret;
1937
1938 ret = FALSE;
1939
1940 if (proxy->priv->bus_type != G_BUS_TYPE_NONE)
1941 {
1942 g_assert (proxy->priv->connection == NULL);
1943 proxy->priv->connection = g_bus_get_sync (proxy->priv->bus_type,
1944 cancellable,
1945 error);
1946 if (proxy->priv->connection == NULL)
1947 goto out;
1948 }
1949
1950 async_initable_init_first (G_ASYNC_INITABLE (initable));
1951
1952 data = g_new0 (InitableAsyncInitableData, 1);
1953 data->context = g_main_context_new ();
1954 data->loop = g_main_loop_new (data->context, FALSE);
1955
1956 g_main_context_push_thread_default (data->context);
1957
1958 async_initable_init_second_async (G_ASYNC_INITABLE (initable),
1959 G_PRIORITY_DEFAULT,
1960 cancellable,
1961 async_initable_init_async_cb,
1962 data);
1963
1964 g_main_loop_run (data->loop);
1965
1966 ret = async_initable_init_second_finish (G_ASYNC_INITABLE (initable),
1967 data->res,
1968 error);
1969
1970 g_main_context_pop_thread_default (data->context);
1971
1972 g_main_context_unref (data->context);
1973 g_main_loop_unref (data->loop);
1974 g_object_unref (data->res);
1975 g_free (data);
1976
1977 out:
1978
1979 return ret;
1980 }
1981
1982 static void
initable_iface_init(GInitableIface * initable_iface)1983 initable_iface_init (GInitableIface *initable_iface)
1984 {
1985 initable_iface->init = initable_init;
1986 }
1987
1988 /* ---------------------------------------------------------------------------------------------------- */
1989
1990 /**
1991 * g_dbus_proxy_new:
1992 * @connection: A #GDBusConnection.
1993 * @flags: Flags used when constructing the proxy.
1994 * @info: (nullable): A #GDBusInterfaceInfo specifying the minimal interface that @proxy conforms to or %NULL.
1995 * @name: (nullable): A bus name (well-known or unique) or %NULL if @connection is not a message bus connection.
1996 * @object_path: An object path.
1997 * @interface_name: A D-Bus interface name.
1998 * @cancellable: (nullable): A #GCancellable or %NULL.
1999 * @callback: Callback function to invoke when the proxy is ready.
2000 * @user_data: User data to pass to @callback.
2001 *
2002 * Creates a proxy for accessing @interface_name on the remote object
2003 * at @object_path owned by @name at @connection and asynchronously
2004 * loads D-Bus properties unless the
2005 * %G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES flag is used. Connect to
2006 * the #GDBusProxy::g-properties-changed signal to get notified about
2007 * property changes.
2008 *
2009 * If the %G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS flag is not set, also sets up
2010 * match rules for signals. Connect to the #GDBusProxy::g-signal signal
2011 * to handle signals from the remote object.
2012 *
2013 * If both %G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES and
2014 * %G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS are set, this constructor is
2015 * guaranteed to complete immediately without blocking.
2016 *
2017 * If @name is a well-known name and the
2018 * %G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START and %G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START_AT_CONSTRUCTION
2019 * flags aren't set and no name owner currently exists, the message bus
2020 * will be requested to launch a name owner for the name.
2021 *
2022 * This is a failable asynchronous constructor - when the proxy is
2023 * ready, @callback will be invoked and you can use
2024 * g_dbus_proxy_new_finish() to get the result.
2025 *
2026 * See g_dbus_proxy_new_sync() and for a synchronous version of this constructor.
2027 *
2028 * #GDBusProxy is used in this [example][gdbus-wellknown-proxy].
2029 *
2030 * Since: 2.26
2031 */
2032 void
g_dbus_proxy_new(GDBusConnection * connection,GDBusProxyFlags flags,GDBusInterfaceInfo * info,const gchar * name,const gchar * object_path,const gchar * interface_name,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)2033 g_dbus_proxy_new (GDBusConnection *connection,
2034 GDBusProxyFlags flags,
2035 GDBusInterfaceInfo *info,
2036 const gchar *name,
2037 const gchar *object_path,
2038 const gchar *interface_name,
2039 GCancellable *cancellable,
2040 GAsyncReadyCallback callback,
2041 gpointer user_data)
2042 {
2043 _g_dbus_initialize ();
2044
2045 g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
2046 g_return_if_fail ((name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) || g_dbus_is_name (name));
2047 g_return_if_fail (g_variant_is_object_path (object_path));
2048 g_return_if_fail (g_dbus_is_interface_name (interface_name));
2049
2050 g_async_initable_new_async (G_TYPE_DBUS_PROXY,
2051 G_PRIORITY_DEFAULT,
2052 cancellable,
2053 callback,
2054 user_data,
2055 "g-flags", flags,
2056 "g-interface-info", info,
2057 "g-name", name,
2058 "g-connection", connection,
2059 "g-object-path", object_path,
2060 "g-interface-name", interface_name,
2061 NULL);
2062 }
2063
2064 /**
2065 * g_dbus_proxy_new_finish:
2066 * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to g_dbus_proxy_new().
2067 * @error: Return location for error or %NULL.
2068 *
2069 * Finishes creating a #GDBusProxy.
2070 *
2071 * Returns: (transfer full): A #GDBusProxy or %NULL if @error is set.
2072 * Free with g_object_unref().
2073 *
2074 * Since: 2.26
2075 */
2076 GDBusProxy *
g_dbus_proxy_new_finish(GAsyncResult * res,GError ** error)2077 g_dbus_proxy_new_finish (GAsyncResult *res,
2078 GError **error)
2079 {
2080 GObject *object;
2081 GObject *source_object;
2082
2083 source_object = g_async_result_get_source_object (res);
2084 g_assert (source_object != NULL);
2085
2086 object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
2087 res,
2088 error);
2089 g_object_unref (source_object);
2090
2091 if (object != NULL)
2092 return G_DBUS_PROXY (object);
2093 else
2094 return NULL;
2095 }
2096
2097 /**
2098 * g_dbus_proxy_new_sync:
2099 * @connection: A #GDBusConnection.
2100 * @flags: Flags used when constructing the proxy.
2101 * @info: (nullable): A #GDBusInterfaceInfo specifying the minimal interface that @proxy conforms to or %NULL.
2102 * @name: (nullable): A bus name (well-known or unique) or %NULL if @connection is not a message bus connection.
2103 * @object_path: An object path.
2104 * @interface_name: A D-Bus interface name.
2105 * @cancellable: (nullable): A #GCancellable or %NULL.
2106 * @error: (nullable): Return location for error or %NULL.
2107 *
2108 * Creates a proxy for accessing @interface_name on the remote object
2109 * at @object_path owned by @name at @connection and synchronously
2110 * loads D-Bus properties unless the
2111 * %G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES flag is used.
2112 *
2113 * If the %G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS flag is not set, also sets up
2114 * match rules for signals. Connect to the #GDBusProxy::g-signal signal
2115 * to handle signals from the remote object.
2116 *
2117 * If both %G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES and
2118 * %G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS are set, this constructor is
2119 * guaranteed to return immediately without blocking.
2120 *
2121 * If @name is a well-known name and the
2122 * %G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START and %G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START_AT_CONSTRUCTION
2123 * flags aren't set and no name owner currently exists, the message bus
2124 * will be requested to launch a name owner for the name.
2125 *
2126 * This is a synchronous failable constructor. See g_dbus_proxy_new()
2127 * and g_dbus_proxy_new_finish() for the asynchronous version.
2128 *
2129 * #GDBusProxy is used in this [example][gdbus-wellknown-proxy].
2130 *
2131 * Returns: (transfer full): A #GDBusProxy or %NULL if error is set.
2132 * Free with g_object_unref().
2133 *
2134 * Since: 2.26
2135 */
2136 GDBusProxy *
g_dbus_proxy_new_sync(GDBusConnection * connection,GDBusProxyFlags flags,GDBusInterfaceInfo * info,const gchar * name,const gchar * object_path,const gchar * interface_name,GCancellable * cancellable,GError ** error)2137 g_dbus_proxy_new_sync (GDBusConnection *connection,
2138 GDBusProxyFlags flags,
2139 GDBusInterfaceInfo *info,
2140 const gchar *name,
2141 const gchar *object_path,
2142 const gchar *interface_name,
2143 GCancellable *cancellable,
2144 GError **error)
2145 {
2146 GInitable *initable;
2147
2148 g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
2149 g_return_val_if_fail ((name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) ||
2150 g_dbus_is_name (name), NULL);
2151 g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
2152 g_return_val_if_fail (g_dbus_is_interface_name (interface_name), NULL);
2153
2154 initable = g_initable_new (G_TYPE_DBUS_PROXY,
2155 cancellable,
2156 error,
2157 "g-flags", flags,
2158 "g-interface-info", info,
2159 "g-name", name,
2160 "g-connection", connection,
2161 "g-object-path", object_path,
2162 "g-interface-name", interface_name,
2163 NULL);
2164 if (initable != NULL)
2165 return G_DBUS_PROXY (initable);
2166 else
2167 return NULL;
2168 }
2169
2170 /* ---------------------------------------------------------------------------------------------------- */
2171
2172 /**
2173 * g_dbus_proxy_new_for_bus:
2174 * @bus_type: A #GBusType.
2175 * @flags: Flags used when constructing the proxy.
2176 * @info: (nullable): A #GDBusInterfaceInfo specifying the minimal interface that @proxy conforms to or %NULL.
2177 * @name: A bus name (well-known or unique).
2178 * @object_path: An object path.
2179 * @interface_name: A D-Bus interface name.
2180 * @cancellable: (nullable): A #GCancellable or %NULL.
2181 * @callback: Callback function to invoke when the proxy is ready.
2182 * @user_data: User data to pass to @callback.
2183 *
2184 * Like g_dbus_proxy_new() but takes a #GBusType instead of a #GDBusConnection.
2185 *
2186 * #GDBusProxy is used in this [example][gdbus-wellknown-proxy].
2187 *
2188 * Since: 2.26
2189 */
2190 void
g_dbus_proxy_new_for_bus(GBusType bus_type,GDBusProxyFlags flags,GDBusInterfaceInfo * info,const gchar * name,const gchar * object_path,const gchar * interface_name,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)2191 g_dbus_proxy_new_for_bus (GBusType bus_type,
2192 GDBusProxyFlags flags,
2193 GDBusInterfaceInfo *info,
2194 const gchar *name,
2195 const gchar *object_path,
2196 const gchar *interface_name,
2197 GCancellable *cancellable,
2198 GAsyncReadyCallback callback,
2199 gpointer user_data)
2200 {
2201 _g_dbus_initialize ();
2202
2203 g_return_if_fail (g_dbus_is_name (name));
2204 g_return_if_fail (g_variant_is_object_path (object_path));
2205 g_return_if_fail (g_dbus_is_interface_name (interface_name));
2206
2207 g_async_initable_new_async (G_TYPE_DBUS_PROXY,
2208 G_PRIORITY_DEFAULT,
2209 cancellable,
2210 callback,
2211 user_data,
2212 "g-flags", flags,
2213 "g-interface-info", info,
2214 "g-name", name,
2215 "g-bus-type", bus_type,
2216 "g-object-path", object_path,
2217 "g-interface-name", interface_name,
2218 NULL);
2219 }
2220
2221 /**
2222 * g_dbus_proxy_new_for_bus_finish:
2223 * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to g_dbus_proxy_new_for_bus().
2224 * @error: Return location for error or %NULL.
2225 *
2226 * Finishes creating a #GDBusProxy.
2227 *
2228 * Returns: (transfer full): A #GDBusProxy or %NULL if @error is set.
2229 * Free with g_object_unref().
2230 *
2231 * Since: 2.26
2232 */
2233 GDBusProxy *
g_dbus_proxy_new_for_bus_finish(GAsyncResult * res,GError ** error)2234 g_dbus_proxy_new_for_bus_finish (GAsyncResult *res,
2235 GError **error)
2236 {
2237 return g_dbus_proxy_new_finish (res, error);
2238 }
2239
2240 /**
2241 * g_dbus_proxy_new_for_bus_sync:
2242 * @bus_type: A #GBusType.
2243 * @flags: Flags used when constructing the proxy.
2244 * @info: (nullable): A #GDBusInterfaceInfo specifying the minimal interface
2245 * that @proxy conforms to or %NULL.
2246 * @name: A bus name (well-known or unique).
2247 * @object_path: An object path.
2248 * @interface_name: A D-Bus interface name.
2249 * @cancellable: (nullable): A #GCancellable or %NULL.
2250 * @error: Return location for error or %NULL.
2251 *
2252 * Like g_dbus_proxy_new_sync() but takes a #GBusType instead of a #GDBusConnection.
2253 *
2254 * #GDBusProxy is used in this [example][gdbus-wellknown-proxy].
2255 *
2256 * Returns: (transfer full): A #GDBusProxy or %NULL if error is set.
2257 * Free with g_object_unref().
2258 *
2259 * Since: 2.26
2260 */
2261 GDBusProxy *
g_dbus_proxy_new_for_bus_sync(GBusType bus_type,GDBusProxyFlags flags,GDBusInterfaceInfo * info,const gchar * name,const gchar * object_path,const gchar * interface_name,GCancellable * cancellable,GError ** error)2262 g_dbus_proxy_new_for_bus_sync (GBusType bus_type,
2263 GDBusProxyFlags flags,
2264 GDBusInterfaceInfo *info,
2265 const gchar *name,
2266 const gchar *object_path,
2267 const gchar *interface_name,
2268 GCancellable *cancellable,
2269 GError **error)
2270 {
2271 GInitable *initable;
2272
2273 _g_dbus_initialize ();
2274
2275 g_return_val_if_fail (g_dbus_is_name (name), NULL);
2276 g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
2277 g_return_val_if_fail (g_dbus_is_interface_name (interface_name), NULL);
2278
2279 initable = g_initable_new (G_TYPE_DBUS_PROXY,
2280 cancellable,
2281 error,
2282 "g-flags", flags,
2283 "g-interface-info", info,
2284 "g-name", name,
2285 "g-bus-type", bus_type,
2286 "g-object-path", object_path,
2287 "g-interface-name", interface_name,
2288 NULL);
2289 if (initable != NULL)
2290 return G_DBUS_PROXY (initable);
2291 else
2292 return NULL;
2293 }
2294
2295 /* ---------------------------------------------------------------------------------------------------- */
2296
2297 /**
2298 * g_dbus_proxy_get_connection:
2299 * @proxy: A #GDBusProxy.
2300 *
2301 * Gets the connection @proxy is for.
2302 *
2303 * Returns: (transfer none): A #GDBusConnection owned by @proxy. Do not free.
2304 *
2305 * Since: 2.26
2306 */
2307 GDBusConnection *
g_dbus_proxy_get_connection(GDBusProxy * proxy)2308 g_dbus_proxy_get_connection (GDBusProxy *proxy)
2309 {
2310 g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
2311 return proxy->priv->connection;
2312 }
2313
2314 /**
2315 * g_dbus_proxy_get_flags:
2316 * @proxy: A #GDBusProxy.
2317 *
2318 * Gets the flags that @proxy was constructed with.
2319 *
2320 * Returns: Flags from the #GDBusProxyFlags enumeration.
2321 *
2322 * Since: 2.26
2323 */
2324 GDBusProxyFlags
g_dbus_proxy_get_flags(GDBusProxy * proxy)2325 g_dbus_proxy_get_flags (GDBusProxy *proxy)
2326 {
2327 g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), 0);
2328 return proxy->priv->flags;
2329 }
2330
2331 /**
2332 * g_dbus_proxy_get_name:
2333 * @proxy: A #GDBusProxy.
2334 *
2335 * Gets the name that @proxy was constructed for.
2336 *
2337 * Returns: A string owned by @proxy. Do not free.
2338 *
2339 * Since: 2.26
2340 */
2341 const gchar *
g_dbus_proxy_get_name(GDBusProxy * proxy)2342 g_dbus_proxy_get_name (GDBusProxy *proxy)
2343 {
2344 g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
2345 return proxy->priv->name;
2346 }
2347
2348 /**
2349 * g_dbus_proxy_get_name_owner:
2350 * @proxy: A #GDBusProxy.
2351 *
2352 * The unique name that owns the name that @proxy is for or %NULL if
2353 * no-one currently owns that name. You may connect to the
2354 * #GObject::notify signal to track changes to the
2355 * #GDBusProxy:g-name-owner property.
2356 *
2357 * Returns: (transfer full) (nullable): The name owner or %NULL if no name
2358 * owner exists. Free with g_free().
2359 *
2360 * Since: 2.26
2361 */
2362 gchar *
g_dbus_proxy_get_name_owner(GDBusProxy * proxy)2363 g_dbus_proxy_get_name_owner (GDBusProxy *proxy)
2364 {
2365 gchar *ret;
2366
2367 g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
2368
2369 G_LOCK (properties_lock);
2370 ret = g_strdup (proxy->priv->name_owner);
2371 G_UNLOCK (properties_lock);
2372 return ret;
2373 }
2374
2375 /**
2376 * g_dbus_proxy_get_object_path:
2377 * @proxy: A #GDBusProxy.
2378 *
2379 * Gets the object path @proxy is for.
2380 *
2381 * Returns: A string owned by @proxy. Do not free.
2382 *
2383 * Since: 2.26
2384 */
2385 const gchar *
g_dbus_proxy_get_object_path(GDBusProxy * proxy)2386 g_dbus_proxy_get_object_path (GDBusProxy *proxy)
2387 {
2388 g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
2389 return proxy->priv->object_path;
2390 }
2391
2392 /**
2393 * g_dbus_proxy_get_interface_name:
2394 * @proxy: A #GDBusProxy.
2395 *
2396 * Gets the D-Bus interface name @proxy is for.
2397 *
2398 * Returns: A string owned by @proxy. Do not free.
2399 *
2400 * Since: 2.26
2401 */
2402 const gchar *
g_dbus_proxy_get_interface_name(GDBusProxy * proxy)2403 g_dbus_proxy_get_interface_name (GDBusProxy *proxy)
2404 {
2405 g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
2406 return proxy->priv->interface_name;
2407 }
2408
2409 /**
2410 * g_dbus_proxy_get_default_timeout:
2411 * @proxy: A #GDBusProxy.
2412 *
2413 * Gets the timeout to use if -1 (specifying default timeout) is
2414 * passed as @timeout_msec in the g_dbus_proxy_call() and
2415 * g_dbus_proxy_call_sync() functions.
2416 *
2417 * See the #GDBusProxy:g-default-timeout property for more details.
2418 *
2419 * Returns: Timeout to use for @proxy.
2420 *
2421 * Since: 2.26
2422 */
2423 gint
g_dbus_proxy_get_default_timeout(GDBusProxy * proxy)2424 g_dbus_proxy_get_default_timeout (GDBusProxy *proxy)
2425 {
2426 gint ret;
2427
2428 g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), -1);
2429
2430 G_LOCK (properties_lock);
2431 ret = proxy->priv->timeout_msec;
2432 G_UNLOCK (properties_lock);
2433 return ret;
2434 }
2435
2436 /**
2437 * g_dbus_proxy_set_default_timeout:
2438 * @proxy: A #GDBusProxy.
2439 * @timeout_msec: Timeout in milliseconds.
2440 *
2441 * Sets the timeout to use if -1 (specifying default timeout) is
2442 * passed as @timeout_msec in the g_dbus_proxy_call() and
2443 * g_dbus_proxy_call_sync() functions.
2444 *
2445 * See the #GDBusProxy:g-default-timeout property for more details.
2446 *
2447 * Since: 2.26
2448 */
2449 void
g_dbus_proxy_set_default_timeout(GDBusProxy * proxy,gint timeout_msec)2450 g_dbus_proxy_set_default_timeout (GDBusProxy *proxy,
2451 gint timeout_msec)
2452 {
2453 g_return_if_fail (G_IS_DBUS_PROXY (proxy));
2454 g_return_if_fail (timeout_msec == -1 || timeout_msec >= 0);
2455
2456 G_LOCK (properties_lock);
2457
2458 if (proxy->priv->timeout_msec != timeout_msec)
2459 {
2460 proxy->priv->timeout_msec = timeout_msec;
2461 G_UNLOCK (properties_lock);
2462
2463 g_object_notify (G_OBJECT (proxy), "g-default-timeout");
2464 }
2465 else
2466 {
2467 G_UNLOCK (properties_lock);
2468 }
2469 }
2470
2471 /**
2472 * g_dbus_proxy_get_interface_info:
2473 * @proxy: A #GDBusProxy
2474 *
2475 * Returns the #GDBusInterfaceInfo, if any, specifying the interface
2476 * that @proxy conforms to. See the #GDBusProxy:g-interface-info
2477 * property for more details.
2478 *
2479 * Returns: (transfer none) (nullable): A #GDBusInterfaceInfo or %NULL.
2480 * Do not unref the returned object, it is owned by @proxy.
2481 *
2482 * Since: 2.26
2483 */
2484 GDBusInterfaceInfo *
g_dbus_proxy_get_interface_info(GDBusProxy * proxy)2485 g_dbus_proxy_get_interface_info (GDBusProxy *proxy)
2486 {
2487 GDBusInterfaceInfo *ret;
2488
2489 g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
2490
2491 G_LOCK (properties_lock);
2492 ret = proxy->priv->expected_interface;
2493 G_UNLOCK (properties_lock);
2494 /* FIXME: returning a borrowed ref with no guarantee that nobody will
2495 * call g_dbus_proxy_set_interface_info() and make it invalid...
2496 */
2497 return ret;
2498 }
2499
2500 /**
2501 * g_dbus_proxy_set_interface_info:
2502 * @proxy: A #GDBusProxy
2503 * @info: (transfer none) (nullable): Minimum interface this proxy conforms to
2504 * or %NULL to unset.
2505 *
2506 * Ensure that interactions with @proxy conform to the given
2507 * interface. See the #GDBusProxy:g-interface-info property for more
2508 * details.
2509 *
2510 * Since: 2.26
2511 */
2512 void
g_dbus_proxy_set_interface_info(GDBusProxy * proxy,GDBusInterfaceInfo * info)2513 g_dbus_proxy_set_interface_info (GDBusProxy *proxy,
2514 GDBusInterfaceInfo *info)
2515 {
2516 g_return_if_fail (G_IS_DBUS_PROXY (proxy));
2517 G_LOCK (properties_lock);
2518
2519 if (proxy->priv->expected_interface != NULL)
2520 {
2521 g_dbus_interface_info_cache_release (proxy->priv->expected_interface);
2522 g_dbus_interface_info_unref (proxy->priv->expected_interface);
2523 }
2524 proxy->priv->expected_interface = info != NULL ? g_dbus_interface_info_ref (info) : NULL;
2525 if (proxy->priv->expected_interface != NULL)
2526 g_dbus_interface_info_cache_build (proxy->priv->expected_interface);
2527
2528 G_UNLOCK (properties_lock);
2529 }
2530
2531 /* ---------------------------------------------------------------------------------------------------- */
2532
2533 static gboolean
maybe_split_method_name(const gchar * method_name,gchar ** out_interface_name,const gchar ** out_method_name)2534 maybe_split_method_name (const gchar *method_name,
2535 gchar **out_interface_name,
2536 const gchar **out_method_name)
2537 {
2538 gboolean was_split;
2539
2540 was_split = FALSE;
2541 g_assert (out_interface_name != NULL);
2542 g_assert (out_method_name != NULL);
2543 *out_interface_name = NULL;
2544 *out_method_name = NULL;
2545
2546 if (strchr (method_name, '.') != NULL)
2547 {
2548 gchar *p;
2549 gchar *last_dot;
2550
2551 p = g_strdup (method_name);
2552 last_dot = strrchr (p, '.');
2553 *last_dot = '\0';
2554
2555 *out_interface_name = p;
2556 *out_method_name = last_dot + 1;
2557
2558 was_split = TRUE;
2559 }
2560
2561 return was_split;
2562 }
2563
2564 typedef struct
2565 {
2566 GVariant *value;
2567 #ifdef G_OS_UNIX
2568 GUnixFDList *fd_list;
2569 #endif
2570 } ReplyData;
2571
2572 static void
reply_data_free(ReplyData * data)2573 reply_data_free (ReplyData *data)
2574 {
2575 g_variant_unref (data->value);
2576 #ifdef G_OS_UNIX
2577 if (data->fd_list != NULL)
2578 g_object_unref (data->fd_list);
2579 #endif
2580 g_slice_free (ReplyData, data);
2581 }
2582
2583 static void
reply_cb(GDBusConnection * connection,GAsyncResult * res,gpointer user_data)2584 reply_cb (GDBusConnection *connection,
2585 GAsyncResult *res,
2586 gpointer user_data)
2587 {
2588 GTask *task = user_data;
2589 GVariant *value;
2590 GError *error;
2591 #ifdef G_OS_UNIX
2592 GUnixFDList *fd_list;
2593 #endif
2594
2595 error = NULL;
2596 #ifdef G_OS_UNIX
2597 value = g_dbus_connection_call_with_unix_fd_list_finish (connection,
2598 &fd_list,
2599 res,
2600 &error);
2601 #else
2602 value = g_dbus_connection_call_finish (connection,
2603 res,
2604 &error);
2605 #endif
2606 if (error != NULL)
2607 {
2608 g_task_return_error (task, error);
2609 }
2610 else
2611 {
2612 ReplyData *data;
2613 data = g_slice_new0 (ReplyData);
2614 data->value = value;
2615 #ifdef G_OS_UNIX
2616 data->fd_list = fd_list;
2617 #endif
2618 g_task_return_pointer (task, data, (GDestroyNotify) reply_data_free);
2619 }
2620
2621 g_object_unref (task);
2622 }
2623
2624 /* properties_lock must be held for as long as you will keep the
2625 * returned value
2626 */
2627 static const GDBusMethodInfo *
lookup_method_info(GDBusProxy * proxy,const gchar * method_name)2628 lookup_method_info (GDBusProxy *proxy,
2629 const gchar *method_name)
2630 {
2631 const GDBusMethodInfo *info = NULL;
2632
2633 if (proxy->priv->expected_interface == NULL)
2634 goto out;
2635
2636 info = g_dbus_interface_info_lookup_method (proxy->priv->expected_interface, method_name);
2637
2638 out:
2639 return info;
2640 }
2641
2642 /* properties_lock must be held for as long as you will keep the
2643 * returned value
2644 */
2645 static const gchar *
get_destination_for_call(GDBusProxy * proxy)2646 get_destination_for_call (GDBusProxy *proxy)
2647 {
2648 const gchar *ret;
2649
2650 ret = NULL;
2651
2652 /* If proxy->priv->name is a unique name, then proxy->priv->name_owner
2653 * is never NULL and always the same as proxy->priv->name. We use this
2654 * knowledge to avoid checking if proxy->priv->name is a unique or
2655 * well-known name.
2656 */
2657 ret = proxy->priv->name_owner;
2658 if (ret != NULL)
2659 goto out;
2660
2661 if (proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START)
2662 goto out;
2663
2664 ret = proxy->priv->name;
2665
2666 out:
2667 return ret;
2668 }
2669
2670 /* ---------------------------------------------------------------------------------------------------- */
2671
2672 static void
g_dbus_proxy_call_internal(GDBusProxy * proxy,const gchar * method_name,GVariant * parameters,GDBusCallFlags flags,gint timeout_msec,GUnixFDList * fd_list,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)2673 g_dbus_proxy_call_internal (GDBusProxy *proxy,
2674 const gchar *method_name,
2675 GVariant *parameters,
2676 GDBusCallFlags flags,
2677 gint timeout_msec,
2678 GUnixFDList *fd_list,
2679 GCancellable *cancellable,
2680 GAsyncReadyCallback callback,
2681 gpointer user_data)
2682 {
2683 GTask *task;
2684 gboolean was_split;
2685 gchar *split_interface_name;
2686 const gchar *split_method_name;
2687 const gchar *target_method_name;
2688 const gchar *target_interface_name;
2689 gchar *destination;
2690 GVariantType *reply_type;
2691 GAsyncReadyCallback my_callback;
2692
2693 g_return_if_fail (G_IS_DBUS_PROXY (proxy));
2694 g_return_if_fail (g_dbus_is_member_name (method_name) || g_dbus_is_interface_name (method_name));
2695 g_return_if_fail (parameters == NULL || g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE));
2696 g_return_if_fail (timeout_msec == -1 || timeout_msec >= 0);
2697 #ifdef G_OS_UNIX
2698 g_return_if_fail (fd_list == NULL || G_IS_UNIX_FD_LIST (fd_list));
2699 #else
2700 g_return_if_fail (fd_list == NULL);
2701 #endif
2702
2703 reply_type = NULL;
2704 split_interface_name = NULL;
2705
2706 /* g_dbus_connection_call() is optimised for the case of a NULL
2707 * callback. If we get a NULL callback from our user then make sure
2708 * we pass along a NULL callback for ourselves as well.
2709 */
2710 if (callback != NULL)
2711 {
2712 my_callback = (GAsyncReadyCallback) reply_cb;
2713 task = g_task_new (proxy, cancellable, callback, user_data);
2714 g_task_set_source_tag (task, g_dbus_proxy_call_internal);
2715 }
2716 else
2717 {
2718 my_callback = NULL;
2719 task = NULL;
2720 }
2721
2722 G_LOCK (properties_lock);
2723
2724 was_split = maybe_split_method_name (method_name, &split_interface_name, &split_method_name);
2725 target_method_name = was_split ? split_method_name : method_name;
2726 target_interface_name = was_split ? split_interface_name : proxy->priv->interface_name;
2727
2728 /* Warn if method is unexpected (cf. :g-interface-info) */
2729 if (!was_split)
2730 {
2731 const GDBusMethodInfo *expected_method_info;
2732 expected_method_info = lookup_method_info (proxy, target_method_name);
2733 if (expected_method_info != NULL)
2734 reply_type = _g_dbus_compute_complete_signature (expected_method_info->out_args);
2735 }
2736
2737 destination = NULL;
2738 if (proxy->priv->name != NULL)
2739 {
2740 destination = g_strdup (get_destination_for_call (proxy));
2741 if (destination == NULL)
2742 {
2743 if (task != NULL)
2744 {
2745 g_task_return_new_error (task,
2746 G_IO_ERROR,
2747 G_IO_ERROR_FAILED,
2748 _("Cannot invoke method; proxy is for the well-known name %s without an owner, and proxy was constructed with the G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START flag"),
2749 proxy->priv->name);
2750 g_object_unref (task);
2751 }
2752 G_UNLOCK (properties_lock);
2753 goto out;
2754 }
2755 }
2756
2757 G_UNLOCK (properties_lock);
2758
2759 #ifdef G_OS_UNIX
2760 g_dbus_connection_call_with_unix_fd_list (proxy->priv->connection,
2761 destination,
2762 proxy->priv->object_path,
2763 target_interface_name,
2764 target_method_name,
2765 parameters,
2766 reply_type,
2767 flags,
2768 timeout_msec == -1 ? proxy->priv->timeout_msec : timeout_msec,
2769 fd_list,
2770 cancellable,
2771 my_callback,
2772 task);
2773 #else
2774 g_dbus_connection_call (proxy->priv->connection,
2775 destination,
2776 proxy->priv->object_path,
2777 target_interface_name,
2778 target_method_name,
2779 parameters,
2780 reply_type,
2781 flags,
2782 timeout_msec == -1 ? proxy->priv->timeout_msec : timeout_msec,
2783 cancellable,
2784 my_callback,
2785 task);
2786 #endif
2787
2788 out:
2789 if (reply_type != NULL)
2790 g_variant_type_free (reply_type);
2791
2792 g_free (destination);
2793 g_free (split_interface_name);
2794 }
2795
2796 static GVariant *
g_dbus_proxy_call_finish_internal(GDBusProxy * proxy,GUnixFDList ** out_fd_list,GAsyncResult * res,GError ** error)2797 g_dbus_proxy_call_finish_internal (GDBusProxy *proxy,
2798 GUnixFDList **out_fd_list,
2799 GAsyncResult *res,
2800 GError **error)
2801 {
2802 GVariant *value;
2803 ReplyData *data;
2804
2805 g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
2806 g_return_val_if_fail (g_task_is_valid (res, proxy), NULL);
2807 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2808
2809 value = NULL;
2810
2811 data = g_task_propagate_pointer (G_TASK (res), error);
2812 if (!data)
2813 goto out;
2814
2815 value = g_variant_ref (data->value);
2816 #ifdef G_OS_UNIX
2817 if (out_fd_list != NULL)
2818 *out_fd_list = data->fd_list != NULL ? g_object_ref (data->fd_list) : NULL;
2819 #endif
2820 reply_data_free (data);
2821
2822 out:
2823 return value;
2824 }
2825
2826 static GVariant *
g_dbus_proxy_call_sync_internal(GDBusProxy * proxy,const gchar * method_name,GVariant * parameters,GDBusCallFlags flags,gint timeout_msec,GUnixFDList * fd_list,GUnixFDList ** out_fd_list,GCancellable * cancellable,GError ** error)2827 g_dbus_proxy_call_sync_internal (GDBusProxy *proxy,
2828 const gchar *method_name,
2829 GVariant *parameters,
2830 GDBusCallFlags flags,
2831 gint timeout_msec,
2832 GUnixFDList *fd_list,
2833 GUnixFDList **out_fd_list,
2834 GCancellable *cancellable,
2835 GError **error)
2836 {
2837 GVariant *ret;
2838 gboolean was_split;
2839 gchar *split_interface_name;
2840 const gchar *split_method_name;
2841 const gchar *target_method_name;
2842 const gchar *target_interface_name;
2843 gchar *destination;
2844 GVariantType *reply_type;
2845
2846 g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
2847 g_return_val_if_fail (g_dbus_is_member_name (method_name) || g_dbus_is_interface_name (method_name), NULL);
2848 g_return_val_if_fail (parameters == NULL || g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE), NULL);
2849 g_return_val_if_fail (timeout_msec == -1 || timeout_msec >= 0, NULL);
2850 #ifdef G_OS_UNIX
2851 g_return_val_if_fail (fd_list == NULL || G_IS_UNIX_FD_LIST (fd_list), NULL);
2852 #else
2853 g_return_val_if_fail (fd_list == NULL, NULL);
2854 #endif
2855 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2856
2857 reply_type = NULL;
2858
2859 G_LOCK (properties_lock);
2860
2861 was_split = maybe_split_method_name (method_name, &split_interface_name, &split_method_name);
2862 target_method_name = was_split ? split_method_name : method_name;
2863 target_interface_name = was_split ? split_interface_name : proxy->priv->interface_name;
2864
2865 /* Warn if method is unexpected (cf. :g-interface-info) */
2866 if (!was_split)
2867 {
2868 const GDBusMethodInfo *expected_method_info;
2869 expected_method_info = lookup_method_info (proxy, target_method_name);
2870 if (expected_method_info != NULL)
2871 reply_type = _g_dbus_compute_complete_signature (expected_method_info->out_args);
2872 }
2873
2874 destination = NULL;
2875 if (proxy->priv->name != NULL)
2876 {
2877 destination = g_strdup (get_destination_for_call (proxy));
2878 if (destination == NULL)
2879 {
2880 g_set_error (error,
2881 G_IO_ERROR,
2882 G_IO_ERROR_FAILED,
2883 _("Cannot invoke method; proxy is for the well-known name %s without an owner, and proxy was constructed with the G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START flag"),
2884 proxy->priv->name);
2885 ret = NULL;
2886 G_UNLOCK (properties_lock);
2887 goto out;
2888 }
2889 }
2890
2891 G_UNLOCK (properties_lock);
2892
2893 #ifdef G_OS_UNIX
2894 ret = g_dbus_connection_call_with_unix_fd_list_sync (proxy->priv->connection,
2895 destination,
2896 proxy->priv->object_path,
2897 target_interface_name,
2898 target_method_name,
2899 parameters,
2900 reply_type,
2901 flags,
2902 timeout_msec == -1 ? proxy->priv->timeout_msec : timeout_msec,
2903 fd_list,
2904 out_fd_list,
2905 cancellable,
2906 error);
2907 #else
2908 ret = g_dbus_connection_call_sync (proxy->priv->connection,
2909 destination,
2910 proxy->priv->object_path,
2911 target_interface_name,
2912 target_method_name,
2913 parameters,
2914 reply_type,
2915 flags,
2916 timeout_msec == -1 ? proxy->priv->timeout_msec : timeout_msec,
2917 cancellable,
2918 error);
2919 #endif
2920
2921 out:
2922 if (reply_type != NULL)
2923 g_variant_type_free (reply_type);
2924
2925 g_free (destination);
2926 g_free (split_interface_name);
2927
2928 return ret;
2929 }
2930
2931 /* ---------------------------------------------------------------------------------------------------- */
2932
2933 /**
2934 * g_dbus_proxy_call:
2935 * @proxy: A #GDBusProxy.
2936 * @method_name: Name of method to invoke.
2937 * @parameters: (nullable): A #GVariant tuple with parameters for the signal or %NULL if not passing parameters.
2938 * @flags: Flags from the #GDBusCallFlags enumeration.
2939 * @timeout_msec: The timeout in milliseconds (with %G_MAXINT meaning
2940 * "infinite") or -1 to use the proxy default timeout.
2941 * @cancellable: (nullable): A #GCancellable or %NULL.
2942 * @callback: (nullable): A #GAsyncReadyCallback to call when the request is satisfied or %NULL if you don't
2943 * care about the result of the method invocation.
2944 * @user_data: The data to pass to @callback.
2945 *
2946 * Asynchronously invokes the @method_name method on @proxy.
2947 *
2948 * If @method_name contains any dots, then @name is split into interface and
2949 * method name parts. This allows using @proxy for invoking methods on
2950 * other interfaces.
2951 *
2952 * If the #GDBusConnection associated with @proxy is closed then
2953 * the operation will fail with %G_IO_ERROR_CLOSED. If
2954 * @cancellable is canceled, the operation will fail with
2955 * %G_IO_ERROR_CANCELLED. If @parameters contains a value not
2956 * compatible with the D-Bus protocol, the operation fails with
2957 * %G_IO_ERROR_INVALID_ARGUMENT.
2958 *
2959 * If the @parameters #GVariant is floating, it is consumed. This allows
2960 * convenient 'inline' use of g_variant_new(), e.g.:
2961 * |[<!-- language="C" -->
2962 * g_dbus_proxy_call (proxy,
2963 * "TwoStrings",
2964 * g_variant_new ("(ss)",
2965 * "Thing One",
2966 * "Thing Two"),
2967 * G_DBUS_CALL_FLAGS_NONE,
2968 * -1,
2969 * NULL,
2970 * (GAsyncReadyCallback) two_strings_done,
2971 * &data);
2972 * ]|
2973 *
2974 * If @proxy has an expected interface (see
2975 * #GDBusProxy:g-interface-info) and @method_name is referenced by it,
2976 * then the return value is checked against the return type.
2977 *
2978 * This is an asynchronous method. When the operation is finished,
2979 * @callback will be invoked in the
2980 * [thread-default main context][g-main-context-push-thread-default]
2981 * of the thread you are calling this method from.
2982 * You can then call g_dbus_proxy_call_finish() to get the result of
2983 * the operation. See g_dbus_proxy_call_sync() for the synchronous
2984 * version of this method.
2985 *
2986 * If @callback is %NULL then the D-Bus method call message will be sent with
2987 * the %G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED flag set.
2988 *
2989 * Since: 2.26
2990 */
2991 void
g_dbus_proxy_call(GDBusProxy * proxy,const gchar * method_name,GVariant * parameters,GDBusCallFlags flags,gint timeout_msec,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)2992 g_dbus_proxy_call (GDBusProxy *proxy,
2993 const gchar *method_name,
2994 GVariant *parameters,
2995 GDBusCallFlags flags,
2996 gint timeout_msec,
2997 GCancellable *cancellable,
2998 GAsyncReadyCallback callback,
2999 gpointer user_data)
3000 {
3001 g_dbus_proxy_call_internal (proxy, method_name, parameters, flags, timeout_msec, NULL, cancellable, callback, user_data);
3002 }
3003
3004 /**
3005 * g_dbus_proxy_call_finish:
3006 * @proxy: A #GDBusProxy.
3007 * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_proxy_call().
3008 * @error: Return location for error or %NULL.
3009 *
3010 * Finishes an operation started with g_dbus_proxy_call().
3011 *
3012 * Returns: %NULL if @error is set. Otherwise a #GVariant tuple with
3013 * return values. Free with g_variant_unref().
3014 *
3015 * Since: 2.26
3016 */
3017 GVariant *
g_dbus_proxy_call_finish(GDBusProxy * proxy,GAsyncResult * res,GError ** error)3018 g_dbus_proxy_call_finish (GDBusProxy *proxy,
3019 GAsyncResult *res,
3020 GError **error)
3021 {
3022 return g_dbus_proxy_call_finish_internal (proxy, NULL, res, error);
3023 }
3024
3025 /**
3026 * g_dbus_proxy_call_sync:
3027 * @proxy: A #GDBusProxy.
3028 * @method_name: Name of method to invoke.
3029 * @parameters: (nullable): A #GVariant tuple with parameters for the signal
3030 * or %NULL if not passing parameters.
3031 * @flags: Flags from the #GDBusCallFlags enumeration.
3032 * @timeout_msec: The timeout in milliseconds (with %G_MAXINT meaning
3033 * "infinite") or -1 to use the proxy default timeout.
3034 * @cancellable: (nullable): A #GCancellable or %NULL.
3035 * @error: Return location for error or %NULL.
3036 *
3037 * Synchronously invokes the @method_name method on @proxy.
3038 *
3039 * If @method_name contains any dots, then @name is split into interface and
3040 * method name parts. This allows using @proxy for invoking methods on
3041 * other interfaces.
3042 *
3043 * If the #GDBusConnection associated with @proxy is disconnected then
3044 * the operation will fail with %G_IO_ERROR_CLOSED. If
3045 * @cancellable is canceled, the operation will fail with
3046 * %G_IO_ERROR_CANCELLED. If @parameters contains a value not
3047 * compatible with the D-Bus protocol, the operation fails with
3048 * %G_IO_ERROR_INVALID_ARGUMENT.
3049 *
3050 * If the @parameters #GVariant is floating, it is consumed. This allows
3051 * convenient 'inline' use of g_variant_new(), e.g.:
3052 * |[<!-- language="C" -->
3053 * g_dbus_proxy_call_sync (proxy,
3054 * "TwoStrings",
3055 * g_variant_new ("(ss)",
3056 * "Thing One",
3057 * "Thing Two"),
3058 * G_DBUS_CALL_FLAGS_NONE,
3059 * -1,
3060 * NULL,
3061 * &error);
3062 * ]|
3063 *
3064 * The calling thread is blocked until a reply is received. See
3065 * g_dbus_proxy_call() for the asynchronous version of this
3066 * method.
3067 *
3068 * If @proxy has an expected interface (see
3069 * #GDBusProxy:g-interface-info) and @method_name is referenced by it,
3070 * then the return value is checked against the return type.
3071 *
3072 * Returns: %NULL if @error is set. Otherwise a #GVariant tuple with
3073 * return values. Free with g_variant_unref().
3074 *
3075 * Since: 2.26
3076 */
3077 GVariant *
g_dbus_proxy_call_sync(GDBusProxy * proxy,const gchar * method_name,GVariant * parameters,GDBusCallFlags flags,gint timeout_msec,GCancellable * cancellable,GError ** error)3078 g_dbus_proxy_call_sync (GDBusProxy *proxy,
3079 const gchar *method_name,
3080 GVariant *parameters,
3081 GDBusCallFlags flags,
3082 gint timeout_msec,
3083 GCancellable *cancellable,
3084 GError **error)
3085 {
3086 return g_dbus_proxy_call_sync_internal (proxy, method_name, parameters, flags, timeout_msec, NULL, NULL, cancellable, error);
3087 }
3088
3089 /* ---------------------------------------------------------------------------------------------------- */
3090
3091 #ifdef G_OS_UNIX
3092
3093 /**
3094 * g_dbus_proxy_call_with_unix_fd_list:
3095 * @proxy: A #GDBusProxy.
3096 * @method_name: Name of method to invoke.
3097 * @parameters: (nullable): A #GVariant tuple with parameters for the signal or %NULL if not passing parameters.
3098 * @flags: Flags from the #GDBusCallFlags enumeration.
3099 * @timeout_msec: The timeout in milliseconds (with %G_MAXINT meaning
3100 * "infinite") or -1 to use the proxy default timeout.
3101 * @fd_list: (nullable): A #GUnixFDList or %NULL.
3102 * @cancellable: (nullable): A #GCancellable or %NULL.
3103 * @callback: (nullable): A #GAsyncReadyCallback to call when the request is satisfied or %NULL if you don't
3104 * care about the result of the method invocation.
3105 * @user_data: The data to pass to @callback.
3106 *
3107 * Like g_dbus_proxy_call() but also takes a #GUnixFDList object.
3108 *
3109 * This method is only available on UNIX.
3110 *
3111 * Since: 2.30
3112 */
3113 void
g_dbus_proxy_call_with_unix_fd_list(GDBusProxy * proxy,const gchar * method_name,GVariant * parameters,GDBusCallFlags flags,gint timeout_msec,GUnixFDList * fd_list,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)3114 g_dbus_proxy_call_with_unix_fd_list (GDBusProxy *proxy,
3115 const gchar *method_name,
3116 GVariant *parameters,
3117 GDBusCallFlags flags,
3118 gint timeout_msec,
3119 GUnixFDList *fd_list,
3120 GCancellable *cancellable,
3121 GAsyncReadyCallback callback,
3122 gpointer user_data)
3123 {
3124 g_dbus_proxy_call_internal (proxy, method_name, parameters, flags, timeout_msec, fd_list, cancellable, callback, user_data);
3125 }
3126
3127 /**
3128 * g_dbus_proxy_call_with_unix_fd_list_finish:
3129 * @proxy: A #GDBusProxy.
3130 * @out_fd_list: (out) (optional): Return location for a #GUnixFDList or %NULL.
3131 * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_proxy_call_with_unix_fd_list().
3132 * @error: Return location for error or %NULL.
3133 *
3134 * Finishes an operation started with g_dbus_proxy_call_with_unix_fd_list().
3135 *
3136 * Returns: %NULL if @error is set. Otherwise a #GVariant tuple with
3137 * return values. Free with g_variant_unref().
3138 *
3139 * Since: 2.30
3140 */
3141 GVariant *
g_dbus_proxy_call_with_unix_fd_list_finish(GDBusProxy * proxy,GUnixFDList ** out_fd_list,GAsyncResult * res,GError ** error)3142 g_dbus_proxy_call_with_unix_fd_list_finish (GDBusProxy *proxy,
3143 GUnixFDList **out_fd_list,
3144 GAsyncResult *res,
3145 GError **error)
3146 {
3147 return g_dbus_proxy_call_finish_internal (proxy, out_fd_list, res, error);
3148 }
3149
3150 /**
3151 * g_dbus_proxy_call_with_unix_fd_list_sync:
3152 * @proxy: A #GDBusProxy.
3153 * @method_name: Name of method to invoke.
3154 * @parameters: (nullable): A #GVariant tuple with parameters for the signal
3155 * or %NULL if not passing parameters.
3156 * @flags: Flags from the #GDBusCallFlags enumeration.
3157 * @timeout_msec: The timeout in milliseconds (with %G_MAXINT meaning
3158 * "infinite") or -1 to use the proxy default timeout.
3159 * @fd_list: (nullable): A #GUnixFDList or %NULL.
3160 * @out_fd_list: (out) (optional): Return location for a #GUnixFDList or %NULL.
3161 * @cancellable: (nullable): A #GCancellable or %NULL.
3162 * @error: Return location for error or %NULL.
3163 *
3164 * Like g_dbus_proxy_call_sync() but also takes and returns #GUnixFDList objects.
3165 *
3166 * This method is only available on UNIX.
3167 *
3168 * Returns: %NULL if @error is set. Otherwise a #GVariant tuple with
3169 * return values. Free with g_variant_unref().
3170 *
3171 * Since: 2.30
3172 */
3173 GVariant *
g_dbus_proxy_call_with_unix_fd_list_sync(GDBusProxy * proxy,const gchar * method_name,GVariant * parameters,GDBusCallFlags flags,gint timeout_msec,GUnixFDList * fd_list,GUnixFDList ** out_fd_list,GCancellable * cancellable,GError ** error)3174 g_dbus_proxy_call_with_unix_fd_list_sync (GDBusProxy *proxy,
3175 const gchar *method_name,
3176 GVariant *parameters,
3177 GDBusCallFlags flags,
3178 gint timeout_msec,
3179 GUnixFDList *fd_list,
3180 GUnixFDList **out_fd_list,
3181 GCancellable *cancellable,
3182 GError **error)
3183 {
3184 return g_dbus_proxy_call_sync_internal (proxy, method_name, parameters, flags, timeout_msec, fd_list, out_fd_list, cancellable, error);
3185 }
3186
3187 #endif /* G_OS_UNIX */
3188
3189 /* ---------------------------------------------------------------------------------------------------- */
3190
3191 static GDBusInterfaceInfo *
_g_dbus_proxy_get_info(GDBusInterface * interface)3192 _g_dbus_proxy_get_info (GDBusInterface *interface)
3193 {
3194 GDBusProxy *proxy = G_DBUS_PROXY (interface);
3195 return g_dbus_proxy_get_interface_info (proxy);
3196 }
3197
3198 static GDBusObject *
_g_dbus_proxy_get_object(GDBusInterface * interface)3199 _g_dbus_proxy_get_object (GDBusInterface *interface)
3200 {
3201 GDBusProxy *proxy = G_DBUS_PROXY (interface);
3202 return proxy->priv->object;
3203 }
3204
3205 static GDBusObject *
_g_dbus_proxy_dup_object(GDBusInterface * interface)3206 _g_dbus_proxy_dup_object (GDBusInterface *interface)
3207 {
3208 GDBusProxy *proxy = G_DBUS_PROXY (interface);
3209 GDBusObject *ret = NULL;
3210
3211 G_LOCK (properties_lock);
3212 if (proxy->priv->object != NULL)
3213 ret = g_object_ref (proxy->priv->object);
3214 G_UNLOCK (properties_lock);
3215 return ret;
3216 }
3217
3218 static void
_g_dbus_proxy_set_object(GDBusInterface * interface,GDBusObject * object)3219 _g_dbus_proxy_set_object (GDBusInterface *interface,
3220 GDBusObject *object)
3221 {
3222 GDBusProxy *proxy = G_DBUS_PROXY (interface);
3223 G_LOCK (properties_lock);
3224 if (proxy->priv->object != NULL)
3225 g_object_remove_weak_pointer (G_OBJECT (proxy->priv->object), (gpointer *) &proxy->priv->object);
3226 proxy->priv->object = object;
3227 if (proxy->priv->object != NULL)
3228 g_object_add_weak_pointer (G_OBJECT (proxy->priv->object), (gpointer *) &proxy->priv->object);
3229 G_UNLOCK (properties_lock);
3230 }
3231
3232 static void
dbus_interface_iface_init(GDBusInterfaceIface * dbus_interface_iface)3233 dbus_interface_iface_init (GDBusInterfaceIface *dbus_interface_iface)
3234 {
3235 dbus_interface_iface->get_info = _g_dbus_proxy_get_info;
3236 dbus_interface_iface->get_object = _g_dbus_proxy_get_object;
3237 dbus_interface_iface->dup_object = _g_dbus_proxy_dup_object;
3238 dbus_interface_iface->set_object = _g_dbus_proxy_set_object;
3239 }
3240
3241 /* ---------------------------------------------------------------------------------------------------- */
3242