Coverage Report

Created: 2026-10-17 07:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/glib/gio/gdbusobjectmanagerclient.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 "gcancellable.h"
26
#include "gdbusobjectmanager.h"
27
#include "gdbusobjectmanagerclient.h"
28
#include "gdbusobject.h"
29
#include "gdbusprivate.h"
30
#include "gioenumtypes.h"
31
#include "gioerror.h"
32
#include "ginitable.h"
33
#include "gasyncresult.h"
34
#include "gasyncinitable.h"
35
#include "gdbusconnection.h"
36
#include "gdbusutils.h"
37
#include "gdbusobject.h"
38
#include "gdbusobjectproxy.h"
39
#include "gdbusproxy.h"
40
#include "gdbusinterface.h"
41
42
#include "glibintl.h"
43
#include "gmarshal-internal.h"
44
45
/**
46
 * GDBusObjectManagerClient:
47
 *
48
 * `GDBusObjectManagerClient` is used to create, monitor and delete object
49
 * proxies for remote objects exported by a [class@Gio.DBusObjectManagerServer]
50
 * (or any code implementing the
51
 * [org.freedesktop.DBus.ObjectManager](http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager)
52
 * interface).
53
 *
54
 * Once an instance of this type has been created, you can connect to
55
 * the [signal@Gio.DBusObjectManager::object-added] and
56
 * [signal@Gio.DBusObjectManager::object-removed signals] and inspect the
57
 * [class@Gio.DBusObjectProxy] objects returned by
58
 * [method@Gio.DBusObjectManager.get_objects].
59
 *
60
 * If the name for a `GDBusObjectManagerClient` is not owned by anyone at
61
 * object construction time, the default behavior is to request the
62
 * message bus to launch an owner for the name. This behavior can be
63
 * disabled using the `G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START`
64
 * flag. It’s also worth noting that this only works if the name of
65
 * interest is activatable in the first place. E.g. in some cases it
66
 * is not possible to launch an owner for the requested name. In this
67
 * case, `GDBusObjectManagerClient` object construction still succeeds but
68
 * there will be no object proxies
69
 * (e.g. [method@Gio.DBusObjectManager.get_objects] returns the empty list) and
70
 * the [property@Gio.DBusObjectManagerClient:name-owner] property is `NULL`.
71
 *
72
 * The owner of the requested name can come and go (for example
73
 * consider a system service being restarted) – `GDBusObjectManagerClient`
74
 * handles this case too; simply connect to the [signal@GObject.Object::notify]
75
 * signal to watch for changes on the
76
 * [property@Gio.DBusObjectManagerClient:name-owner] property. When the name
77
 * owner vanishes, the behavior is that
78
 * [property@Gio.DBusObjectManagerClient:name-owner] is set to `NULL` (this
79
 * includes emission of the [signal@GObject.Object::notify] signal) and then
80
 * [signal@Gio.DBusObjectManager::object-removed] signals are synthesized
81
 * for all currently existing object proxies. Since
82
 * [property@Gio.DBusObjectManagerClient:name-owner] is `NULL` when this
83
 * happens, you can use this information to disambiguate a synthesized signal
84
 * from a genuine signal caused by object removal on the remote
85
 * [iface@Gio.DBusObjectManager]. Similarly, when a new name owner appears,
86
 * [signal@Gio.DBusObjectManager::object-added] signals are synthesized
87
 * while [property@Gio.DBusObjectManagerClient:name-owner] is still `NULL`. Only
88
 * when all object proxies have been added, the
89
 * [property@Gio.DBusObjectManagerClient:name-owner] is set to the new name
90
 * owner (this includes emission of the [signal@GObject.Object::notify] signal).
91
 * Furthermore, you are guaranteed that
92
 * [property@Gio.DBusObjectManagerClient:name-owner] will alternate between a
93
 * name owner (e.g. `:1.42`) and `NULL` even in the case where
94
 * the name of interest is atomically replaced
95
 *
96
 * Ultimately, `GDBusObjectManagerClient` is used to obtain
97
 * [class@Gio.DBusProxy] instances. All signals (including the
98
 * `org.freedesktop.DBus.Properties::PropertiesChanged` signal)
99
 * delivered to [class@Gio.DBusProxy] instances are guaranteed to originate
100
 * from the name owner. This guarantee along with the behavior
101
 * described above, means that certain race conditions including the
102
 * “half the proxy is from the old owner and the other half is from
103
 * the new owner” problem cannot happen.
104
 *
105
 * To avoid having the application connect to signals on the returned
106
 * [class@Gio.DBusObjectProxy] and [class@Gio.DBusProxy] objects, the
107
 * [signal@Gio.DBusObject::interface-added],
108
 * [signal@Gio.DBusObject::interface-removed],
109
 * [signal@Gio.DBusProxy::g-properties-changed] and
110
 * [signal@Gio.DBusProxy::g-signal] signals
111
 * are also emitted on the `GDBusObjectManagerClient` instance managing these
112
 * objects. The signals emitted are
113
 * [signal@Gio.DBusObjectManager::interface-added],
114
 * [signal@Gio.DBusObjectManager::interface-removed],
115
 * [signal@Gio.DBusObjectManagerClient::interface-proxy-properties-changed] and
116
 * [signal@Gio.DBusObjectManagerClient::interface-proxy-signal].
117
 *
118
 * Note that all callbacks and signals are emitted in the
119
 * thread-default main context (see
120
 * [method@GLib.MainContext.push_thread_default]) that the
121
 * `GDBusObjectManagerClient` object was constructed in. Additionally, the
122
 * [class@Gio.DBusObjectProxy] and [class@Gio.DBusProxy] objects
123
 * originating from the `GDBusObjectManagerClient` object will be created in
124
 * the same context and, consequently, will deliver signals in the
125
 * same main loop.
126
 *
127
 * Since: 2.30
128
 */
129
130
struct _GDBusObjectManagerClientPrivate
131
{
132
  GMutex lock;
133
134
  GBusType bus_type;
135
  GDBusConnection *connection;
136
  gchar *object_path;
137
  gchar *name;
138
  gchar *name_owner;
139
  GDBusObjectManagerClientFlags flags;
140
141
  GDBusProxy *control_proxy;
142
143
  GHashTable *map_object_path_to_object_proxy;
144
145
  guint signal_subscription_id;
146
  gchar *match_rule;
147
148
  GDBusProxyTypeFunc get_proxy_type_func;
149
  gpointer get_proxy_type_user_data;
150
  GDestroyNotify get_proxy_type_destroy_notify;
151
152
  gulong name_owner_signal_id;
153
  gulong signal_signal_id;
154
  GCancellable *cancel;
155
};
156
157
enum
158
{
159
  PROP_0,
160
  PROP_BUS_TYPE,
161
  PROP_CONNECTION,
162
  PROP_FLAGS,
163
  PROP_OBJECT_PATH,
164
  PROP_NAME,
165
  PROP_NAME_OWNER,
166
  PROP_GET_PROXY_TYPE_FUNC,
167
  PROP_GET_PROXY_TYPE_USER_DATA,
168
  PROP_GET_PROXY_TYPE_DESTROY_NOTIFY
169
};
170
171
enum
172
{
173
  INTERFACE_PROXY_SIGNAL_SIGNAL,
174
  INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL,
175
  LAST_SIGNAL
176
};
177
178
static guint signals[LAST_SIGNAL] = { 0 };
179
180
static void initable_iface_init       (GInitableIface *initable_iface);
181
static void async_initable_iface_init (GAsyncInitableIface *async_initable_iface);
182
static void dbus_object_manager_interface_init (GDBusObjectManagerIface *iface);
183
184
0
G_DEFINE_TYPE_WITH_CODE (GDBusObjectManagerClient, g_dbus_object_manager_client, G_TYPE_OBJECT,
185
0
                         G_ADD_PRIVATE (GDBusObjectManagerClient)
186
0
                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)
187
0
                         G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init)
188
0
                         G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_OBJECT_MANAGER, dbus_object_manager_interface_init))
189
0
190
0
static void maybe_unsubscribe_signals (GDBusObjectManagerClient *manager);
191
0
192
0
static void on_control_proxy_g_signal (GDBusProxy   *proxy,
193
0
                                       const gchar  *sender_name,
194
0
                                       const gchar  *signal_name,
195
0
                                       GVariant     *parameters,
196
0
                                       gpointer      user_data);
197
0
198
0
static void process_get_all_result (GDBusObjectManagerClient *manager,
199
0
                                    GVariant          *value,
200
0
                                    const gchar       *name_owner);
201
0
202
0
static void
203
0
g_dbus_object_manager_client_dispose (GObject *object)
204
0
{
205
0
  GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (object);
206
207
0
  if (manager->priv->cancel != NULL)
208
0
    {
209
0
      g_cancellable_cancel (manager->priv->cancel);
210
0
      g_clear_object (&manager->priv->cancel);
211
0
    }
212
213
0
  G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class)->dispose (object);
214
0
}
215
216
static void
217
g_dbus_object_manager_client_finalize (GObject *object)
218
0
{
219
0
  GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (object);
220
221
0
  maybe_unsubscribe_signals (manager);
222
223
0
  g_hash_table_unref (manager->priv->map_object_path_to_object_proxy);
224
225
0
  if (manager->priv->control_proxy != NULL && manager->priv->signal_signal_id != 0)
226
0
    g_signal_handler_disconnect (manager->priv->control_proxy,
227
0
                                 manager->priv->signal_signal_id);
228
0
  manager->priv->signal_signal_id = 0;
229
230
0
  if (manager->priv->control_proxy != NULL && manager->priv->name_owner_signal_id != 0)
231
0
    g_signal_handler_disconnect (manager->priv->control_proxy,
232
0
                                 manager->priv->name_owner_signal_id);
233
0
  manager->priv->name_owner_signal_id = 0;
234
235
0
  g_clear_object (&manager->priv->control_proxy);
236
237
0
  if (manager->priv->connection != NULL)
238
0
    g_object_unref (manager->priv->connection);
239
0
  g_free (manager->priv->object_path);
240
0
  g_free (manager->priv->name);
241
0
  g_free (manager->priv->name_owner);
242
243
0
  if (manager->priv->get_proxy_type_destroy_notify != NULL)
244
0
    manager->priv->get_proxy_type_destroy_notify (manager->priv->get_proxy_type_user_data);
245
246
0
  g_mutex_clear (&manager->priv->lock);
247
248
0
  if (G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class)->finalize != NULL)
