Branch data Line data Source code
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 [ + + + - : 445 : G_DEFINE_TYPE_WITH_CODE (GDBusObjectManagerClient, g_dbus_object_manager_client, G_TYPE_OBJECT,
+ + ]
185 : : G_ADD_PRIVATE (GDBusObjectManagerClient)
186 : : G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)
187 : : G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init)
188 : : G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_OBJECT_MANAGER, dbus_object_manager_interface_init))
189 : :
190 : : static void maybe_unsubscribe_signals (GDBusObjectManagerClient *manager);
191 : :
192 : : static void on_control_proxy_g_signal (GDBusProxy *proxy,
193 : : const gchar *sender_name,
194 : : const gchar *signal_name,
195 : : GVariant *parameters,
196 : : gpointer user_data);
197 : :
198 : : static void process_get_all_result (GDBusObjectManagerClient *manager,
199 : : GVariant *value,
200 : : const gchar *name_owner);
201 : :
202 : : static void
203 : 8 : g_dbus_object_manager_client_dispose (GObject *object)
204 : : {
205 : 8 : GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (object);
206 : :
207 [ + - ]: 8 : if (manager->priv->cancel != NULL)
208 : : {
209 : 8 : g_cancellable_cancel (manager->priv->cancel);
210 : 8 : g_clear_object (&manager->priv->cancel);
211 : : }
212 : :
213 : 8 : G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class)->dispose (object);
214 : 8 : }
215 : :
216 : : static void
217 : 8 : g_dbus_object_manager_client_finalize (GObject *object)
218 : : {
219 : 8 : GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (object);
220 : :
221 : 8 : maybe_unsubscribe_signals (manager);
222 : :
223 : 8 : g_hash_table_unref (manager->priv->map_object_path_to_object_proxy);
224 : :
225 [ + + + - ]: 8 : if (manager->priv->control_proxy != NULL && manager->priv->signal_signal_id != 0)
226 : 5 : g_signal_handler_disconnect (manager->priv->control_proxy,
227 : 5 : manager->priv->signal_signal_id);
228 : 8 : manager->priv->signal_signal_id = 0;
229 : :
230 [ + + + - ]: 8 : if (manager->priv->control_proxy != NULL && manager->priv->name_owner_signal_id != 0)
231 : 5 : g_signal_handler_disconnect (manager->priv->control_proxy,
232 : 5 : manager->priv->name_owner_signal_id);
233 : 8 : manager->priv->name_owner_signal_id = 0;
234 : :
235 : 8 : g_clear_object (&manager->priv->control_proxy);
236 : :
237 [ + - ]: 8 : if (manager->priv->connection != NULL)
238 : 8 : g_object_unref (manager->priv->connection);
239 : 8 : g_free (manager->priv->object_path);
240 : 8 : g_free (manager->priv->name);
241 : 8 : g_free (manager->priv->name_owner);
242 : :
243 [ - + ]: 8 : 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 : 8 : g_mutex_clear (&manager->priv->lock);
247 : :
248 [ + - ]: 8 : if (G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class)->finalize != NULL)
249 : 8 : G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class)->finalize (object);
250 : 8 : }
251 : :
252 : : static void
253 : 15 : g_dbus_object_manager_client_get_property (GObject *_object,
254 : : guint prop_id,
255 : : GValue *value,
256 : : GParamSpec *pspec)
257 : : {
258 : 15 : GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_object);
259 : :
260 [ + + + + : 15 : switch (prop_id)
+ - ]
261 : : {
262 : 3 : case PROP_CONNECTION:
263 : 3 : g_value_set_object (value, g_dbus_object_manager_client_get_connection (manager));
264 : 3 : break;
265 : :
266 : 3 : case PROP_OBJECT_PATH:
267 : 3 : g_value_set_string (value, g_dbus_object_manager_get_object_path (G_DBUS_OBJECT_MANAGER (manager)));
268 : 3 : break;
269 : :
270 : 3 : case PROP_NAME:
271 : 3 : g_value_set_string (value, g_dbus_object_manager_client_get_name (manager));
272 : 3 : break;
273 : :
274 : 3 : case PROP_FLAGS:
275 : 3 : g_value_set_flags (value, g_dbus_object_manager_client_get_flags (manager));
276 : 3 : break;
277 : :
278 : 3 : case PROP_NAME_OWNER:
279 : 3 : g_value_take_string (value, g_dbus_object_manager_client_get_name_owner (manager));
280 : 3 : break;
281 : :
282 : 0 : default:
283 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (manager, prop_id, pspec);
284 : 0 : break;
285 : : }
286 : 15 : }
287 : :
288 : : static void
289 : 64 : g_dbus_object_manager_client_set_property (GObject *_object,
290 : : guint prop_id,
291 : : const GValue *value,
292 : : GParamSpec *pspec)
293 : : {
294 : 64 : GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_object);
295 : : const gchar *name;
296 : :
297 [ + + + + : 64 : switch (prop_id)
+ + + +
- ]
298 : : {
299 : 8 : case PROP_BUS_TYPE:
300 : 8 : manager->priv->bus_type = g_value_get_enum (value);
301 : 8 : break;
302 : :
303 : 8 : case PROP_CONNECTION:
304 [ + - ]: 8 : if (g_value_get_object (value) != NULL)
305 : : {
306 : 8 : g_assert (manager->priv->connection == NULL);
307 : 8 : g_assert (G_IS_DBUS_CONNECTION (g_value_get_object (value)));
308 : 8 : manager->priv->connection = g_value_dup_object (value);
309 : : }
310 : 8 : break;
311 : :
312 : 8 : case PROP_OBJECT_PATH:
313 : 8 : g_assert (manager->priv->object_path == NULL);
314 : 8 : g_assert (g_variant_is_object_path (g_value_get_string (value)));
315 : 8 : manager->priv->object_path = g_value_dup_string (value);
316 : 8 : break;
317 : :
318 : 8 : case PROP_NAME:
319 : 8 : g_assert (manager->priv->name == NULL);
320 : 8 : name = g_value_get_string (value);
321 : 8 : g_assert (name == NULL || g_dbus_is_name (name));
322 : 8 : manager->priv->name = g_strdup (name);
323 : 8 : break;
324 : :
325 : 8 : case PROP_FLAGS:
326 : 8 : manager->priv->flags = g_value_get_flags (value);
327 : 8 : break;
328 : :
329 : 8 : case PROP_GET_PROXY_TYPE_FUNC:
330 : 8 : manager->priv->get_proxy_type_func = g_value_get_pointer (value);
331 : 8 : break;
332 : :
333 : 8 : case PROP_GET_PROXY_TYPE_USER_DATA:
334 : 8 : manager->priv->get_proxy_type_user_data = g_value_get_pointer (value);
335 : 8 : break;
336 : :
337 : 8 : case PROP_GET_PROXY_TYPE_DESTROY_NOTIFY:
338 : 8 : manager->priv->get_proxy_type_destroy_notify = g_value_get_pointer (value);
339 : 8 : break;
340 : :
341 : 0 : default:
342 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (manager, prop_id, pspec);
343 : 0 : break;
344 : : }
345 : 64 : }
346 : :
347 : : static void
348 : 5 : g_dbus_object_manager_client_class_init (GDBusObjectManagerClientClass *klass)
349 : : {
350 : 5 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
351 : :
352 : 5 : gobject_class->dispose = g_dbus_object_manager_client_dispose;
353 : 5 : gobject_class->finalize = g_dbus_object_manager_client_finalize;
354 : 5 : gobject_class->set_property = g_dbus_object_manager_client_set_property;
355 : 5 : 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 : 5 : g_object_class_install_property (gobject_class,
365 : : PROP_CONNECTION,
366 : : g_param_spec_object ("connection", NULL, NULL,
367 : : G_TYPE_DBUS_CONNECTION,
368 : : G_PARAM_READABLE |
369 : : G_PARAM_WRITABLE |
370 : : G_PARAM_CONSTRUCT_ONLY |
371 : : 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 : 5 : g_object_class_install_property (gobject_class,
384 : : PROP_BUS_TYPE,
385 : : g_param_spec_enum ("bus-type", NULL, NULL,
386 : : G_TYPE_BUS_TYPE,
387 : : G_BUS_TYPE_NONE,
388 : : G_PARAM_WRITABLE |
389 : : G_PARAM_CONSTRUCT_ONLY |
390 : : G_PARAM_STATIC_NAME |
391 : : G_PARAM_STATIC_BLURB |
392 : : G_PARAM_STATIC_NICK));
393 : :
394 : : /**
395 : : * GDBusObjectManagerClient:flags:
396 : : *
397 : : * Flags from the #GDBusObjectManagerClientFlags enumeration.
398 : : *
399 : : * Since: 2.30
400 : : */
401 : 5 : g_object_class_install_property (gobject_class,
402 : : PROP_FLAGS,
403 : : g_param_spec_flags ("flags", NULL, NULL,
404 : : G_TYPE_DBUS_OBJECT_MANAGER_CLIENT_FLAGS,
405 : : G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
406 : : G_PARAM_READABLE |
407 : : G_PARAM_WRITABLE |
408 : : G_PARAM_CONSTRUCT_ONLY |
409 : : G_PARAM_STATIC_NAME |
410 : : G_PARAM_STATIC_BLURB |
411 : : 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 : 5 : g_object_class_install_property (gobject_class,
421 : : PROP_OBJECT_PATH,
422 : : g_param_spec_string ("object-path", NULL, NULL,
423 : : NULL,
424 : : G_PARAM_READABLE |
425 : : G_PARAM_WRITABLE |
426 : : G_PARAM_CONSTRUCT_ONLY |
427 : : 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 : 5 : g_object_class_install_property (gobject_class,
437 : : PROP_NAME,
438 : : g_param_spec_string ("name", NULL, NULL,
439 : : NULL,
440 : : G_PARAM_READABLE |
441 : : G_PARAM_WRITABLE |
442 : : G_PARAM_CONSTRUCT_ONLY |
443 : : 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 : 5 : g_object_class_install_property (gobject_class,
455 : : PROP_NAME_OWNER,
456 : : g_param_spec_string ("name-owner", NULL, NULL,
457 : : NULL,
458 : : G_PARAM_READABLE |
459 : : 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 : 5 : g_object_class_install_property (gobject_class,
470 : : PROP_GET_PROXY_TYPE_FUNC,
471 : : g_param_spec_pointer ("get-proxy-type-func", NULL, NULL,
472 : : G_PARAM_READABLE |
473 : : G_PARAM_WRITABLE |
474 : : G_PARAM_CONSTRUCT_ONLY |
475 : : 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 : 5 : g_object_class_install_property (gobject_class,
485 : : PROP_GET_PROXY_TYPE_USER_DATA,
486 : : g_param_spec_pointer ("get-proxy-type-user-data", NULL, NULL,
487 : : G_PARAM_READABLE |
488 : : G_PARAM_WRITABLE |
489 : : G_PARAM_CONSTRUCT_ONLY |
490 : : 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 : 5 : g_object_class_install_property (gobject_class,
500 : : PROP_GET_PROXY_TYPE_DESTROY_NOTIFY,
501 : : g_param_spec_pointer ("get-proxy-type-destroy-notify", NULL, NULL,
502 : : G_PARAM_READABLE |
503 : : G_PARAM_WRITABLE |
504 : : G_PARAM_CONSTRUCT_ONLY |
505 : : 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 : 5 : signals[INTERFACE_PROXY_SIGNAL_SIGNAL] =
528 : 5 : g_signal_new (I_("interface-proxy-signal"),
529 : : G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
530 : : G_SIGNAL_RUN_LAST,
531 : : G_STRUCT_OFFSET (GDBusObjectManagerClientClass, interface_proxy_signal),
532 : : NULL,
533 : : NULL,
534 : : _g_cclosure_marshal_VOID__OBJECT_OBJECT_STRING_STRING_VARIANT,
535 : : G_TYPE_NONE,
536 : : 5,
537 : : G_TYPE_DBUS_OBJECT_PROXY,
538 : : G_TYPE_DBUS_PROXY,
539 : : G_TYPE_STRING,
540 : : G_TYPE_STRING,
541 : : G_TYPE_VARIANT);
542 : 5 : g_signal_set_va_marshaller (signals[INTERFACE_PROXY_SIGNAL_SIGNAL],
543 : : G_TYPE_FROM_CLASS (klass),
544 : : _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 : 5 : signals[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL] =
570 : 5 : g_signal_new (I_("interface-proxy-properties-changed"),
571 : : G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
572 : : G_SIGNAL_RUN_LAST,
573 : : G_STRUCT_OFFSET (GDBusObjectManagerClientClass, interface_proxy_properties_changed),
574 : : NULL,
575 : : NULL,
576 : : _g_cclosure_marshal_VOID__OBJECT_OBJECT_VARIANT_BOXED,
577 : : G_TYPE_NONE,
578 : : 4,
579 : : G_TYPE_DBUS_OBJECT_PROXY,
580 : : G_TYPE_DBUS_PROXY,
581 : : G_TYPE_VARIANT,
582 : : G_TYPE_STRV);
583 : 5 : g_signal_set_va_marshaller (signals[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL],
584 : : G_TYPE_FROM_CLASS (klass),
585 : : _g_cclosure_marshal_VOID__OBJECT_OBJECT_VARIANT_BOXEDv);
586 : 5 : }
587 : :
588 : : static void
589 : 8 : g_dbus_object_manager_client_init (GDBusObjectManagerClient *manager)
590 : : {
591 : 8 : manager->priv = g_dbus_object_manager_client_get_instance_private (manager);
592 : 8 : g_mutex_init (&manager->priv->lock);
593 : 8 : manager->priv->map_object_path_to_object_proxy = g_hash_table_new_full (g_str_hash,
594 : : g_str_equal,
595 : : g_free,
596 : : (GDestroyNotify) g_object_unref);
597 : 8 : manager->priv->cancel = g_cancellable_new ();
598 : 8 : }
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 : 0 : 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 : : {
637 : : 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 : : 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 : : cancellable,
647 : : error,
648 : : "connection", connection,
649 : : "flags", flags,
650 : : "name", name,
651 : : "object-path", object_path,
652 : : "get-proxy-type-func", get_proxy_type_func,
653 : : "get-proxy-type-user-data", get_proxy_type_user_data,
654 : : "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
655 : : NULL);
656 [ # # ]: 0 : if (initable != NULL)
657 : 0 : return G_DBUS_OBJECT_MANAGER (initable);
658 : : else
659 : 0 : return NULL;
660 : : }
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 : 2 : 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 : : {
698 : 2 : g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
699 : 2 : g_return_if_fail ((name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) ||
700 : : g_dbus_is_name (name));
701 : 2 : g_return_if_fail (g_variant_is_object_path (object_path));
702 : :
703 : 2 : g_async_initable_new_async (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
704 : : G_PRIORITY_DEFAULT,
705 : : cancellable,
706 : : callback,
707 : : user_data,
708 : : "connection", connection,
709 : : "flags", flags,
710 : : "name", name,
711 : : "object-path", object_path,
712 : : "get-proxy-type-func", get_proxy_type_func,
713 : : "get-proxy-type-user-data", get_proxy_type_user_data,
714 : : "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
715 : : NULL);
716 : : }
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 : 2 : g_dbus_object_manager_client_new_finish (GAsyncResult *res,
733 : : GError **error)
734 : : {
735 : : GObject *object;
736 : : GObject *source_object;
737 : :
738 : 2 : source_object = g_async_result_get_source_object (res);
739 : 2 : g_assert (source_object != NULL);
740 : :
741 : 2 : object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
742 : : res,
743 : : error);
744 : 2 : g_object_unref (source_object);
745 : :
746 [ + - ]: 2 : if (object != NULL)
747 : 2 : return G_DBUS_OBJECT_MANAGER (object);
748 : : else
749 : 0 : return NULL;
750 : : }
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 : 0 : 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 : : {
790 : : 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 : : cancellable,
799 : : error,
800 : : "bus-type", bus_type,
801 : : "flags", flags,
802 : : "name", name,
803 : : "object-path", object_path,
804 : : "get-proxy-type-func", get_proxy_type_func,
805 : : "get-proxy-type-user-data", get_proxy_type_user_data,
806 : : "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
807 : : NULL);
808 [ # # ]: 0 : if (initable != NULL)
809 : 0 : return G_DBUS_OBJECT_MANAGER (initable);
810 : : else
811 : 0 : return NULL;
812 : : }
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 : 0 : 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 : : {
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 : : G_PRIORITY_DEFAULT,
857 : : cancellable,
858 : : callback,
859 : : user_data,
860 : : "bus-type", bus_type,
861 : : "flags", flags,
862 : : "name", name,
863 : : "object-path", object_path,
864 : : "get-proxy-type-func", get_proxy_type_func,
865 : : "get-proxy-type-user-data", get_proxy_type_user_data,
866 : : "get-proxy-type-destroy-notify", get_proxy_type_destroy_notify,
867 : : NULL);
868 : : }
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 : 0 : g_dbus_object_manager_client_new_for_bus_finish (GAsyncResult *res,
885 : : GError **error)
886 : : {
887 : : GObject *object;
888 : : 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 : : res,
895 : : error);
896 : 0 : g_object_unref (source_object);
897 : :
898 [ # # ]: 0 : if (object != NULL)
899 : 0 : return G_DBUS_OBJECT_MANAGER (object);
900 : : else
901 : 0 : return NULL;
902 : : }
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 : 3 : g_dbus_object_manager_client_get_connection (GDBusObjectManagerClient *manager)
919 : : {
920 : : GDBusConnection *ret;
921 : 3 : g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
922 : 3 : g_mutex_lock (&manager->priv->lock);
923 : 3 : ret = manager->priv->connection;
924 : 3 : g_mutex_unlock (&manager->priv->lock);
925 : 3 : return ret;
926 : : }
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 : 3 : g_dbus_object_manager_client_get_name (GDBusObjectManagerClient *manager)
942 : : {
943 : : const gchar *ret;
944 : 3 : g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
945 : 3 : g_mutex_lock (&manager->priv->lock);
946 : 3 : ret = manager->priv->name;
947 : 3 : g_mutex_unlock (&manager->priv->lock);
948 : 3 : return ret;
949 : : }
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 : 3 : g_dbus_object_manager_client_get_flags (GDBusObjectManagerClient *manager)
964 : : {
965 : : GDBusObjectManagerClientFlags ret;
966 : 3 : g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE);
967 : 3 : g_mutex_lock (&manager->priv->lock);
968 : 3 : ret = manager->priv->flags;
969 : 3 : g_mutex_unlock (&manager->priv->lock);
970 : 3 : return ret;
971 : : }
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 : 3 : g_dbus_object_manager_client_get_name_owner (GDBusObjectManagerClient *manager)
989 : : {
990 : : gchar *ret;
991 : 3 : g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
992 : 3 : g_mutex_lock (&manager->priv->lock);
993 : 3 : ret = g_strdup (manager->priv->name_owner);
994 : 3 : g_mutex_unlock (&manager->priv->lock);
995 : 3 : return ret;
996 : : }
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 : 54 : 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 : : {
1012 : 54 : GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (user_data);
1013 : : GDBusObjectProxy *object_proxy;
1014 : : GDBusInterface *interface;
1015 : :
1016 : 54 : g_mutex_lock (&manager->priv->lock);
1017 : 54 : object_proxy = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1018 [ + + ]: 54 : if (object_proxy == NULL)
1019 : : {
1020 : 36 : g_mutex_unlock (&manager->priv->lock);
1021 : 36 : goto out;
1022 : : }
1023 : 18 : g_object_ref (object_proxy);
1024 : 18 : 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 : 18 : g_object_ref (manager);
1029 [ + + ]: 18 : if (g_strcmp0 (interface_name, "org.freedesktop.DBus.Properties") == 0)
1030 : : {
1031 [ + - ]: 15 : if (g_strcmp0 (signal_name, "PropertiesChanged") == 0)
1032 : : {
1033 : : const gchar *properties_interface_name;
1034 : : GVariant *changed_properties;
1035 : : const gchar **invalidated_properties;
1036 : :
1037 : 15 : g_variant_get (parameters,
1038 : : "(&s@a{sv}^a&s)",
1039 : : &properties_interface_name,
1040 : : &changed_properties,
1041 : : &invalidated_properties);
1042 : :
1043 : 15 : interface = g_dbus_object_get_interface (G_DBUS_OBJECT (object_proxy), properties_interface_name);
1044 [ + - ]: 15 : if (interface != NULL)
1045 : : {
1046 : : GVariantIter property_iter;
1047 : : const gchar *property_name;
1048 : : GVariant *property_value;
1049 : : guint n;
1050 : :
1051 : : /* update caches... */
1052 : 15 : g_variant_iter_init (&property_iter, changed_properties);
1053 [ + + ]: 30 : while (g_variant_iter_next (&property_iter,
1054 : : "{&sv}",
1055 : : &property_name,
1056 : : &property_value))
1057 : : {
1058 : 15 : g_dbus_proxy_set_cached_property (G_DBUS_PROXY (interface),
1059 : : property_name,
1060 : : property_value);
1061 : 15 : g_variant_unref (property_value);
1062 : : }
1063 : :
1064 [ - + ]: 15 : for (n = 0; invalidated_properties[n] != NULL; n++)
1065 : : {
1066 : 0 : g_dbus_proxy_set_cached_property (G_DBUS_PROXY (interface),
1067 : 0 : invalidated_properties[n],
1068 : : NULL);
1069 : : }
1070 : : /* ... and then synthesize the signal */
1071 : 15 : g_signal_emit_by_name (interface,
1072 : : "g-properties-changed",
1073 : : changed_properties,
1074 : : invalidated_properties);
1075 : 15 : g_signal_emit (manager,
1076 : : signals[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL],
1077 : : 0,
1078 : : object_proxy,
1079 : : interface,
1080 : : changed_properties,
1081 : : invalidated_properties);
1082 : 15 : g_object_unref (interface);
1083 : : }
1084 : 15 : g_variant_unref (changed_properties);
1085 : 15 : g_free (invalidated_properties);
1086 : : }
1087 : : }
1088 : : else
1089 : : {
1090 : : /* regular signal - just dispatch it */
1091 : 3 : interface = g_dbus_object_get_interface (G_DBUS_OBJECT (object_proxy), interface_name);
1092 [ + - ]: 3 : if (interface != NULL)
1093 : : {
1094 : 3 : g_signal_emit_by_name (interface,
1095 : : "g-signal",
1096 : : sender_name,
1097 : : signal_name,
1098 : : parameters);
1099 : 3 : g_signal_emit (manager,
1100 : : signals[INTERFACE_PROXY_SIGNAL_SIGNAL],
1101 : : 0,
1102 : : object_proxy,
1103 : : interface,
1104 : : sender_name,
1105 : : signal_name,
1106 : : parameters);
1107 : 3 : g_object_unref (interface);
1108 : : }
1109 : : }
1110 : 18 : g_object_unref (manager);
1111 : :
1112 : 54 : out:
1113 : 54 : g_clear_object (&object_proxy);
1114 : 54 : }
1115 : :
1116 : : static void
1117 : 8 : subscribe_signals (GDBusObjectManagerClient *manager,
1118 : : const gchar *name_owner)
1119 : : {
1120 : 8 : GError *error = NULL;
1121 : : GVariant *ret;
1122 : :
1123 : 8 : g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager));
1124 : 8 : g_return_if_fail (manager->priv->signal_subscription_id == 0);
1125 : 8 : g_return_if_fail (name_owner == NULL || g_dbus_is_unique_name (name_owner));
1126 : :
1127 [ + + ]: 8 : if (name_owner != NULL)
1128 : : {
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 [ - + ]: 6 : if (g_str_equal (manager->priv->object_path, "/"))
1135 : : {
1136 : 0 : manager->priv->match_rule = g_strdup_printf ("type='signal',sender='%s'",
1137 : : name_owner);
1138 : : }
1139 : : else
1140 : : {
1141 : 6 : manager->priv->match_rule = g_strdup_printf ("type='signal',sender='%s',path_namespace='%s'",
1142 : 6 : name_owner, manager->priv->object_path);
1143 : : }
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 : 6 : ret = g_dbus_connection_call_sync (manager->priv->connection,
1148 : : "org.freedesktop.DBus",
1149 : : "/org/freedesktop/DBus",
1150 : : "org.freedesktop.DBus",
1151 : : "AddMatch",
1152 : : g_variant_new ("(s)",
1153 : 6 : manager->priv->match_rule),
1154 : : NULL, /* reply_type */
1155 : : G_DBUS_CALL_FLAGS_NONE,
1156 : : -1, /* default timeout */
1157 : : NULL, /* TODO: Cancellable */
1158 : : &error);
1159 : :
1160 : : /* yay, bus daemon supports path_namespace */
1161 [ + - ]: 6 : if (ret != NULL)
1162 : 6 : g_variant_unref (ret);
1163 : : }
1164 : :
1165 [ + - ]: 8 : if (error == NULL)
1166 : : {
1167 : : /* still need to ask GDBusConnection for the callbacks */
1168 : 8 : manager->priv->signal_subscription_id =
1169 : 8 : g_dbus_connection_signal_subscribe (manager->priv->connection,
1170 : : name_owner,
1171 : : NULL, /* interface */
1172 : : NULL, /* member */
1173 : : NULL, /* path - TODO: really want wildcard support here */
1174 : : NULL, /* arg0 */
1175 : : G_DBUS_SIGNAL_FLAGS_NONE |
1176 : : G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
1177 : : signal_cb,
1178 : : manager,
1179 : : NULL); /* user_data_free_func */
1180 : :
1181 : : }
1182 : : else
1183 : : {
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 : : name_owner,
1204 : : NULL, /* interface */
1205 : : NULL, /* member */
1206 : : NULL, /* path - TODO: really want wildcard support here */
1207 : : NULL, /* arg0 */
1208 : : G_DBUS_SIGNAL_FLAGS_NONE,
1209 : : signal_cb,
1210 : : manager,
1211 : : NULL); /* user_data_free_func */
1212 : : }
1213 : : }
1214 : :
1215 : : static void
1216 : 11 : maybe_unsubscribe_signals (GDBusObjectManagerClient *manager)
1217 : : {
1218 : 11 : g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager));
1219 : :
1220 [ + + ]: 11 : if (manager->priv->signal_subscription_id > 0)
1221 : : {
1222 : 8 : g_dbus_connection_signal_unsubscribe (manager->priv->connection,
1223 : 8 : manager->priv->signal_subscription_id);
1224 : 8 : manager->priv->signal_subscription_id = 0;
1225 : : }
1226 : :
1227 [ + + ]: 11 : if (manager->priv->match_rule != NULL)
1228 : : {
1229 : : /* Since the AddMatch call succeeded this is guaranteed to not
1230 : : * fail - therefore, don't bother checking the return value
1231 : : */
1232 : 6 : g_dbus_connection_call (manager->priv->connection,
1233 : : "org.freedesktop.DBus",
1234 : : "/org/freedesktop/DBus",
1235 : : "org.freedesktop.DBus",
1236 : : "RemoveMatch",
1237 : : g_variant_new ("(s)",
1238 : 6 : manager->priv->match_rule),
1239 : : NULL, /* reply_type */
1240 : : G_DBUS_CALL_FLAGS_NONE,
1241 : : -1, /* default timeout */
1242 : : NULL, /* GCancellable */
1243 : : NULL, /* GAsyncReadyCallback */
1244 : : NULL); /* user data */
1245 : 6 : g_free (manager->priv->match_rule);
1246 : 6 : manager->priv->match_rule = NULL;
1247 : : }
1248 : :
1249 : : }
1250 : :
1251 : : /* ---------------------------------------------------------------------------------------------------- */
1252 : :
1253 : : static GWeakRef *
1254 : 16 : weak_ref_new (GObject *object)
1255 : : {
1256 : 16 : GWeakRef *weak_ref = g_new0 (GWeakRef, 1);
1257 : 16 : g_weak_ref_init (weak_ref, object);
1258 : 16 : return g_steal_pointer (&weak_ref);
1259 : : }
1260 : :
1261 : : static void
1262 : 16 : weak_ref_free (GWeakRef *weak_ref)
1263 : : {
1264 : 16 : g_weak_ref_clear (weak_ref);
1265 : 16 : g_free (weak_ref);
1266 : 16 : }
1267 : :
1268 : : static void
1269 : 0 : on_get_managed_objects_finish (GObject *source,
1270 : : GAsyncResult *result,
1271 : : gpointer user_data)
1272 : : {
1273 : :
1274 : 0 : GDBusProxy *proxy = G_DBUS_PROXY (source);
1275 : 0 : GWeakRef *manager_weak = user_data;
1276 : : 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 : : {
1287 : 0 : goto out;
1288 : : }
1289 : :
1290 : 0 : new_name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy);
1291 [ # # ]: 0 : if (value == NULL)
1292 : : {
1293 : 0 : maybe_unsubscribe_signals (manager);
1294 [ # # ]: 0 : if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
1295 : : {
1296 : 0 : g_warning ("Error calling GetManagedObjects() when name owner %s for name %s came back: %s",
1297 : : new_name_owner,
1298 : : manager->priv->name,
1299 : : error->message);
1300 : : }
1301 : : }
1302 : : else
1303 : : {
1304 : 0 : process_get_all_result (manager, value, new_name_owner);
1305 : : }
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 : 0 : on_notify_g_name_owner (GObject *object,
1324 : : GParamSpec *pspec,
1325 : : gpointer user_data)
1326 : : {
1327 : 0 : GWeakRef *manager_weak = user_data;
1328 : 0 : GDBusObjectManagerClient *manager = NULL;
1329 : : gchar *old_name_owner;
1330 : : 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 : : {
1343 : : 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 : : {
1359 : : 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 : : }
1363 : 0 : g_clear_pointer (&proxies, g_ptr_array_unref);
1364 : :
1365 : : /* nuke local filter */
1366 : 0 : maybe_unsubscribe_signals (manager);
1367 : : }
1368 : : else
1369 : : {
1370 : 0 : g_mutex_unlock (&manager->priv->lock);
1371 : : }
1372 : :
1373 [ # # ]: 0 : if (new_name_owner != NULL)
1374 : : {
1375 : : //g_debug ("repopulating for %s", new_name_owner);
1376 : :
1377 : 0 : subscribe_signals (manager,
1378 : : new_name_owner);
1379 : 0 : g_dbus_proxy_call (manager->priv->control_proxy,
1380 : : "GetManagedObjects",
1381 : : NULL, /* parameters */
1382 : : G_DBUS_CALL_FLAGS_NONE,
1383 : : -1,
1384 : 0 : manager->priv->cancel,
1385 : : on_get_managed_objects_finish,
1386 : 0 : weak_ref_new (G_OBJECT (manager)));
1387 : : }
1388 : 0 : g_free (new_name_owner);
1389 : 0 : g_free (old_name_owner);
1390 : 0 : g_object_unref (manager);
1391 : : }
1392 : :
1393 : : static gboolean
1394 : 8 : initable_init (GInitable *initable,
1395 : : GCancellable *cancellable,
1396 : : GError **error)
1397 : : {
1398 : 8 : GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (initable);
1399 : : gboolean ret;
1400 : : GVariant *value;
1401 : : GDBusProxyFlags proxy_flags;
1402 : :
1403 : 8 : ret = FALSE;
1404 : :
1405 [ - + ]: 8 : if (manager->priv->bus_type != G_BUS_TYPE_NONE)
1406 : : {
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 : : }
1412 : :
1413 : 8 : proxy_flags = G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES;
1414 [ + + ]: 8 : if (manager->priv->flags & G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START)
1415 : 2 : proxy_flags |= G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START;
1416 : :
1417 : 16 : manager->priv->control_proxy = g_dbus_proxy_new_sync (manager->priv->connection,
1418 : : proxy_flags,
1419 : : NULL, /* GDBusInterfaceInfo* */
1420 : 8 : manager->priv->name,
1421 : 8 : manager->priv->object_path,
1422 : : "org.freedesktop.DBus.ObjectManager",
1423 : : cancellable,
1424 : : error);
1425 [ - + ]: 8 : 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 : 16 : manager->priv->name_owner_signal_id =
1438 : 8 : g_signal_connect_data (G_OBJECT (manager->priv->control_proxy),
1439 : : "notify::g-name-owner",
1440 : : G_CALLBACK (on_notify_g_name_owner),
1441 : 8 : weak_ref_new (G_OBJECT (manager)),
1442 : : (GClosureNotify) weak_ref_free,
1443 : : G_CONNECT_DEFAULT);
1444 : :
1445 : 16 : manager->priv->signal_signal_id =
1446 : 8 : g_signal_connect_data (manager->priv->control_proxy,
1447 : : "g-signal",
1448 : : G_CALLBACK (on_control_proxy_g_signal),
1449 : 8 : weak_ref_new (G_OBJECT (manager)),
1450 : : (GClosureNotify) weak_ref_free,
1451 : : G_CONNECT_DEFAULT);
1452 : :
1453 : 8 : manager->priv->name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy);
1454 [ + + - + ]: 8 : if (manager->priv->name_owner == NULL && manager->priv->name != NULL)
1455 : : {
1456 : : /* it's perfectly fine if there's no name owner.. we're just going to
1457 : : * wait until one is ready
1458 : : */
1459 : : }
1460 : : else
1461 : : {
1462 : : /* yay, we can get the objects */
1463 : 8 : subscribe_signals (manager,
1464 : 8 : manager->priv->name_owner);
1465 : 8 : value = g_dbus_proxy_call_sync (manager->priv->control_proxy,
1466 : : "GetManagedObjects",
1467 : : NULL, /* parameters */
1468 : : G_DBUS_CALL_FLAGS_NONE,
1469 : : -1,
1470 : : cancellable,
1471 : : error);
1472 [ + + ]: 8 : if (value == NULL)
1473 : : {
1474 : 3 : maybe_unsubscribe_signals (manager);
1475 : :
1476 [ - + ]: 3 : g_warn_if_fail (manager->priv->signal_signal_id != 0);
1477 : 3 : g_signal_handler_disconnect (manager->priv->control_proxy,
1478 : 3 : manager->priv->signal_signal_id);
1479 : 3 : manager->priv->signal_signal_id = 0;
1480 : :
1481 [ - + ]: 3 : g_warn_if_fail (manager->priv->name_owner_signal_id != 0);
1482 : 3 : g_signal_handler_disconnect (manager->priv->control_proxy,
1483 : 3 : manager->priv->name_owner_signal_id);
1484 : 3 : manager->priv->name_owner_signal_id = 0;
1485 : :
1486 : 3 : g_object_unref (manager->priv->control_proxy);
1487 : 3 : manager->priv->control_proxy = NULL;
1488 : :
1489 : 3 : goto out;
1490 : : }
1491 : :
1492 : 5 : process_get_all_result (manager, value, manager->priv->name_owner);
1493 : 5 : g_variant_unref (value);
1494 : : }
1495 : :
1496 : 5 : ret = TRUE;
1497 : :
1498 : 8 : out:
1499 : 8 : return ret;
1500 : : }
1501 : :
1502 : : static void
1503 : 5 : initable_iface_init (GInitableIface *initable_iface)
1504 : : {
1505 : 5 : initable_iface->init = initable_init;
1506 : 5 : }
1507 : :
1508 : : static void
1509 : 5 : async_initable_iface_init (GAsyncInitableIface *async_initable_iface)
1510 : : {
1511 : : /* for now, just use default: run GInitable code in thread */
1512 : 5 : }
1513 : :
1514 : : /* ---------------------------------------------------------------------------------------------------- */
1515 : :
1516 : : static void
1517 : 25 : add_interfaces (GDBusObjectManagerClient *manager,
1518 : : const gchar *object_path,
1519 : : GVariant *ifaces_and_properties,
1520 : : const gchar *name_owner)
1521 : : {
1522 : : GDBusObjectProxy *op;
1523 : : gboolean added;
1524 : : GVariantIter iter;
1525 : : const gchar *interface_name;
1526 : : GVariant *properties;
1527 : : GList *interface_added_signals, *l;
1528 : : GDBusProxy *interface_proxy;
1529 : :
1530 : 25 : g_return_if_fail (name_owner == NULL || g_dbus_is_unique_name (name_owner));
1531 : :
1532 : 25 : g_mutex_lock (&manager->priv->lock);
1533 : :
1534 : 25 : interface_added_signals = NULL;
1535 : 25 : added = FALSE;
1536 : :
1537 : 25 : op = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1538 [ + + ]: 25 : if (op == NULL)
1539 : : {
1540 : : GType object_proxy_type;
1541 [ + + ]: 22 : if (manager->priv->get_proxy_type_func != NULL)
1542 : : {
1543 : 18 : object_proxy_type = manager->priv->get_proxy_type_func (manager,
1544 : : object_path,
1545 : : NULL,
1546 : 18 : manager->priv->get_proxy_type_user_data);
1547 [ + - - + ]: 18 : g_warn_if_fail (g_type_is_a (object_proxy_type, G_TYPE_DBUS_OBJECT_PROXY));
1548 : : }
1549 : : else
1550 : : {
1551 : 4 : object_proxy_type = G_TYPE_DBUS_OBJECT_PROXY;
1552 : : }
1553 : 22 : op = g_object_new (object_proxy_type,
1554 : 22 : "g-connection", manager->priv->connection,
1555 : : "g-object-path", object_path,
1556 : : NULL);
1557 : 22 : added = TRUE;
1558 : : }
1559 : 25 : g_object_ref (op);
1560 : :
1561 : 25 : g_variant_iter_init (&iter, ifaces_and_properties);
1562 [ + + ]: 53 : while (g_variant_iter_next (&iter,
1563 : : "{&s@a{sv}}",
1564 : : &interface_name,
1565 : : &properties))
1566 : : {
1567 : : GError *error;
1568 : : GType interface_proxy_type;
1569 : :
1570 [ + + ]: 28 : if (manager->priv->get_proxy_type_func != NULL)
1571 : : {
1572 : 24 : interface_proxy_type = manager->priv->get_proxy_type_func (manager,
1573 : : object_path,
1574 : : interface_name,
1575 : 24 : manager->priv->get_proxy_type_user_data);
1576 [ + - - + ]: 24 : g_warn_if_fail (g_type_is_a (interface_proxy_type, G_TYPE_DBUS_PROXY));
1577 : : }
1578 : : else
1579 : : {
1580 : 4 : interface_proxy_type = G_TYPE_DBUS_PROXY;
1581 : : }
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 : 28 : error = NULL;
1587 : 28 : interface_proxy = g_initable_new (interface_proxy_type,
1588 : : NULL, /* GCancellable */
1589 : : &error,
1590 : 28 : "g-connection", manager->priv->connection,
1591 : : "g-flags", G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
1592 : : G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
1593 : : "g-name", name_owner,
1594 : : "g-object-path", object_path,
1595 : : "g-interface-name", interface_name,
1596 : : NULL);
1597 [ - + ]: 28 : if (interface_proxy == NULL)
1598 : : {
1599 : 0 : g_warning ("%s: Error constructing proxy for path %s and interface %s: %s",
1600 : : G_STRLOC,
1601 : : object_path,
1602 : : interface_name,
1603 : : error->message);
1604 : 0 : g_error_free (error);
1605 : : }
1606 : : else
1607 : : {
1608 : : GVariantIter property_iter;
1609 : : const gchar *property_name;
1610 : : GVariant *property_value;
1611 : :
1612 : : /* associate the interface proxy with the object */
1613 : 28 : g_dbus_interface_set_object (G_DBUS_INTERFACE (interface_proxy),
1614 : 28 : G_DBUS_OBJECT (op));
1615 : :
1616 : 28 : g_variant_iter_init (&property_iter, properties);
1617 [ + + ]: 438 : while (g_variant_iter_next (&property_iter,
1618 : : "{&sv}",
1619 : : &property_name,
1620 : : &property_value))
1621 : : {
1622 : 410 : g_dbus_proxy_set_cached_property (interface_proxy,
1623 : : property_name,
1624 : : property_value);
1625 : 410 : g_variant_unref (property_value);
1626 : : }
1627 : :
1628 : 28 : _g_dbus_object_proxy_add_interface (op, interface_proxy);
1629 [ + + ]: 28 : if (!added)
1630 : 3 : interface_added_signals = g_list_append (interface_added_signals, g_object_ref (interface_proxy));
1631 : 28 : g_object_unref (interface_proxy);
1632 : : }
1633 : 28 : g_variant_unref (properties);
1634 : : }
1635 : :
1636 [ + + ]: 25 : if (added)
1637 : : {
1638 : 22 : g_hash_table_insert (manager->priv->map_object_path_to_object_proxy,
1639 : 22 : g_strdup (object_path),
1640 : : op);
1641 : : }
1642 : :
1643 : 25 : g_mutex_unlock (&manager->priv->lock);
1644 : :
1645 : : /* now that we don't hold the lock any more, emit signals */
1646 : 25 : g_object_ref (manager);
1647 [ + + ]: 28 : for (l = interface_added_signals; l != NULL; l = l->next)
1648 : : {
1649 : 3 : interface_proxy = G_DBUS_PROXY (l->data);
1650 : 3 : g_signal_emit_by_name (manager, "interface-added", op, interface_proxy);
1651 : 3 : g_object_unref (interface_proxy);
1652 : : }
1653 : 25 : g_list_free (interface_added_signals);
1654 : :
1655 [ + + ]: 25 : if (added)
1656 : 22 : g_signal_emit_by_name (manager, "object-added", op);
1657 : :
1658 : 25 : g_object_unref (manager);
1659 : 25 : g_object_unref (op);
1660 : : }
1661 : :
1662 : : static void
1663 : 15 : remove_interfaces (GDBusObjectManagerClient *manager,
1664 : : const gchar *object_path,
1665 : : const gchar *const *interface_names)
1666 : : {
1667 : : GDBusObjectProxy *op;
1668 : : GList *interfaces;
1669 : : guint n;
1670 : : guint num_interfaces;
1671 : : guint num_interfaces_to_remove;
1672 : :
1673 : 15 : g_mutex_lock (&manager->priv->lock);
1674 : :
1675 : 15 : op = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1676 [ - + ]: 15 : if (op == NULL)
1677 : : {
1678 : 0 : g_debug ("%s: Processing InterfaceRemoved signal for path %s but no object proxy exists",
1679 : : G_STRLOC,
1680 : : object_path);
1681 : 0 : g_mutex_unlock (&manager->priv->lock);
1682 : 0 : return;
1683 : : }
1684 : :
1685 : 15 : interfaces = g_dbus_object_get_interfaces (G_DBUS_OBJECT (op));
1686 : 15 : num_interfaces = g_list_length (interfaces);
1687 : 15 : g_list_free_full (interfaces, g_object_unref);
1688 : :
1689 : 15 : num_interfaces_to_remove = g_strv_length ((gchar **) interface_names);
1690 : :
1691 : : /* see if we are going to completety remove the object */
1692 : 15 : g_object_ref (manager);
1693 [ + + ]: 15 : if (num_interfaces_to_remove == num_interfaces)
1694 : : {
1695 : 12 : g_object_ref (op);
1696 [ - + ]: 12 : g_warn_if_fail (g_hash_table_remove (manager->priv->map_object_path_to_object_proxy, object_path));
1697 : 12 : g_mutex_unlock (&manager->priv->lock);
1698 : 12 : g_signal_emit_by_name (manager, "object-removed", op);
1699 : 12 : g_object_unref (op);
1700 : : }
1701 : : else
1702 : : {
1703 : 3 : g_object_ref (op);
1704 : 3 : g_mutex_unlock (&manager->priv->lock);
1705 [ + - + + ]: 6 : for (n = 0; interface_names != NULL && interface_names[n] != NULL; n++)
1706 : : {
1707 : : GDBusInterface *interface;
1708 : 3 : interface = g_dbus_object_get_interface (G_DBUS_OBJECT (op), interface_names[n]);
1709 : 3 : _g_dbus_object_proxy_remove_interface (op, interface_names[n]);
1710 [ + - ]: 3 : if (interface != NULL)
1711 : : {
1712 : 3 : g_signal_emit_by_name (manager, "interface-removed", op, interface);
1713 : 3 : g_object_unref (interface);
1714 : : }
1715 : : }
1716 : 3 : g_object_unref (op);
1717 : : }
1718 : 15 : g_object_unref (manager);
1719 : : }
1720 : :
1721 : : static void
1722 : 5 : process_get_all_result (GDBusObjectManagerClient *manager,
1723 : : GVariant *value,
1724 : : const gchar *name_owner)
1725 : : {
1726 : : GVariant *arg0;
1727 : : const gchar *object_path;
1728 : : GVariant *ifaces_and_properties;
1729 : : GVariantIter iter;
1730 : :
1731 : 5 : g_return_if_fail (name_owner == NULL || g_dbus_is_unique_name (name_owner));
1732 : :
1733 : 5 : arg0 = g_variant_get_child_value (value, 0);
1734 : 5 : g_variant_iter_init (&iter, arg0);
1735 [ + + ]: 9 : while (g_variant_iter_next (&iter,
1736 : : "{&o@a{sa{sv}}}",
1737 : : &object_path,
1738 : : &ifaces_and_properties))
1739 : : {
1740 : 4 : add_interfaces (manager, object_path, ifaces_and_properties, name_owner);
1741 : 4 : g_variant_unref (ifaces_and_properties);
1742 : : }
1743 : 5 : g_variant_unref (arg0);
1744 : : }
1745 : :
1746 : : static void
1747 : 36 : 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 : : {
1753 : 36 : GWeakRef *manager_weak = user_data;
1754 : 36 : GDBusObjectManagerClient *manager = NULL;
1755 : : const gchar *object_path;
1756 : :
1757 : 36 : manager = G_DBUS_OBJECT_MANAGER_CLIENT (g_weak_ref_get (manager_weak));
1758 [ - + ]: 36 : 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 [ + + ]: 36 : if (g_strcmp0 (signal_name, "InterfacesAdded") == 0)
1764 : : {
1765 : : GVariant *ifaces_and_properties;
1766 : 21 : g_variant_get (parameters,
1767 : : "(&o@a{sa{sv}})",
1768 : : &object_path,
1769 : : &ifaces_and_properties);
1770 : 21 : add_interfaces (manager, object_path, ifaces_and_properties, manager->priv->name_owner);
1771 : 21 : g_variant_unref (ifaces_and_properties);
1772 : : }
1773 [ + - ]: 15 : else if (g_strcmp0 (signal_name, "InterfacesRemoved") == 0)
1774 : : {
1775 : : const gchar **ifaces;
1776 : 15 : g_variant_get (parameters,
1777 : : "(&o^a&s)",
1778 : : &object_path,
1779 : : &ifaces);
1780 : 15 : remove_interfaces (manager, object_path, ifaces);
1781 : 15 : g_free (ifaces);
1782 : : }
1783 : :
1784 : 36 : g_object_unref (manager);
1785 : : }
1786 : :
1787 : : /* ---------------------------------------------------------------------------------------------------- */
1788 : :
1789 : : static const gchar *
1790 : 6 : g_dbus_object_manager_client_get_object_path (GDBusObjectManager *_manager)
1791 : : {
1792 : 6 : GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
1793 : 6 : return manager->priv->object_path;
1794 : : }
1795 : :
1796 : : static GDBusObject *
1797 : 16 : g_dbus_object_manager_client_get_object (GDBusObjectManager *_manager,
1798 : : const gchar *object_path)
1799 : : {
1800 : 16 : GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
1801 : : GDBusObject *ret;
1802 : :
1803 : 16 : g_mutex_lock (&manager->priv->lock);
1804 : 16 : ret = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1805 [ + - ]: 16 : if (ret != NULL)
1806 : 16 : g_object_ref (ret);
1807 : 16 : g_mutex_unlock (&manager->priv->lock);
1808 : 16 : return ret;
1809 : : }
1810 : :
1811 : : static GDBusInterface *
1812 : 10 : g_dbus_object_manager_client_get_interface (GDBusObjectManager *_manager,
1813 : : const gchar *object_path,
1814 : : const gchar *interface_name)
1815 : : {
1816 : : GDBusInterface *ret;
1817 : : GDBusObject *object;
1818 : :
1819 : 10 : ret = NULL;
1820 : :
1821 : 10 : object = g_dbus_object_manager_get_object (_manager, object_path);
1822 [ - + ]: 10 : if (object == NULL)
1823 : 0 : goto out;
1824 : :
1825 : 10 : ret = g_dbus_object_get_interface (object, interface_name);
1826 : 10 : g_object_unref (object);
1827 : :
1828 : 10 : out:
1829 : 10 : return ret;
1830 : : }
1831 : :
1832 : : static GList *
1833 : 6 : g_dbus_object_manager_client_get_objects (GDBusObjectManager *_manager)
1834 : : {
1835 : 6 : GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
1836 : : GList *ret;
1837 : :
1838 : 6 : g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
1839 : :
1840 : 6 : g_mutex_lock (&manager->priv->lock);
1841 : 6 : ret = g_hash_table_get_values (manager->priv->map_object_path_to_object_proxy);
1842 : 6 : g_list_foreach (ret, (GFunc) g_object_ref, NULL);
1843 : 6 : g_mutex_unlock (&manager->priv->lock);
1844 : :
1845 : 6 : return ret;
1846 : : }
1847 : :
1848 : :
1849 : : static void
1850 : 5 : dbus_object_manager_interface_init (GDBusObjectManagerIface *iface)
1851 : : {
1852 : 5 : iface->get_object_path = g_dbus_object_manager_client_get_object_path;
1853 : 5 : iface->get_objects = g_dbus_object_manager_client_get_objects;
1854 : 5 : iface->get_object = g_dbus_object_manager_client_get_object;
1855 : 5 : iface->get_interface = g_dbus_object_manager_client_get_interface;
1856 : 5 : }
1857 : :
1858 : : /* ---------------------------------------------------------------------------------------------------- */
|