Coverage Report

Created: 2025-10-10 07:05

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