249
0
    G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class)->finalize (object);
250
0
}
251
252
static void
253
g_dbus_object_manager_client_get_property (GObject    *_object,
254
                                           guint       prop_id,
255
                                           GValue     *value,
256
                                           GParamSpec *pspec)
257
0
{
258
0
  GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_object);
259
260
0
  switch (prop_id)
261
0
    {
262
0
    case PROP_CONNECTION:
263
0
      g_value_set_object (value, g_dbus_object_manager_client_get_connection (manager));
264
0
      break;
265
266
0
    case PROP_OBJECT_PATH:
267
0
      g_value_set_string (value, g_dbus_object_manager_get_object_path (G_DBUS_OBJECT_MANAGER (manager)));
268
0
      break;
269
270
0
    case PROP_NAME:
271
0
      g_value_set_string (value, g_dbus_object_manager_client_get_name (manager));
272
0
      break;
273
274
0
    case PROP_FLAGS:
275
0
      g_value_set_flags (value, g_dbus_object_manager_client_get_flags (manager));
276
0
      break;
277
278
0
    case PROP_NAME_OWNER:
279
0
      g_value_take_string (value, g_dbus_object_manager_client_get_name_owner (manager));
280
0
      break;
281
282
0
    default:
283
0
      G_OBJECT_WARN_INVALID_PROPERTY_ID (manager, prop_id, pspec);
284
0
      break;
285
0
    }
286
0
}
287
288
static void
289
g_dbus_object_manager_client_set_property (GObject       *_object,
290
                                           guint          prop_id,
291
                                           const GValue  *value,
292
                                           GParamSpec    *pspec)
293
0
{
294
0
  GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_object);
295
0
  const gchar *name;
296
297
0
  switch (prop_id)
298
0
    {
299
0
    case PROP_BUS_TYPE:
300
0
      manager->priv->bus_type = g_value_get_enum (value);
301
0
      break;
302
303
0
    case PROP_CONNECTION:
304
0
      if (g_value_get_object (value) != NULL)
305
0
        {
306
0
          g_assert (manager->priv->connection == NULL);
307
0
          g_assert (G_IS_DBUS_CONNECTION (g_value_get_object (value)));
308
0
          manager->priv->connection = g_value_dup_object (value);
309
0
        }
310
0
      break;
311
312
0
    case PROP_OBJECT_PATH:
313
0
      g_assert (manager->priv->object_path == NULL);
314
0
      g_assert (g_variant_is_object_path (g_value_get_string (value)));
315
0
      manager->priv->object_path = g_value_dup_string (value);
316
0
      break;
317
318
0
    case PROP_NAME:
319
0
      g_assert (manager->priv->name == NULL);
320
0
      name = g_value_get_string (value);
321
0
      g_assert (name == NULL || g_dbus_is_name (name));
322
0
      manager->priv->name = g_strdup (name);
323
0
      break;
324
325
0
    case PROP_FLAGS:
326
0
      manager->priv->flags = g_value_get_flags (value);
327
0
      break;
328
329
0
    case PROP_GET_PROXY_TYPE_FUNC:
330
0
      manager->priv->get_proxy_type_func = g_value_get_pointer (value);
331
0
      break;
332
333
0
    case PROP_GET_PROXY_TYPE_USER_DATA:
334
0
      manager->priv->get_proxy_type_user_data = g_value_get_pointer (value);
335
0
      break;
336
337
0
    case PROP_GET_PROXY_TYPE_DESTROY_NOTIFY:
338
0
      manager->priv->get_proxy_type_destroy_notify = g_value_get_pointer (value);
339
0
      break;
340
341
0
    default:
342
0
      G_OBJECT_WARN_INVALID_PROPERTY_ID (manager, prop_id, pspec);
343
0
      break;
344
0
    }
