1 | /* GDBus - GLib D-Bus Library |
2 | * |
3 | * Copyright (C) 2008-2010 Red Hat, Inc. |
4 | * |
5 | * This library is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU Lesser General Public |
7 | * License as published by the Free Software Foundation; either |
8 | * version 2.1 of the License, or (at your option) any later version. |
9 | * |
10 | * This library is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | * Lesser General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU Lesser General |
16 | * Public License along with this library; if not, see <http://www.gnu.org/licenses/>. |
17 | * |
18 | * Author: David Zeuthen <davidz@redhat.com> |
19 | */ |
20 | |
21 | #include "config.h" |
22 | |
23 | #include "gdbusobjectmanager.h" |
24 | #include "gdbusobjectmanagerserver.h" |
25 | #include "gdbusobject.h" |
26 | #include "gdbusobjectskeleton.h" |
27 | #include "gdbusinterfaceskeleton.h" |
28 | #include "gdbusconnection.h" |
29 | #include "gdbusintrospection.h" |
30 | #include "gdbusmethodinvocation.h" |
31 | #include "gdbuserror.h" |
32 | |
33 | #include "gioerror.h" |
34 | |
35 | #include "glibintl.h" |
36 | |
37 | /** |
38 | * SECTION:gdbusobjectmanagerserver |
39 | * @short_description: Service-side object manager |
40 | * @include: gio/gio.h |
41 | * |
42 | * #GDBusObjectManagerServer is used to export #GDBusObject instances using |
43 | * the standardized |
44 | * [org.freedesktop.DBus.ObjectManager](http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager) |
45 | * interface. For example, remote D-Bus clients can get all objects |
46 | * and properties in a single call. Additionally, any change in the |
47 | * object hierarchy is broadcast using signals. This means that D-Bus |
48 | * clients can keep caches up to date by only listening to D-Bus |
49 | * signals. |
50 | * |
51 | * The recommended path to export an object manager at is the path form of the |
52 | * well-known name of a D-Bus service, or below. For example, if a D-Bus service |
53 | * is available at the well-known name `net.example.ExampleService1`, the object |
54 | * manager should typically be exported at `/net/example/ExampleService1`, or |
55 | * below (to allow for multiple object managers in a service). |
56 | * |
57 | * It is supported, but not recommended, to export an object manager at the root |
58 | * path, `/`. |
59 | * |
60 | * See #GDBusObjectManagerClient for the client-side code that is |
61 | * intended to be used with #GDBusObjectManagerServer or any D-Bus |
62 | * object implementing the org.freedesktop.DBus.ObjectManager |
63 | * interface. |
64 | */ |
65 | |
66 | typedef struct |
67 | { |
68 | GDBusObjectSkeleton *object; |
69 | GDBusObjectManagerServer *manager; |
70 | GHashTable *map_iface_name_to_iface; |
71 | gboolean exported; |
72 | } RegistrationData; |
73 | |
74 | static void registration_data_free (RegistrationData *data); |
75 | |
76 | static void export_all (GDBusObjectManagerServer *manager); |
77 | static void unexport_all (GDBusObjectManagerServer *manager, gboolean only_manager); |
78 | |
79 | static void g_dbus_object_manager_server_emit_interfaces_added (GDBusObjectManagerServer *manager, |
80 | RegistrationData *data, |
81 | const gchar *const *interfaces, |
82 | const gchar *object_path); |
83 | |
84 | static void g_dbus_object_manager_server_emit_interfaces_removed (GDBusObjectManagerServer *manager, |
85 | RegistrationData *data, |
86 | const gchar *const *interfaces); |
87 | |
88 | static gboolean g_dbus_object_manager_server_unexport_unlocked (GDBusObjectManagerServer *manager, |
89 | const gchar *object_path); |
90 | |
91 | struct _GDBusObjectManagerServerPrivate |
92 | { |
93 | GMutex lock; |
94 | GDBusConnection *connection; |
95 | gchar *object_path; |
96 | gchar *object_path_ending_in_slash; |
97 | GHashTable *map_object_path_to_data; |
98 | guint manager_reg_id; |
99 | }; |
100 | |
101 | enum |
102 | { |
103 | PROP_0, |
104 | PROP_CONNECTION, |
105 | PROP_OBJECT_PATH |
106 | }; |
107 | |
108 | static void dbus_object_manager_interface_init (GDBusObjectManagerIface *iface); |
109 | |
110 | G_DEFINE_TYPE_WITH_CODE (GDBusObjectManagerServer, g_dbus_object_manager_server, G_TYPE_OBJECT, |
111 | G_ADD_PRIVATE (GDBusObjectManagerServer) |
112 | G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_OBJECT_MANAGER, dbus_object_manager_interface_init)) |
113 | |
114 | static void g_dbus_object_manager_server_constructed (GObject *object); |
115 | |
116 | static void |
117 | g_dbus_object_manager_server_finalize (GObject *object) |
118 | { |
119 | GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object); |
120 | |
121 | if (manager->priv->connection != NULL) |
122 | { |
123 | unexport_all (manager, TRUE); |
124 | g_object_unref (object: manager->priv->connection); |
125 | } |
126 | g_hash_table_unref (hash_table: manager->priv->map_object_path_to_data); |
127 | g_free (mem: manager->priv->object_path); |
128 | g_free (mem: manager->priv->object_path_ending_in_slash); |
129 | |
130 | g_mutex_clear (mutex: &manager->priv->lock); |
131 | |
132 | if (G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->finalize != NULL) |
133 | G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->finalize (object); |
134 | } |
135 | |
136 | static void |
137 | g_dbus_object_manager_server_get_property (GObject *object, |
138 | guint prop_id, |
139 | GValue *value, |
140 | GParamSpec *pspec) |
141 | { |
142 | GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object); |
143 | |
144 | switch (prop_id) |
145 | { |
146 | case PROP_CONNECTION: |
147 | g_mutex_lock (mutex: &manager->priv->lock); |
148 | g_value_set_object (value, v_object: manager->priv->connection); |
149 | g_mutex_unlock (mutex: &manager->priv->lock); |
150 | break; |
151 | |
152 | case PROP_OBJECT_PATH: |
153 | g_value_set_string (value, v_string: g_dbus_object_manager_get_object_path (G_DBUS_OBJECT_MANAGER (manager))); |
154 | break; |
155 | |
156 | default: |
157 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
158 | break; |
159 | } |
160 | } |
161 | |
162 | static void |
163 | g_dbus_object_manager_server_set_property (GObject *object, |
164 | guint prop_id, |
165 | const GValue *value, |
166 | GParamSpec *pspec) |
167 | { |
168 | GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object); |
169 | |
170 | switch (prop_id) |
171 | { |
172 | case PROP_CONNECTION: |
173 | g_dbus_object_manager_server_set_connection (manager, connection: g_value_get_object (value)); |
174 | break; |
175 | |
176 | case PROP_OBJECT_PATH: |
177 | g_assert (manager->priv->object_path == NULL); |
178 | g_assert (g_variant_is_object_path (g_value_get_string (value))); |
179 | manager->priv->object_path = g_value_dup_string (value); |
180 | if (g_str_equal (v1: manager->priv->object_path, v2: "/" )) |
181 | manager->priv->object_path_ending_in_slash = g_strdup (str: manager->priv->object_path); |
182 | else |
183 | manager->priv->object_path_ending_in_slash = g_strdup_printf (format: "%s/" , manager->priv->object_path); |
184 | break; |
185 | |
186 | default: |
187 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
188 | break; |
189 | } |
190 | } |
191 | |
192 | static void |
193 | g_dbus_object_manager_server_class_init (GDBusObjectManagerServerClass *klass) |
194 | { |
195 | GObjectClass *gobject_class = G_OBJECT_CLASS (klass); |
196 | |
197 | gobject_class->finalize = g_dbus_object_manager_server_finalize; |
198 | gobject_class->constructed = g_dbus_object_manager_server_constructed; |
199 | gobject_class->set_property = g_dbus_object_manager_server_set_property; |
200 | gobject_class->get_property = g_dbus_object_manager_server_get_property; |
201 | |
202 | /** |
203 | * GDBusObjectManagerServer:connection: |
204 | * |
205 | * The #GDBusConnection to export objects on. |
206 | * |
207 | * Since: 2.30 |
208 | */ |
209 | g_object_class_install_property (oclass: gobject_class, |
210 | property_id: PROP_CONNECTION, |
211 | pspec: g_param_spec_object (name: "connection" , |
212 | nick: "Connection" , |
213 | blurb: "The connection to export objects on" , |
214 | G_TYPE_DBUS_CONNECTION, |
215 | flags: G_PARAM_READABLE | |
216 | G_PARAM_WRITABLE | |
217 | G_PARAM_STATIC_STRINGS)); |
218 | |
219 | /** |
220 | * GDBusObjectManagerServer:object-path: |
221 | * |
222 | * The object path to register the manager object at. |
223 | * |
224 | * Since: 2.30 |
225 | */ |
226 | g_object_class_install_property (oclass: gobject_class, |
227 | property_id: PROP_OBJECT_PATH, |
228 | pspec: g_param_spec_string (name: "object-path" , |
229 | nick: "Object Path" , |
230 | blurb: "The object path to register the manager object at" , |
231 | NULL, |
232 | flags: G_PARAM_READABLE | |
233 | G_PARAM_WRITABLE | |
234 | G_PARAM_CONSTRUCT_ONLY | |
235 | G_PARAM_STATIC_STRINGS)); |
236 | } |
237 | |
238 | static void |
239 | g_dbus_object_manager_server_init (GDBusObjectManagerServer *manager) |
240 | { |
241 | manager->priv = g_dbus_object_manager_server_get_instance_private (self: manager); |
242 | g_mutex_init (mutex: &manager->priv->lock); |
243 | manager->priv->map_object_path_to_data = g_hash_table_new_full (hash_func: g_str_hash, |
244 | key_equal_func: g_str_equal, |
245 | key_destroy_func: g_free, |
246 | value_destroy_func: (GDestroyNotify) registration_data_free); |
247 | } |
248 | |
249 | /** |
250 | * g_dbus_object_manager_server_new: |
251 | * @object_path: The object path to export the manager object at. |
252 | * |
253 | * Creates a new #GDBusObjectManagerServer object. |
254 | * |
255 | * The returned server isn't yet exported on any connection. To do so, |
256 | * use g_dbus_object_manager_server_set_connection(). Normally you |
257 | * want to export all of your objects before doing so to avoid |
258 | * [InterfacesAdded](http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager) |
259 | * signals being emitted. |
260 | * |
261 | * Returns: A #GDBusObjectManagerServer object. Free with g_object_unref(). |
262 | * |
263 | * Since: 2.30 |
264 | */ |
265 | GDBusObjectManagerServer * |
266 | g_dbus_object_manager_server_new (const gchar *object_path) |
267 | { |
268 | g_return_val_if_fail (g_variant_is_object_path (object_path), NULL); |
269 | return G_DBUS_OBJECT_MANAGER_SERVER (g_object_new (G_TYPE_DBUS_OBJECT_MANAGER_SERVER, |
270 | "object-path" , object_path, |
271 | NULL)); |
272 | } |
273 | |
274 | /** |
275 | * g_dbus_object_manager_server_set_connection: |
276 | * @manager: A #GDBusObjectManagerServer. |
277 | * @connection: (nullable): A #GDBusConnection or %NULL. |
278 | * |
279 | * Exports all objects managed by @manager on @connection. If |
280 | * @connection is %NULL, stops exporting objects. |
281 | */ |
282 | void |
283 | g_dbus_object_manager_server_set_connection (GDBusObjectManagerServer *manager, |
284 | GDBusConnection *connection) |
285 | { |
286 | g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager)); |
287 | g_return_if_fail (connection == NULL || G_IS_DBUS_CONNECTION (connection)); |
288 | |
289 | g_mutex_lock (mutex: &manager->priv->lock); |
290 | |
291 | if (manager->priv->connection == connection) |
292 | { |
293 | g_mutex_unlock (mutex: &manager->priv->lock); |
294 | goto out; |
295 | } |
296 | |
297 | if (manager->priv->connection != NULL) |
298 | { |
299 | unexport_all (manager, FALSE); |
300 | g_object_unref (object: manager->priv->connection); |
301 | manager->priv->connection = NULL; |
302 | } |
303 | |
304 | manager->priv->connection = connection != NULL ? g_object_ref (connection) : NULL; |
305 | if (manager->priv->connection != NULL) |
306 | export_all (manager); |
307 | |
308 | g_mutex_unlock (mutex: &manager->priv->lock); |
309 | |
310 | g_object_notify (G_OBJECT (manager), property_name: "connection" ); |
311 | out: |
312 | ; |
313 | } |
314 | |
315 | /** |
316 | * g_dbus_object_manager_server_get_connection: |
317 | * @manager: A #GDBusObjectManagerServer |
318 | * |
319 | * Gets the #GDBusConnection used by @manager. |
320 | * |
321 | * Returns: (transfer full): A #GDBusConnection object or %NULL if |
322 | * @manager isn't exported on a connection. The returned object should |
323 | * be freed with g_object_unref(). |
324 | * |
325 | * Since: 2.30 |
326 | */ |
327 | GDBusConnection * |
328 | g_dbus_object_manager_server_get_connection (GDBusObjectManagerServer *manager) |
329 | { |
330 | GDBusConnection *ret; |
331 | g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager), NULL); |
332 | g_mutex_lock (mutex: &manager->priv->lock); |
333 | ret = manager->priv->connection != NULL ? g_object_ref (manager->priv->connection) : NULL; |
334 | g_mutex_unlock (mutex: &manager->priv->lock); |
335 | return ret; |
336 | } |
337 | |
338 | /* ---------------------------------------------------------------------------------------------------- */ |
339 | |
340 | static void |
341 | registration_data_export_interface (RegistrationData *data, |
342 | GDBusInterfaceSkeleton *interface_skeleton, |
343 | const gchar *object_path) |
344 | { |
345 | GDBusInterfaceInfo *info; |
346 | GError *error; |
347 | |
348 | info = g_dbus_interface_skeleton_get_info (interface_: interface_skeleton); |
349 | error = NULL; |
350 | if (data->manager->priv->connection != NULL) |
351 | { |
352 | if (!g_dbus_interface_skeleton_export (interface_: interface_skeleton, |
353 | connection: data->manager->priv->connection, |
354 | object_path, |
355 | error: &error)) |
356 | { |
357 | g_warning ("%s: Error registering object at %s with interface %s: %s" , |
358 | G_STRLOC, |
359 | object_path, |
360 | info->name, |
361 | error->message); |
362 | g_error_free (error); |
363 | } |
364 | } |
365 | |
366 | g_assert (g_hash_table_lookup (data->map_iface_name_to_iface, info->name) == NULL); |
367 | g_hash_table_insert (hash_table: data->map_iface_name_to_iface, |
368 | key: info->name, |
369 | g_object_ref (interface_skeleton)); |
370 | |
371 | /* if we are already exported, then... */ |
372 | if (data->exported) |
373 | { |
374 | const gchar *interfaces[2]; |
375 | /* emit InterfacesAdded on the ObjectManager object */ |
376 | interfaces[0] = info->name; |
377 | interfaces[1] = NULL; |
378 | g_dbus_object_manager_server_emit_interfaces_added (manager: data->manager, data, interfaces, object_path); |
379 | } |
380 | } |
381 | |
382 | static void |
383 | registration_data_unexport_interface (RegistrationData *data, |
384 | GDBusInterfaceSkeleton *interface_skeleton) |
385 | { |
386 | GDBusInterfaceInfo *info; |
387 | GDBusInterfaceSkeleton *iface; |
388 | |
389 | info = g_dbus_interface_skeleton_get_info (interface_: interface_skeleton); |
390 | iface = g_hash_table_lookup (hash_table: data->map_iface_name_to_iface, key: info->name); |
391 | g_assert (iface != NULL); |
392 | |
393 | if (data->manager->priv->connection != NULL) |
394 | g_dbus_interface_skeleton_unexport (interface_: iface); |
395 | |
396 | g_warn_if_fail (g_hash_table_remove (data->map_iface_name_to_iface, info->name)); |
397 | |
398 | /* if we are already exported, then... */ |
399 | if (data->exported) |
400 | { |
401 | const gchar *interfaces[2]; |
402 | /* emit InterfacesRemoved on the ObjectManager object */ |
403 | interfaces[0] = info->name; |
404 | interfaces[1] = NULL; |
405 | g_dbus_object_manager_server_emit_interfaces_removed (manager: data->manager, data, interfaces); |
406 | } |
407 | } |
408 | |
409 | /* ---------------------------------------------------------------------------------------------------- */ |
410 | |
411 | static void |
412 | on_interface_added (GDBusObject *object, |
413 | GDBusInterface *interface, |
414 | gpointer user_data) |
415 | { |
416 | RegistrationData *data = user_data; |
417 | const gchar *object_path; |
418 | g_mutex_lock (mutex: &data->manager->priv->lock); |
419 | object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object)); |
420 | registration_data_export_interface (data, G_DBUS_INTERFACE_SKELETON (interface), object_path); |
421 | g_mutex_unlock (mutex: &data->manager->priv->lock); |
422 | } |
423 | |
424 | static void |
425 | on_interface_removed (GDBusObject *object, |
426 | GDBusInterface *interface, |
427 | gpointer user_data) |
428 | { |
429 | RegistrationData *data = user_data; |
430 | g_mutex_lock (mutex: &data->manager->priv->lock); |
431 | registration_data_unexport_interface (data, G_DBUS_INTERFACE_SKELETON (interface)); |
432 | g_mutex_unlock (mutex: &data->manager->priv->lock); |
433 | } |
434 | |
435 | /* ---------------------------------------------------------------------------------------------------- */ |
436 | |
437 | |
438 | static void |
439 | registration_data_free (RegistrationData *data) |
440 | { |
441 | GHashTableIter iter; |
442 | GDBusInterfaceSkeleton *iface; |
443 | |
444 | data->exported = FALSE; |
445 | |
446 | g_hash_table_iter_init (iter: &iter, hash_table: data->map_iface_name_to_iface); |
447 | while (g_hash_table_iter_next (iter: &iter, NULL, value: (gpointer) &iface)) |
448 | { |
449 | if (data->manager->priv->connection != NULL) |
450 | g_dbus_interface_skeleton_unexport (interface_: iface); |
451 | } |
452 | |
453 | g_signal_handlers_disconnect_by_func (data->object, G_CALLBACK (on_interface_added), data); |
454 | g_signal_handlers_disconnect_by_func (data->object, G_CALLBACK (on_interface_removed), data); |
455 | g_object_unref (object: data->object); |
456 | g_hash_table_destroy (hash_table: data->map_iface_name_to_iface); |
457 | g_free (mem: data); |
458 | } |
459 | |
460 | /* ---------------------------------------------------------------------------------------------------- */ |
461 | |
462 | static void |
463 | g_dbus_object_manager_server_export_unlocked (GDBusObjectManagerServer *manager, |
464 | GDBusObjectSkeleton *object, |
465 | const gchar *object_path) |
466 | { |
467 | RegistrationData *data; |
468 | GList *existing_interfaces; |
469 | GList *l; |
470 | GPtrArray *interface_names; |
471 | |
472 | g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager)); |
473 | g_return_if_fail (G_IS_DBUS_OBJECT (object)); |
474 | g_return_if_fail (g_str_has_prefix (object_path, manager->priv->object_path_ending_in_slash)); |
475 | |
476 | interface_names = g_ptr_array_new (); |
477 | |
478 | data = g_hash_table_lookup (hash_table: manager->priv->map_object_path_to_data, key: object_path); |
479 | if (data != NULL) |
480 | g_dbus_object_manager_server_unexport_unlocked (manager, object_path); |
481 | |
482 | data = g_new0 (RegistrationData, 1); |
483 | data->object = g_object_ref (object); |
484 | data->manager = manager; |
485 | data->map_iface_name_to_iface = g_hash_table_new_full (hash_func: g_str_hash, |
486 | key_equal_func: g_str_equal, |
487 | NULL, |
488 | value_destroy_func: (GDestroyNotify) g_object_unref); |
489 | |
490 | g_signal_connect (object, |
491 | "interface-added" , |
492 | G_CALLBACK (on_interface_added), |
493 | data); |
494 | g_signal_connect (object, |
495 | "interface-removed" , |
496 | G_CALLBACK (on_interface_removed), |
497 | data); |
498 | |
499 | /* Register all known interfaces - note that data->exported is FALSE so |
500 | * we don't emit any InterfacesAdded signals. |
501 | */ |
502 | existing_interfaces = g_dbus_object_get_interfaces (G_DBUS_OBJECT (object)); |
503 | for (l = existing_interfaces; l != NULL; l = l->next) |
504 | { |
505 | GDBusInterfaceSkeleton *interface_skeleton = G_DBUS_INTERFACE_SKELETON (l->data); |
506 | registration_data_export_interface (data, interface_skeleton, object_path); |
507 | g_ptr_array_add (array: interface_names, data: g_dbus_interface_skeleton_get_info (interface_: interface_skeleton)->name); |
508 | } |
509 | g_list_free_full (list: existing_interfaces, free_func: g_object_unref); |
510 | g_ptr_array_add (array: interface_names, NULL); |
511 | |
512 | data->exported = TRUE; |
513 | |
514 | /* now emit InterfacesAdded() for all the interfaces */ |
515 | g_dbus_object_manager_server_emit_interfaces_added (manager, data, interfaces: (const gchar *const *) interface_names->pdata, object_path); |
516 | g_ptr_array_unref (array: interface_names); |
517 | |
518 | g_hash_table_insert (hash_table: manager->priv->map_object_path_to_data, |
519 | key: g_strdup (str: object_path), |
520 | value: data); |
521 | } |
522 | |
523 | /** |
524 | * g_dbus_object_manager_server_export: |
525 | * @manager: A #GDBusObjectManagerServer. |
526 | * @object: A #GDBusObjectSkeleton. |
527 | * |
528 | * Exports @object on @manager. |
529 | * |
530 | * If there is already a #GDBusObject exported at the object path, |
531 | * then the old object is removed. |
532 | * |
533 | * The object path for @object must be in the hierarchy rooted by the |
534 | * object path for @manager. |
535 | * |
536 | * Note that @manager will take a reference on @object for as long as |
537 | * it is exported. |
538 | * |
539 | * Since: 2.30 |
540 | */ |
541 | void |
542 | g_dbus_object_manager_server_export (GDBusObjectManagerServer *manager, |
543 | GDBusObjectSkeleton *object) |
544 | { |
545 | g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager)); |
546 | g_mutex_lock (mutex: &manager->priv->lock); |
547 | g_dbus_object_manager_server_export_unlocked (manager, object, |
548 | object_path: g_dbus_object_get_object_path (G_DBUS_OBJECT (object))); |
549 | g_mutex_unlock (mutex: &manager->priv->lock); |
550 | } |
551 | |
552 | /** |
553 | * g_dbus_object_manager_server_export_uniquely: |
554 | * @manager: A #GDBusObjectManagerServer. |
555 | * @object: An object. |
556 | * |
557 | * Like g_dbus_object_manager_server_export() but appends a string of |
558 | * the form _N (with N being a natural number) to @object's object path |
559 | * if an object with the given path already exists. As such, the |
560 | * #GDBusObjectProxy:g-object-path property of @object may be modified. |
561 | * |
562 | * Since: 2.30 |
563 | */ |
564 | void |
565 | g_dbus_object_manager_server_export_uniquely (GDBusObjectManagerServer *manager, |
566 | GDBusObjectSkeleton *object) |
567 | { |
568 | gchar *orig_object_path; |
569 | gchar *object_path; |
570 | guint count; |
571 | gboolean modified; |
572 | |
573 | orig_object_path = g_strdup (str: g_dbus_object_get_object_path (G_DBUS_OBJECT (object))); |
574 | |
575 | g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager)); |
576 | g_return_if_fail (G_IS_DBUS_OBJECT (object)); |
577 | g_return_if_fail (g_str_has_prefix (orig_object_path, manager->priv->object_path_ending_in_slash)); |
578 | |
579 | g_mutex_lock (mutex: &manager->priv->lock); |
580 | |
581 | object_path = g_strdup (str: orig_object_path); |
582 | count = 1; |
583 | modified = FALSE; |
584 | while (TRUE) |
585 | { |
586 | RegistrationData *data; |
587 | data = g_hash_table_lookup (hash_table: manager->priv->map_object_path_to_data, key: object_path); |
588 | if (data == NULL) |
589 | { |
590 | break; |
591 | } |
592 | g_free (mem: object_path); |
593 | object_path = g_strdup_printf (format: "%s_%d" , orig_object_path, count++); |
594 | modified = TRUE; |
595 | } |
596 | |
597 | g_dbus_object_manager_server_export_unlocked (manager, object, object_path); |
598 | |
599 | g_mutex_unlock (mutex: &manager->priv->lock); |
600 | |
601 | if (modified) |
602 | g_dbus_object_skeleton_set_object_path (G_DBUS_OBJECT_SKELETON (object), object_path); |
603 | |
604 | g_free (mem: object_path); |
605 | g_free (mem: orig_object_path); |
606 | |
607 | } |
608 | |
609 | /** |
610 | * g_dbus_object_manager_server_is_exported: |
611 | * @manager: A #GDBusObjectManagerServer. |
612 | * @object: An object. |
613 | * |
614 | * Returns whether @object is currently exported on @manager. |
615 | * |
616 | * Returns: %TRUE if @object is exported |
617 | * |
618 | * Since: 2.34 |
619 | **/ |
620 | gboolean |
621 | g_dbus_object_manager_server_is_exported (GDBusObjectManagerServer *manager, |
622 | GDBusObjectSkeleton *object) |
623 | { |
624 | RegistrationData *data = NULL; |
625 | const gchar *object_path; |
626 | gboolean object_is_exported; |
627 | |
628 | g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager), FALSE); |
629 | g_return_val_if_fail (G_IS_DBUS_OBJECT (object), FALSE); |
630 | |
631 | g_mutex_lock (mutex: &manager->priv->lock); |
632 | |
633 | object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (object)); |
634 | if (object_path != NULL) |
635 | data = g_hash_table_lookup (hash_table: manager->priv->map_object_path_to_data, key: object_path); |
636 | object_is_exported = (data != NULL); |
637 | |
638 | g_mutex_unlock (mutex: &manager->priv->lock); |
639 | |
640 | return object_is_exported; |
641 | } |
642 | |
643 | /* ---------------------------------------------------------------------------------------------------- */ |
644 | |
645 | static gboolean |
646 | g_dbus_object_manager_server_unexport_unlocked (GDBusObjectManagerServer *manager, |
647 | const gchar *object_path) |
648 | { |
649 | RegistrationData *data; |
650 | gboolean ret; |
651 | |
652 | g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager), FALSE); |
653 | g_return_val_if_fail (g_variant_is_object_path (object_path), FALSE); |
654 | g_return_val_if_fail (g_str_has_prefix (object_path, manager->priv->object_path_ending_in_slash), FALSE); |
655 | |
656 | ret = FALSE; |
657 | |
658 | data = g_hash_table_lookup (hash_table: manager->priv->map_object_path_to_data, key: object_path); |
659 | if (data != NULL) |
660 | { |
661 | GPtrArray *interface_names; |
662 | GHashTableIter iter; |
663 | const gchar *iface_name; |
664 | |
665 | interface_names = g_ptr_array_new (); |
666 | g_hash_table_iter_init (iter: &iter, hash_table: data->map_iface_name_to_iface); |
667 | while (g_hash_table_iter_next (iter: &iter, key: (gpointer) &iface_name, NULL)) |
668 | g_ptr_array_add (array: interface_names, data: (gpointer) iface_name); |
669 | g_ptr_array_add (array: interface_names, NULL); |
670 | /* now emit InterfacesRemoved() for all the interfaces */ |
671 | g_dbus_object_manager_server_emit_interfaces_removed (manager, data, interfaces: (const gchar *const *) interface_names->pdata); |
672 | g_ptr_array_unref (array: interface_names); |
673 | |
674 | g_hash_table_remove (hash_table: manager->priv->map_object_path_to_data, key: object_path); |
675 | ret = TRUE; |
676 | } |
677 | |
678 | return ret; |
679 | } |
680 | |
681 | /** |
682 | * g_dbus_object_manager_server_unexport: |
683 | * @manager: A #GDBusObjectManagerServer. |
684 | * @object_path: An object path. |
685 | * |
686 | * If @manager has an object at @path, removes the object. Otherwise |
687 | * does nothing. |
688 | * |
689 | * Note that @object_path must be in the hierarchy rooted by the |
690 | * object path for @manager. |
691 | * |
692 | * Returns: %TRUE if object at @object_path was removed, %FALSE otherwise. |
693 | * |
694 | * Since: 2.30 |
695 | */ |
696 | gboolean |
697 | g_dbus_object_manager_server_unexport (GDBusObjectManagerServer *manager, |
698 | const gchar *object_path) |
699 | { |
700 | gboolean ret; |
701 | g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager), FALSE); |
702 | g_mutex_lock (mutex: &manager->priv->lock); |
703 | ret = g_dbus_object_manager_server_unexport_unlocked (manager, object_path); |
704 | g_mutex_unlock (mutex: &manager->priv->lock); |
705 | return ret; |
706 | } |
707 | |
708 | |
709 | /* ---------------------------------------------------------------------------------------------------- */ |
710 | |
711 | static const GDBusArgInfo manager_interfaces_added_signal_info_arg0 = |
712 | { |
713 | -1, |
714 | "object_path" , |
715 | "o" , |
716 | (GDBusAnnotationInfo**) NULL, |
717 | }; |
718 | |
719 | static const GDBusArgInfo manager_interfaces_added_signal_info_arg1 = |
720 | { |
721 | -1, |
722 | "interfaces_and_properties" , |
723 | "a{sa{sv}}" , |
724 | (GDBusAnnotationInfo**) NULL, |
725 | }; |
726 | |
727 | static const GDBusArgInfo * const manager_interfaces_added_signal_info_arg_pointers[] = |
728 | { |
729 | &manager_interfaces_added_signal_info_arg0, |
730 | &manager_interfaces_added_signal_info_arg1, |
731 | NULL |
732 | }; |
733 | |
734 | static const GDBusSignalInfo manager_interfaces_added_signal_info = |
735 | { |
736 | -1, |
737 | "InterfacesAdded" , |
738 | (GDBusArgInfo**) &manager_interfaces_added_signal_info_arg_pointers, |
739 | (GDBusAnnotationInfo**) NULL |
740 | }; |
741 | |
742 | /* ---------- */ |
743 | |
744 | static const GDBusArgInfo manager_interfaces_removed_signal_info_arg0 = |
745 | { |
746 | -1, |
747 | "object_path" , |
748 | "o" , |
749 | (GDBusAnnotationInfo**) NULL, |
750 | }; |
751 | |
752 | static const GDBusArgInfo manager_interfaces_removed_signal_info_arg1 = |
753 | { |
754 | -1, |
755 | "interfaces" , |
756 | "as" , |
757 | (GDBusAnnotationInfo**) NULL, |
758 | }; |
759 | |
760 | static const GDBusArgInfo * const manager_interfaces_removed_signal_info_arg_pointers[] = |
761 | { |
762 | &manager_interfaces_removed_signal_info_arg0, |
763 | &manager_interfaces_removed_signal_info_arg1, |
764 | NULL |
765 | }; |
766 | |
767 | static const GDBusSignalInfo manager_interfaces_removed_signal_info = |
768 | { |
769 | -1, |
770 | "InterfacesRemoved" , |
771 | (GDBusArgInfo**) &manager_interfaces_removed_signal_info_arg_pointers, |
772 | (GDBusAnnotationInfo**) NULL |
773 | }; |
774 | |
775 | /* ---------- */ |
776 | |
777 | static const GDBusSignalInfo * const manager_signal_info_pointers[] = |
778 | { |
779 | &manager_interfaces_added_signal_info, |
780 | &manager_interfaces_removed_signal_info, |
781 | NULL |
782 | }; |
783 | |
784 | /* ---------- */ |
785 | |
786 | static const GDBusArgInfo manager_get_all_method_info_out_arg0 = |
787 | { |
788 | -1, |
789 | "object_paths_interfaces_and_properties" , |
790 | "a{oa{sa{sv}}}" , |
791 | (GDBusAnnotationInfo**) NULL, |
792 | }; |
793 | |
794 | static const GDBusArgInfo * const manager_get_all_method_info_out_arg_pointers[] = |
795 | { |
796 | &manager_get_all_method_info_out_arg0, |
797 | NULL |
798 | }; |
799 | |
800 | static const GDBusMethodInfo manager_get_all_method_info = |
801 | { |
802 | -1, |
803 | "GetManagedObjects" , |
804 | (GDBusArgInfo**) NULL, |
805 | (GDBusArgInfo**) &manager_get_all_method_info_out_arg_pointers, |
806 | (GDBusAnnotationInfo**) NULL |
807 | }; |
808 | |
809 | static const GDBusMethodInfo * const manager_method_info_pointers[] = |
810 | { |
811 | &manager_get_all_method_info, |
812 | NULL |
813 | }; |
814 | |
815 | /* ---------- */ |
816 | |
817 | static const GDBusInterfaceInfo manager_interface_info = |
818 | { |
819 | -1, |
820 | "org.freedesktop.DBus.ObjectManager" , |
821 | (GDBusMethodInfo **) manager_method_info_pointers, |
822 | (GDBusSignalInfo **) manager_signal_info_pointers, |
823 | (GDBusPropertyInfo **) NULL, |
824 | (GDBusAnnotationInfo **) NULL |
825 | }; |
826 | |
827 | static void |
828 | manager_method_call (GDBusConnection *connection, |
829 | const gchar *sender, |
830 | const gchar *object_path, |
831 | const gchar *interface_name, |
832 | const gchar *method_name, |
833 | GVariant *parameters, |
834 | GDBusMethodInvocation *invocation, |
835 | gpointer user_data) |
836 | { |
837 | GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (user_data); |
838 | GVariantBuilder array_builder; |
839 | GHashTableIter object_iter; |
840 | RegistrationData *data; |
841 | |
842 | g_mutex_lock (mutex: &manager->priv->lock); |
843 | |
844 | if (g_strcmp0 (str1: method_name, str2: "GetManagedObjects" ) == 0) |
845 | { |
846 | g_variant_builder_init (builder: &array_builder, G_VARIANT_TYPE ("a{oa{sa{sv}}}" )); |
847 | g_hash_table_iter_init (iter: &object_iter, hash_table: manager->priv->map_object_path_to_data); |
848 | while (g_hash_table_iter_next (iter: &object_iter, NULL, value: (gpointer) &data)) |
849 | { |
850 | GVariantBuilder interfaces_builder; |
851 | GHashTableIter interface_iter; |
852 | GDBusInterfaceSkeleton *iface; |
853 | const gchar *iter_object_path; |
854 | |
855 | g_variant_builder_init (builder: &interfaces_builder, G_VARIANT_TYPE ("a{sa{sv}}" )); |
856 | g_hash_table_iter_init (iter: &interface_iter, hash_table: data->map_iface_name_to_iface); |
857 | while (g_hash_table_iter_next (iter: &interface_iter, NULL, value: (gpointer) &iface)) |
858 | { |
859 | GVariant *properties = g_dbus_interface_skeleton_get_properties (interface_: iface); |
860 | g_variant_builder_add (builder: &interfaces_builder, format_string: "{s@a{sv}}" , |
861 | g_dbus_interface_skeleton_get_info (interface_: iface)->name, |
862 | properties); |
863 | g_variant_unref (value: properties); |
864 | } |
865 | iter_object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object)); |
866 | g_variant_builder_add (builder: &array_builder, |
867 | format_string: "{oa{sa{sv}}}" , |
868 | iter_object_path, |
869 | &interfaces_builder); |
870 | } |
871 | |
872 | g_dbus_method_invocation_return_value (invocation, |
873 | parameters: g_variant_new (format_string: "(a{oa{sa{sv}}})" , |
874 | &array_builder)); |
875 | } |
876 | else |
877 | { |
878 | g_dbus_method_invocation_return_error (invocation, |
879 | G_DBUS_ERROR, |
880 | code: G_DBUS_ERROR_UNKNOWN_METHOD, |
881 | format: "Unknown method %s - only GetManagedObjects() is supported" , |
882 | method_name); |
883 | } |
884 | g_mutex_unlock (mutex: &manager->priv->lock); |
885 | } |
886 | |
887 | static const GDBusInterfaceVTable manager_interface_vtable = |
888 | { |
889 | manager_method_call, /* handle_method_call */ |
890 | NULL, /* get_property */ |
891 | NULL, /* set_property */ |
892 | { 0 } |
893 | }; |
894 | |
895 | /* ---------------------------------------------------------------------------------------------------- */ |
896 | |
897 | static void |
898 | g_dbus_object_manager_server_constructed (GObject *object) |
899 | { |
900 | GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object); |
901 | |
902 | if (manager->priv->connection != NULL) |
903 | export_all (manager); |
904 | |
905 | if (G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->constructed != NULL) |
906 | G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->constructed (object); |
907 | } |
908 | |
909 | static void |
910 | g_dbus_object_manager_server_emit_interfaces_added (GDBusObjectManagerServer *manager, |
911 | RegistrationData *data, |
912 | const gchar *const *interfaces, |
913 | const gchar *object_path) |
914 | { |
915 | GVariantBuilder array_builder; |
916 | GError *error; |
917 | guint n; |
918 | |
919 | if (data->manager->priv->connection == NULL) |
920 | goto out; |
921 | |
922 | g_variant_builder_init (builder: &array_builder, G_VARIANT_TYPE ("a{sa{sv}}" )); |
923 | for (n = 0; interfaces[n] != NULL; n++) |
924 | { |
925 | GDBusInterfaceSkeleton *iface; |
926 | GVariant *properties; |
927 | |
928 | iface = g_hash_table_lookup (hash_table: data->map_iface_name_to_iface, key: interfaces[n]); |
929 | g_assert (iface != NULL); |
930 | properties = g_dbus_interface_skeleton_get_properties (interface_: iface); |
931 | g_variant_builder_add (builder: &array_builder, format_string: "{s@a{sv}}" , interfaces[n], properties); |
932 | g_variant_unref (value: properties); |
933 | } |
934 | |
935 | error = NULL; |
936 | g_dbus_connection_emit_signal (connection: data->manager->priv->connection, |
937 | NULL, /* destination_bus_name */ |
938 | object_path: manager->priv->object_path, |
939 | interface_name: manager_interface_info.name, |
940 | signal_name: "InterfacesAdded" , |
941 | parameters: g_variant_new (format_string: "(oa{sa{sv}})" , |
942 | object_path, |
943 | &array_builder), |
944 | error: &error); |
945 | if (error) |
946 | { |
947 | if (!g_error_matches (error, G_IO_ERROR, code: G_IO_ERROR_CLOSED)) |
948 | g_warning ("Couldn't emit InterfacesAdded signal: %s" , error->message); |
949 | g_error_free (error); |
950 | } |
951 | out: |
952 | ; |
953 | } |
954 | |
955 | static void |
956 | g_dbus_object_manager_server_emit_interfaces_removed (GDBusObjectManagerServer *manager, |
957 | RegistrationData *data, |
958 | const gchar *const *interfaces) |
959 | { |
960 | GVariantBuilder array_builder; |
961 | GError *error; |
962 | guint n; |
963 | const gchar *object_path; |
964 | |
965 | if (data->manager->priv->connection == NULL) |
966 | goto out; |
967 | |
968 | g_variant_builder_init (builder: &array_builder, G_VARIANT_TYPE ("as" )); |
969 | for (n = 0; interfaces[n] != NULL; n++) |
970 | g_variant_builder_add (builder: &array_builder, format_string: "s" , interfaces[n]); |
971 | |
972 | error = NULL; |
973 | object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object)); |
974 | g_dbus_connection_emit_signal (connection: data->manager->priv->connection, |
975 | NULL, /* destination_bus_name */ |
976 | object_path: manager->priv->object_path, |
977 | interface_name: manager_interface_info.name, |
978 | signal_name: "InterfacesRemoved" , |
979 | parameters: g_variant_new (format_string: "(oas)" , |
980 | object_path, |
981 | &array_builder), |
982 | error: &error); |
983 | if (error) |
984 | { |
985 | if (!g_error_matches (error, G_IO_ERROR, code: G_IO_ERROR_CLOSED)) |
986 | g_warning ("Couldn't emit InterfacesRemoved signal: %s" , error->message); |
987 | g_error_free (error); |
988 | } |
989 | out: |
990 | ; |
991 | } |
992 | |
993 | /* ---------------------------------------------------------------------------------------------------- */ |
994 | |
995 | static GList * |
996 | g_dbus_object_manager_server_get_objects (GDBusObjectManager *_manager) |
997 | { |
998 | GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (_manager); |
999 | GList *ret; |
1000 | GHashTableIter iter; |
1001 | RegistrationData *data; |
1002 | |
1003 | g_mutex_lock (mutex: &manager->priv->lock); |
1004 | |
1005 | ret = NULL; |
1006 | g_hash_table_iter_init (iter: &iter, hash_table: manager->priv->map_object_path_to_data); |
1007 | while (g_hash_table_iter_next (iter: &iter, NULL, value: (gpointer) &data)) |
1008 | { |
1009 | ret = g_list_prepend (list: ret, g_object_ref (data->object)); |
1010 | } |
1011 | |
1012 | g_mutex_unlock (mutex: &manager->priv->lock); |
1013 | |
1014 | return ret; |
1015 | } |
1016 | |
1017 | static const gchar * |
1018 | g_dbus_object_manager_server_get_object_path (GDBusObjectManager *_manager) |
1019 | { |
1020 | GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (_manager); |
1021 | return manager->priv->object_path; |
1022 | } |
1023 | |
1024 | static GDBusObject * |
1025 | g_dbus_object_manager_server_get_object (GDBusObjectManager *_manager, |
1026 | const gchar *object_path) |
1027 | { |
1028 | GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (_manager); |
1029 | GDBusObject *ret; |
1030 | RegistrationData *data; |
1031 | |
1032 | ret = NULL; |
1033 | |
1034 | g_mutex_lock (mutex: &manager->priv->lock); |
1035 | data = g_hash_table_lookup (hash_table: manager->priv->map_object_path_to_data, key: object_path); |
1036 | if (data != NULL) |
1037 | ret = g_object_ref (G_DBUS_OBJECT (data->object)); |
1038 | g_mutex_unlock (mutex: &manager->priv->lock); |
1039 | |
1040 | return ret; |
1041 | } |
1042 | |
1043 | static GDBusInterface * |
1044 | g_dbus_object_manager_server_get_interface (GDBusObjectManager *_manager, |
1045 | const gchar *object_path, |
1046 | const gchar *interface_name) |
1047 | { |
1048 | GDBusInterface *ret; |
1049 | GDBusObject *object; |
1050 | |
1051 | ret = NULL; |
1052 | |
1053 | object = g_dbus_object_manager_get_object (manager: _manager, object_path); |
1054 | if (object == NULL) |
1055 | goto out; |
1056 | |
1057 | ret = g_dbus_object_get_interface (object, interface_name); |
1058 | g_object_unref (object); |
1059 | |
1060 | out: |
1061 | return ret; |
1062 | } |
1063 | |
1064 | static void |
1065 | dbus_object_manager_interface_init (GDBusObjectManagerIface *iface) |
1066 | { |
1067 | iface->get_object_path = g_dbus_object_manager_server_get_object_path; |
1068 | iface->get_objects = g_dbus_object_manager_server_get_objects; |
1069 | iface->get_object = g_dbus_object_manager_server_get_object; |
1070 | iface->get_interface = g_dbus_object_manager_server_get_interface; |
1071 | } |
1072 | |
1073 | /* ---------------------------------------------------------------------------------------------------- */ |
1074 | |
1075 | static void |
1076 | export_all (GDBusObjectManagerServer *manager) |
1077 | { |
1078 | GHashTableIter iter; |
1079 | const gchar *object_path; |
1080 | RegistrationData *data; |
1081 | GHashTableIter iface_iter; |
1082 | GDBusInterfaceSkeleton *iface; |
1083 | GError *error; |
1084 | |
1085 | g_return_if_fail (manager->priv->connection != NULL); |
1086 | |
1087 | error = NULL; |
1088 | g_warn_if_fail (manager->priv->manager_reg_id == 0); |
1089 | manager->priv->manager_reg_id = g_dbus_connection_register_object (connection: manager->priv->connection, |
1090 | object_path: manager->priv->object_path, |
1091 | interface_info: (GDBusInterfaceInfo *) &manager_interface_info, |
1092 | vtable: &manager_interface_vtable, |
1093 | user_data: manager, |
1094 | NULL, /* user_data_free_func */ |
1095 | error: &error); |
1096 | if (manager->priv->manager_reg_id == 0) |
1097 | { |
1098 | g_warning ("%s: Error registering manager at %s: %s" , |
1099 | G_STRLOC, |
1100 | manager->priv->object_path, |
1101 | error->message); |
1102 | g_error_free (error); |
1103 | } |
1104 | |
1105 | g_hash_table_iter_init (iter: &iter, hash_table: manager->priv->map_object_path_to_data); |
1106 | while (g_hash_table_iter_next (iter: &iter, key: (gpointer) &object_path, value: (gpointer) &data)) |
1107 | { |
1108 | g_hash_table_iter_init (iter: &iface_iter, hash_table: data->map_iface_name_to_iface); |
1109 | while (g_hash_table_iter_next (iter: &iface_iter, NULL, value: (gpointer) &iface)) |
1110 | { |
1111 | g_warn_if_fail (g_dbus_interface_skeleton_get_connection (iface) == NULL); |
1112 | error = NULL; |
1113 | if (!g_dbus_interface_skeleton_export (interface_: iface, |
1114 | connection: manager->priv->connection, |
1115 | object_path, |
1116 | error: &error)) |
1117 | { |
1118 | g_warning ("%s: Error registering object at %s with interface %s: %s" , |
1119 | G_STRLOC, |
1120 | object_path, |
1121 | g_dbus_interface_skeleton_get_info (iface)->name, |
1122 | error->message); |
1123 | g_error_free (error); |
1124 | } |
1125 | } |
1126 | } |
1127 | } |
1128 | |
1129 | static void |
1130 | unexport_all (GDBusObjectManagerServer *manager, gboolean only_manager) |
1131 | { |
1132 | GHashTableIter iter; |
1133 | RegistrationData *data; |
1134 | GHashTableIter iface_iter; |
1135 | GDBusInterfaceSkeleton *iface; |
1136 | |
1137 | g_return_if_fail (manager->priv->connection != NULL); |
1138 | |
1139 | g_warn_if_fail (manager->priv->manager_reg_id > 0); |
1140 | if (manager->priv->manager_reg_id > 0) |
1141 | { |
1142 | g_warn_if_fail (g_dbus_connection_unregister_object (manager->priv->connection, |
1143 | manager->priv->manager_reg_id)); |
1144 | manager->priv->manager_reg_id = 0; |
1145 | } |
1146 | if (only_manager) |
1147 | goto out; |
1148 | |
1149 | g_hash_table_iter_init (iter: &iter, hash_table: manager->priv->map_object_path_to_data); |
1150 | while (g_hash_table_iter_next (iter: &iter, NULL, value: (gpointer) &data)) |
1151 | { |
1152 | g_hash_table_iter_init (iter: &iface_iter, hash_table: data->map_iface_name_to_iface); |
1153 | while (g_hash_table_iter_next (iter: &iface_iter, NULL, value: (gpointer) &iface)) |
1154 | { |
1155 | g_warn_if_fail (g_dbus_interface_skeleton_get_connection (iface) != NULL); |
1156 | g_dbus_interface_skeleton_unexport (interface_: iface); |
1157 | } |
1158 | } |
1159 | out: |
1160 | ; |
1161 | } |
1162 | |
1163 | /* ---------------------------------------------------------------------------------------------------- */ |
1164 | |