X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Fgdbusobjectmanagerserver.c;h=bb6f8c23e851a8afbd1f0ea6ec1cf0ffc07084c2;hb=8df2cca08a5c06286303b39a34121c7e6925bf15;hp=1f348f2f585125d86dabd53e9230852e6603b09e;hpb=0e352fdb182e63ff163b0feda198cb3b6b20aa3a;p=platform%2Fupstream%2Fglib.git diff --git a/gio/gdbusobjectmanagerserver.c b/gio/gdbusobjectmanagerserver.c index 1f348f2..bb6f8c2 100644 --- a/gio/gdbusobjectmanagerserver.c +++ b/gio/gdbusobjectmanagerserver.c @@ -13,9 +13,7 @@ * 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, write to the - * Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. + * Public License along with this library; if not, see . * * Author: David Zeuthen */ @@ -40,16 +38,18 @@ * @include: gio/gio.h * * #GDBusObjectManagerServer is used to export #GDBusObject instances using - * the standardized org.freedesktop.DBus.ObjectManager + * 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. * - * See #GDBusObjectManagerClient for the client-side code that is intended to - * be used with #GDBusObjectManagerServer. + * See #GDBusObjectManagerClient 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. */ typedef struct @@ -62,16 +62,24 @@ typedef struct 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 *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; @@ -89,7 +97,8 @@ enum static void dbus_object_manager_interface_init (GDBusObjectManagerIface *iface); G_DEFINE_TYPE_WITH_CODE (GDBusObjectManagerServer, g_dbus_object_manager_server, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_OBJECT_MANAGER, dbus_object_manager_interface_init)); + 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); @@ -98,29 +107,35 @@ 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); - if (manager->priv->manager_reg_id > 0) - g_warn_if_fail (g_dbus_connection_unregister_object (manager->priv->connection, manager->priv->manager_reg_id)); - g_object_unref (manager->priv->connection); 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) +g_dbus_object_manager_server_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) { - GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (_object); + GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object); switch (prop_id) { case PROP_CONNECTION: - g_value_set_object (value, g_dbus_object_manager_server_get_connection (manager)); + 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: @@ -128,25 +143,23 @@ g_dbus_object_manager_server_get_property (GObject *_object, break; default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec); + 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) +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); + GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object); switch (prop_id) { case PROP_CONNECTION: - g_assert (manager->priv->connection == NULL); - g_assert (G_IS_DBUS_CONNECTION (g_value_get_object (value))); - manager->priv->connection = g_value_dup_object (value); + g_dbus_object_manager_server_set_connection (manager, g_value_get_object (value)); break; case PROP_OBJECT_PATH: @@ -157,7 +170,7 @@ g_dbus_object_manager_server_set_property (GObject *_object, break; default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec); + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } @@ -187,7 +200,6 @@ g_dbus_object_manager_server_class_init (GDBusObjectManagerServerClass *klass) G_TYPE_DBUS_CONNECTION, G_PARAM_READABLE | G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); /** @@ -207,16 +219,13 @@ g_dbus_object_manager_server_class_init (GDBusObjectManagerServerClass *klass) G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); - - g_type_class_add_private (klass, sizeof (GDBusObjectManagerServerPrivate)); } static void g_dbus_object_manager_server_init (GDBusObjectManagerServer *manager) { - manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, - G_TYPE_DBUS_OBJECT_MANAGER_SERVER, - GDBusObjectManagerServerPrivate); + 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, @@ -225,28 +234,68 @@ g_dbus_object_manager_server_init (GDBusObjectManagerServer *manager) /** * g_dbus_object_manager_server_new: - * @connection: A #GDBusConnection. * @object_path: The object path to export the manager object at. * * Creates a new #GDBusObjectManagerServer object. * - * TODO: make it so that the objects are not exported yet - - * e.g. start()/stop() semantics. + * 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 + * signals being emitted. * * Returns: A #GDBusObjectManagerServer object. Free with g_object_unref(). * * Since: 2.30 */ GDBusObjectManagerServer * -g_dbus_object_manager_server_new (GDBusConnection *connection, - const gchar *object_path) +g_dbus_object_manager_server_new (const gchar *object_path) { - g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL); 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, - "connection", connection, - "object-path", object_path, - NULL)); + "object-path", object_path, + NULL)); +} + +/** + * g_dbus_object_manager_server_set_connection: + * @manager: A #GDBusObjectManagerServer. + * @connection: (allow-none): 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: + ; } /** @@ -255,45 +304,49 @@ g_dbus_object_manager_server_new (GDBusConnection *connection, * * Gets the #GDBusConnection used by @manager. * - * Returns: (transfer none): A #GDBusConnection object. Do not free, - * the object belongs to @manager. + * Returns: (transfer full): 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); - return manager->priv->connection; + 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) + GDBusInterfaceSkeleton *interface_skeleton, + const gchar *object_path) { GDBusInterfaceInfo *info; GError *error; - const gchar *object_path; - - object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object)); info = g_dbus_interface_skeleton_get_info (interface_skeleton); error = NULL; - if (!g_dbus_interface_skeleton_export (interface_skeleton, - data->manager->priv->connection, - object_path, - &error)) + if (data->manager->priv->connection != NULL) { - /* TODO: probably wrong to complain on stderr */ - g_warning ("%s: Error registering object at %s with interface %s: %s", - G_STRLOC, - object_path, - info->name, - error->message); - g_error_free (error); - goto out; + 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); @@ -308,11 +361,8 @@ registration_data_export_interface (RegistrationData *data, /* 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); + g_dbus_object_manager_server_emit_interfaces_added (data->manager, data, interfaces, object_path); } - - out: - ; } static void @@ -326,7 +376,8 @@ registration_data_unexport_interface (RegistrationData *data, iface = g_hash_table_lookup (data->map_iface_name_to_iface, info->name); g_assert (iface != NULL); - g_dbus_interface_skeleton_unexport (iface); + 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)); @@ -349,7 +400,11 @@ on_interface_added (GDBusObject *object, gpointer user_data) { RegistrationData *data = user_data; - registration_data_export_interface (data, G_DBUS_INTERFACE_SKELETON (interface)); + 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 @@ -358,7 +413,9 @@ on_interface_removed (GDBusObject *object, 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); } /* ---------------------------------------------------------------------------------------------------- */ @@ -374,7 +431,10 @@ registration_data_free (RegistrationData *data) g_hash_table_iter_init (&iter, data->map_iface_name_to_iface); while (g_hash_table_iter_next (&iter, NULL, (gpointer) &iface)) - g_dbus_interface_skeleton_unexport (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); @@ -385,35 +445,15 @@ registration_data_free (RegistrationData *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) +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; - const gchar *object_path; - - 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)); @@ -423,7 +463,7 @@ g_dbus_object_manager_server_export (GDBusObjectManagerServer *manager, data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path); if (data != NULL) - g_dbus_object_manager_server_unexport (manager, object_path); + g_dbus_object_manager_server_unexport_unlocked (manager, object_path); data = g_new0 (RegistrationData, 1); data->object = g_object_ref (object); @@ -449,17 +489,16 @@ g_dbus_object_manager_server_export (GDBusObjectManagerServer *manager, 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); + 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_foreach (existing_interfaces, (GFunc) g_object_unref, NULL); - g_list_free (existing_interfaces); + 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); + 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, @@ -468,15 +507,43 @@ g_dbus_object_manager_server_export (GDBusObjectManagerServer *manager, } /** + * 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:object-path property - * of @object may be modified. + * 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 */ @@ -495,6 +562,8 @@ g_dbus_object_manager_server_export_uniquely (GDBusObjectManagerServer *manager, g_return_if_fail (G_IS_DBUS_OBJECT (object)); g_return_if_fail (g_str_has_prefix (orig_object_path, manager->priv->object_path_ending_in_slash)); + g_mutex_lock (&manager->priv->lock); + object_path = g_strdup (orig_object_path); count = 1; modified = FALSE; @@ -511,33 +580,57 @@ g_dbus_object_manager_server_export_uniquely (GDBusObjectManagerServer *manager, 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_dbus_object_manager_server_export (manager, object); - g_free (object_path); g_free (orig_object_path); + } /** - * g_dbus_object_manager_server_unexport: + * g_dbus_object_manager_server_is_exported: * @manager: A #GDBusObjectManagerServer. - * @object_path: An object path. - * - * If @manager has an object at @path, removes the object. Otherwise - * does nothing. + * @object: An object. * - * Note that @object_path must be in the hierarchy rooted by the - * object path for @manager. + * Returns whether @object is currently exported on @manager. * - * Returns: %TRUE if object at @object_path was removed, %FALSE otherwise. + * Returns: %TRUE if @object is exported * - * Since: 2.30 - */ + * Since: 2.34 + **/ gboolean -g_dbus_object_manager_server_unexport (GDBusObjectManagerServer *manager, - const gchar *object_path) +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; @@ -571,6 +664,33 @@ g_dbus_object_manager_server_unexport (GDBusObjectManagerServer *manager, 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; +} + /* ---------------------------------------------------------------------------------------------------- */ @@ -705,6 +825,8 @@ manager_method_call (GDBusConnection *connection, GHashTableIter object_iter; RegistrationData *data; + g_mutex_lock (&manager->priv->lock); + if (g_strcmp0 (method_name, "GetManagedObjects") == 0) { g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("a{oa{sa{sv}}}")); @@ -720,10 +842,11 @@ manager_method_call (GDBusConnection *connection, g_hash_table_iter_init (&interface_iter, data->map_iface_name_to_iface); while (g_hash_table_iter_next (&interface_iter, NULL, (gpointer) &iface)) { - g_variant_builder_add_value (&interfaces_builder, - g_variant_new ("{s@a{sv}}", - g_dbus_interface_skeleton_get_info (iface)->name, - g_dbus_interface_skeleton_get_properties (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, @@ -744,6 +867,7 @@ manager_method_call (GDBusConnection *connection, "Unknown method %s - only GetManagedObjects() is supported", method_name); } + g_mutex_unlock (&manager->priv->lock); } static const GDBusInterfaceVTable manager_interface_vtable = @@ -759,25 +883,9 @@ static void g_dbus_object_manager_server_constructed (GObject *object) { GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object); - GError *error; - error = NULL; - 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) - { - /* TODO: probably wrong to complain on stderr */ - g_warning ("%s: Error registering manager at %s: %s", - G_STRLOC, - manager->priv->object_path, - error->message); - g_error_free (error); - } + 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); @@ -785,28 +893,31 @@ g_dbus_object_manager_server_constructed (GObject *object) static void g_dbus_object_manager_server_emit_interfaces_added (GDBusObjectManagerServer *manager, - RegistrationData *data, - const gchar *const *interfaces) + RegistrationData *data, + const gchar *const *interfaces, + const gchar *object_path) { GVariantBuilder array_builder; GError *error; guint n; - const gchar *object_path; + + if (data->manager->priv->connection == NULL) + goto out; g_variant_builder_init (&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); - g_variant_builder_add_value (&array_builder, - g_variant_new ("{s@a{sv}}", - interfaces[n], - g_dbus_interface_skeleton_get_properties (iface))); + 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; - 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, @@ -817,18 +928,23 @@ g_dbus_object_manager_server_emit_interfaces_added (GDBusObjectManagerServer *ma &array_builder), &error); g_assert_no_error (error); + out: + ; } static void g_dbus_object_manager_server_emit_interfaces_removed (GDBusObjectManagerServer *manager, - RegistrationData *data, - const gchar *const *interfaces) + 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 (&array_builder, G_VARIANT_TYPE ("as")); for (n = 0; interfaces[n] != NULL; n++) g_variant_builder_add (&array_builder, "s", interfaces[n]); @@ -845,6 +961,8 @@ g_dbus_object_manager_server_emit_interfaces_removed (GDBusObjectManagerServer * &array_builder), &error); g_assert_no_error (error); + out: + ; } /* ---------------------------------------------------------------------------------------------------- */ @@ -857,6 +975,8 @@ g_dbus_object_manager_server_get_objects (GDBusObjectManager *_manager) 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)) @@ -864,6 +984,8 @@ g_dbus_object_manager_server_get_objects (GDBusObjectManager *_manager) ret = g_list_prepend (ret, g_object_ref (data->object)); } + g_mutex_unlock (&manager->priv->lock); + return ret; } @@ -883,9 +1005,13 @@ g_dbus_object_manager_server_get_object (GDBusObjectManager *_manager, 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 (data->object); + g_mutex_unlock (&manager->priv->lock); + return ret; } @@ -918,3 +1044,95 @@ dbus_object_manager_interface_init (GDBusObjectManagerIface *iface) 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: + ; +} + +/* ---------------------------------------------------------------------------------------------------- */