345
0
}
346
347
static void
348
g_dbus_object_manager_client_class_init (GDBusObjectManagerClientClass *klass)
349
0
{
350
0
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
351
352
0
  gobject_class->dispose      = g_dbus_object_manager_client_dispose;
353
0
  gobject_class->finalize     = g_dbus_object_manager_client_finalize;
354
0
  gobject_class->set_property = g_dbus_object_manager_client_set_property;
355
0
  gobject_class->get_property = g_dbus_object_manager_client_get_property;
356
357
  /**
358
   * GDBusObjectManagerClient:connection:
359
   *
360
   * The #GDBusConnection to use.
361
   *
362
   * Since: 2.30
363
   */
364
0
  g_object_class_install_property (gobject_class,
365
0
                                   PROP_CONNECTION,
366
0
                                   g_param_spec_object ("connection", NULL, NULL,
367
0
                                                        G_TYPE_DBUS_CONNECTION,
368
0
                                                        G_PARAM_READABLE |
369
0
                                                        G_PARAM_WRITABLE |
370
0
                                                        G_PARAM_CONSTRUCT_ONLY |
371
0
                                                        G_PARAM_STATIC_STRINGS));
372
373
  /**
374
   * GDBusObjectManagerClient:bus-type:
375
   *
376
   * If this property is not %G_BUS_TYPE_NONE, then
377
   * #GDBusObjectManagerClient:connection must be %NULL and will be set to the
378
   * #GDBusConnection obtained by calling g_bus_get() with the value
379
   * of this property.
380
   *
381
   * Since: 2.30
382
   */
383
0
  g_object_class_install_property (gobject_class,
384
0
                                   PROP_BUS_TYPE,
385
0
                                   g_param_spec_enum ("bus-type", NULL, NULL,
386
0
                                                      G_TYPE_BUS_TYPE,
387
0
                                                      G_BUS_TYPE_NONE,
388
0
                                                      G_PARAM_WRITABLE |
389
0
                                                      G_PARAM_CONSTRUCT_ONLY |
390
0
                                                      G_PARAM_STATIC_NAME |
391
0
                                                      G_PARAM_STATIC_BLURB |
392
0
                                                      G_PARAM_STATIC_NICK));
393
394
  /**
395
   * GDBusObjectManagerClient:flags:
396
   *
397
   * Flags from the #GDBusObjectManagerClientFlags enumeration.
398
   *
399
   * Since: 2.30
400
   */
401
0
  g_object_class_install_property (gobject_class,
402
0
                                   PROP_FLAGS,
403
0
                                   g_param_spec_flags ("flags", NULL, NULL,
404
0
                                                       G_TYPE_DBUS_OBJECT_MANAGER_CLIENT_FLAGS,
405
0
                                                       G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
406
0
                                                       G_PARAM_READABLE |
407
0
                                                       G_PARAM_WRITABLE |
408
0
                                                       G_PARAM_CONSTRUCT_ONLY |
409
0
                                                       G_PARAM_STATIC_NAME |
410
0
                                                       G_PARAM_STATIC_BLURB |
411
0
                                                       G_PARAM_STATIC_NICK));
412
413
  /**
414
   * GDBusObjectManagerClient:object-path:
415
   *
416
   * The object path the manager is for.
417
   *
418
   * Since: 2.30
419
   */
420
0
  g_object_class_install_property (gobject_class,
421
0
                                   PROP_OBJECT_PATH,
422
0
                                   g_param_spec_string ("object-path", NULL, NULL,
423
0
                                                        NULL,
424
0
                                                        G_PARAM_READABLE |
425
0
                                                        G_PARAM_WRITABLE |
426
0
                                                        G_PARAM_CONSTRUCT_ONLY |
427
0
                                                        G_PARAM_STATIC_STRINGS));
428
429
  /**
430
   * GDBusObjectManagerClient:name:
431
   *
432
   * The well-known name or unique name that the manager is for.
433
   *
434
   * Since: 2.30
435
   */
436
0
  g_object_class_install_property (gobject_class,
437
0
                                   PROP_NAME,
438
0
                                   g_param_spec_string ("name", NULL, NULL,
439
0
                                                        NULL,
440
0
                                                        G_PARAM_READABLE |
441
0
                                                        G_PARAM_WRITABLE |
442
0
                                                        G_PARAM_CONSTRUCT_ONLY |
443
0
                                                        G_PARAM_STATIC_STRINGS));
444
445
  /**
446
   * GDBusObjectManagerClient:name-owner:
447
   *
448
   * The unique name that owns #GDBusObjectManagerClient:name or %NULL if
449
   * no-one is currently owning the name. Connect to the
450
   * #GObject::notify signal to track changes to this property.
451
   *
452
   * Since: 2.30
453
   */
454
0
  g_object_class_install_property (gobject_class,
455
0
                                   PROP_NAME_OWNER,
456
0
                                   g_param_spec_string ("name-owner", NULL, NULL,
457
0
                                                        NULL,
458
0
                                                        G_PARAM_READABLE |
459
0
                                                        G_PARAM_STATIC_STRINGS));
460
461
  /**
462
   * GDBusObjectManagerClient:get-proxy-type-func:
463
   *
464
   * The #GDBusProxyTypeFunc to use when determining what #GType to
465
   * use for interface proxies or %NULL.
466
   *
467
   * Since: 2.30
468
   */
469
0
  g_object_class_install_property (gobject_class,
470
0
                                   PROP_GET_PROXY_TYPE_FUNC,
471
0
                                   g_param_spec_pointer ("get-proxy-type-func", NULL, NULL,
472
0
                                                         G_PARAM_READABLE |
473
0
                                                         G_PARAM_WRITABLE |
474
0
                                                         G_PARAM_CONSTRUCT_ONLY |
475
0
                                                         G_PARAM_STATIC_STRINGS));
476
477
  /**
478
   * GDBusObjectManagerClient:get-proxy-type-user-data:
479
   *
480
   * The #gpointer user_data to pass to #GDBusObjectManagerClient:get-proxy-type-func.
481
   *
482
   * Since: 2.30
483
   */
484
0
  g_object_class_install_property (gobject_class,
485
0
                                   PROP_GET_PROXY_TYPE_USER_DATA,
486
0
                                   g_param_spec_pointer ("get-proxy-type-user-data", NULL, NULL,
487
0
                                                         G_PARAM_READABLE |
488
0
                                                         G_PARAM_WRITABLE |
489
0
                                                         G_PARAM_CONSTRUCT_ONLY |
490
0
                                                         G_PARAM_STATIC_STRINGS));
491
492
  /**
493
   * GDBusObjectManagerClient:get-proxy-type-destroy-notify:
494
   *
495
   * A #GDestroyNotify for the #gpointer user_data in #GDBusObjectManagerClient:get-proxy-type-user-data.
496
   *
497
   * Since: 2.30
498
   */
499
0
  g_object_class_install_property (gobject_class,
500
0
                                   PROP_GET_PROXY_TYPE_DESTROY_NOTIFY,
501
0
                                   g_param_spec_pointer ("get-proxy-type-destroy-notify", NULL, NULL,
502
0
                                                         G_PARAM_READABLE |
503
0
                                                         G_PARAM_WRITABLE |
504
0
                                                         G_PARAM_CONSTRUCT_ONLY |
505
0
                                                         G_PARAM_STATIC_STRINGS));
506
507
  /**
508
   * GDBusObjectManagerClient::interface-proxy-signal:
509
   * @manager: The #GDBusObjectManagerClient emitting the signal.
510
   * @object_proxy: The #GDBusObjectProxy on which an interface is emitting a D-Bus signal.
511
   * @interface_proxy: The #GDBusProxy that is emitting a D-Bus signal.
512
   * @sender_name: The sender of the signal or NULL if the connection is not a bus connection.
513
   * @signal_name: The signal name.
514
   * @parameters: A #GVariant tuple with parameters for the signal.
515
   *
516
   * Emitted when a D-Bus signal is received on @interface_proxy.
517
   *
518
   * This signal exists purely as a convenience to avoid having to
519
   * connect signals to all interface proxies managed by @manager.
520
   *
521
   * This signal is emitted in the
522
   * [thread-default main context][g-main-context-push-thread-default]
523
   * that @manager was constructed in.
524
   *
525
   * Since: 2.30
526
   */
527
0
  signals[INTERFACE_PROXY_SIGNAL_SIGNAL] =
528
0
    g_signal_new (I_("interface-proxy-signal"),
529
0
                  G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
530
0
                  G_SIGNAL_RUN_LAST,
531
0
                  G_STRUCT_OFFSET (GDBusObjectManagerClientClass, interface_proxy_signal),
532
0
                  NULL,
533
0
                  NULL,
534
0
                  _g_cclosure_marshal_VOID__OBJECT_OBJECT_STRING_STRING_VARIANT,
535
0
                  G_TYPE_NONE,
536
0
                  5,
537
0
                  G_TYPE_DBUS_OBJECT_PROXY,
538
0
                  G_TYPE_DBUS_PROXY,
539
0
                  G_TYPE_STRING,
540
0
                  G_TYPE_STRING,
541
0
                  G_TYPE_VARIANT);
542
0
  g_signal_set_va_marshaller (signals[INTERFACE_PROXY_SIGNAL_SIGNAL],
543
0
                              G_TYPE_FROM_CLASS (klass),
544
0
                              _g_cclosure_marshal_VOID__OBJECT_OBJECT_STRING_STRING_VARIANTv);
545
546
  /**
547
   * GDBusObjectManagerClient::interface-proxy-properties-changed:
548
   * @manager: The #GDBusObjectManagerClient emitting the signal.
549
   * @object_proxy: The #GDBusObjectProxy on which an interface has properties that are changing.
550
   * @interface_proxy: The #GDBusProxy that has properties that are changing.
551
   * @changed_properties: A #GVariant containing the properties that changed (type: `a{sv}`).
552
   * @invalidated_properties: (array zero-terminated=1) (element-type utf8): A %NULL terminated
553
   *   array of properties that were invalidated.
554
   *
555
   * Emitted when one or more D-Bus properties on proxy changes. The
556
   * local cache has already been updated when this signal fires. Note
557
   * that both @changed_properties and @invalidated_properties are
558
   * guaranteed to never be %NULL (either may be empty though).
559
   *
560
   * This signal exists purely as a convenience to avoid having to
561
   * connect signals to all interface proxies managed by @manager.
562
   *
563
   * This signal is emitted in the
564
   * [thread-default main context][g-main-context-push-thread-default]
565
   * that @manager was constructed in.
566
   *
567
   * Since: 2.30
568
   */
569
0
  signals[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL] =
570
0
    g_signal_new (I_("interface-proxy-properties-changed"),
571
0
                  G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
572
0
                  G_SIGNAL_RUN_LAST,
573
0
                  G_STRUCT_OFFSET (GDBusObjectManagerClientClass, interface_proxy_properties_changed),
574
0
                  NULL,
575
0
                  NULL,
576
0
                  _g_cclosure_marshal_VOID__OBJECT_OBJECT_VARIANT_BOXED,
577
0
                  G_TYPE_NONE,
578
0
                  4,
579
0
                  G_TYPE_DBUS_OBJECT_PROXY,
580
0
                  G_TYPE_DBUS_PROXY,
581
0
                  G_TYPE_VARIANT,
582
0
                  G_TYPE_STRV);
583
0
  g_signal_set_va_marshaller (signals[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL],
584
0
                              G_TYPE_FROM_CLASS (klass),
585
0
                              _g_cclosure_marshal_VOID__OBJECT_OBJECT_VARIANT_BOXEDv);
586
0
}
587
588
static void
589
g_dbus_object_manager_client_init (GDBusObjectManagerClient *manager)
590
0
{
591
0
  manager->priv = g_dbus_object_manager_client_get_instance_private (manager);
592
0
  g_mutex_init (&manager->priv->lock);
593
0
  manager->priv->map_object_path_to_object_proxy = g_hash_table_new_full (g_str_hash,
594
0
                                                                          g_str_equal,
595
0
                                                                          g_free,
596
0
                                                                          (GDestroyNotify) g_object_unref);
597
0
  manager->priv->cancel = g_cancellable_new ();
598
0
}
599
600
/* ---------------------------------------------------------------------------------------------------- */
601
602
/**
603
 * g_dbus_object_manager_client_new_sync:
604
 * @connection: A #GDBusConnection.
605
 * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
606
 * @name: (nullable): The owner of the control object (unique or well-known name), or %NULL when not using a message bus connection.
607
 * @object_path: The object path of the control object.
608
 * @get_proxy_type_func: (nullable): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
609
 * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
610
 * @get_proxy_type_destroy_notify: (nullable): Free function for @get_proxy_type_user_data or %NULL.
611
 * @cancellable: (nullable): A #GCancellable or %NULL
612
 * @error: Return location for error or %NULL.
613
 *
614
 * Creates a new #GDBusObjectManagerClient object.
615
 *
616
 * This is a synchronous failable constructor - the calling thread is
617
 * blocked until a reply is received. See g_dbus_object_manager_client_new()
618
 * for the asynchronous version.
619
 *
620
 * Returns: (transfer full) (type GDBusObjectManagerClient): A
621
 *   #GDBusObjectManagerClient object or %NULL if @error is set. Free
622
 *   with g_object_unref().
623
 *
624
 * Since: 2.30
625
 */
626
GDBusObjectManager *
627
g_dbus_object_manager_client_new_sync (GDBusConnection               *connection,
628
                                       GDBusObjectManagerClientFlags  flags,
629
                                       const gchar                   *name,
630
                                       const gchar                   *object_path,
631
                                       GDBusProxyTypeFunc             get_proxy_type_func,
632
                                       gpointer                       get_proxy_type_user_data,
633
                                       GDestroyNotify                 get_proxy_type_destroy_notify,
634
                                       GCancellable                  *cancellable,
635
                                       GError                       **error)
636
0
{
637
0
  GInitable *initable;
638
639
0
  g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
640
0
  g_return_val_if_fail ((name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) ||
641
0
                        g_dbus_is_name (name), NULL);
642
0
  g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
643
0
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
644
645
0
  initable = g_initable_new (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
646
0
                             cancellable,
647
0
                             error,
648
0
                             "connection", connection,
649
0
                             "flags", flags,
650
0
                             "name", name,
651
0
                             "object-path", object_path,
652
0
                             "get-proxy-type-func", get_proxy_type_func,
653
0
                             "get-proxy-type-user-data", get_proxy_type_user_data,
654
0
                             "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
655
0
                             NULL);
656
0
  if (initable != NULL)
657
0
    return G_DBUS_OBJECT_MANAGER (initable);
658
0
  else
659
0
    return NULL;
660
0
}
661
662
/**
663
 * g_dbus_object_manager_client_new:
664
 * @connection: A #GDBusConnection.
665
 * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
666
 * @name: The owner of the control object (unique or well-known name).
667
 * @object_path: The object path of the control object.
668
 * @get_proxy_type_func: (nullable): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
669
 * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
670
 * @get_proxy_type_destroy_notify: (nullable): Free function for @get_proxy_type_user_data or %NULL.
671
 * @cancellable: (nullable): A #GCancellable or %NULL
672
 * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
673
 * @user_data: The data to pass to @callback.
674
 *
675
 * Asynchronously creates a new #GDBusObjectManagerClient object.
676
 *
677
 * This is an asynchronous failable constructor. When the result is
678
 * ready, @callback will be invoked in the
679
 * [thread-default main context][g-main-context-push-thread-default]
680
 * of the thread you are calling this method from. You can
681
 * then call g_dbus_object_manager_client_new_finish() to get the result. See
682
 * g_dbus_object_manager_client_new_sync() for the synchronous version.
683
 *
684
 * Since: 2.30
685
 */
