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