Coverage Report

Created: 2026-07-16 06:32

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