686
void
687
g_dbus_object_manager_client_new (GDBusConnection               *connection,
688
                                  GDBusObjectManagerClientFlags  flags,
689
                                  const gchar                   *name,
690
                                  const gchar                   *object_path,
691
                                  GDBusProxyTypeFunc             get_proxy_type_func,
692
                                  gpointer                       get_proxy_type_user_data,
693
                                  GDestroyNotify                 get_proxy_type_destroy_notify,
694
                                  GCancellable                  *cancellable,
695
                                  GAsyncReadyCallback            callback,
696
                                  gpointer                       user_data)
697
0
{
698
0
  g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
699
0
  g_return_if_fail ((name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) ||
700
0
                        g_dbus_is_name (name));
701
0
  g_return_if_fail (g_variant_is_object_path (object_path));
702
703
0
  g_async_initable_new_async (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
704
0
                              G_PRIORITY_DEFAULT,
705
0
                              cancellable,
706
0
                              callback,
707
0
                              user_data,
708
0
                              "connection", connection,
709
0
                              "flags", flags,
710
0
                              "name", name,
711
0
                              "object-path", object_path,
712
0
                              "get-proxy-type-func", get_proxy_type_func,
713
0
                              "get-proxy-type-user-data", get_proxy_type_user_data,
714
0
                              "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
715
0
                              NULL);
716
0
}
717
718
/**
719
 * g_dbus_object_manager_client_new_finish:
720
 * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_object_manager_client_new().
721
 * @error: Return location for error or %NULL.
722
 *
723
 * Finishes an operation started with g_dbus_object_manager_client_new().
724
 *
725
 * Returns: (transfer full) (type GDBusObjectManagerClient): A
726
 *   #GDBusObjectManagerClient object or %NULL if @error is set. Free
727
 *   with g_object_unref().
728
 *
729
 * Since: 2.30
730
 */
731
GDBusObjectManager *
732
g_dbus_object_manager_client_new_finish (GAsyncResult   *res,
733
                                         GError        **error)
734
0
{
735
0
  GObject *object;
736
0
  GObject *source_object;
737
738
0
  source_object = g_async_result_get_source_object (res);
739
0
  g_assert (source_object != NULL);
740
741
0
  object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
742
0
                                        res,
743
0
                                        error);
744
0
  g_object_unref (source_object);
745
746
0
  if (object != NULL)
747
0
    return G_DBUS_OBJECT_MANAGER (object);
748
0
  else
749
0
    return NULL;
750
0
}
751
752
/* ---------------------------------------------------------------------------------------------------- */
753
754
/**
755
 * g_dbus_object_manager_client_new_for_bus_sync:
756
 * @bus_type: A #GBusType.
757
 * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
758
 * @name: The owner of the control object (unique or well-known name).
759
 * @object_path: The object path of the control object.
760
 * @get_proxy_type_func: (nullable): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
761
 * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
762
 * @get_proxy_type_destroy_notify: (nullable): Free function for @get_proxy_type_user_data or %NULL.
763
 * @cancellable: (nullable): A #GCancellable or %NULL
764
 * @error: Return location for error or %NULL.
765
 *
766
 * Like g_dbus_object_manager_client_new_sync() but takes a #GBusType instead
767
 * of a #GDBusConnection.
768
 *
769
 * This is a synchronous failable constructor - the calling thread is
770
 * blocked until a reply is received. See g_dbus_object_manager_client_new_for_bus()
771
 * for the asynchronous version.
772
 *
773
 * Returns: (transfer full) (type GDBusObjectManagerClient): A
774
 *   #GDBusObjectManagerClient object or %NULL if @error is set. Free
775
 *   with g_object_unref().
776
 *
777
 * Since: 2.30
778
 */
779
GDBusObjectManager *
780
g_dbus_object_manager_client_new_for_bus_sync (GBusType                       bus_type,
781
                                               GDBusObjectManagerClientFlags  flags,
782
                                               const gchar                   *name,
783
                                               const gchar                   *object_path,
784
                                               GDBusProxyTypeFunc             get_proxy_type_func,
785
                                               gpointer                       get_proxy_type_user_data,
786
                                               GDestroyNotify                 get_proxy_type_destroy_notify,
787
                                               GCancellable                  *cancellable,
788
                                               GError                       **error)
789
0
{
790
0
  GInitable *initable;
791
792
0
  g_return_val_if_fail (bus_type != G_BUS_TYPE_NONE, NULL);
793
0
  g_return_val_if_fail (g_dbus_is_name (name), NULL);
794
0
  g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
795
0
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
796
797
0
  initable = g_initable_new (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
798
0
                             cancellable,
799
0
                             error,
800
0
                             "bus-type", bus_type,
801
0
                             "flags", flags,
802
0
                             "name", name,
803
0
                             "object-path", object_path,
804
0
                             "get-proxy-type-func", get_proxy_type_func,
805
0
                             "get-proxy-type-user-data", get_proxy_type_user_data,
806
0
                             "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
807
0
                             NULL);
808
0
  if (initable != NULL)
809
0
    return G_DBUS_OBJECT_MANAGER (initable);
810
0
  else
811
0
    return NULL;
812
0
}
813
814
/**
815
 * g_dbus_object_manager_client_new_for_bus:
816
 * @bus_type: A #GBusType.
817
 * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
818
 * @name: The owner of the control object (unique or well-known name).
819
 * @object_path: The object path of the control object.
820
 * @get_proxy_type_func: (nullable): A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
821
 * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
822
 * @get_proxy_type_destroy_notify: (nullable): Free function for @get_proxy_type_user_data or %NULL.
823
 * @cancellable: (nullable): A #GCancellable or %NULL
824
 * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
825
 * @user_data: The data to pass to @callback.
826
 *
827
 * Like g_dbus_object_manager_client_new() but takes a #GBusType instead of a
828
 * #GDBusConnection.
829
 *
830
 * This is an asynchronous failable constructor. When the result is
831
 * ready, @callback will be invoked in the
832
 * [thread-default main loop][g-main-context-push-thread-default]
833
 * of the thread you are calling this method from. You can
834
 * then call g_dbus_object_manager_client_new_for_bus_finish() to get the result. See
835
 * g_dbus_object_manager_client_new_for_bus_sync() for the synchronous version.
836
 *
837
 * Since: 2.30
838
 */
839
void
840
g_dbus_object_manager_client_new_for_bus (GBusType                       bus_type,
841
                                          GDBusObjectManagerClientFlags  flags,
842
                                          const gchar                   *name,
843
                                          const gchar                   *object_path,
844
                                          GDBusProxyTypeFunc             get_proxy_type_func,
845
                                          gpointer                       get_proxy_type_user_data,
846
                                          GDestroyNotify                 get_proxy_type_destroy_notify,
847
                                          GCancellable                  *cancellable,
848
                                          GAsyncReadyCallback            callback,
849
                                          gpointer                       user_data)
850
0
{
851
0
  g_return_if_fail (bus_type != G_BUS_TYPE_NONE);
852
0
  g_return_if_fail (g_dbus_is_name (name));
853
0
  g_return_if_fail (g_variant_is_object_path (object_path));
854
855
0
  g_async_initable_new_async (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
856
0
                              G_PRIORITY_DEFAULT,
857
0
                              cancellable,
858
0
                              callback,
859
0
                              user_data,
860
0
                              "bus-type", bus_type,
861
0
                              "flags", flags,
862
0
                              "name", name,
863
0
                              "object-path", object_path,
864
0
                              "get-proxy-type-func", get_proxy_type_func,
865
0
                              "get-proxy-type-user-data", get_proxy_type_user_data,
866
0
                              "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
867
0
                              NULL);
868
0
}
869
870
/**
871
 * g_dbus_object_manager_client_new_for_bus_finish:
872
 * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_object_manager_client_new_for_bus().
873
 * @error: Return location for error or %NULL.
874
 *
875
 * Finishes an operation started with g_dbus_object_manager_client_new_for_bus().
876
 *
877
 * Returns: (transfer full) (type GDBusObjectManagerClient): A
878
 *   #GDBusObjectManagerClient object or %NULL if @error is set. Free
879
 *   with g_object_unref().
880
 *
881
 * Since: 2.30
882
 */
883
GDBusObjectManager *
884
g_dbus_object_manager_client_new_for_bus_finish (GAsyncResult   *res,
885
                                                 GError        **error)
886
0
{
887
0
  GObject *object;
888
0
  GObject *source_object;
889
890
0
  source_object = g_async_result_get_source_object (res);
891
0
  g_assert (source_object != NULL);
892
893
0
  object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
894
0
                                        res,
895
0
                                        error);
896
0
  g_object_unref (source_object);
897
898
0
  if (object != NULL)
899
0
    return G_DBUS_OBJECT_MANAGER (object);
900
0
  else
901
0
    return NULL;
902
0
}
903
904
/* ---------------------------------------------------------------------------------------------------- */
905
906
/**
907
 * g_dbus_object_manager_client_get_connection:
908
 * @manager: A #GDBusObjectManagerClient
909
 *
910
 * Gets the #GDBusConnection used by @manager.
911
 *
912
 * Returns: (transfer none): A #GDBusConnection object. Do not free,
913
 *   the object belongs to @manager.
914
 *
915
 * Since: 2.30
916
 */
