mirror of
				https://gitlab.gnome.org/GNOME/glib.git
				synced 2025-10-31 16:32:18 +01:00 
			
		
		
		
	All uses of g_variant_builder_init() in gio are safe to translate to the new g_variant_builder_init_static() alternative as the type will outlive the call to g_variant_builder_end() (or is already static in nature).
		
			
				
	
	
		
			1190 lines
		
	
	
		
			40 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1190 lines
		
	
	
		
			40 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* GDBus - GLib D-Bus Library
 | |
|  *
 | |
|  * Copyright (C) 2008-2010 Red Hat, Inc.
 | |
|  *
 | |
|  * SPDX-License-Identifier: LGPL-2.1-or-later
 | |
|  *
 | |
|  * This library is free software; you can redistribute it and/or
 | |
|  * modify it under the terms of the GNU Lesser General Public
 | |
|  * License as published by the Free Software Foundation; either
 | |
|  * version 2.1 of the License, or (at your option) any later version.
 | |
|  *
 | |
|  * This library is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
|  * Lesser General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU Lesser General
 | |
|  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | |
|  *
 | |
|  * Author: David Zeuthen <davidz@redhat.com>
 | |
|  */
 | |
| 
 | |
| #include "config.h"
 | |
| 
 | |
| #include "gdbusobjectmanager.h"
 | |
| #include "gdbusobjectmanagerserver.h"
 | |
| #include "gdbusobject.h"
 | |
| #include "gdbusobjectskeleton.h"
 | |
| #include "gdbusinterfaceskeleton.h"
 | |
| #include "gdbusconnection.h"
 | |
| #include "gdbusintrospection.h"
 | |
| #include "gdbusmethodinvocation.h"
 | |
| #include "gdbuserror.h"
 | |
| 
 | |
| #include "gioerror.h"
 | |
| 
 | |
| #include "gdbusprivate.h"
 | |
| 
 | |
| #include "glibintl.h"
 | |
| 
 | |
| /**
 | |
|  * GDBusObjectManagerServer:
 | |
|  *
 | |
|  * `GDBusObjectManagerServer` is used to export [iface@Gio.DBusObject] instances
 | |
|  * using the standardized
 | |
|  * [`org.freedesktop.DBus.ObjectManager`](http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager)
 | |
|  * interface. For example, remote D-Bus clients can get all objects
 | |
|  * and properties in a single call. Additionally, any change in the
 | |
|  * object hierarchy is broadcast using signals. This means that D-Bus
 | |
|  * clients can keep caches up to date by only listening to D-Bus
 | |
|  * signals.
 | |
|  *
 | |
|  * The recommended path to export an object manager at is the path form of the
 | |
|  * well-known name of a D-Bus service, or below. For example, if a D-Bus service
 | |
|  * is available at the well-known name `net.example.ExampleService1`, the object
 | |
|  * manager should typically be exported at `/net/example/ExampleService1`, or
 | |
|  * below (to allow for multiple object managers in a service).
 | |
|  *
 | |
|  * It is supported, but not recommended, to export an object manager at the root
 | |
|  * path, `/`.
 | |
|  *
 | |
|  * See [class@Gio.DBusObjectManagerClient] for the client-side code that is
 | |
|  * intended to be used with `GDBusObjectManagerServer` or any D-Bus
 | |
|  * object implementing the `org.freedesktop.DBus.ObjectManager` interface.
 | |
|  *
 | |
|  * Since: 2.30
 | |
|  */
 | |
| 
 | |
| typedef struct
 | |
| {
 | |
|   GDBusObjectSkeleton *object;
 | |
|   GDBusObjectManagerServer *manager;
 | |
|   GHashTable *map_iface_name_to_iface;
 | |
|   gboolean exported;
 | |
| } RegistrationData;
 | |
| 
 | |
| static void registration_data_free (RegistrationData *data);
 | |
| 
 | |
| static void export_all (GDBusObjectManagerServer *manager);
 | |
| static void unexport_all (GDBusObjectManagerServer *manager, gboolean only_manager);
 | |
| 
 | |
| static void g_dbus_object_manager_server_emit_interfaces_added (GDBusObjectManagerServer *manager,
 | |
|                                                          RegistrationData   *data,
 | |
|                                                          const gchar *const *interfaces,
 | |
|                                                          const gchar *object_path);
 | |
| 
 | |
| static void g_dbus_object_manager_server_emit_interfaces_removed (GDBusObjectManagerServer *manager,
 | |
|                                                            RegistrationData   *data,
 | |
|                                                            const gchar *const *interfaces);
 | |
| 
 | |
| static gboolean g_dbus_object_manager_server_unexport_unlocked (GDBusObjectManagerServer  *manager,
 | |
|                                                                 const gchar               *object_path);
 | |
| 
 | |
| struct _GDBusObjectManagerServerPrivate
 | |
| {
 | |
|   GMutex lock;
 | |
|   GDBusConnection *connection;
 | |
|   gchar *object_path;
 | |
|   gchar *object_path_ending_in_slash;
 | |
|   GHashTable *map_object_path_to_data;
 | |
|   guint manager_reg_id;
 | |
| };
 | |
| 
 | |
| enum
 | |
| {
 | |
|   PROP_0,
 | |
|   PROP_CONNECTION,
 | |
|   PROP_OBJECT_PATH
 | |
| };
 | |
| 
 | |
| static void dbus_object_manager_interface_init (GDBusObjectManagerIface *iface);
 | |
| 
 | |
| G_DEFINE_TYPE_WITH_CODE (GDBusObjectManagerServer, g_dbus_object_manager_server, G_TYPE_OBJECT,
 | |
|                          G_ADD_PRIVATE (GDBusObjectManagerServer)
 | |
|                          G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_OBJECT_MANAGER, dbus_object_manager_interface_init))
 | |
| 
 | |
| static void g_dbus_object_manager_server_constructed (GObject *object);
 | |
| 
 | |
| static void
 | |
| g_dbus_object_manager_server_finalize (GObject *object)
 | |
| {
 | |
|   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object);
 | |
| 
 | |
|   if (manager->priv->connection != NULL)
 | |
|     {
 | |
|       unexport_all (manager, TRUE);
 | |
|       g_object_unref (manager->priv->connection);
 | |
|     }
 | |
|   g_hash_table_unref (manager->priv->map_object_path_to_data);
 | |
|   g_free (manager->priv->object_path);
 | |
