Coverage Report

Created: 2025-11-16 07:45

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