917
GDBusConnection *
918
g_dbus_object_manager_client_get_connection (GDBusObjectManagerClient *manager)
919
0
{
920
0
  GDBusConnection *ret;
921
0
  g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
922
0
  g_mutex_lock (&manager->priv->lock);
923
0
  ret = manager->priv->connection;
924
0
  g_mutex_unlock (&manager->priv->lock);
925
0
  return ret;
926
0
}
927
928
/**
929
 * g_dbus_object_manager_client_get_name:
930
 * @manager: A #GDBusObjectManagerClient
931
 *
932
 * Gets the name that @manager is for, or %NULL if not a message bus
933
 * connection.
934
 *
935
 * Returns: A unique or well-known name. Do not free, the string
936
 * belongs to @manager.
937
 *
938
 * Since: 2.30
939
 */
940
const gchar *
941
g_dbus_object_manager_client_get_name (GDBusObjectManagerClient *manager)
942
0
{
943
0
  const gchar *ret;
944
0
  g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
945
0
  g_mutex_lock (&manager->priv->lock);
946
0
  ret = manager->priv->name;
947
0
  g_mutex_unlock (&manager->priv->lock);
948
0
  return ret;
949
0
}
950
951
/**
952
 * g_dbus_object_manager_client_get_flags:
953
 * @manager: A #GDBusObjectManagerClient
954
 *
955
 * Gets the flags that @manager was constructed with.
956
 *
957
 * Returns: Zero of more flags from the #GDBusObjectManagerClientFlags
958
 * enumeration.
959
 *
960
 * Since: 2.30
961
 */
962
GDBusObjectManagerClientFlags
963
g_dbus_object_manager_client_get_flags (GDBusObjectManagerClient *manager)
964
0
{
965
0
  GDBusObjectManagerClientFlags ret;
966
0
  g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE);
967
0
  g_mutex_lock (&manager->priv->lock);
968
0
  ret = manager->priv->flags;
969
0
  g_mutex_unlock (&manager->priv->lock);
970
0
  return ret;
971
0
}
972
973
/**
974
 * g_dbus_object_manager_client_get_name_owner:
975
 * @manager: A #GDBusObjectManagerClient.
976
 *
977
 * The unique name that owns the name that @manager is for or %NULL if
978
 * no-one currently owns that name. You can connect to the
979
 * #GObject::notify signal to track changes to the
980
 * #GDBusObjectManagerClient:name-owner property.
981
 *
982
 * Returns: (nullable): The name owner or %NULL if no name owner
983
 * exists. Free with g_free().
984
 *
985
 * Since: 2.30
986
 */
987
gchar *
988
g_dbus_object_manager_client_get_name_owner (GDBusObjectManagerClient *manager)
989
0
{
990
0
  gchar *ret;
991
0
  g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
992
0
  g_mutex_lock (&manager->priv->lock);
993
0
  ret = g_strdup (manager->priv->name_owner);
994
0
  g_mutex_unlock (&manager->priv->lock);
995
0
  return ret;
996
0
}
997
998
/* ---------------------------------------------------------------------------------------------------- */
999
1000
/* signal handler for all objects we manage - we dispatch signals
1001
 * from here to the objects
1002
 */
1003
static void
1004
signal_cb (GDBusConnection *connection,
1005
           const gchar     *sender_name,
1006
           const gchar     *object_path,
1007
           const gchar     *interface_name,
1008
           const gchar     *signal_name,
1009
           GVariant        *parameters,
1010
           gpointer         user_data)
1011
0
{
1012
0
  GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (user_data);
1013
0
  GDBusObjectProxy *object_proxy;
1014
0
  GDBusInterface *interface;
1015
1016
0
  g_mutex_lock (&manager->priv->lock);
1017
0
  object_proxy = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1018
0
  if (object_proxy == NULL)
1019
0
    {
1020
0
      g_mutex_unlock (&manager->priv->lock);
1021
0
      goto out;
1022
0
    }
1023
0
  g_object_ref (object_proxy);
1024
0
  g_mutex_unlock (&manager->priv->lock);
1025
1026
  //g_debug ("yay, signal_cb %s %s: %s\n", signal_name, object_path, g_variant_print (parameters, TRUE));
1027
1028
0
  g_object_ref (manager);
1029
0
  if (g_strcmp0 (interface_name, "org.freedesktop.DBus.Properties") == 0)
1030
0
    {
1031
0
      if (g_strcmp0 (signal_name, "PropertiesChanged") == 0)
1032
0
        {
1033
0
          const gchar *properties_interface_name;
1034
0
          GVariant *changed_properties;
1035
0
          const gchar **invalidated_properties;
1036
1037
0
          g_variant_get (parameters,
1038
0
                         "(&s@a{sv}^a&s)",
1039
0
                         &properties_interface_name,
1040
0
                         &changed_properties,
1041
0
                         &invalidated_properties);
1042
1043
0
          interface = g_dbus_object_get_interface (G_DBUS_OBJECT (object_proxy), properties_interface_name);
1044
0
          if (interface != NULL)
1045
0
            {
1046
0
              GVariantIter property_iter;
1047
0
              const gchar *property_name;
1048
0
              GVariant *property_value;
1049
0
              guint n;
1050
1051
              /* update caches... */
1052
0
              g_variant_iter_init (&property_iter, changed_properties);
1053
0
              while (g_variant_iter_next (&property_iter,
1054
0
                                          "{&sv}",
1055
0
                                          &property_name,
1056
0
                                          &property_value))
1057
0
                {
1058
0
                  g_dbus_proxy_set_cached_property (G_DBUS_PROXY (interface),
1059
0
                                                    property_name,
1060
0
                                                    property_value);
1061
0
                  g_variant_unref (property_value);
1062
0
                }
1063
1064
0
              for (n = 0; invalidated_properties[n] != NULL; n++)
1065
0
                {
1066
0
                  g_dbus_proxy_set_cached_property (G_DBUS_PROXY (interface),
1067
0
                                                    invalidated_properties[n],
1068
0
                                                    NULL);
1069
0
                }
1070
              /* ... and then synthesize the signal */
1071
0
              g_signal_emit_by_name (interface,
1072
0
                                     "g-properties-changed",
1073
0
                                     changed_properties,
1074
0
                                     invalidated_properties);
1075
0
              g_signal_emit (manager,
1076
0
                             signals[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL],
1077
0
                             0,
1078
0
                             object_proxy,
1079
0
                             interface,
1080
0
                             changed_properties,
1081
0
                             invalidated_properties);
1082
0
              g_object_unref (interface);
1083
0
            }
1084
0
          g_variant_unref (changed_properties);
1085
0
          g_free (invalidated_properties);
1086
0
        }
1087
0
    }
1088
0
  else
1089
0
    {
1090
      /* regular signal - just dispatch it */
1091
0
      interface = g_dbus_object_get_interface (G_DBUS_OBJECT (object_proxy), interface_name);
1092
0
      if (interface != NULL)
1093
0
        {
1094
0
          g_signal_emit_by_name (interface,
1095
0
                                 "g-signal",
1096
0
                                 sender_name,
1097
0
                                 signal_name,
1098
0
                                 parameters);
1099
0
          g_signal_emit (manager,
1100
0
                         signals[INTERFACE_PROXY_SIGNAL_SIGNAL],
1101
0
                         0,
1102
0
                         object_proxy,
1103
0
                         interface,
1104
0
                         sender_name,
1105
0
                         signal_name,
1106
0
                         parameters);
1107
0
          g_object_unref (interface);
1108
0
        }
1109
0
    }
1110
0
  g_object_unref (manager);
1111
1112
0
 out:
1113
0
  g_clear_object (&object_proxy);
1114
0
}
1115
1116
static void
1117
subscribe_signals (GDBusObjectManagerClient *manager,
1118
                   const gchar *name_owner)
1119
0
{
1120
0
  GError *error = NULL;
1121
0
  GVariant *ret;
1122
1123
0
  g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager));
1124
0
  g_return_if_fail (manager->priv->signal_subscription_id == 0);
1125
0
  g_return_if_fail (name_owner == NULL || g_dbus_is_unique_name (name_owner));
1126
1127
0
  if (name_owner != NULL)
1128
0
    {
1129
      /* Only add path_namespace if it's non-'/'. This removes a no-op key from
1130
       * the match rule, and also works around a D-Bus bug where
1131
       * path_namespace='/' matches nothing in D-Bus versions < 1.6.18.
1132
       *
1133
       * See: https://bugs.freedesktop.org/show_bug.cgi?id=70799 */
1134
0
      if (g_str_equal (manager->priv->object_path, "/"))
1135
0
        {
1136
0
          manager->priv->match_rule = g_strdup_printf ("type='signal',sender='%s'",
1137
0
                                                       name_owner);
1138
0
        }
1139
0
      else
1140
0
        {
1141
0
          manager->priv->match_rule = g_strdup_printf ("type='signal',sender='%s',path_namespace='%s'",
1142
0
                                                       name_owner, manager->priv->object_path);
1143
0
        }
1144
1145
      /* The bus daemon may not implement path_namespace so gracefully
1146
       * handle this by using a fallback triggered if @error is set. */
1147
0
      ret = g_dbus_connection_call_sync (manager->priv->connection,
1148
0
                                         "org.freedesktop.DBus",
1149
0
                                         "/org/freedesktop/DBus",
1150
0
                                         "org.freedesktop.DBus",
1151
0
                                         "AddMatch",
1152
0
                                         g_variant_new ("(s)",
1153
0
                                                        manager->priv->match_rule),
1154
0
                                         NULL, /* reply_type */
1155
0
                                         G_DBUS_CALL_FLAGS_NONE,
1156
0
                                         -1, /* default timeout */
1157
0
                                         NULL, /* TODO: Cancellable */
1158
0
                                         &error);
1159
1160
      /* yay, bus daemon supports path_namespace */
1161
0
      if (ret != NULL)
1162
0
        g_variant_unref (ret);
1163
0
    }