|   g_free (manager->priv->object_path_ending_in_slash);
 | |
| 
 | |
|   g_mutex_clear (&manager->priv->lock);
 | |
| 
 | |
|   if (G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->finalize != NULL)
 | |
|     G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->finalize (object);
 | |
| }
 | |
| 
 | |
| static void
 | |
| g_dbus_object_manager_server_get_property (GObject    *object,
 | |
|                                            guint       prop_id,
 | |
|                                            GValue     *value,
 | |
|                                            GParamSpec *pspec)
 | |
| {
 | |
|   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object);
 | |
| 
 | |
|   switch (prop_id)
 | |
|     {
 | |
|     case PROP_CONNECTION:
 | |
|       g_mutex_lock (&manager->priv->lock);
 | |
|       g_value_set_object (value, manager->priv->connection);
 | |
|       g_mutex_unlock (&manager->priv->lock);
 | |
|       break;
 | |
| 
 | |
|     case PROP_OBJECT_PATH:
 | |
|       g_value_set_string (value, g_dbus_object_manager_get_object_path (G_DBUS_OBJECT_MANAGER (manager)));
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | |
|       break;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| g_dbus_object_manager_server_set_property (GObject       *object,
 | |
|                                            guint          prop_id,
 | |
|                                            const GValue  *value,
 | |
|                                            GParamSpec    *pspec)
 | |
| {
 | |
|   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object);
 | |
| 
 | |
|   switch (prop_id)
 | |
|     {
 | |
|     case PROP_CONNECTION:
 | |
|       g_dbus_object_manager_server_set_connection (manager, g_value_get_object (value));
 | |
|       break;
 | |
| 
 | |
|     case PROP_OBJECT_PATH:
 | |
|       g_assert (manager->priv->object_path == NULL);
 | |
|       g_assert (g_variant_is_object_path (g_value_get_string (value)));
 | |
|       manager->priv->object_path = g_value_dup_string (value);
 | |
|       if (g_str_equal (manager->priv->object_path, "/"))
 | |
|         manager->priv->object_path_ending_in_slash = g_strdup (manager->priv->object_path);
 | |
|       else
 | |
|         manager->priv->object_path_ending_in_slash = g_strdup_printf ("%s/", manager->priv->object_path);
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | |
|       break;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| g_dbus_object_manager_server_class_init (GDBusObjectManagerServerClass *klass)
 | |
| {
 | |
|   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 | |
| 
 | |
|   gobject_class->finalize     = g_dbus_object_manager_server_finalize;
 | |
|   gobject_class->constructed  = g_dbus_object_manager_server_constructed;
 | |
|   gobject_class->set_property = g_dbus_object_manager_server_set_property;
 | |
|   gobject_class->get_property = g_dbus_object_manager_server_get_property;
 | |
| 
 | |
|   /**
 | |
|    * GDBusObjectManagerServer:connection:
 | |
|    *
 | |
|    * The #GDBusConnection to export objects on.
 | |
|    *
 | |
|    * Since: 2.30
 | |
|    */
 | |
|   g_object_class_install_property (gobject_class,
 | |
|                                    PROP_CONNECTION,
 | |
|                                    g_param_spec_object ("connection", NULL, NULL,
 | |
|                                                         G_TYPE_DBUS_CONNECTION,
 | |
|                                                         G_PARAM_READABLE |
 | |
|                                                         G_PARAM_WRITABLE |
 | |
|                                                         G_PARAM_STATIC_STRINGS));
 | |
| 
 | |
|   /**
 | |
|    * GDBusObjectManagerServer:object-path:
 | |
|    *
 | |
|    * The object path to register the manager object at.
 | |
|    *
 | |
|    * Since: 2.30
 | |
|    */
 | |
|   g_object_class_install_property (gobject_class,
 | |
|                                    PROP_OBJECT_PATH,
 | |
|                                    g_param_spec_string ("object-path", NULL, NULL,
 | |
|                                                         NULL,
 | |
|                                                         G_PARAM_READABLE |
 | |
|                                                         G_PARAM_WRITABLE |
 | |
|                                                         G_PARAM_CONSTRUCT_ONLY |
 | |
|                                                         G_PARAM_STATIC_STRINGS));
 | |
| }
 | |
| 
 | |
| static void
 | |
| g_dbus_object_manager_server_init (GDBusObjectManagerServer *manager)
 | |
| {
 | |
|   manager->priv = g_dbus_object_manager_server_get_instance_private (manager);
 | |
|   g_mutex_init (&manager->priv->lock);
 | |
|   manager->priv->map_object_path_to_data = g_hash_table_new_full (g_str_hash,
 | |
|                                                                   g_str_equal,
 | |
|                                                                   g_free,
 | |
|                                                                   (GDestroyNotify) registration_data_free);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * g_dbus_object_manager_server_new:
 | |
|  * @object_path: The object path to export the manager object at.
 | |
|  *
 | |
|  * Creates a new #GDBusObjectManagerServer object.
 | |
|  *
 | |
|  * The returned server isn't yet exported on any connection. To do so,
 | |
|  * use g_dbus_object_manager_server_set_connection(). Normally you
 | |
|  * want to export all of your objects before doing so to avoid
 | |
|  * [InterfacesAdded](http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager)
 | |
|  * signals being emitted.
 | |
|  *
 | |
|  * Returns: A #GDBusObjectManagerServer object. Free with g_object_unref().
 | |
|  *
 | |
|  * Since: 2.30
 | |
|  */
 | |
| GDBusObjectManagerServer *
 | |
| g_dbus_object_manager_server_new (const gchar     *object_path)
 | |
| {
 | |
|   g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
 | |
|   return G_DBUS_OBJECT_MANAGER_SERVER (g_object_new (G_TYPE_DBUS_OBJECT_MANAGER_SERVER,
 | |
|                                                      "object-path", object_path,
 | |
|                                                      NULL));
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * g_dbus_object_manager_server_set_connection:
 | |
|  * @manager: A #GDBusObjectManagerServer.
 | |
|  * @connection: (nullable): A #GDBusConnection or %NULL.
 | |
|  *
 | |
|  * Exports all objects managed by @manager on @connection. If
 | |
|  * @connection is %NULL, stops exporting objects.
 | |
|  */
 | |
| void
 | |
| g_dbus_object_manager_server_set_connection (GDBusObjectManagerServer  *manager,
 | |
|                                              GDBusConnection           *connection)
 | |
| {
 | |
|   g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager));
 | |
|   g_return_if_fail (connection == NULL || G_IS_DBUS_CONNECTION (connection));
 | |
| 
 | |
|   g_mutex_lock (&manager->priv->lock);
 | |
| 
 | |
|   if (manager->priv->connection == connection)
 | |
|     {
 | |
|       g_mutex_unlock (&manager->priv->lock);
 | |
|       goto out;
 | |
|     }
 | |
| 
 | |
|   if (manager->priv->connection != NULL)
 | |
|     {
 | |
|       unexport_all (manager, FALSE);
 | |
|       g_object_unref (manager->priv->connection);
 | |
|       manager->priv->connection = NULL;
 | |
|     }
 | |
| 
 | |
|   manager->priv->connection = connection != NULL ? g_object_ref (connection) : NULL;
 | |
|   if (manager->priv->connection != NULL)
 | |
|     export_all (manager);
 | |
| 
 | |
|   g_mutex_unlock (&manager->priv->lock);
 | |
| 
 | |
|   g_object_notify (G_OBJECT (manager), "connection");
 | |
|  out:
 | |
|   ;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * g_dbus_object_manager_server_get_connection:
 | |
|  * @manager: A #GDBusObjectManagerServer
 | |
|  *
 | |
|  * Gets the #GDBusConnection used by @manager.
 | |
|  *
 | |
|  * Returns: (transfer full) (nullable): A #GDBusConnection object or %NULL if
 | |
|  *   @manager isn't exported on a connection. The returned object should
 | |
|  *   be freed with g_object_unref().
 | |
|  *
 | |
|  * Since: 2.30
 | |
|  */
 | |
| GDBusConnection *
 | |
| g_dbus_object_manager_server_get_connection (GDBusObjectManagerServer *manager)
 | |
| {
 | |
|   GDBusConnection *ret;
 | |
|   g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager), NULL);
 | |
|   g_mutex_lock (&manager->priv->lock);
 | |
|   ret = manager->priv->connection != NULL ? g_object_ref (manager->priv->connection) : NULL;
 | |
|   g_mutex_unlock (&manager->priv->lock);
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| 
 | |
| static void
 | |
| registration_data_export_interface (RegistrationData        *data,
 | |
|                                     GDBusInterfaceSkeleton  *interface_skeleton,
 | |
|                                     const gchar             *object_path)
 | |
| {
 | |
|   GDBusInterfaceInfo *info;
 | |
|   GError *error;
 | |
| 
 | |
|   info = g_dbus_interface_skeleton_get_info (interface_skeleton);
 | |
|   error = NULL;
 | |
|   if (data->manager->priv->connection != NULL)
 | |
|     {
 | |
|       if (!g_dbus_interface_skeleton_export (interface_skeleton,
 | |
|                                              data->manager->priv->connection,
 | |
|                                              object_path,
 | |
|                                              &error))
 | |
|         {
 | |
|           g_warning ("%s: Error registering object at %s with interface %s: %s",
 | |
|                      G_STRLOC,
 | |
|                      object_path,
 | |
|                      info->name,
 | |
|                      error->message);
 | |
|           g_error_free (error);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|   g_assert (g_hash_table_lookup (data->map_iface_name_to_iface, info->name) == NULL);
 | |
|   g_hash_table_insert (data->map_iface_name_to_iface,
 | |
|                        info->name,
 | |
|                        g_object_ref (interface_skeleton));
 | |
| 
 | |
|   /* if we are already exported, then... */
 | |
|   if (data->exported)
 | |
|     {
 | |
|       const gchar *interfaces[2];
 | |
|       /* emit InterfacesAdded on the ObjectManager object */
 | |
|       interfaces[0] = info->name;
 | |
|       interfaces[1] = NULL;
 | |
|       g_dbus_object_manager_server_emit_interfaces_added (data->manager, data, interfaces, object_path);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| registration_data_unexport_interface (RegistrationData       *data,
 | |
|                                       GDBusInterfaceSkeleton *interface_skeleton)
 | |
| {
 | |
|   GDBusInterfaceInfo *info;
 | |
|   GDBusInterfaceSkeleton *iface;
 | |
| 
 | |
|   info = g_dbus_interface_skeleton_get_info (interface_skeleton);
 | |
|   iface = g_hash_table_lookup (data->map_iface_name_to_iface, info->name);
 | |
|   g_assert (iface != NULL);
 | |
| 
 | |
|   if (data->manager->priv->connection != NULL)
 | |
|     g_dbus_interface_skeleton_unexport (iface);
 | |
| 
 | |
|   g_warn_if_fail (g_hash_table_remove (data->map_iface_name_to_iface, info->name));
 | |
| 
 | |
|   /* if we are already exported, then... */
 | |
|   if (data->exported)
 | |
|     {
 | |
|       const gchar *interfaces[2];
 | |
|       /* emit InterfacesRemoved on the ObjectManager object */
 | |
|       interfaces[0] = info->name;
 | |
|       interfaces[1] = NULL;
 | |
|       g_dbus_object_manager_server_emit_interfaces_removed (data->manager, data, interfaces);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| 
 | |
| static void
 | |
| on_interface_added (GDBusObject    *object,
 | |
|                     GDBusInterface *interface,
 | |
|                     gpointer        user_data)
 | |
| {
 | |
|   RegistrationData *data = user_data;
 | |
|   const gchar *object_path;
 | |
|   g_mutex_lock (&data->manager->priv->lock);
 | |
|   object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object));
 | |
|   registration_data_export_interface (data, G_DBUS_INTERFACE_SKELETON (interface), object_path);
 | |
|   g_mutex_unlock (&data->manager->priv->lock);
 | |
| }
 | |
| 
 | |
| static void
 | |
| on_interface_removed (GDBusObject    *object,
 | |
|                       GDBusInterface *interface,
 | |
|                       gpointer        user_data)
 | |
| {
 | |
|   RegistrationData *data = user_data;
 | |
|   g_mutex_lock (&data->manager->priv->lock);
 | |
|   registration_data_unexport_interface (data, G_DBUS_INTERFACE_SKELETON (interface));
 | |
|   g_mutex_unlock (&data->manager->priv->lock);
 | |
| }
 | |
| 
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| 
 | |
| 
 | |
| static void
 | |
| registration_data_free (RegistrationData *data)
 | |
| {
 | |
|   GHashTableIter iter;
 | |
|   GDBusInterfaceSkeleton *iface;
 | |
| 
 | |
|   data->exported = FALSE;
 | |
| 
 | |
|   g_hash_table_iter_init (&iter, data->map_iface_name_to_iface);
 | |
|   while (g_hash_table_iter_next (&iter, NULL, (gpointer) &iface))
 | |
|     {
 | |
|       if (data->manager->priv->connection != NULL)
 | |
|         g_dbus_interface_skeleton_unexport (iface);
 | |
|     }
 | |
| 
 | |
|   g_signal_handlers_disconnect_by_func (data->object, G_CALLBACK (on_interface_added), data);
 | |
|   g_signal_handlers_disconnect_by_func (data->object, G_CALLBACK (on_interface_removed), data);
 | |
|   g_object_unref (data->object);
 | |
|   g_hash_table_destroy (data->map_iface_name_to_iface);
 | |
|   g_free (data);
 | |
| }
 | |
| 
 | |
| /* Validate whether an object path is valid as a child of the manager. According
 | |
|  * to the specification:
 | |
|  * https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager
 | |
|  * this means that:
 | |
|  * > All returned object paths are children of the object path implementing this
 | |
|  * > interface, i.e. their object paths start with the ObjectManager's object
 | |
|  * > path plus '/'
 | |
|  *
 | |
|  * For example, if the manager is at `/org/gnome/Example`, children will be
 | |
|  * `/org/gnome/Example/(.+)`.
 | |
|  *
 | |
|  * It is permissible (but not encouraged) for the manager to be at `/`. If so,
 | |
|  * children will be `/(.+)`.
 | |
|  */
 | |
| static gboolean
 | |
| is_valid_child_object_path (GDBusObjectManagerServer *manager,
 | |
|                             const gchar              *child_object_path)
 | |
| {
 | |
|   /* Historically GDBus accepted @child_object_paths at `/` if the @manager
 | |
|    * itself is also at `/". This is not spec-compliant, but making GDBus enforce
 | |
|    * the spec more strictly would be an incompatible change.
 | |
|    *
 | |
|    * See https://gitlab.gnome.org/GNOME/glib/-/issues/2500 */
 | |
|   g_warn_if_fail (!g_str_equal (child_object_path, manager->priv->object_path_ending_in_slash));
 | |
| 
 | |
|   return g_str_has_prefix (child_object_path, manager->priv->object_path_ending_in_slash);
 | |
| }
 | |
| 
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| 
 | |
| static void
 | |
| g_dbus_object_manager_server_export_unlocked (GDBusObjectManagerServer  *manager,
 | |
|                                               GDBusObjectSkeleton       *object,
 | |
|                                               const gchar               *object_path)
 | |
| {
 | |
|   RegistrationData *data;
 | |
|   GList *existing_interfaces;
 | |
|   GList *l;
 | |
|   GPtrArray *interface_names;
 | |
| 
 | |
|   g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager));
 | |
|   g_return_if_fail (G_IS_DBUS_OBJECT (object));
 | |
|   g_return_if_fail (is_valid_child_object_path (manager, object_path));
 | |
| 
 | |
|   interface_names = g_ptr_array_new ();
 | |
| 
 | |
|   data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
 | |
|   if (data != NULL)
 | |
|     g_dbus_object_manager_server_unexport_unlocked (manager, object_path);
 | |
| 
 | |
|   data = g_new0 (RegistrationData, 1);
 | |
|   data->object = g_object_ref (object);
 | |
|   data->manager = manager;
 | |
|   data->map_iface_name_to_iface = g_hash_table_new_full (g_str_hash,
 | |
|                                                          g_str_equal,
 | |
|                                                          NULL,
 | |
|                                                          (GDestroyNotify) g_object_unref);
 | |
| 
 | |
|   g_signal_connect (object,
 | |
|                     "interface-added",
 | |
|                     G_CALLBACK (on_interface_added),
 | |
|                     data);
 | |
|   g_signal_connect (object,
 | |
|                     "interface-removed",
 | |
|                     G_CALLBACK (on_interface_removed),
 | |
|                     data);
 | |
| 
 | |
|   /* Register all known interfaces - note that data->exported is FALSE so
 | |
|    * we don't emit any InterfacesAdded signals.
 | |
|    */
 | |
|   existing_interfaces = g_dbus_object_get_interfaces (G_DBUS_OBJECT (object));
 | |
|   for (l = existing_interfaces; l != NULL; l = l->next)
 | |
|     {
 | |
|       GDBusInterfaceSkeleton *interface_skeleton = G_DBUS_INTERFACE_SKELETON (l->data);
 | |
|       registration_data_export_interface (data, interface_skeleton, object_path);
 | |
|       g_ptr_array_add (interface_names, g_dbus_interface_skeleton_get_info (interface_skeleton)->name);
 | |
|     }
 | |
|   g_list_free_full (existing_interfaces, g_object_unref);
 | |
|   g_ptr_array_add (interface_names, NULL);
 | |
| 
 | |
|   data->exported = TRUE;
 | |
| 
 | |
|   /* now emit InterfacesAdded() for all the interfaces */
 | |
|   g_dbus_object_manager_server_emit_interfaces_added (manager, data, (const gchar *const *) interface_names->pdata, object_path);
 | |
|   g_ptr_array_unref (interface_names);
 | |
| 
 | |
|   g_hash_table_insert (manager->priv->map_object_path_to_data,
 | |
|                        g_strdup (object_path),
 | |
|                        data);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * g_dbus_object_manager_server_export:
 | |
|  * @manager: A #GDBusObjectManagerServer.
 | |
|  * @object: A #GDBusObjectSkeleton.
 | |
|  *
 | |
|  * Exports @object on @manager.
 | |
|  *
 | |
|  * If there is already a #GDBusObject exported at the object path,
 | |
|  * then the old object is removed.
 | |
|  *
 | |
|  * The object path for @object must be in the hierarchy rooted by the
 | |
|  * object path for @manager.
 | |
|  *
 | |
|  * Note that @manager will take a reference on @object for as long as
 | |
|  * it is exported.
 | |
|  *
 | |
|  * Since: 2.30
 | |
|  */
 | |
| void
 | |
| g_dbus_object_manager_server_export (GDBusObjectManagerServer  *manager,
 | |
|                                      GDBusObjectSkeleton       *object)
 | |
| {
 | |
|   g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager));
 | |
|   g_mutex_lock (&manager->priv->lock);
 | |
|   g_dbus_object_manager_server_export_unlocked (manager, object,
 | |
|                                                 g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
 | |
|   g_mutex_unlock (&manager->priv->lock);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * g_dbus_object_manager_server_export_uniquely:
 | |
|  * @manager: A #GDBusObjectManagerServer.
 | |
|  * @object: An object.
 | |
|  *
 | |
|  * Like g_dbus_object_manager_server_export() but appends a string of
 | |
|  * the form _N (with N being a natural number) to @object's object path
 | |
|  * if an object with the given path already exists. As such, the
 | |
|  * #GDBusObjectProxy:g-object-path property of @object may be modified.
 | |
|  *
 | |
|  * Since: 2.30
 | |
|  */
 | |
| void
 | |
| g_dbus_object_manager_server_export_uniquely (GDBusObjectManagerServer *manager,
 | |
|                                               GDBusObjectSkeleton      *object)
 | |
| {
 | |
|   const gchar *orig_object_path;
 | |
|   gchar *object_path;
 | |
|   guint count;
 | |
|   gboolean modified;
 | |
| 
 | |
|   orig_object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (object));
 | |
| 
 | |
|   g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager));
 | |
|   g_return_if_fail (G_IS_DBUS_OBJECT (object));
 | |
|   g_return_if_fail (is_valid_child_object_path (manager, orig_object_path));
 | |
| 
 | |
|   g_mutex_lock (&manager->priv->lock);
 | |
| 
 | |
|   object_path = g_strdup (orig_object_path);
 | |
|   count = 1;
 | |
|   modified = FALSE;
 | |
|   while (TRUE)
 | |
|     {
 | |
|       RegistrationData *data;
 | |
|       data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
 | |
|       if (data == NULL)
 | |
|         {
 | |
|           break;
 | |
|         }
 | |
|       g_free (object_path);
 | |
|       object_path = g_strdup_printf ("%s_%d", orig_object_path, count++);
 | |
|       modified = TRUE;
 | |
|     }
 | |
| 
 | |
|   g_dbus_object_manager_server_export_unlocked (manager, object, object_path);
 | |
| 
 | |
|   g_mutex_unlock (&manager->priv->lock);
 | |
| 
 | |
|   if (modified)
 | |
|     g_dbus_object_skeleton_set_object_path (G_DBUS_OBJECT_SKELETON (object), object_path);
 | |
| 
 | |
|   g_free (object_path);
 | |
| 
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * g_dbus_object_manager_server_is_exported:
 | |
|  * @manager: A #GDBusObjectManagerServer.
 | |
|  * @object: An object.
 | |
|  *
 | |
|  * Returns whether @object is currently exported on @manager.
 | |
|  *
 | |
|  * Returns: %TRUE if @object is exported
 | |
|  *
 | |
|  * Since: 2.34
 | |
|  **/
 | |
| gboolean
 | |
| g_dbus_object_manager_server_is_exported (GDBusObjectManagerServer *manager,
 | |
|                                           GDBusObjectSkeleton      *object)
 | |
| {
 | |
|   RegistrationData *data = NULL;
 | |
|   const gchar *object_path;
 | |
|   gboolean object_is_exported;
 | |
| 
 | |
|   g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager), FALSE);
 | |
|   g_return_val_if_fail (G_IS_DBUS_OBJECT (object), FALSE);
 | |
| 
 | |
|   g_mutex_lock (&manager->priv->lock);
 | |
| 
 | |
|   object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (object));
 | |
|   if (object_path != NULL)
 | |
|     data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
 | |
|   object_is_exported = (data != NULL);
 | |
| 
 | |
|   g_mutex_unlock (&manager->priv->lock);
 | |
| 
 | |
|   return object_is_exported;
 | |
| }
 | |
