Coverage Report

Created: 2025-06-13 06:55

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