Coverage Report

Created: 2025-07-23 08:13

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