| 
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| 
 | |
| static gboolean
 | |
| g_dbus_object_manager_server_unexport_unlocked (GDBusObjectManagerServer  *manager,
 | |
|                                                 const gchar               *object_path)
 | |
| {
 | |
|   RegistrationData *data;
 | |
|   gboolean ret;
 | |
| 
 | |
|   g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager), FALSE);
 | |
|   g_return_val_if_fail (g_variant_is_object_path (object_path), FALSE);
 | |
|   g_return_val_if_fail (is_valid_child_object_path (manager, object_path), FALSE);
 | |
| 
 | |
|   ret = FALSE;
 | |
| 
 | |
|   data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
 | |
|   if (data != NULL)
 | |
|     {
 | |
|       GPtrArray *interface_names;
 | |
|       GHashTableIter iter;
 | |
|       const gchar *iface_name;
 | |
| 
 | |
|       interface_names = g_ptr_array_new ();
 | |
|       g_hash_table_iter_init (&iter, data->map_iface_name_to_iface);
 | |
|       while (g_hash_table_iter_next (&iter, (gpointer) &iface_name, NULL))
 | |
|         g_ptr_array_add (interface_names, (gpointer) iface_name);
 | |
|       g_ptr_array_add (interface_names, NULL);
 | |
|       /* now emit InterfacesRemoved() for all the interfaces */
 | |
|       g_dbus_object_manager_server_emit_interfaces_removed (manager, data, (const gchar *const *) interface_names->pdata);
 | |
|       g_ptr_array_unref (interface_names);
 | |
| 
 | |
|       g_hash_table_remove (manager->priv->map_object_path_to_data, object_path);
 | |
|       ret = TRUE;
 | |
|     }
 | |
