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