Add some more cases to the app-id unit tests
[glib.git] / gio / gdbusobjectmanagerserver.c
blob31bfa859999a78d30caff5387e178859e018119c
1 /* GDBus - GLib D-Bus Library
3 * Copyright (C) 2008-2010 Red Hat, Inc.
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 of the License, or (at your option) any later version.
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.
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/>.
18 * Author: David Zeuthen <davidz@redhat.com>
21 #include "config.h"
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"
33 #include "gioerror.h"
35 #include "glibintl.h"
37 /**
38 * SECTION:gdbusobjectmanagerserver
39 * @short_description: Service-side object manager
40 * @include: gio/gio.h
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.
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).
57 * It is supported, but not recommended, to export an object manager at the root
58 * path, `/`.
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.
66 typedef struct
68 GDBusObjectSkeleton *object;
69 GDBusObjectManagerServer *manager;
70 GHashTable *map_iface_name_to_iface;
71 gboolean exported;
72 } RegistrationData;
74 static void registration_data_free (RegistrationData *data);
76 static void export_all (GDBusObjectManagerServer *manager);
77 static void unexport_all (GDBusObjectManagerServer *manager, gboolean only_manager);
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);
84 static void g_dbus_object_manager_server_emit_interfaces_removed (GDBusObjectManagerServer *manager,
85 RegistrationData *data,
86 const gchar *const *interfaces);
88 static gboolean g_dbus_object_manager_server_unexport_unlocked (GDBusObjectManagerServer *manager,
89 const gchar *object_path);
91 struct _GDBusObjectManagerServerPrivate
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;
101 enum
103 PROP_0,
104 PROP_CONNECTION,
105 PROP_OBJECT_PATH
108 static void dbus_object_manager_interface_init (GDBusObjectManagerIface *iface);
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))
114 static void g_dbus_object_manager_server_constructed (GObject *object);
116 static void
117 g_dbus_object_manager_server_finalize (GObject *object)
119 GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object);
121 if (manager->priv->connection != NULL)
123 unexport_all (manager, TRUE);
124 g_object_unref (manager->priv->connection);
126 g_hash_table_unref (manager->priv->map_object_path_to_data);
127 g_free (manager->priv->object_path);
128 g_free (manager->priv->object_path_ending_in_slash);
130 g_mutex_clear (&manager->priv->lock);
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);
136 static void
137 g_dbus_object_manager_server_get_property (GObject *object,
138 guint prop_id,
139 GValue *value,
140 GParamSpec *pspec)
142 GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object);
144 switch (prop_id)
146 case PROP_CONNECTION:
147 g_mutex_lock (&manager->priv->lock);
148 g_value_set_object (value, manager->priv->connection);
149 g_mutex_unlock (&manager->priv->lock);
150 break;
152 case PROP_OBJECT_PATH:
153 g_value_set_string (value, g_dbus_object_manager_get_object_path (G_DBUS_OBJECT_MANAGER (manager)));
154 break;
156 default:
157 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
158 break;
162 static void
163 g_dbus_object_manager_server_set_property (GObject *object,
164 guint prop_id,
165 const GValue *value,
166 GParamSpec *pspec)
168 GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object);
170 switch (prop_id)
172 case PROP_CONNECTION:
173 g_dbus_object_manager_server_set_connection (manager, g_value_get_object (value));
174 break;
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 (manager->priv->object_path, "/"))
181 manager->priv->object_path_ending_in_slash = g_strdup (manager->priv->object_path);
182 else
183 manager->priv->object_path_ending_in_slash = g_strdup_printf ("%s/", manager->priv->object_path);
184 break;
186 default:
187 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
188 break;
192 static void
193 g_dbus_object_manager_server_class_init (GDBusObjectManagerServerClass *klass)
195 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
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;
203 * GDBusObjectManagerServer:connection:
205 * The #GDBusConnection to export objects on.
207 * Since: 2.30
209 g_object_class_install_property (gobject_class,
210 PROP_CONNECTION,
211 g_param_spec_object ("connection",
212 "Connection",
213 "The connection to export objects on",
214 G_TYPE_DBUS_CONNECTION,
215 G_PARAM_READABLE |
216 G_PARAM_WRITABLE |
217 G_PARAM_STATIC_STRINGS));
220 * GDBusObjectManagerServer:object-path:
222 * The object path to register the manager object at.
224 * Since: 2.30
226 g_object_class_install_property (gobject_class,
227 PROP_OBJECT_PATH,
228 g_param_spec_string ("object-path",
229 "Object Path",
230 "The object path to register the manager object at",
231 NULL,
232 G_PARAM_READABLE |
233 G_PARAM_WRITABLE |
234 G_PARAM_CONSTRUCT_ONLY |
235 G_PARAM_STATIC_STRINGS));
238 static void
239 g_dbus_object_manager_server_init (GDBusObjectManagerServer *manager)
241 manager->priv = g_dbus_object_manager_server_get_instance_private (manager);
242 g_mutex_init (&manager->priv->lock);
243 manager->priv->map_object_path_to_data = g_hash_table_new_full (g_str_hash,
244 g_str_equal,
245 g_free,
246 (GDestroyNotify) registration_data_free);
250 * g_dbus_object_manager_server_new:
251 * @object_path: The object path to export the manager object at.
253 * Creates a new #GDBusObjectManagerServer object.
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.
261 * Returns: A #GDBusObjectManagerServer object. Free with g_object_unref().
263 * Since: 2.30
265 GDBusObjectManagerServer *
266 g_dbus_object_manager_server_new (const gchar *object_path)
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));
275 * g_dbus_object_manager_server_set_connection:
276 * @manager: A #GDBusObjectManagerServer.
277 * @connection: (nullable): A #GDBusConnection or %NULL.
279 * Exports all objects managed by @manager on @connection. If
280 * @connection is %NULL, stops exporting objects.
282 void
283 g_dbus_object_manager_server_set_connection (GDBusObjectManagerServer *manager,
284 GDBusConnection *connection)
286 g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager));
287 g_return_if_fail (connection == NULL || G_IS_DBUS_CONNECTION (connection));
289 g_mutex_lock (&manager->priv->lock);
291 if (manager->priv->connection == connection)
293 g_mutex_unlock (&manager->priv->lock);
294 goto out;
297 if (manager->priv->connection != NULL)
299 unexport_all (manager, FALSE);
300 g_object_unref (manager->priv->connection);
301 manager->priv->connection = NULL;
304 manager->priv->connection = connection != NULL ? g_object_ref (connection) : NULL;
305 if (manager->priv->connection != NULL)
306 export_all (manager);
308 g_mutex_unlock (&manager->priv->lock);
310 g_object_notify (G_OBJECT (manager), "connection");
311 out:
316 * g_dbus_object_manager_server_get_connection:
317 * @manager: A #GDBusObjectManagerServer
319 * Gets the #GDBusConnection used by @manager.
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().
325 * Since: 2.30
327 GDBusConnection *
328 g_dbus_object_manager_server_get_connection (GDBusObjectManagerServer *manager)
330 GDBusConnection *ret;
331 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager), NULL);
332 g_mutex_lock (&manager->priv->lock);
333 ret = manager->priv->connection != NULL ? g_object_ref (manager->priv->connection) : NULL;
334 g_mutex_unlock (&manager->priv->lock);
335 return ret;
338 /* ---------------------------------------------------------------------------------------------------- */
340 static void
341 registration_data_export_interface (RegistrationData *data,
342 GDBusInterfaceSkeleton *interface_skeleton,
343 const gchar *object_path)
345 GDBusInterfaceInfo *info;
346 GError *error;
348 info = g_dbus_interface_skeleton_get_info (interface_skeleton);
349 error = NULL;
350 if (data->manager->priv->connection != NULL)
352 if (!g_dbus_interface_skeleton_export (interface_skeleton,
353 data->manager->priv->connection,
354 object_path,
355 &error))
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);
366 g_assert (g_hash_table_lookup (data->map_iface_name_to_iface, info->name) == NULL);
367 g_hash_table_insert (data->map_iface_name_to_iface,
368 info->name,
369 g_object_ref (interface_skeleton));
371 /* if we are already exported, then... */
372 if (data->exported)
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 (data->manager, data, interfaces, object_path);
382 static void
383 registration_data_unexport_interface (RegistrationData *data,
384 GDBusInterfaceSkeleton *interface_skeleton)
386 GDBusInterfaceInfo *info;
387 GDBusInterfaceSkeleton *iface;
389 info = g_dbus_interface_skeleton_get_info (interface_skeleton);
390 iface = g_hash_table_lookup (data->map_iface_name_to_iface, info->name);
391 g_assert (iface != NULL);
393 if (data->manager->priv->connection != NULL)
394 g_dbus_interface_skeleton_unexport (iface);
396 g_warn_if_fail (g_hash_table_remove (data->map_iface_name_to_iface, info->name));
398 /* if we are already exported, then... */
399 if (data->exported)
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 (data->manager, data, interfaces);
409 /* ---------------------------------------------------------------------------------------------------- */
411 static void
412 on_interface_added (GDBusObject *object,
413 GDBusInterface *interface,
414 gpointer user_data)
416 RegistrationData *data = user_data;
417 const gchar *object_path;
418 g_mutex_lock (&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 (&data->manager->priv->lock);
424 static void
425 on_interface_removed (GDBusObject *object,
426 GDBusInterface *interface,
427 gpointer user_data)
429 RegistrationData *data = user_data;
430 g_mutex_lock (&data->manager->priv->lock);
431 registration_data_unexport_interface (data, G_DBUS_INTERFACE_SKELETON (interface));
432 g_mutex_unlock (&data->manager->priv->lock);
435 /* ---------------------------------------------------------------------------------------------------- */
438 static void
439 registration_data_free (RegistrationData *data)
441 GHashTableIter iter;
442 GDBusInterfaceSkeleton *iface;
444 data->exported = FALSE;
446 g_hash_table_iter_init (&iter, data->map_iface_name_to_iface);
447 while (g_hash_table_iter_next (&iter, NULL, (gpointer) &iface))
449 if (data->manager->priv->connection != NULL)
450 g_dbus_interface_skeleton_unexport (iface);
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 (data->object);
456 g_hash_table_destroy (data->map_iface_name_to_iface);
457 g_free (data);
460 /* ---------------------------------------------------------------------------------------------------- */
462 static void
463 g_dbus_object_manager_server_export_unlocked (GDBusObjectManagerServer *manager,
464 GDBusObjectSkeleton *object,
465 const gchar *object_path)
467 RegistrationData *data;
468 GList *existing_interfaces;
469 GList *l;
470 GPtrArray *interface_names;
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));
476 interface_names = g_ptr_array_new ();
478 data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
479 if (data != NULL)
480 g_dbus_object_manager_server_unexport_unlocked (manager, object_path);
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 (g_str_hash,
486 g_str_equal,
487 NULL,
488 (GDestroyNotify) g_object_unref);
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);
499 /* Register all known interfaces - note that data->exported is FALSE so
500 * we don't emit any InterfacesAdded signals.
502 existing_interfaces = g_dbus_object_get_interfaces (G_DBUS_OBJECT (object));
503 for (l = existing_interfaces; l != NULL; l = l->next)
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 (interface_names, g_dbus_interface_skeleton_get_info (interface_skeleton)->name);
509 g_list_free_full (existing_interfaces, g_object_unref);
510 g_ptr_array_add (interface_names, NULL);
512 data->exported = TRUE;
514 /* now emit InterfacesAdded() for all the interfaces */
515 g_dbus_object_manager_server_emit_interfaces_added (manager, data, (const gchar *const *) interface_names->pdata, object_path);
516 g_ptr_array_unref (interface_names);
518 g_hash_table_insert (manager->priv->map_object_path_to_data,
519 g_strdup (object_path),
520 data);
524 * g_dbus_object_manager_server_export:
525 * @manager: A #GDBusObjectManagerServer.
526 * @object: A #GDBusObjectSkeleton.
528 * Exports @object on @manager.
530 * If there is already a #GDBusObject exported at the object path,
531 * then the old object is removed.
533 * The object path for @object must be in the hierarchy rooted by the
534 * object path for @manager.
536 * Note that @manager will take a reference on @object for as long as
537 * it is exported.
539 * Since: 2.30
541 void
542 g_dbus_object_manager_server_export (GDBusObjectManagerServer *manager,
543 GDBusObjectSkeleton *object)
545 g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager));
546 g_mutex_lock (&manager->priv->lock);
547 g_dbus_object_manager_server_export_unlocked (manager, object,
548 g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
549 g_mutex_unlock (&manager->priv->lock);
553 * g_dbus_object_manager_server_export_uniquely:
554 * @manager: A #GDBusObjectManagerServer.
555 * @object: An object.
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.
562 * Since: 2.30
564 void
565 g_dbus_object_manager_server_export_uniquely (GDBusObjectManagerServer *manager,
566 GDBusObjectSkeleton *object)
568 gchar *orig_object_path;
569 gchar *object_path;
570 guint count;
571 gboolean modified;
573 orig_object_path = g_strdup (g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
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));
579 g_mutex_lock (&manager->priv->lock);
581 object_path = g_strdup (orig_object_path);
582 count = 1;
583 modified = FALSE;
584 while (TRUE)
586 RegistrationData *data;
587 data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
588 if (data == NULL)
590 break;
592 g_free (object_path);
593 object_path = g_strdup_printf ("%s_%d", orig_object_path, count++);
594 modified = TRUE;
597 g_dbus_object_manager_server_export_unlocked (manager, object, object_path);
599 g_mutex_unlock (&manager->priv->lock);
601 if (modified)
602 g_dbus_object_skeleton_set_object_path (G_DBUS_OBJECT_SKELETON (object), object_path);
604 g_free (object_path);
605 g_free (orig_object_path);
610 * g_dbus_object_manager_server_is_exported:
611 * @manager: A #GDBusObjectManagerServer.
612 * @object: An object.
614 * Returns whether @object is currently exported on @manager.
616 * Returns: %TRUE if @object is exported
618 * Since: 2.34
620 gboolean
621 g_dbus_object_manager_server_is_exported (GDBusObjectManagerServer *manager,
622 GDBusObjectSkeleton *object)
624 RegistrationData *data = NULL;
625 const gchar *object_path;
626 gboolean object_is_exported;
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);
631 g_mutex_lock (&manager->priv->lock);
633 object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (object));
634 if (object_path != NULL)
635 data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
636 object_is_exported = (data != NULL);
638 g_mutex_unlock (&manager->priv->lock);
640 return object_is_exported;
643 /* ---------------------------------------------------------------------------------------------------- */
645 static gboolean
646 g_dbus_object_manager_server_unexport_unlocked (GDBusObjectManagerServer *manager,
647 const gchar *object_path)
649 RegistrationData *data;
650 gboolean ret;
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);
656 ret = FALSE;
658 data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
659 if (data != NULL)
661 GPtrArray *interface_names;
662 GHashTableIter iter;
663 const gchar *iface_name;
665 interface_names = g_ptr_array_new ();
666 g_hash_table_iter_init (&iter, data->map_iface_name_to_iface);
667 while (g_hash_table_iter_next (&iter, (gpointer) &iface_name, NULL))
668 g_ptr_array_add (interface_names, (gpointer) iface_name);
669 g_ptr_array_add (interface_names, NULL);
670 /* now emit InterfacesRemoved() for all the interfaces */
671 g_dbus_object_manager_server_emit_interfaces_removed (manager, data, (const gchar *const *) interface_names->pdata);
672 g_ptr_array_unref (interface_names);
674 g_hash_table_remove (manager->priv->map_object_path_to_data, object_path);
675 ret = TRUE;
678 return ret;
682 * g_dbus_object_manager_server_unexport:
683 * @manager: A #GDBusObjectManagerServer.
684 * @object_path: An object path.
686 * If @manager has an object at @path, removes the object. Otherwise
687 * does nothing.
689 * Note that @object_path must be in the hierarchy rooted by the
690 * object path for @manager.
692 * Returns: %TRUE if object at @object_path was removed, %FALSE otherwise.
694 * Since: 2.30
696 gboolean
697 g_dbus_object_manager_server_unexport (GDBusObjectManagerServer *manager,
698 const gchar *object_path)
700 gboolean ret;
701 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager), FALSE);
702 g_mutex_lock (&manager->priv->lock);
703 ret = g_dbus_object_manager_server_unexport_unlocked (manager, object_path);
704 g_mutex_unlock (&manager->priv->lock);
705 return ret;
709 /* ---------------------------------------------------------------------------------------------------- */
711 static const GDBusArgInfo manager_interfaces_added_signal_info_arg0 =
714 "object_path",
715 "o",
716 (GDBusAnnotationInfo**) NULL,
719 static const GDBusArgInfo manager_interfaces_added_signal_info_arg1 =
722 "interfaces_and_properties",
723 "a{sa{sv}}",
724 (GDBusAnnotationInfo**) NULL,
727 static const GDBusArgInfo * const manager_interfaces_added_signal_info_arg_pointers[] =
729 &manager_interfaces_added_signal_info_arg0,
730 &manager_interfaces_added_signal_info_arg1,
731 NULL
734 static const GDBusSignalInfo manager_interfaces_added_signal_info =
737 "InterfacesAdded",
738 (GDBusArgInfo**) &manager_interfaces_added_signal_info_arg_pointers,
739 (GDBusAnnotationInfo**) NULL
742 /* ---------- */
744 static const GDBusArgInfo manager_interfaces_removed_signal_info_arg0 =
747 "object_path",
748 "o",
749 (GDBusAnnotationInfo**) NULL,
752 static const GDBusArgInfo manager_interfaces_removed_signal_info_arg1 =
755 "interfaces",
756 "as",
757 (GDBusAnnotationInfo**) NULL,
760 static const GDBusArgInfo * const manager_interfaces_removed_signal_info_arg_pointers[] =
762 &manager_interfaces_removed_signal_info_arg0,
763 &manager_interfaces_removed_signal_info_arg1,
764 NULL
767 static const GDBusSignalInfo manager_interfaces_removed_signal_info =
770 "InterfacesRemoved",
771 (GDBusArgInfo**) &manager_interfaces_removed_signal_info_arg_pointers,
772 (GDBusAnnotationInfo**) NULL
775 /* ---------- */
777 static const GDBusSignalInfo * const manager_signal_info_pointers[] =
779 &manager_interfaces_added_signal_info,
780 &manager_interfaces_removed_signal_info,
781 NULL
784 /* ---------- */
786 static const GDBusArgInfo manager_get_all_method_info_out_arg0 =
789 "object_paths_interfaces_and_properties",
790 "a{oa{sa{sv}}}",
791 (GDBusAnnotationInfo**) NULL,
794 static const GDBusArgInfo * const manager_get_all_method_info_out_arg_pointers[] =
796 &manager_get_all_method_info_out_arg0,
797 NULL
800 static const GDBusMethodInfo manager_get_all_method_info =
803 "GetManagedObjects",
804 (GDBusArgInfo**) NULL,
805 (GDBusArgInfo**) &manager_get_all_method_info_out_arg_pointers,
806 (GDBusAnnotationInfo**) NULL
809 static const GDBusMethodInfo * const manager_method_info_pointers[] =
811 &manager_get_all_method_info,
812 NULL
815 /* ---------- */
817 static const GDBusInterfaceInfo manager_interface_info =
820 "org.freedesktop.DBus.ObjectManager",
821 (GDBusMethodInfo **) manager_method_info_pointers,
822 (GDBusSignalInfo **) manager_signal_info_pointers,
823 (GDBusPropertyInfo **) NULL,
824 (GDBusAnnotationInfo **) NULL
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)
837 GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (user_data);
838 GVariantBuilder array_builder;
839 GHashTableIter object_iter;
840 RegistrationData *data;
842 g_mutex_lock (&manager->priv->lock);
844 if (g_strcmp0 (method_name, "GetManagedObjects") == 0)
846 g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("a{oa{sa{sv}}}"));
847 g_hash_table_iter_init (&object_iter, manager->priv->map_object_path_to_data);
848 while (g_hash_table_iter_next (&object_iter, NULL, (gpointer) &data))
850 GVariantBuilder interfaces_builder;
851 GHashTableIter interface_iter;
852 GDBusInterfaceSkeleton *iface;
853 const gchar *iter_object_path;
855 g_variant_builder_init (&interfaces_builder, G_VARIANT_TYPE ("a{sa{sv}}"));
856 g_hash_table_iter_init (&interface_iter, data->map_iface_name_to_iface);
857 while (g_hash_table_iter_next (&interface_iter, NULL, (gpointer) &iface))
859 GVariant *properties = g_dbus_interface_skeleton_get_properties (iface);
860 g_variant_builder_add (&interfaces_builder, "{s@a{sv}}",
861 g_dbus_interface_skeleton_get_info (iface)->name,
862 properties);
863 g_variant_unref (properties);
865 iter_object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object));
866 g_variant_builder_add (&array_builder,
867 "{oa{sa{sv}}}",
868 iter_object_path,
869 &interfaces_builder);
872 g_dbus_method_invocation_return_value (invocation,
873 g_variant_new ("(a{oa{sa{sv}}})",
874 &array_builder));
876 else
878 g_dbus_method_invocation_return_error (invocation,
879 G_DBUS_ERROR,
880 G_DBUS_ERROR_UNKNOWN_METHOD,
881 "Unknown method %s - only GetManagedObjects() is supported",
882 method_name);
884 g_mutex_unlock (&manager->priv->lock);
887 static const GDBusInterfaceVTable manager_interface_vtable =
889 manager_method_call, /* handle_method_call */
890 NULL, /* get_property */
891 NULL /* set_property */
894 /* ---------------------------------------------------------------------------------------------------- */
896 static void
897 g_dbus_object_manager_server_constructed (GObject *object)
899 GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object);
901 if (manager->priv->connection != NULL)
902 export_all (manager);
904 if (G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->constructed != NULL)
905 G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->constructed (object);
908 static void
909 g_dbus_object_manager_server_emit_interfaces_added (GDBusObjectManagerServer *manager,
910 RegistrationData *data,
911 const gchar *const *interfaces,
912 const gchar *object_path)
914 GVariantBuilder array_builder;
915 GError *error;
916 guint n;
918 if (data->manager->priv->connection == NULL)
919 goto out;
921 g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("a{sa{sv}}"));
922 for (n = 0; interfaces[n] != NULL; n++)
924 GDBusInterfaceSkeleton *iface;
925 GVariant *properties;
927 iface = g_hash_table_lookup (data->map_iface_name_to_iface, interfaces[n]);
928 g_assert (iface != NULL);
929 properties = g_dbus_interface_skeleton_get_properties (iface);
930 g_variant_builder_add (&array_builder, "{s@a{sv}}", interfaces[n], properties);
931 g_variant_unref (properties);
934 error = NULL;
935 g_dbus_connection_emit_signal (data->manager->priv->connection,
936 NULL, /* destination_bus_name */
937 manager->priv->object_path,
938 manager_interface_info.name,
939 "InterfacesAdded",
940 g_variant_new ("(oa{sa{sv}})",
941 object_path,
942 &array_builder),
943 &error);
944 if (error)
946 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED))
947 g_warning ("Couldn't emit InterfacesAdded signal: %s", error->message);
948 g_error_free (error);
950 out:
954 static void
955 g_dbus_object_manager_server_emit_interfaces_removed (GDBusObjectManagerServer *manager,
956 RegistrationData *data,
957 const gchar *const *interfaces)
959 GVariantBuilder array_builder;
960 GError *error;
961 guint n;
962 const gchar *object_path;
964 if (data->manager->priv->connection == NULL)
965 goto out;
967 g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("as"));
968 for (n = 0; interfaces[n] != NULL; n++)
969 g_variant_builder_add (&array_builder, "s", interfaces[n]);
971 error = NULL;
972 object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object));
973 g_dbus_connection_emit_signal (data->manager->priv->connection,
974 NULL, /* destination_bus_name */
975 manager->priv->object_path,
976 manager_interface_info.name,
977 "InterfacesRemoved",
978 g_variant_new ("(oas)",
979 object_path,
980 &array_builder),
981 &error);
982 if (error)
984 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED))
985 g_warning ("Couldn't emit InterfacesRemoved signal: %s", error->message);
986 g_error_free (error);
988 out:
992 /* ---------------------------------------------------------------------------------------------------- */
994 static GList *
995 g_dbus_object_manager_server_get_objects (GDBusObjectManager *_manager)
997 GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (_manager);
998 GList *ret;
999 GHashTableIter iter;
1000 RegistrationData *data;
1002 g_mutex_lock (&manager->priv->lock);
1004 ret = NULL;
1005 g_hash_table_iter_init (&iter, manager->priv->map_object_path_to_data);
1006 while (g_hash_table_iter_next (&iter, NULL, (gpointer) &data))
1008 ret = g_list_prepend (ret, g_object_ref (data->object));
1011 g_mutex_unlock (&manager->priv->lock);
1013 return ret;
1016 static const gchar *
1017 g_dbus_object_manager_server_get_object_path (GDBusObjectManager *_manager)
1019 GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (_manager);
1020 return manager->priv->object_path;
1023 static GDBusObject *
1024 g_dbus_object_manager_server_get_object (GDBusObjectManager *_manager,
1025 const gchar *object_path)
1027 GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (_manager);
1028 GDBusObject *ret;
1029 RegistrationData *data;
1031 ret = NULL;
1033 g_mutex_lock (&manager->priv->lock);
1034 data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
1035 if (data != NULL)
1036 ret = g_object_ref (data->object);
1037 g_mutex_unlock (&manager->priv->lock);
1039 return ret;
1042 static GDBusInterface *
1043 g_dbus_object_manager_server_get_interface (GDBusObjectManager *_manager,
1044 const gchar *object_path,
1045 const gchar *interface_name)
1047 GDBusInterface *ret;
1048 GDBusObject *object;
1050 ret = NULL;
1052 object = g_dbus_object_manager_get_object (_manager, object_path);
1053 if (object == NULL)
1054 goto out;
1056 ret = g_dbus_object_get_interface (object, interface_name);
1057 g_object_unref (object);
1059 out:
1060 return ret;
1063 static void
1064 dbus_object_manager_interface_init (GDBusObjectManagerIface *iface)
1066 iface->get_object_path = g_dbus_object_manager_server_get_object_path;
1067 iface->get_objects = g_dbus_object_manager_server_get_objects;
1068 iface->get_object = g_dbus_object_manager_server_get_object;
1069 iface->get_interface = g_dbus_object_manager_server_get_interface;
1072 /* ---------------------------------------------------------------------------------------------------- */
1074 static void
1075 export_all (GDBusObjectManagerServer *manager)
1077 GHashTableIter iter;
1078 const gchar *object_path;
1079 RegistrationData *data;
1080 GHashTableIter iface_iter;
1081 GDBusInterfaceSkeleton *iface;
1082 GError *error;
1084 g_return_if_fail (manager->priv->connection != NULL);
1086 error = NULL;
1087 g_warn_if_fail (manager->priv->manager_reg_id == 0);
1088 manager->priv->manager_reg_id = g_dbus_connection_register_object (manager->priv->connection,
1089 manager->priv->object_path,
1090 (GDBusInterfaceInfo *) &manager_interface_info,
1091 &manager_interface_vtable,
1092 manager,
1093 NULL, /* user_data_free_func */
1094 &error);
1095 if (manager->priv->manager_reg_id == 0)
1097 g_warning ("%s: Error registering manager at %s: %s",
1098 G_STRLOC,
1099 manager->priv->object_path,
1100 error->message);
1101 g_error_free (error);
1104 g_hash_table_iter_init (&iter, manager->priv->map_object_path_to_data);
1105 while (g_hash_table_iter_next (&iter, (gpointer) &object_path, (gpointer) &data))
1107 g_hash_table_iter_init (&iface_iter, data->map_iface_name_to_iface);
1108 while (g_hash_table_iter_next (&iface_iter, NULL, (gpointer) &iface))
1110 g_warn_if_fail (g_dbus_interface_skeleton_get_connection (iface) == NULL);
1111 error = NULL;
1112 if (!g_dbus_interface_skeleton_export (iface,
1113 manager->priv->connection,
1114 object_path,
1115 &error))
1117 g_warning ("%s: Error registering object at %s with interface %s: %s",
1118 G_STRLOC,
1119 object_path,
1120 g_dbus_interface_skeleton_get_info (iface)->name,
1121 error->message);
1122 g_error_free (error);
1128 static void
1129 unexport_all (GDBusObjectManagerServer *manager, gboolean only_manager)
1131 GHashTableIter iter;
1132 RegistrationData *data;
1133 GHashTableIter iface_iter;
1134 GDBusInterfaceSkeleton *iface;
1136 g_return_if_fail (manager->priv->connection != NULL);
1138 g_warn_if_fail (manager->priv->manager_reg_id > 0);
1139 if (manager->priv->manager_reg_id > 0)
1141 g_warn_if_fail (g_dbus_connection_unregister_object (manager->priv->connection,
1142 manager->priv->manager_reg_id));
1143 manager->priv->manager_reg_id = 0;
1145 if (only_manager)
1146 goto out;
1148 g_hash_table_iter_init (&iter, manager->priv->map_object_path_to_data);
1149 while (g_hash_table_iter_next (&iter, NULL, (gpointer) &data))
1151 g_hash_table_iter_init (&iface_iter, data->map_iface_name_to_iface);
1152 while (g_hash_table_iter_next (&iface_iter, NULL, (gpointer) &iface))
1154 g_warn_if_fail (g_dbus_interface_skeleton_get_connection (iface) != NULL);
1155 g_dbus_interface_skeleton_unexport (iface);
1158 out:
1162 /* ---------------------------------------------------------------------------------------------------- */