| 
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * g_dbus_object_manager_server_unexport:
 | |
|  * @manager: A #GDBusObjectManagerServer.
 | |
|  * @object_path: An object path.
 | |
|  *
 | |
|  * If @manager has an object at @path, removes the object. Otherwise
 | |
|  * does nothing.
 | |
|  *
 | |
|  * Note that @object_path must be in the hierarchy rooted by the
 | |
|  * object path for @manager.
 | |
|  *
 | |
|  * Returns: %TRUE if object at @object_path was removed, %FALSE otherwise.
 | |
|  *
 | |
|  * Since: 2.30
 | |
|  */
 | |
| gboolean
 | |
| g_dbus_object_manager_server_unexport (GDBusObjectManagerServer  *manager,
 | |
|                                        const gchar         *object_path)
 | |
| {
 | |
|   gboolean ret;
 | |
|   g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager), FALSE);
 | |
|   g_mutex_lock (&manager->priv->lock);
 | |
|   ret = g_dbus_object_manager_server_unexport_unlocked (manager, object_path);
 | |
|   g_mutex_unlock (&manager->priv->lock);
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| 
 | |
| static const GDBusArgInfo manager_interfaces_added_signal_info_arg0 =
 | |
| {
 | |
|   -1,
 | |
|   "object_path",
 | |
|   "o",
 | |
|   (GDBusAnnotationInfo**) NULL,
 | |
| };
 | |
