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, DBUS_INTERFACE_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 : : DBUS_SERVICE_DBUS,
1149 : : DBUS_PATH_DBUS,
1150 : : DBUS_INTERFACE_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 : 8 : g_dbus_connection_signal_unsubscribe (manager->priv->connection,
1222 : 8 : g_steal_handle_id (&manager->priv->signal_subscription_id));
1223 : :
1224 : 11 : if (manager->priv->match_rule != NULL)
1225 : : {
1226 : : /* Since the AddMatch call succeeded this is guaranteed to not
1227 : : * fail - therefore, don't bother checking the return value
1228 : : */
1229 : 6 : g_dbus_connection_call (manager->priv->connection,
1230 : : DBUS_SERVICE_DBUS,
1231 : : DBUS_PATH_DBUS,
1232 : : DBUS_INTERFACE_DBUS,
1233 : : "RemoveMatch",
1234 : : g_variant_new ("(s)",
1235 : 6 : manager->priv->match_rule),
1236 : : NULL, /* reply_type */
1237 : : G_DBUS_CALL_FLAGS_NONE,
1238 : : -1, /* default timeout */
1239 : : NULL, /* GCancellable */
1240 : : NULL, /* GAsyncReadyCallback */
1241 : : NULL); /* user data */
1242 : 6 : g_free (manager->priv->match_rule);
1243 : 6 : manager->priv->match_rule = NULL;
1244 : : }
1245 : :
1246 : : }
1247 : :
1248 : : /* ---------------------------------------------------------------------------------------------------- */
1249 : :
1250 : : static GWeakRef *
1251 : 16 : weak_ref_new (GObject *object)
1252 : : {
1253 : 16 : GWeakRef *weak_ref = g_new0 (GWeakRef, 1);
1254 : 16 : g_weak_ref_init (weak_ref, object);
1255 : 16 : return g_steal_pointer (&weak_ref);
1256 : : }
1257 : :
1258 : : static void
1259 : 16 : weak_ref_free (GWeakRef *weak_ref)
1260 : : {
1261 : 16 : g_weak_ref_clear (weak_ref);
1262 : 16 : g_free (weak_ref);
1263 : 16 : }
1264 : :
1265 : : static void
1266 : 0 : on_get_managed_objects_finish (GObject *source,
1267 : : GAsyncResult *result,
1268 : : gpointer user_data)
1269 : : {
1270 : :
1271 : 0 : GDBusProxy *proxy = G_DBUS_PROXY (source);
1272 : 0 : GWeakRef *manager_weak = user_data;
1273 : : GDBusObjectManagerClient *manager;
1274 : 0 : GError *error = NULL;
1275 : 0 : GVariant *value = NULL;
1276 : 0 : gchar *new_name_owner = NULL;
1277 : :
1278 : 0 : value = g_dbus_proxy_call_finish (proxy, result, &error);
1279 : :
1280 : 0 : manager = G_DBUS_OBJECT_MANAGER_CLIENT (g_weak_ref_get (manager_weak));
1281 : : /* Manager got disposed, nothing to do */
1282 : 0 : if (manager == NULL)
1283 : : {
1284 : 0 : goto out;
1285 : : }
1286 : :
1287 : 0 : new_name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy);
1288 : 0 : if (value == NULL)
1289 : : {
1290 : 0 : maybe_unsubscribe_signals (manager);
1291 : 0 : if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
1292 : : {
1293 : 0 : g_warning ("Error calling GetManagedObjects() when name owner %s for name %s came back: %s",
1294 : : new_name_owner,
1295 : : manager->priv->name,
1296 : : error->message);
1297 : : }
1298 : : }
1299 : : else
1300 : : {
1301 : 0 : process_get_all_result (manager, value, new_name_owner);
1302 : : }
1303 : :
1304 : : /* do the :name-owner notify *AFTER* emitting ::object-proxy-added signals - this
1305 : : * way the user knows that the signals were emitted because the name owner came back
1306 : : */
1307 : 0 : g_mutex_lock (&manager->priv->lock);
1308 : 0 : manager->priv->name_owner = g_steal_pointer (&new_name_owner);
1309 : 0 : g_mutex_unlock (&manager->priv->lock);
1310 : 0 : g_object_notify (G_OBJECT (manager), "name-owner");
1311 : :
1312 : 0 : g_object_unref (manager);
1313 : 0 : out:
1314 : 0 : g_clear_error (&error);
1315 : 0 : g_clear_pointer (&value, g_variant_unref);
1316 : 0 : weak_ref_free (manager_weak);
1317 : 0 : }
1318 : :
1319 : : static void
1320 : 0 : on_notify_g_name_owner (GObject *object,
1321 : : GParamSpec *pspec,
1322 : : gpointer user_data)
1323 : : {
1324 : 0 : GWeakRef *manager_weak = user_data;
1325 : 0 : GDBusObjectManagerClient *manager = NULL;
1326 : : gchar *old_name_owner;
1327 : : gchar *new_name_owner;
1328 : :
1329 : 0 : manager = G_DBUS_OBJECT_MANAGER_CLIENT (g_weak_ref_get (manager_weak));
1330 : 0 : if (manager == NULL)
1331 : 0 : return;
1332 : :
1333 : 0 : g_mutex_lock (&manager->priv->lock);
1334 : 0 : old_name_owner = manager->priv->name_owner;
1335 : 0 : new_name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy);
1336 : 0 : manager->priv->name_owner = NULL;
1337 : :
1338 : 0 : if (g_strcmp0 (old_name_owner, new_name_owner) != 0)
1339 : : {
1340 : : GPtrArray *proxies;
1341 : :
1342 : : /* remote manager changed; nuke all local proxies */
1343 : 0 : proxies = g_hash_table_steal_all_values (
1344 : 0 : manager->priv->map_object_path_to_object_proxy);
1345 : :
1346 : 0 : g_mutex_unlock (&manager->priv->lock);
1347 : :
1348 : : /* do the :name-owner notify with a NULL name - this way the user knows
1349 : : * the ::object-proxy-removed following is because the name owner went
1350 : : * away
1351 : : */
1352 : 0 : g_object_notify (G_OBJECT (manager), "name-owner");
1353 : :
1354 : 0 : for (guint i = 0; i < proxies->len; ++i)
1355 : : {
1356 : : GDBusObjectProxy *object_proxy =
1357 : 0 : G_DBUS_OBJECT_PROXY (g_ptr_array_index (proxies, i));
1358 : 0 : g_signal_emit_by_name (manager, "object-removed", object_proxy);
1359 : : }
1360 : 0 : g_clear_pointer (&proxies, g_ptr_array_unref);
1361 : :
1362 : : /* nuke local filter */
1363 : 0 : maybe_unsubscribe_signals (manager);
1364 : : }
1365 : : else
1366 : : {
1367 : 0 : g_mutex_unlock (&manager->priv->lock);
1368 : : }
1369 : :
1370 : 0 : if (new_name_owner != NULL)
1371 : : {
1372 : : //g_debug ("repopulating for %s", new_name_owner);
1373 : :
1374 : 0 : subscribe_signals (manager,
1375 : : new_name_owner);
1376 : 0 : g_dbus_proxy_call (manager->priv->control_proxy,
1377 : : "GetManagedObjects",
1378 : : NULL, /* parameters */
1379 : : G_DBUS_CALL_FLAGS_NONE,
1380 : : -1,
1381 : 0 : manager->priv->cancel,
1382 : : on_get_managed_objects_finish,
1383 : 0 : weak_ref_new (G_OBJECT (manager)));
1384 : : }
1385 : 0 : g_free (new_name_owner);
1386 : 0 : g_free (old_name_owner);
1387 : 0 : g_object_unref (manager);
1388 : : }
1389 : :
1390 : : static gboolean
1391 : 8 : initable_init (GInitable *initable,
1392 : : GCancellable *cancellable,
1393 : : GError **error)
1394 : : {
1395 : 8 : GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (initable);
1396 : : gboolean ret;
1397 : : GVariant *value;
1398 : : GDBusProxyFlags proxy_flags;
1399 : :
1400 : 8 : ret = FALSE;
1401 : :
1402 : 8 : if (manager->priv->bus_type != G_BUS_TYPE_NONE)
1403 : : {
1404 : 0 : g_assert (manager->priv->connection == NULL);
1405 : 0 : manager->priv->connection = g_bus_get_sync (manager->priv->bus_type, cancellable, error);
1406 : 0 : if (manager->priv->connection == NULL)
1407 : 0 : goto out;
1408 : : }
1409 : :
1410 : 8 : proxy_flags = G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES;
1411 : 8 : if (manager->priv->flags & G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START)
1412 : 2 : proxy_flags |= G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START;
1413 : :
1414 : 16 : manager->priv->control_proxy = g_dbus_proxy_new_sync (manager->priv->connection,
1415 : : proxy_flags,
1416 : : NULL, /* GDBusInterfaceInfo* */
1417 : 8 : manager->priv->name,
1418 : 8 : manager->priv->object_path,
1419 : : DBUS_INTERFACE_OBJECT_MANAGER,
1420 : : cancellable,
1421 : : error);
1422 : 8 : if (manager->priv->control_proxy == NULL)
1423 : 0 : goto out;
1424 : :
1425 : : /* Use weak refs here. The @control_proxy will emit its signals in the current
1426 : : * #GMainContext (since we constructed it just above). However, the user may
1427 : : * drop the last external reference to this #GDBusObjectManagerClient in
1428 : : * another thread between a signal being emitted and scheduled in an idle
1429 : : * callback in this #GMainContext, and that idle callback being invoked. We
1430 : : * can’t use a strong reference here, as there’s no
1431 : : * g_dbus_object_manager_client_disconnect() (or similar) method to tell us
1432 : : * when the last external reference to this object has been dropped, so we
1433 : : * can’t break a strong reference count cycle. So use weak refs. */
1434 : 16 : manager->priv->name_owner_signal_id =
1435 : 8 : g_signal_connect_data (G_OBJECT (manager->priv->control_proxy),
1436 : : "notify::g-name-owner",
1437 : : G_CALLBACK (on_notify_g_name_owner),
1438 : 8 : weak_ref_new (G_OBJECT (manager)),
1439 : : (GClosureNotify) weak_ref_free,
1440 : : G_CONNECT_DEFAULT);
1441 : :
1442 : 16 : manager->priv->signal_signal_id =
1443 : 8 : g_signal_connect_data (manager->priv->control_proxy,
1444 : : "g-signal",
1445 : : G_CALLBACK (on_control_proxy_g_signal),
1446 : 8 : weak_ref_new (G_OBJECT (manager)),
1447 : : (GClosureNotify) weak_ref_free,
1448 : : G_CONNECT_DEFAULT);
1449 : :
1450 : 8 : manager->priv->name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy);
1451 : 8 : if (manager->priv->name_owner == NULL && manager->priv->name != NULL)
1452 : : {
1453 : : /* it's perfectly fine if there's no name owner.. we're just going to
1454 : : * wait until one is ready
1455 : : */
1456 : : }
1457 : : else
1458 : : {
1459 : : /* yay, we can get the objects */
1460 : 8 : subscribe_signals (manager,
1461 : 8 : manager->priv->name_owner);
1462 : 8 : value = g_dbus_proxy_call_sync (manager->priv->control_proxy,
1463 : : "GetManagedObjects",
1464 : : NULL, /* parameters */
1465 : : G_DBUS_CALL_FLAGS_NONE,
1466 : : -1,
1467 : : cancellable,
1468 : : error);
1469 : 8 : if (value == NULL)
1470 : : {
1471 : 3 : maybe_unsubscribe_signals (manager);
1472 : :
1473 : 3 : g_warn_if_fail (manager->priv->signal_signal_id != 0);
1474 : 3 : g_signal_handler_disconnect (manager->priv->control_proxy,
1475 : 3 : manager->priv->signal_signal_id);
1476 : 3 : manager->priv->signal_signal_id = 0;
1477 : :
1478 : 3 : g_warn_if_fail (manager->priv->name_owner_signal_id != 0);
1479 : 3 : g_signal_handler_disconnect (manager->priv->control_proxy,
1480 : 3 : manager->priv->name_owner_signal_id);
1481 : 3 : manager->priv->name_owner_signal_id = 0;
1482 : :
1483 : 3 : g_object_unref (manager->priv->control_proxy);
1484 : 3 : manager->priv->control_proxy = NULL;
1485 : :
1486 : 3 : goto out;
1487 : : }
1488 : :
1489 : 5 : process_get_all_result (manager, value, manager->priv->name_owner);
1490 : 5 : g_variant_unref (value);
1491 : : }
1492 : :
1493 : 5 : ret = TRUE;
1494 : :
1495 : 8 : out:
1496 : 8 : return ret;
1497 : : }
1498 : :
1499 : : static void
1500 : 5 : initable_iface_init (GInitableIface *initable_iface)
1501 : : {
1502 : 5 : initable_iface->init = initable_init;
1503 : 5 : }
1504 : :
1505 : : static void
1506 : 5 : async_initable_iface_init (GAsyncInitableIface *async_initable_iface)
1507 : : {
1508 : : /* for now, just use default: run GInitable code in thread */
1509 : 5 : }
1510 : :
1511 : : /* ---------------------------------------------------------------------------------------------------- */
1512 : :
1513 : : static void
1514 : 25 : add_interfaces (GDBusObjectManagerClient *manager,
1515 : : const gchar *object_path,
1516 : : GVariant *ifaces_and_properties,
1517 : : const gchar *name_owner)
1518 : : {
1519 : : GDBusObjectProxy *op;
1520 : : gboolean added;
1521 : : GVariantIter iter;
1522 : : const gchar *interface_name;
1523 : : GVariant *properties;
1524 : : GList *interface_added_signals, *l;
1525 : : GDBusProxy *interface_proxy;
1526 : :
1527 : 25 : g_return_if_fail (name_owner == NULL || g_dbus_is_unique_name (name_owner));
1528 : :
1529 : 25 : g_mutex_lock (&manager->priv->lock);
1530 : :
1531 : 25 : interface_added_signals = NULL;
1532 : 25 : added = FALSE;
1533 : :
1534 : 25 : op = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1535 : 25 : if (op == NULL)
1536 : : {
1537 : : GType object_proxy_type;
1538 : 22 : if (manager->priv->get_proxy_type_func != NULL)
1539 : : {
1540 : 18 : object_proxy_type = manager->priv->get_proxy_type_func (manager,
1541 : : object_path,
1542 : : NULL,
1543 : 18 : manager->priv->get_proxy_type_user_data);
1544 : 18 : g_warn_if_fail (g_type_is_a (object_proxy_type, G_TYPE_DBUS_OBJECT_PROXY));
1545 : : }
1546 : : else
1547 : : {
1548 : 4 : object_proxy_type = G_TYPE_DBUS_OBJECT_PROXY;
1549 : : }
1550 : 22 : op = g_object_new (object_proxy_type,
1551 : 22 : "g-connection", manager->priv->connection,
1552 : : "g-object-path", object_path,
1553 : : NULL);
1554 : 22 : added = TRUE;
1555 : : }
1556 : 25 : g_object_ref (op);
1557 : :
1558 : 25 : g_variant_iter_init (&iter, ifaces_and_properties);
1559 : 53 : while (g_variant_iter_next (&iter,
1560 : : "{&s@a{sv}}",
1561 : : &interface_name,
1562 : : &properties))
1563 : : {
1564 : : GError *error;
1565 : : GType interface_proxy_type;
1566 : :
1567 : 28 : if (manager->priv->get_proxy_type_func != NULL)
1568 : : {
1569 : 24 : interface_proxy_type = manager->priv->get_proxy_type_func (manager,
1570 : : object_path,
1571 : : interface_name,
1572 : 24 : manager->priv->get_proxy_type_user_data);
1573 : 24 : g_warn_if_fail (g_type_is_a (interface_proxy_type, G_TYPE_DBUS_PROXY));
1574 : : }
1575 : : else
1576 : : {
1577 : 4 : interface_proxy_type = G_TYPE_DBUS_PROXY;
1578 : : }
1579 : :
1580 : : /* this is fine - there is no blocking IO because we pass DO_NOT_LOAD_PROPERTIES and
1581 : : * DO_NOT_CONNECT_SIGNALS and use a unique name
1582 : : */
1583 : 28 : error = NULL;
1584 : 28 : interface_proxy = g_initable_new (interface_proxy_type,
1585 : : NULL, /* GCancellable */
1586 : : &error,
1587 : 28 : "g-connection", manager->priv->connection,
1588 : : "g-flags", G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
1589 : : G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
1590 : : "g-name", name_owner,
1591 : : "g-object-path", object_path,
1592 : : "g-interface-name", interface_name,
1593 : : NULL);
1594 : 28 : if (interface_proxy == NULL)
1595 : : {
1596 : 0 : g_warning ("%s: Error constructing proxy for path %s and interface %s: %s",
1597 : : G_STRLOC,
1598 : : object_path,
1599 : : interface_name,
1600 : : error->message);
1601 : 0 : g_error_free (error);
1602 : : }
1603 : : else
1604 : : {
1605 : : GVariantIter property_iter;
1606 : : const gchar *property_name;
1607 : : GVariant *property_value;
1608 : :
1609 : : /* associate the interface proxy with the object */
1610 : 28 : g_dbus_interface_set_object (G_DBUS_INTERFACE (interface_proxy),
1611 : 28 : G_DBUS_OBJECT (op));
1612 : :
1613 : 28 : g_variant_iter_init (&property_iter, properties);
1614 : 438 : while (g_variant_iter_next (&property_iter,
1615 : : "{&sv}",
1616 : : &property_name,
1617 : : &property_value))
1618 : : {
1619 : 410 : g_dbus_proxy_set_cached_property (interface_proxy,
1620 : : property_name,
1621 : : property_value);
1622 : 410 : g_variant_unref (property_value);
1623 : : }
1624 : :
1625 : 28 : _g_dbus_object_proxy_add_interface (op, interface_proxy);
1626 : 28 : if (!added)
1627 : 3 : interface_added_signals = g_list_append (interface_added_signals, g_object_ref (interface_proxy));
1628 : 28 : g_object_unref (interface_proxy);
1629 : : }
1630 : 28 : g_variant_unref (properties);
1631 : : }
1632 : :
1633 : 25 : if (added)
1634 : : {
1635 : 22 : g_hash_table_insert (manager->priv->map_object_path_to_object_proxy,
1636 : 22 : g_strdup (object_path),
1637 : : op);
1638 : : }
1639 : :
1640 : 25 : g_mutex_unlock (&manager->priv->lock);
1641 : :
1642 : : /* now that we don't hold the lock any more, emit signals */
1643 : 25 : g_object_ref (manager);
1644 : 28 : for (l = interface_added_signals; l != NULL; l = l->next)
1645 : : {
1646 : 3 : interface_proxy = G_DBUS_PROXY (l->data);
1647 : 3 : g_signal_emit_by_name (manager, "interface-added", op, interface_proxy);
1648 : 3 : g_object_unref (interface_proxy);
1649 : : }
1650 : 25 : g_list_free (interface_added_signals);
1651 : :
1652 : 25 : if (added)
1653 : 22 : g_signal_emit_by_name (manager, "object-added", op);
1654 : :
1655 : 25 : g_object_unref (manager);
1656 : 25 : g_object_unref (op);
1657 : : }
1658 : :
1659 : : static void
1660 : 15 : remove_interfaces (GDBusObjectManagerClient *manager,
1661 : : const gchar *object_path,
1662 : : const gchar *const *interface_names)
1663 : : {
1664 : : GDBusObjectProxy *op;
1665 : : GList *interfaces;
1666 : : guint n;
1667 : : guint num_interfaces;
1668 : : guint num_interfaces_to_remove;
1669 : :
1670 : 15 : g_mutex_lock (&manager->priv->lock);
1671 : :
1672 : 15 : op = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1673 : 15 : if (op == NULL)
1674 : : {
1675 : 0 : g_debug ("%s: Processing InterfaceRemoved signal for path %s but no object proxy exists",
1676 : : G_STRLOC,
1677 : : object_path);
1678 : 0 : g_mutex_unlock (&manager->priv->lock);
1679 : 0 : return;
1680 : : }
1681 : :
1682 : 15 : interfaces = g_dbus_object_get_interfaces (G_DBUS_OBJECT (op));
1683 : 15 : num_interfaces = g_list_length (interfaces);
1684 : 15 : g_list_free_full (interfaces, g_object_unref);
1685 : :
1686 : 15 : num_interfaces_to_remove = g_strv_length ((gchar **) interface_names);
1687 : :
1688 : : /* see if we are going to completety remove the object */
1689 : 15 : g_object_ref (manager);
1690 : 15 : if (num_interfaces_to_remove == num_interfaces)
1691 : : {
1692 : 12 : g_object_ref (op);
1693 : 12 : g_warn_if_fail (g_hash_table_remove (manager->priv->map_object_path_to_object_proxy, object_path));
1694 : 12 : g_mutex_unlock (&manager->priv->lock);
1695 : 12 : g_signal_emit_by_name (manager, "object-removed", op);
1696 : 12 : g_object_unref (op);
1697 : : }
1698 : : else
1699 : : {
1700 : 3 : g_object_ref (op);
1701 : 3 : g_mutex_unlock (&manager->priv->lock);
1702 : 6 : for (n = 0; interface_names != NULL && interface_names[n] != NULL; n++)
1703 : : {
1704 : : GDBusInterface *interface;
1705 : 3 : interface = g_dbus_object_get_interface (G_DBUS_OBJECT (op), interface_names[n]);
1706 : 3 : _g_dbus_object_proxy_remove_interface (op, interface_names[n]);
1707 : 3 : if (interface != NULL)
1708 : : {
1709 : 3 : g_signal_emit_by_name (manager, "interface-removed", op, interface);
1710 : 3 : g_object_unref (interface);
1711 : : }
1712 : : }
1713 : 3 : g_object_unref (op);
1714 : : }
1715 : 15 : g_object_unref (manager);
1716 : : }
1717 : :
1718 : : static void
1719 : 5 : process_get_all_result (GDBusObjectManagerClient *manager,
1720 : : GVariant *value,
1721 : : const gchar *name_owner)
1722 : : {
1723 : : GVariant *arg0;
1724 : : const gchar *object_path;
1725 : : GVariant *ifaces_and_properties;
1726 : : GVariantIter iter;
1727 : :
1728 : 5 : g_return_if_fail (name_owner == NULL || g_dbus_is_unique_name (name_owner));
1729 : :
1730 : 5 : arg0 = g_variant_get_child_value (value, 0);
1731 : 5 : g_variant_iter_init (&iter, arg0);
1732 : 9 : while (g_variant_iter_next (&iter,
1733 : : "{&o@a{sa{sv}}}",
1734 : : &object_path,
1735 : : &ifaces_and_properties))
1736 : : {
1737 : 4 : add_interfaces (manager, object_path, ifaces_and_properties, name_owner);
1738 : 4 : g_variant_unref (ifaces_and_properties);
1739 : : }
1740 : 5 : g_variant_unref (arg0);
1741 : : }
1742 : :
1743 : : static void
1744 : 36 : on_control_proxy_g_signal (GDBusProxy *proxy,
1745 : : const gchar *sender_name,
1746 : : const gchar *signal_name,
1747 : : GVariant *parameters,
1748 : : gpointer user_data)
1749 : : {
1750 : 36 : GWeakRef *manager_weak = user_data;
1751 : 36 : GDBusObjectManagerClient *manager = NULL;
1752 : : const gchar *object_path;
1753 : :
1754 : 36 : manager = G_DBUS_OBJECT_MANAGER_CLIENT (g_weak_ref_get (manager_weak));
1755 : 36 : if (manager == NULL)
1756 : 0 : return;
1757 : :
1758 : : //g_debug ("yay, g_signal %s: %s\n", signal_name, g_variant_print (parameters, TRUE));
1759 : :
1760 : 36 : if (g_strcmp0 (signal_name, "InterfacesAdded") == 0)
1761 : : {
1762 : : GVariant *ifaces_and_properties;
1763 : 21 : g_variant_get (parameters,
1764 : : "(&o@a{sa{sv}})",
1765 : : &object_path,
1766 : : &ifaces_and_properties);
1767 : 21 : add_interfaces (manager, object_path, ifaces_and_properties, manager->priv->name_owner);
1768 : 21 : g_variant_unref (ifaces_and_properties);
1769 : : }
1770 : 15 : else if (g_strcmp0 (signal_name, "InterfacesRemoved") == 0)
1771 : : {
1772 : : const gchar **ifaces;
1773 : 15 : g_variant_get (parameters,
1774 : : "(&o^a&s)",
1775 : : &object_path,
1776 : : &ifaces);
1777 : 15 : remove_interfaces (manager, object_path, ifaces);
1778 : 15 : g_free (ifaces);
1779 : : }
1780 : :
1781 : 36 : g_object_unref (manager);
1782 : : }
1783 : :
1784 : : /* ---------------------------------------------------------------------------------------------------- */
1785 : :
1786 : : static const gchar *
1787 : 6 : g_dbus_object_manager_client_get_object_path (GDBusObjectManager *_manager)
1788 : : {
1789 : 6 : GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
1790 : 6 : return manager->priv->object_path;
1791 : : }
1792 : :
1793 : : static GDBusObject *
1794 : 16 : g_dbus_object_manager_client_get_object (GDBusObjectManager *_manager,
1795 : : const gchar *object_path)
1796 : : {
1797 : 16 : GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
1798 : : GDBusObject *ret;
1799 : :
1800 : 16 : g_mutex_lock (&manager->priv->lock);
1801 : 16 : ret = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
1802 : 16 : if (ret != NULL)
1803 : 16 : g_object_ref (ret);
1804 : 16 : g_mutex_unlock (&manager->priv->lock);
1805 : 16 : return ret;
1806 : : }
1807 : :
1808 : : static GDBusInterface *
1809 : 10 : g_dbus_object_manager_client_get_interface (GDBusObjectManager *_manager,
1810 : : const gchar *object_path,
1811 : : const gchar *interface_name)
1812 : : {
1813 : : GDBusInterface *ret;
1814 : : GDBusObject *object;
1815 : :
1816 : 10 : ret = NULL;
1817 : :
1818 : 10 : object = g_dbus_object_manager_get_object (_manager, object_path);
1819 : 10 : if (object == NULL)
1820 : 0 : goto out;
1821 : :
1822 : 10 : ret = g_dbus_object_get_interface (object, interface_name);
1823 : 10 : g_object_unref (object);
1824 : :
1825 : 10 : out:
1826 : 10 : return ret;
1827 : : }
1828 : :
1829 : : static GList *
1830 : 6 : g_dbus_object_manager_client_get_objects (GDBusObjectManager *_manager)
1831 : : {
1832 : 6 : GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
1833 : : GList *ret;
1834 : :
1835 : 6 : g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
1836 : :
1837 : 6 : g_mutex_lock (&manager->priv->lock);
1838 : 6 : ret = g_hash_table_get_values (manager->priv->map_object_path_to_object_proxy);
1839 : 6 : g_list_foreach (ret, (GFunc) g_object_ref, NULL);
1840 : 6 : g_mutex_unlock (&manager->priv->lock);
1841 : :
1842 : 6 : return ret;
1843 : : }
1844 : :
1845 : :
1846 : : static void
1847 : 5 : dbus_object_manager_interface_init (GDBusObjectManagerIface *iface)
1848 : : {
1849 : 5 : iface->get_object_path = g_dbus_object_manager_client_get_object_path;
1850 : 5 : iface->get_objects = g_dbus_object_manager_client_get_objects;
1851 : 5 : iface->get_object = g_dbus_object_manager_client_get_object;
1852 : 5 : iface->get_interface = g_dbus_object_manager_client_get_interface;
1853 : 5 : }
1854 : :
1855 : : /* ---------------------------------------------------------------------------------------------------- */
|