1164
1165
0
  if (error == NULL)
1166
0
    {
1167
      /* still need to ask GDBusConnection for the callbacks */
1168
0
      manager->priv->signal_subscription_id =
1169
0
        g_dbus_connection_signal_subscribe (manager->priv->connection,
1170
0
                                            name_owner,
1171
0
                                            NULL, /* interface */
1172
0
                                            NULL, /* member */
1173
0
                                            NULL, /* path - TODO: really want wildcard support here */
1174
0
                                            NULL, /* arg0 */
1175
0
                                            G_DBUS_SIGNAL_FLAGS_NONE |
1176
0
                                            G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
1177
0
                                            signal_cb,
1178
0
                                            manager,
1179
0
                                            NULL); /* user_data_free_func */
1180
1181
0
    }
1182
0
  else
1183
0
    {
1184
      /* TODO: we could report this to the user
1185
      g_warning ("Message bus daemon does not support path_namespace: %s (%s %d)",
1186
                 error->message,
1187
                 g_quark_to_string (error->domain),
1188
                 error->code);
1189
      */
1190
1191
0
      g_error_free (error);
1192
1193
      /* no need to call RemoveMatch when done since it didn't work */
1194
0
      g_free (manager->priv->match_rule);
1195
0
      manager->priv->match_rule = NULL;
1196
1197
      /* Fallback is to subscribe to *all* signals from the name owner which
1198
       * is rather wasteful. It's probably not a big practical problem because
1199
       * users typically want all objects that the name owner supplies.
1200
       */
1201
0
      manager->priv->signal_subscription_id =
1202
0
        g_dbus_connection_signal_subscribe (manager->priv->connection,
1203
0
                                            name_owner,
1204
0
                                            NULL, /* interface */
1205
0
                                            NULL, /* member */
1206
0
                                            NULL, /* path - TODO: really want wildcard support here */
1207
0
                                            NULL, /* arg0 */
1208
0
                                            G_DBUS_SIGNAL_FLAGS_NONE,
1209
0
                                            signal_cb,
1210
0
                                            manager,
1211
0
                                            NULL); /* user_data_free_func */
1212
0
    }
1213
0
}
1214
1215
static void
1216
maybe_unsubscribe_signals (GDBusObjectManagerClient *manager)
1217
0
{
1218
0
  g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager));
1219
1220
0
  if (manager->priv->signal_subscription_id > 0)
1221
0
    {
1222
0
      g_dbus_connection_signal_unsubscribe (manager->priv->connection,
1223
0
                                            manager->priv->signal_subscription_id);
1224
0
      manager->priv->signal_subscription_id = 0;
1225
0
    }
1226
1227
0
  if (manager->priv->match_rule != NULL)
1228
0
    {
1229
      /* Since the AddMatch call succeeded this is guaranteed to not
1230
       * fail - therefore, don't bother checking the return value
1231
       */
1232
0
      g_dbus_connection_call (manager->priv->connection,
1233
0
                              "org.freedesktop.DBus",
1234
0
                              "/org/freedesktop/DBus",
1235
0
                              "org.freedesktop.DBus",
1236
0
                              "RemoveMatch",
1237
0
                              g_variant_new ("(s)",
1238
0
                                             manager->priv->match_rule),
1239
0
                              NULL, /* reply_type */
1240
0
                              G_DBUS_CALL_FLAGS_NONE,
1241
0
                              -1, /* default timeout */
1242
0
                              NULL, /* GCancellable */
1243
0
                              NULL, /* GAsyncReadyCallback */
1244
0
                              NULL); /* user data */
1245
0
      g_free (manager->priv->match_rule);
1246
0
      manager->priv->match_rule = NULL;
1247
0
    }
1248
1249
0
}
1250
1251
/* ---------------------------------------------------------------------------------------------------- */
1252
1253
static GWeakRef *
1254
weak_ref_new (GObject *object)
1255
0
{
1256
0
  GWeakRef *weak_ref = g_new0 (GWeakRef, 1);
1257
0
  g_weak_ref_init (weak_ref, object);
1258
0
  return g_steal_pointer (&weak_ref);
1259
0
}
1260
1261
static void
1262
weak_ref_free (GWeakRef *weak_ref)
1263
0
{
1264
0
  g_weak_ref_clear (weak_ref);
1265
0
  g_free (weak_ref);
1266
0
}
1267
1268
static void
1269
on_get_managed_objects_finish (GObject      *source,
1270
                               GAsyncResult *result,
1271
                               gpointer      user_data)
1272
0
{
1273
1274
0
  GDBusProxy *proxy = G_DBUS_PROXY (source);
1275
0
  GWeakRef *manager_weak = user_data;
1276
0
  GDBusObjectManagerClient *manager;
1277
0
  GError *error = NULL;
1278
0
  GVariant *value = NULL;
1279
0
  gchar *new_name_owner = NULL;
1280
1281
0
  value = g_dbus_proxy_call_finish (proxy, result, &error);
1282
1283
0
  manager = G_DBUS_OBJECT_MANAGER_CLIENT (g_weak_ref_get (manager_weak));
1284
  /* Manager got disposed, nothing to do */
1285
0
  if (manager == NULL)
1286
0
    {
1287
0
      goto out;
1288
0
    }
1289
1290
0
  new_name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy);
1291
0
  if (value == NULL)
1292
0
    {
1293
0
      maybe_unsubscribe_signals (manager);
1294
0
      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
1295
0
        {
1296
0
          g_warning ("Error calling GetManagedObjects() when name owner %s for name %s came back: %s",
1297
0
                     new_name_owner,
1298
0
                     manager->priv->name,
1299
0
                     error->message);
1300
0
        }
1301
0
    }
1302
0
  else
1303
0
    {
1304
0
      process_get_all_result (manager, value, new_name_owner);
1305
0
    }
1306
1307
  /* do the :name-owner notify *AFTER* emitting ::object-proxy-added signals - this
1308
   * way the user knows that the signals were emitted because the name owner came back
1309
   */
1310
0
  g_mutex_lock (&manager->priv->lock);
1311
0
  manager->priv->name_owner = g_steal_pointer (&new_name_owner);
1312
0
  g_mutex_unlock (&manager->priv->lock);
1313
0
  g_object_notify (G_OBJECT (manager), "name-owner");
1314
1315
0
  g_object_unref (manager);
1316
0
 out:
1317
0
  g_clear_error (&error);
1318
0
  g_clear_pointer (&value, g_variant_unref);
1319
0
  weak_ref_free (manager_weak);
1320
0
}
1321
1322
static void
1323
on_notify_g_name_owner (GObject    *object,
1324
                        GParamSpec *pspec,
1325
                        gpointer    user_data)
1326
0
{
1327
0
  GWeakRef *manager_weak = user_data;
1328
0
  GDBusObjectManagerClient *manager = NULL;
1329
0
  gchar *old_name_owner;
1330
0
  gchar *new_name_owner;
1331
1332
0
  manager = G_DBUS_OBJECT_MANAGER_CLIENT (g_weak_ref_get (manager_weak));
1333
0
  if (manager == NULL)
1334
0
    return;
1335
1336
0
  g_mutex_lock (&manager->priv->lock);
1337
0
  old_name_owner = manager->priv->name_owner;
1338
0
  new_name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy);
1339
0
  manager->priv->name_owner = NULL;
1340
1341
0
  if (g_strcmp0 (old_name_owner, new_name_owner) != 0)
1342
0
    {
1343
0
      GPtrArray *proxies;
1344
1345
      /* remote manager changed; nuke all local proxies  */
1346
0
      proxies = g_hash_table_steal_all_values (
1347
0
        manager->priv->map_object_path_to_object_proxy);
1348
1349
0
      g_mutex_unlock (&manager->priv->lock);
1350
1351
      /* do the :name-owner notify with a NULL name - this way the user knows
1352
       * the ::object-proxy-removed following is because the name owner went
1353
       * away
1354
       */
1355
0
      g_object_notify (G_OBJECT (manager), "name-owner");
1356
1357
0
      for (guint i = 0; i < proxies->len; ++i)
1358
0
        {
1359
0
          GDBusObjectProxy *object_proxy =
1360
0
            G_DBUS_OBJECT_PROXY (g_ptr_array_index (proxies, i));
1361
0
          g_signal_emit_by_name (manager, "object-removed", object_proxy);
1362
0
        }
1363
0
      g_clear_pointer (&proxies, g_ptr_array_unref);
1364
1365
      /* nuke local filter */
1366
0
      maybe_unsubscribe_signals (manager);
1367
0
    }
1368
0
  else
1369
0
    {
1370
0
      g_mutex_unlock (&manager->priv->lock);
1371
0
    }
1372
1373
0
  if (new_name_owner != NULL)
1374
0
    {
1375
      //g_debug ("repopulating for %s", new_name_owner);
1376
1377
0
      subscribe_signals (manager,
1378
0
                         new_name_owner);
1379
0
      g_dbus_proxy_call (manager->priv->control_proxy,
1380
0
                         "GetManagedObjects",
1381
0
                         NULL, /* parameters */
1382
0
                         G_DBUS_CALL_FLAGS_NONE,
1383
0
                         -1,
1384
0
                         manager->priv->cancel,
1385
0
                         on_get_managed_objects_finish,
1386
0
                         weak_ref_new (G_OBJECT (manager)));
1387
0
    }
1388
0
  g_free (new_name_owner);
1389
0
  g_free (old_name_owner);
1390
0
  g_object_unref (manager);