| 
 | |
| static const GDBusArgInfo manager_interfaces_added_signal_info_arg1 =
 | |
| {
 | |
|   -1,
 | |
|   "interfaces_and_properties",
 | |
|   "a{sa{sv}}",
 | |
|   (GDBusAnnotationInfo**) NULL,
 | |
| };
 | |
| 
 | |
| static const GDBusArgInfo * const manager_interfaces_added_signal_info_arg_pointers[] =
 | |
| {
 | |
|   &manager_interfaces_added_signal_info_arg0,
 | |
|   &manager_interfaces_added_signal_info_arg1,
 | |
|   NULL
 | |
| };
 | |
| 
 | |
| static const GDBusSignalInfo manager_interfaces_added_signal_info =
 | |
| {
 | |
|   -1,
 | |
|   "InterfacesAdded",
 | |
|   (GDBusArgInfo**) &manager_interfaces_added_signal_info_arg_pointers,
 | |
|   (GDBusAnnotationInfo**) NULL
 | |
| };
 | |
| 
 | |
| /* ---------- */
 | |
| 
 | |
| static const GDBusArgInfo manager_interfaces_removed_signal_info_arg0 =
 | |
| {
 | |
|   -1,
 | |
|   "object_path",
 | |
|   "o",
 | |
|   (GDBusAnnotationInfo**) NULL,
 | |
| };
 | |
| 
 | |
| static const GDBusArgInfo manager_interfaces_removed_signal_info_arg1 =
 | |
| {
 | |
|   -1,
 | |
|   "interfaces",
 | |
|   "as",
 | |
|   (GDBusAnnotationInfo**) NULL,
 | |
| };
 | |
| 
 | |
| static const GDBusArgInfo * const manager_interfaces_removed_signal_info_arg_pointers[] =
 | |
| {
 | |
|   &manager_interfaces_removed_signal_info_arg0,
 | |
|   &manager_interfaces_removed_signal_info_arg1,
 | |
|   NULL
 | |
| };
 | |
| 
 | |
| static const GDBusSignalInfo manager_interfaces_removed_signal_info =
 | |
| {
 | |
|   -1,
 | |
|   "InterfacesRemoved",
 | |
|   (GDBusArgInfo**) &manager_interfaces_removed_signal_info_arg_pointers,
 | |
|   (GDBusAnnotationInfo**) NULL
 | |
| };
 | |
| 
 | |
| /* ---------- */
 | |
| 
 | |
| static const GDBusSignalInfo * const manager_signal_info_pointers[] =
 | |
| {
 | |
|   &manager_interfaces_added_signal_info,
 | |
|   &manager_interfaces_removed_signal_info,
 | |
|   NULL
 | |
| };
 | |
| 
 | |
| /* ---------- */
 | |
| 
 | |
| static const GDBusArgInfo manager_get_all_method_info_out_arg0 =
 | |
| {
 | |
|   -1,
 | |
|   "object_paths_interfaces_and_properties",
 | |
|   "a{oa{sa{sv}}}",
 | |
|   (GDBusAnnotationInfo**) NULL,
 | |
| };
 | |
| 
 | |
| static const GDBusArgInfo * const manager_get_all_method_info_out_arg_pointers[] =
 | |
| {
 | |
|   &manager_get_all_method_info_out_arg0,
 | |
|   NULL
 | |
| };
 | |
| 
 | |
| static const GDBusMethodInfo manager_get_all_method_info =
 | |
| {
 | |
|   -1,
 | |
|   "GetManagedObjects",
 | |
|   (GDBusArgInfo**) NULL,
 | |
|   (GDBusArgInfo**) &manager_get_all_method_info_out_arg_pointers,
 | |
|   (GDBusAnnotationInfo**) NULL
 | |
| };
 | |
| 
 | |
| static const GDBusMethodInfo * const manager_method_info_pointers[] =
 | |
| {
 | |
|   &manager_get_all_method_info,
 | |
|   NULL
 | |
| };
 | |
| 
 | |
| /* ---------- */
 | |
| 
 | |
| static const GDBusInterfaceInfo manager_interface_info =
 | |
| {
 | |
|   -1,
 | |
|   DBUS_INTERFACE_OBJECT_MANAGER,
 | |
|   (GDBusMethodInfo **) manager_method_info_pointers,
 | |
|   (GDBusSignalInfo **) manager_signal_info_pointers,
 | |
|   (GDBusPropertyInfo **) NULL,
 | |
|   (GDBusAnnotationInfo **) NULL
 | |
| };
 | |
| 
 | |
| static void
 | |
| manager_method_call (GDBusConnection       *connection,
 | |
|                      const gchar           *sender,
 | |
|                      const gchar           *object_path,
 | |
|                      const gchar           *interface_name,
 | |
|                      const gchar           *method_name,
 | |
|                      GVariant              *parameters,
 | |
|                      GDBusMethodInvocation *invocation,
 | |
|                      gpointer               user_data)
 | |
| {
 | |
|   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (user_data);
 | |
|   GVariantBuilder array_builder;
 | |
|   GHashTableIter object_iter;
 | |
|   RegistrationData *data;
 | |
| 
 | |
|   g_mutex_lock (&manager->priv->lock);
 | |
| 
 | |
|   if (g_strcmp0 (method_name, "GetManagedObjects") == 0)
 | |
|     {
 | |
|       g_variant_builder_init_static (&array_builder, G_VARIANT_TYPE ("a{oa{sa{sv}}}"));
 | |
|       g_hash_table_iter_init (&object_iter, manager->priv->map_object_path_to_data);
 | |
|       while (g_hash_table_iter_next (&object_iter, NULL, (gpointer) &data))
 | |
|         {
 | |
|           GVariantBuilder interfaces_builder;
 | |
|           GHashTableIter interface_iter;
 | |
|           GDBusInterfaceSkeleton *iface;
 | |
|           const gchar *iter_object_path;
 | |
| 
 | |
|           g_variant_builder_init_static (&interfaces_builder, G_VARIANT_TYPE ("a{sa{sv}}"));
 | |
|           g_hash_table_iter_init (&interface_iter, data->map_iface_name_to_iface);
 | |
|           while (g_hash_table_iter_next (&interface_iter, NULL, (gpointer) &iface))
 | |
|             {
 | |
|               GVariant *properties = g_dbus_interface_skeleton_get_properties (iface);
 | |
|               g_variant_builder_add (&interfaces_builder, "{s@a{sv}}",
 | |
|                                      g_dbus_interface_skeleton_get_info (iface)->name,
 | |
|                                      properties);
 | |
|               g_variant_unref (properties);
 | |
|             }
 | |
|           iter_object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object));
 | |
|           g_variant_builder_add (&array_builder,
 | |
|                                  "{oa{sa{sv}}}",
 | |
|                                  iter_object_path,
 | |
|                                  &interfaces_builder);
 | |
|         }
 | |