1391
0
}
1392
1393
static gboolean
1394
initable_init (GInitable     *initable,
1395
               GCancellable  *cancellable,
1396
               GError       **error)
1397
0
{
1398
0
  GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (initable);
1399
0
  gboolean ret;
1400
0
  GVariant *value;
1401
0
  GDBusProxyFlags proxy_flags;
1402
1403
0
  ret = FALSE;
1404
1405
0
  if (manager->priv->bus_type != G_BUS_TYPE_NONE)
1406
0
    {
1407
0
      g_assert (manager->priv->connection == NULL);
1408
0
      manager->priv->connection = g_bus_get_sync (manager->priv->bus_type, cancellable, error);
1409
0
      if (manager->priv->connection == NULL)
1410
0
        goto out;
1411
0
    }
1412
1413
0
  proxy_flags = G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES;
1414
0
  if (manager->priv->flags & G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START)
1415
0
    proxy_flags |= G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START;
1416
1417
0
  manager->priv->control_proxy = g_dbus_proxy_new_sync (manager->priv->connection,
1418
0
                                                        proxy_flags,
1419
0
                                                        NULL, /* GDBusInterfaceInfo* */
1420
0
                                                        manager->priv->name,
1421
0
                                                        manager->priv->object_path,
1422
0
                                                        "org.freedesktop.DBus.ObjectManager",
1423
0
                                                        cancellable,
1424
0
                                                        error);
1425
0
  if (manager->priv->control_proxy == NULL)
1426
0
    goto out;
1427
1428
  /* Use weak refs here. The @control_proxy will emit its signals in the current
1429
   * #GMainContext (since we constructed it just above). However, the user may
1430
   * drop the last external reference to this #GDBusObjectManagerClient in
1431
   * another thread between a signal being emitted and scheduled in an idle
1432
   * callback in this #GMainContext, and that idle callback being invoked. We
1433
   * can’t use a strong reference here, as there’s no
1434
   * g_dbus_object_manager_client_disconnect() (or similar) method to tell us
1435
   * when the last external reference to this object has been dropped, so we
1436
   * can’t break a strong reference count cycle. So use weak refs. */
1437
0
  manager->priv->name_owner_signal_id =
1438
0
      g_signal_connect_data (G_OBJECT (manager->priv->control_proxy),
1439
0
                            "notify::g-name-owner",
1440
0
                            G_CALLBACK (on_notify_g_name_owner),
1441
0
                            weak_ref_new (G_OBJECT (manager)),
1442
0
                            (GClosureNotify) weak_ref_free,
1443
0
                            G_CONNECT_DEFAULT);
1444
1445
0
  manager->priv->signal_signal_id =
1446
0
      g_signal_connect_data (manager->priv->control_proxy,
1447
0
                            "g-signal",
1448
0
                            G_CALLBACK (on_control_proxy_g_signal),
1449
0
                            weak_ref_new (G_OBJECT (manager)),
1450
0
                            (GClosureNotify) weak_ref_free,
1451
0
                            G_CONNECT_DEFAULT);
1452
1453
0
  manager->priv->name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy);
1454
0
  if (manager->priv->name_owner == NULL && manager->priv->name != NULL)
1455
0
    {
1456
      /* it's perfectly fine if there's no name owner.. we're just going to
1457
       * wait until one is ready
1458
       */
1459
0
    }
1460
0
  else
1461
0
    {
1462
      /* yay, we can get the objects */
1463
0
      subscribe_signals (manager,
1464
0
                         manager->priv->name_owner);
1465
0
      value = g_dbus_proxy_call_sync (manager->priv->control_proxy,
1466
0
                                      "GetManagedObjects",
1467
0
                                      NULL, /* parameters */
1468
0
                                      G_DBUS_CALL_FLAGS_NONE,
1469
0
                                      -1,
1470
0
                                      cancellable,
1471
0
                                      error);
1472
0
      if (value == NULL)
1473
0
        {
1474
0
          maybe_unsubscribe_signals (manager);
1475
1476
0
          g_warn_if_fail (manager->priv->signal_signal_id != 0);
1477
0
          g_signal_handler_disconnect (manager->priv->control_proxy,
1478
0
                                       manager->priv->signal_signal_id);
1479
0
          manager->priv->signal_signal_id = 0;
1480
1481
0
          g_warn_if_fail (manager->priv->name_owner_signal_id != 0);
1482
0
          g_signal_handler_disconnect (manager->priv->control_proxy,
1483
0
                                       manager->priv->name_owner_signal_id);
1484
0
          manager->priv->name_owner_signal_id = 0;
1485
1486
0
          g_object_unref (manager->priv->control_proxy);
1487
0
          manager->priv->control_proxy = NULL;
1488
1489
0
          goto out;
1490
0
        }
1491
1492
0
      process_get_all_result (manager, value, manager->priv->name_owner);
1493
0
      g_variant_unref (value);
1494
0
    }
1495
1496
0
  ret = TRUE;
1497
1498
0
 out:
1499
0
  return ret;
1500
0
}
1501
1502
static void
1503
initable_iface_init (GInitableIface *initable_iface)
1504
0
{
1505
0
  initable_iface->init = initable_init;
1506
0
}
1507
1508
static void
1509
async_initable_iface_init (GAsyncInitableIface *async_initable_iface)
1510
0
{
1511
  /* for now, just use default: run GInitable code in thread */
1512
0
}
1513
1514
/* ---------------------------------------------------------------------------------------------------- */
1515
1516
static void
1517
add_interfaces (GDBusObjectManagerClient *manager,
1518
                const gchar       *object_path,
1519
                GVariant          *ifaces_and_properties,
1520
                const gchar       *name_owner)
1521
0
{
1522
0
  GDBusObjectProxy *op;
1523
0
  gboolean added;
1524
0
  GVariantIter iter;
1525
0
  const gchar *interface_name;
1526
0
  GVariant *properties;
1527
0
  GList *interface_added_signals, *l;
1528
0
  GDBusProxy *interface_proxy;
1529
1530
0
  g_return_if_fail (name_owner == NULL || g_dbus_is_unique_name (name_owner));
1531
1532
0
  g_mutex_lock (&manager->priv->lock);
1533
1534
0
  interface_added_signals = NULL;
1535
0
  added = FALSE;
1536
1537
0
  op = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1538
0
  if (op == NULL)
1539
0
    {
1540
0
      GType object_proxy_type;
1541
0
      if (manager->priv->get_proxy_type_func != NULL)
1542
0
        {
1543
0
          object_proxy_type = manager->priv->get_proxy_type_func (manager,
1544
0
                                                                  object_path,
1545
0
                                                                  NULL,
1546
0
                                                                  manager->priv->get_proxy_type_user_data);
1547
0
          g_warn_if_fail (g_type_is_a (object_proxy_type, G_TYPE_DBUS_OBJECT_PROXY));
1548
0
        }
1549
0
      else
1550
0
        {
1551
0
          object_proxy_type = G_TYPE_DBUS_OBJECT_PROXY;
1552
0
        }
1553
0
      op = g_object_new (object_proxy_type,
1554
0
                         "g-connection", manager->priv->connection,
1555
0
                         "g-object-path", object_path,
1556
0
                         NULL);
1557
0
      added = TRUE;
1558
0
    }
1559
0
  g_object_ref (op);
1560
1561
0
  g_variant_iter_init (&iter, ifaces_and_properties);
1562
0
  while (g_variant_iter_next (&iter,
1563
0
                              "{&s@a{sv}}",
1564
0
                              &interface_name,
1565
0
                              &properties))
1566
0
    {
1567
0
      GError *error;
1568
0
      GType interface_proxy_type;
1569
1570
0
      if (manager->priv->get_proxy_type_func != NULL)
1571
0
        {
1572
0
          interface_proxy_type = manager->priv->get_proxy_type_func (manager,
1573
0
                                                                     object_path,
1574
0
                                                                     interface_name,
1575
0
                                                                     manager->priv->get_proxy_type_user_data);
1576
0
          g_warn_if_fail (g_type_is_a (interface_proxy_type, G_TYPE_DBUS_PROXY));
1577
0
        }
1578
0
      else
1579
0
        {
1580
0
          interface_proxy_type = G_TYPE_DBUS_PROXY;
1581
0
        }
1582
1583
      /* this is fine - there is no blocking IO because we pass DO_NOT_LOAD_PROPERTIES and
1584
       * DO_NOT_CONNECT_SIGNALS and use a unique name
1585
       */
1586
0
      error = NULL;
1587
0
      interface_proxy = g_initable_new (interface_proxy_type,
1588
0
                                        NULL, /* GCancellable */
1589
0
                                        &error,
1590
0
                                        "g-connection", manager->priv->connection,
1591
0
                                        "g-flags", G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
1592
0
                                                   G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
1593
0
                                        "g-name", name_owner,
1594
0
                                        "g-object-path", object_path,
1595
0
                                        "g-interface-name", interface_name,
1596
0
                                        NULL);
1597
0
      if (interface_proxy == NULL)
1598
0
        {
1599
0
          g_warning ("%s: Error constructing proxy for path %s and interface %s: %s",
1600
0
                     G_STRLOC,
1601
0
                     object_path,
1602
0
                     interface_name,
1603
0
                     error->message);
1604
0
          g_error_free (error);
1605
0
        }
1606
0
      else
1607
0
        {
1608
0
          GVariantIter property_iter;
1609
0
          const gchar *property_name;
1610
0
          GVariant *property_value;
1611
1612
          /* associate the interface proxy with the object */
1613
0
          g_dbus_interface_set_object (G_DBUS_INTERFACE (interface_proxy),
1614
0
                                       G_DBUS_OBJECT (op));
1615
1616
0
          g_variant_iter_init (&property_iter, properties);
1617
0
          while (g_variant_iter_next (&property_iter,
1618
0
                                      "{&sv}",
1619
0
                                      &property_name,
1620
0
                                      &property_value))
1621
0
            {
1622
0
              g_dbus_proxy_set_cached_property (interface_proxy,
1623
0
                                                property_name,
1624
0
                                                property_value);
1625
0
              g_variant_unref (property_value);
1626
0
            }
1627
1628
0
          _g_dbus_object_proxy_add_interface (op, interface_proxy);
1629
0
          if (!added)
1630
0
            interface_added_signals = g_list_append (interface_added_signals, g_object_ref (interface_proxy));
1631
0
          g_object_unref (interface_proxy);
1632
0
        }
1633
0
      g_variant_unref (properties);
1634
0
    }
1635
1636
0
  if (added)
1637
0
    {
1638
0
      g_hash_table_insert (manager->priv->map_object_path_to_object_proxy,
1639
0
                           g_strdup (object_path),
1640
0
                           op);
1641
0
    }
1642
1643
0
  g_mutex_unlock (&manager->priv->lock);
1644
1645
  /* now that we don't hold the lock any more, emit signals */
1646
0
  g_object_ref (manager);
1647
0
  for (l = interface_added_signals; l != NULL; l = l->next)
1648
0
    {
1649
0
      interface_proxy = G_DBUS_PROXY (l->data);
1650
0
      g_signal_emit_by_name (manager, "interface-added", op, interface_proxy);
1651
0
      g_object_unref (interface_proxy);
1652
0
    }
1653
0
  g_list_free (interface_added_signals);
1654
1655
0
  if (added)
1656
0
    g_signal_emit_by_name (manager, "object-added", op);
1657
1658
0
  g_object_unref (manager);
1659
0
  g_object_unref (op);
1660
0
}
1661
1662
static void
1663
remove_interfaces (GDBusObjectManagerClient   *manager,
1664
                   const gchar         *object_path,
1665
                   const gchar *const  *interface_names)