| 
 | |
|       g_dbus_method_invocation_return_value (invocation,
 | |
|                                              g_variant_new ("(a{oa{sa{sv}}})",
 | |
|                                                             &array_builder));
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       g_dbus_method_invocation_return_error (invocation,
 | |
|                                              G_DBUS_ERROR,
 | |
|                                              G_DBUS_ERROR_UNKNOWN_METHOD,
 | |
|                                              "Unknown method %s - only GetManagedObjects() is supported",
 | |
|                                              method_name);
 | |
|     }
 | |
|   g_mutex_unlock (&manager->priv->lock);
 | |
| }
 | |
| 
 | |
| static const GDBusInterfaceVTable manager_interface_vtable =
 | |
| {
 | |
|   manager_method_call, /* handle_method_call */
 | |
|   NULL, /* get_property */
 | |
|   NULL, /* set_property */
 | |
|   { 0 }
 | |
| };
 | |
| 
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| 
 | |
| static void
 | |
| g_dbus_object_manager_server_constructed (GObject *object)
 | |
| {
 | |
|   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object);
 | |
| 
 | |
|   if (manager->priv->connection != NULL)
 | |
|     export_all (manager);
 | |
| 
 | |
|   if (G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->constructed != NULL)
 | |
|     G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->constructed (object);
 | |
| }
 | |
| 
 | |
| static void
 | |
| g_dbus_object_manager_server_emit_interfaces_added (GDBusObjectManagerServer *manager,
 | |
|                                                     RegistrationData   *data,
 | |
|                                                     const gchar *const *interfaces,
 | |
|                                                     const gchar *object_path)
 | |
| {
 | |
|   GVariantBuilder array_builder;
 | |
|   GError *error;
 | |
|   guint n;
 | |
| 
 | |
|   if (data->manager->priv->connection == NULL)
 | |
|     goto out;
 | |
| 
 | |
|   g_variant_builder_init_static (&array_builder, G_VARIANT_TYPE ("a{sa{sv}}"));
 | |
|   for (n = 0; interfaces[n] != NULL; n++)
 | |
|     {
 | |
|       GDBusInterfaceSkeleton *iface;
 | |
|       GVariant *properties;
 | |
| 
 | |
|       iface = g_hash_table_lookup (data->map_iface_name_to_iface, interfaces[n]);
 | |
|       g_assert (iface != NULL);
 | |
|       properties = g_dbus_interface_skeleton_get_properties (iface);
 | |
|       g_variant_builder_add (&array_builder, "{s@a{sv}}", interfaces[n], properties);
 | |
|       g_variant_unref (properties);
 | |
|     }
 | |
| 
 | |
|   error = NULL;
 | |
|   g_dbus_connection_emit_signal (data->manager->priv->connection,
 | |
|                                  NULL, /* destination_bus_name */
 | |
|                                  manager->priv->object_path,
 | |
|                                  manager_interface_info.name,
 | |
|                                  "InterfacesAdded",
 | |
|                                  g_variant_new ("(oa{sa{sv}})",
 | |
|                                                 object_path,
 | |
|                                                 &array_builder),
 | |
|                                  &error);
 | |
|   if (error)
 | |
|     {
 | |
|       if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED))
 | |
|         g_warning ("Couldn't emit InterfacesAdded signal: %s", error->message);
 | |
|       g_error_free (error);
 | |
|     }
 | |
|  out:
 | |
|   ;
 | |
| }
 | |
| 
 | |
| static void
 | |
| g_dbus_object_manager_server_emit_interfaces_removed (GDBusObjectManagerServer *manager,
 | |
|                                                       RegistrationData   *data,
 | |
|                                                       const gchar *const *interfaces)
 | |
| {
 | |
|   GVariantBuilder array_builder;
 | |
|   GError *error;
 | |
|   guint n;
 | |
|   const gchar *object_path;
 | |
| 
 | |
|   if (data->manager->priv->connection == NULL)
 | |
|     goto out;
 | |
| 
 | |
|   g_variant_builder_init_static (&array_builder, G_VARIANT_TYPE ("as"));
 | |
|   for (n = 0; interfaces[n] != NULL; n++)
 | |
|     g_variant_builder_add (&array_builder, "s", interfaces[n]);
 | |
| 
 | |
|   error = NULL;
 | |
|   object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object));
 | |
|   g_dbus_connection_emit_signal (data->manager->priv->connection,
 | |
|                                  NULL, /* destination_bus_name */
 | |
|                                  manager->priv->object_path,
 | |
|                                  manager_interface_info.name,
 | |
|                                  "InterfacesRemoved",
 | |
|                                  g_variant_new ("(oas)",
 | |
|                                                 object_path,
 | |
|                                                 &array_builder),
 | |
|                                  &error);
 | |
|   if (error)
 | |
|     {
 | |
|       if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED))
 | |
|         g_warning ("Couldn't emit InterfacesRemoved signal: %s", error->message);
 | |
|       g_error_free (error);
 | |
|     }
 | |
|  out:
 | |
|   ;
 | |
| }
 | |
| 
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| 
 | |
| static GList *
 | |
| g_dbus_object_manager_server_get_objects (GDBusObjectManager  *_manager)
 | |
| {
 | |
|   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (_manager);
 | |
|   GList *ret;
 | |
|   GHashTableIter iter;
 | |
|   RegistrationData *data;
 | |
| 
 | |
|   g_mutex_lock (&manager->priv->lock);
 | |
| 
 | |
|   ret = NULL;
 | |
|   g_hash_table_iter_init (&iter, manager->priv->map_object_path_to_data);
 | |
|   while (g_hash_table_iter_next (&iter, NULL, (gpointer) &data))
 | |
|     {
 | |
|       ret = g_list_prepend (ret, g_object_ref (data->object));
 | |
|     }
 | |
| 
 | |
|   g_mutex_unlock (&manager->priv->lock);
 | |
| 
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| static const gchar *
 | |
| g_dbus_object_manager_server_get_object_path (GDBusObjectManager *_manager)
 | |
| {
 | |
|   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (_manager);
 | |
|   return manager->priv->object_path;
 | |
| }
 | |
| 
 | |
| static GDBusObject *
 | |
| g_dbus_object_manager_server_get_object (GDBusObjectManager *_manager,
 | |
|                                          const gchar        *object_path)
 | |
| {
 | |
|   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (_manager);
 | |
|   GDBusObject *ret;
 | |
|   RegistrationData *data;
 | |
| 
 | |
|   ret = NULL;
 | |
| 
 | |
|   g_mutex_lock (&manager->priv->lock);
 | |
|   data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
 | |
|   if (data != NULL)
 | |
|     ret = g_object_ref (G_DBUS_OBJECT (data->object));
 | |
|   g_mutex_unlock (&manager->priv->lock);
 | |
| 
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| static GDBusInterface *
 | |
| g_dbus_object_manager_server_get_interface  (GDBusObjectManager  *_manager,
 | |
|                                              const gchar         *object_path,
 | |
|                                              const gchar         *interface_name)
 | |
| {
 | |
|   GDBusInterface *ret;
 | |
|   GDBusObject *object;
 | |
| 
 | |
|   ret = NULL;
 | |
| 
 | |
|   object = g_dbus_object_manager_get_object (_manager, object_path);
 | |
|   if (object == NULL)
 | |
|     goto out;
 | |
| 
 | |
|   ret = g_dbus_object_get_interface (object, interface_name);
 | |
|   g_object_unref (object);
 | |
| 
 | |
|  out:
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| static void
 | |
| dbus_object_manager_interface_init (GDBusObjectManagerIface *iface)
 | |
| {
 | |
|   iface->get_object_path = g_dbus_object_manager_server_get_object_path;
 | |
|   iface->get_objects     = g_dbus_object_manager_server_get_objects;
 | |
|   iface->get_object      = g_dbus_object_manager_server_get_object;
 | |
|   iface->get_interface   = g_dbus_object_manager_server_get_interface;
 | |
| }
 | |
| 
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| 
 | |
| static void
 | |
| export_all (GDBusObjectManagerServer *manager)
 | |
| {
 | |
|   GHashTableIter iter;
 | |
|   const gchar *object_path;
 | |
|   RegistrationData *data;
 | |
|   GHashTableIter iface_iter;
 | |
|   GDBusInterfaceSkeleton *iface;
 | |
|   GError *error;
 | |
| 
 | |
|   g_return_if_fail (manager->priv->connection != NULL);
 | |
| 
 | |
|   error = NULL;
 | |
|   g_warn_if_fail (manager->priv->manager_reg_id == 0);
 | |
|   manager->priv->manager_reg_id = g_dbus_connection_register_object (manager->priv->connection,
 | |
|                                                                      manager->priv->object_path,
 | |
|                                                                      (GDBusInterfaceInfo *) &manager_interface_info,
 | |
|                                                                      &manager_interface_vtable,
 | |
|                                                                      manager,
 | |
|                                                                      NULL, /* user_data_free_func */
 | |
|                                                                      &error);
 | |
|   if (manager->priv->manager_reg_id == 0)
 | |
|     {
 | |
|       g_warning ("%s: Error registering manager at %s: %s",
 | |
|                  G_STRLOC,
 | |
|                  manager->priv->object_path,
 | |
|                  error->message);
 | |
|       g_error_free (error);
 | |
|     }
 | |
| 
 | |
|   g_hash_table_iter_init (&iter, manager->priv->map_object_path_to_data);
 | |
|   while (g_hash_table_iter_next (&iter, (gpointer) &object_path, (gpointer) &data))
 | |
|     {
 | |
|       g_hash_table_iter_init (&iface_iter, data->map_iface_name_to_iface);
 | |
|       while (g_hash_table_iter_next (&iface_iter, NULL, (gpointer) &iface))
 | |
|         {
 | |
|           g_warn_if_fail (g_dbus_interface_skeleton_get_connection (iface) == NULL);
 | |
|           error = NULL;
 | |
|           if (!g_dbus_interface_skeleton_export (iface,
 | |
|                                                  manager->priv->connection,
 | |
|                                                  object_path,
 | |
|                                                  &error))
 | |
|             {
 | |
|               g_warning ("%s: Error registering object at %s with interface %s: %s",
 | |
|                          G_STRLOC,
 | |
|                          object_path,
 | |
|                          g_dbus_interface_skeleton_get_info (iface)->name,
 | |
|                          error->message);
 | |
|               g_error_free (error);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| unexport_all (GDBusObjectManagerServer *manager, gboolean only_manager)
 | |
| {
 | |
|   GHashTableIter iter;
 | |
|   RegistrationData *data;
 | |
|   GHashTableIter iface_iter;
 | |
|   GDBusInterfaceSkeleton *iface;
 | |
| 
 | |
|   g_return_if_fail (manager->priv->connection != NULL);
 | |
| 
 | |
|   g_warn_if_fail (manager->priv->manager_reg_id > 0);
 | |
|   if (manager->priv->manager_reg_id > 0)
 | |
|     {
 | |
|       g_warn_if_fail (g_dbus_connection_unregister_object (manager->priv->connection,
 | |
|                                                            manager->priv->manager_reg_id));
 | |
|       manager->priv->manager_reg_id = 0;
 | |
|     }
 | |
|   if (only_manager)
 | |
|     goto out;
 | |
| 
 | |
|   g_hash_table_iter_init (&iter, manager->priv->map_object_path_to_data);
 | |
|   while (g_hash_table_iter_next (&iter, NULL, (gpointer) &data))
 | |
|     {
 | |
|       g_hash_table_iter_init (&iface_iter, data->map_iface_name_to_iface);
 | |
|       while (g_hash_table_iter_next (&iface_iter, NULL, (gpointer) &iface))
 | |
|         {
 | |
|           g_warn_if_fail (g_dbus_interface_skeleton_get_connection (iface) != NULL);
 | |
|           g_dbus_interface_skeleton_unexport (iface);
 | |
|         }
 | |
|     }
 | |
|  out:
 | |
|   ;
 | |
| }
 | |
| 
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 |