1666
0
{
1667
0
  GDBusObjectProxy *op;
1668
0
  GList *interfaces;
1669
0
  guint n;
1670
0
  guint num_interfaces;
1671
0
  guint num_interfaces_to_remove;
1672
1673
0
  g_mutex_lock (&manager->priv->lock);
1674
1675
0
  op = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1676
0
  if (op == NULL)
1677
0
    {
1678
0
      g_debug ("%s: Processing InterfaceRemoved signal for path %s but no object proxy exists",
1679
0
               G_STRLOC,
1680
0
               object_path);
1681
0
      g_mutex_unlock (&manager->priv->lock);
1682
0
      return;
1683
0
    }
1684
1685
0
  interfaces = g_dbus_object_get_interfaces (G_DBUS_OBJECT (op));
1686
0
  num_interfaces = g_list_length (interfaces);
1687
0
  g_list_free_full (interfaces, g_object_unref);
1688
1689
0
  num_interfaces_to_remove = g_strv_length ((gchar **) interface_names);
1690
1691
  /* see if we are going to completety remove the object */
1692
0
  g_object_ref (manager);
1693
0
  if (num_interfaces_to_remove == num_interfaces)
1694
0
    {
1695
0
      g_object_ref (op);
1696
0
      g_warn_if_fail (g_hash_table_remove (manager->priv->map_object_path_to_object_proxy, object_path));
1697
0
      g_mutex_unlock (&manager->priv->lock);
1698
0
      g_signal_emit_by_name (manager, "object-removed", op);
1699
0
      g_object_unref (op);
1700
0
    }
1701
0
  else
1702
0
    {
1703
0
      g_object_ref (op);
1704
0
      g_mutex_unlock (&manager->priv->lock);
1705
0
      for (n = 0; interface_names != NULL && interface_names[n] != NULL; n++)
1706
0
        {
1707
0
          GDBusInterface *interface;
1708
0
          interface = g_dbus_object_get_interface (G_DBUS_OBJECT (op), interface_names[n]);
1709
0
          _g_dbus_object_proxy_remove_interface (op, interface_names[n]);
1710
0
          if (interface != NULL)
1711
0
            {
1712
0
              g_signal_emit_by_name (manager, "interface-removed", op, interface);
1713
0
              g_object_unref (interface);
1714
0
            }
1715
0
        }
1716
0
      g_object_unref (op);
1717
0
    }
1718
0
  g_object_unref (manager);
1719
0
}
1720
1721
static void
1722
process_get_all_result (GDBusObjectManagerClient *manager,
1723
                        GVariant          *value,
1724
                        const gchar       *name_owner)
1725
0
{
1726
0
  GVariant *arg0;
1727
0
  const gchar *object_path;
1728
0
  GVariant *ifaces_and_properties;
1729
0
  GVariantIter iter;
1730
1731
0
  g_return_if_fail (name_owner == NULL || g_dbus_is_unique_name (name_owner));
1732
1733
0
  arg0 = g_variant_get_child_value (value, 0);
1734
0
  g_variant_iter_init (&iter, arg0);
1735
0
  while (g_variant_iter_next (&iter,
1736
0
                              "{&o@a{sa{sv}}}",
1737
0
                              &object_path,
1738
0
                              &ifaces_and_properties))
1739
0
    {
1740
0
      add_interfaces (manager, object_path, ifaces_and_properties, name_owner);
1741
0
      g_variant_unref (ifaces_and_properties);
1742
0
    }
1743
0
  g_variant_unref (arg0);
1744
0
}
1745
1746
static void
1747
on_control_proxy_g_signal (GDBusProxy   *proxy,
1748
                           const gchar  *sender_name,
1749
                           const gchar  *signal_name,
1750
                           GVariant     *parameters,
1751
                           gpointer      user_data)
1752
0
{
1753
0
  GWeakRef *manager_weak = user_data;
1754
0
  GDBusObjectManagerClient *manager = NULL;
1755
0
  const gchar *object_path;
1756
1757
0
  manager = G_DBUS_OBJECT_MANAGER_CLIENT (g_weak_ref_get (manager_weak));
1758
0
  if (manager == NULL)
1759
0
    return;
1760
1761
  //g_debug ("yay, g_signal %s: %s\n", signal_name, g_variant_print (parameters, TRUE));
1762
1763
0
  if (g_strcmp0 (signal_name, "InterfacesAdded") == 0)
1764
0
    {
1765
0
      GVariant *ifaces_and_properties;
1766
0
      g_variant_get (parameters,
1767
0
                     "(&o@a{sa{sv}})",
1768
0
                     &object_path,
1769
0
                     &ifaces_and_properties);
1770
0
      add_interfaces (manager, object_path, ifaces_and_properties, manager->priv->name_owner);
1771
0
      g_variant_unref (ifaces_and_properties);
1772
0
    }
1773
0
  else if (g_strcmp0 (signal_name, "InterfacesRemoved") == 0)
1774
0
    {
1775
0
      const gchar **ifaces;
1776
0
      g_variant_get (parameters,
1777
0
                     "(&o^a&s)",
1778
0
                     &object_path,
1779
0
                     &ifaces);
1780
0
      remove_interfaces (manager, object_path, ifaces);
1781
0
      g_free (ifaces);
1782
0
    }
1783
1784
0
  g_object_unref (manager);
1785
0
}
1786
1787
/* ---------------------------------------------------------------------------------------------------- */
1788
1789
static const gchar *
1790
g_dbus_object_manager_client_get_object_path (GDBusObjectManager *_manager)
1791
0
{
1792
0
  GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
1793
0
  return manager->priv->object_path;
1794
0
}
1795
1796
static GDBusObject *
1797
g_dbus_object_manager_client_get_object (GDBusObjectManager *_manager,
1798
                                         const gchar        *object_path)
1799
0
{
1800
0
  GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
1801
0
  GDBusObject *ret;
1802
1803
0
  g_mutex_lock (&manager->priv->lock);
1804
0
  ret = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1805
0
  if (ret != NULL)
1806
0
    g_object_ref (ret);
1807
0
  g_mutex_unlock (&manager->priv->lock);
1808
0
  return ret;
1809
0
}
1810
1811
static GDBusInterface *
1812
g_dbus_object_manager_client_get_interface  (GDBusObjectManager  *_manager,
1813
                                             const gchar         *object_path,
1814
                                             const gchar         *interface_name)
1815
0
{
1816
0
  GDBusInterface *ret;
1817
0
  GDBusObject *object;
1818
1819
0
  ret = NULL;
1820
1821
0
  object = g_dbus_object_manager_get_object (_manager, object_path);
1822
0
  if (object == NULL)
1823
0
    goto out;
1824
1825
0
  ret = g_dbus_object_get_interface (object, interface_name);
1826
0
  g_object_unref (object);
1827
1828
0
 out:
1829
0
  return ret;
1830
0
}
1831
1832
static GList *
1833
g_dbus_object_manager_client_get_objects (GDBusObjectManager *_manager)
1834
0
{
1835
0
  GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
1836
0
  GList *ret;
1837
1838
0
  g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
1839
1840
0
  g_mutex_lock (&manager->priv->lock);
1841
0
  ret = g_hash_table_get_values (manager->priv->map_object_path_to_object_proxy);
1842
0
  g_list_foreach (ret, (GFunc) g_object_ref, NULL);
1843
0
  g_mutex_unlock (&manager->priv->lock);
1844
1845
0
  return ret;
1846
0
}
1847
1848
1849
static void
1850
dbus_object_manager_interface_init (GDBusObjectManagerIface *iface)
1851
0
{
1852
0
  iface->get_object_path = g_dbus_object_manager_client_get_object_path;
1853
0
  iface->get_objects     = g_dbus_object_manager_client_get_objects;
1854
0
  iface->get_object      = g_dbus_object_manager_client_get_object;
1855
0
  iface->get_interface   = g_dbus_object_manager_client_get_interface;
1856
0
}
1857
1858
/* ---------------------------------------------------------------------------------------------------- */