From: David Zeuthen Date: Wed, 4 May 2011 07:37:46 +0000 (-0400) Subject: GDBusObjectManagerServer: Allow setting :connection property X-Git-Tag: 2.29.4~8 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1ab29b6c4a2ddf5a60b4cc353422d605197b7696;p=platform%2Fupstream%2Fglib.git GDBusObjectManagerServer: Allow setting :connection property .. and add a C setter to do this. Also make the C getter return a reference since the property may be set from another thread. Also change the constructor to _not_ take a GDBusConnection since this is something you almost always want to do _after_ creating it. The API/ABI break is fine as there has never been a GLib release with this type. https://bugzilla.gnome.org/show_bug.cgi?id=648959 Signed-off-by: David Zeuthen --- diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt index 751cd1c..af17009 100644 --- a/docs/reference/gio/gio-sections.txt +++ b/docs/reference/gio/gio-sections.txt @@ -3294,6 +3294,7 @@ GDBusObjectManagerServer GDBusObjectManagerServerClass g_dbus_object_manager_server_new g_dbus_object_manager_server_get_connection +g_dbus_object_manager_server_set_connection g_dbus_object_manager_server_export g_dbus_object_manager_server_export_uniquely g_dbus_object_manager_server_unexport diff --git a/gio/gdbusobjectmanagerserver.c b/gio/gdbusobjectmanagerserver.c index ecb9024..7f71b24 100644 --- a/gio/gdbusobjectmanagerserver.c +++ b/gio/gdbusobjectmanagerserver.c @@ -64,6 +64,9 @@ 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); @@ -100,10 +103,12 @@ 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); @@ -112,17 +117,17 @@ g_dbus_object_manager_server_finalize (GObject *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_value_set_object (value, manager->priv->connection); break; case PROP_OBJECT_PATH: @@ -130,25 +135,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: @@ -159,7 +162,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; } } @@ -189,7 +192,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)); /** @@ -227,28 +229,61 @@ 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)); + + if (manager->priv->connection == connection) + 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_object_notify (G_OBJECT (manager), "connection"); + out: + ; } /** @@ -257,8 +292,9 @@ 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 */ @@ -266,7 +302,7 @@ GDBusConnection * g_dbus_object_manager_server_get_connection (GDBusObjectManagerServer *manager) { g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager), NULL); - return manager->priv->connection; + return manager->priv->connection != NULL ? g_object_ref (manager->priv->connection) : NULL; } /* ---------------------------------------------------------------------------------------------------- */ @@ -283,19 +319,20 @@ registration_data_export_interface (RegistrationData *data, 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); @@ -312,9 +349,6 @@ registration_data_export_interface (RegistrationData *data, interfaces[1] = NULL; g_dbus_object_manager_server_emit_interfaces_added (data->manager, data, interfaces); } - - out: - ; } static void @@ -328,7 +362,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)); @@ -376,7 +411,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); @@ -761,25 +799,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); @@ -787,14 +809,17 @@ 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) { 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++) { @@ -819,18 +844,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]); @@ -847,6 +877,8 @@ g_dbus_object_manager_server_emit_interfaces_removed (GDBusObjectManagerServer * &array_builder), &error); g_assert_no_error (error); + out: + ; } /* ---------------------------------------------------------------------------------------------------- */ @@ -920,3 +952,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: + ; +} + +/* ---------------------------------------------------------------------------------------------------- */ diff --git a/gio/gdbusobjectmanagerserver.h b/gio/gdbusobjectmanagerserver.h index 5d6d11a..5abe00f 100644 --- a/gio/gdbusobjectmanagerserver.h +++ b/gio/gdbusobjectmanagerserver.h @@ -69,9 +69,10 @@ struct _GDBusObjectManagerServerClass }; GType g_dbus_object_manager_server_get_type (void) G_GNUC_CONST; -GDBusObjectManagerServer *g_dbus_object_manager_server_new (GDBusConnection *connection, - const gchar *object_path); +GDBusObjectManagerServer *g_dbus_object_manager_server_new (const gchar *object_path); GDBusConnection *g_dbus_object_manager_server_get_connection (GDBusObjectManagerServer *manager); +void g_dbus_object_manager_server_set_connection (GDBusObjectManagerServer *manager, + GDBusConnection *connection); void g_dbus_object_manager_server_export (GDBusObjectManagerServer *manager, GDBusObjectSkeleton *object); void g_dbus_object_manager_server_export_uniquely (GDBusObjectManagerServer *manager, diff --git a/gio/gio.symbols b/gio/gio.symbols index 6cb5934..59e1a14 100644 --- a/gio/gio.symbols +++ b/gio/gio.symbols @@ -2179,6 +2179,7 @@ g_dbus_object_manager_client_new_sync g_dbus_object_manager_server_export g_dbus_object_manager_server_export_uniquely g_dbus_object_manager_server_get_connection +g_dbus_object_manager_server_set_connection g_dbus_object_manager_server_get_type g_dbus_object_manager_server_new g_dbus_object_manager_server_unexport diff --git a/gio/tests/gdbus-example-objectmanager-server.c b/gio/tests/gdbus-example-objectmanager-server.c index 0ef9c49..367b4f4 100644 --- a/gio/tests/gdbus-example-objectmanager-server.c +++ b/gio/tests/gdbus-example-objectmanager-server.c @@ -68,7 +68,7 @@ on_bus_acquired (GDBusConnection *connection, g_print ("Acquired a message bus connection\n"); /* Create a new org.freedesktop.DBus.ObjectManager rooted at /example/Animals */ - manager = g_dbus_object_manager_server_new (connection, "/example/Animals"); + manager = g_dbus_object_manager_server_new ("/example/Animals"); for (n = 0; n < 10; n++) { @@ -111,6 +111,9 @@ on_bus_acquired (GDBusConnection *connection, g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (object)); g_object_unref (object); } + + /* Export all objects */ + g_dbus_object_manager_server_set_connection (manager, connection); } static void diff --git a/gio/tests/gdbus-test-codegen.c b/gio/tests/gdbus-test-codegen.c index 896573c..fe192fa 100644 --- a/gio/tests/gdbus-test-codegen.c +++ b/gio/tests/gdbus-test-codegen.c @@ -1762,7 +1762,8 @@ check_object_manager (void) g_error_free (error); g_assert (pm == NULL); - manager = g_dbus_object_manager_server_new (c, "/managed"); + manager = g_dbus_object_manager_server_new ("/managed"); + g_dbus_object_manager_server_set_connection (manager, c); /* Check that the manager object is visible */ info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed", loop); @@ -1985,6 +1986,17 @@ check_object_manager (void) om_check_get_all (c, loop, "({objectpath '/managed/first': {'com.acme.Coyote': {'Mood': <''>}}, '/managed/second': {'org.project.Bar': {'y': , 'b': , 'n': , 'q': , 'i': <0>, 'u': , 'x': , 't': , 'd': <0.0>, 's': <''>, 'o': , 'g': , 'ay': , 'as': <@as []>, 'aay': <@aay []>, 'ao': <@ao []>, 'ag': <@ag []>, 'FinallyNormalName': <''>, 'ReadonlyProperty': <''>, 'unset_i': <0>, 'unset_d': <0.0>, 'unset_s': <''>, 'unset_o': , 'unset_g': , 'unset_ay': , 'unset_as': <@as []>, 'unset_ao': <@ao []>, 'unset_ag': <@ag []>, 'unset_struct': <(0, 0.0, '', objectpath '/', signature '', @ay [], @as [], @ao [], @ag [])>}, 'org.project.Bat': {'force_i': <0>, 'force_s': <''>, 'force_ay': <@ay []>, 'force_struct': <(0,)>}}},)"); + /* Set connection to NULL, causing everything to be unexported.. verify this.. and + * then set the connection back.. and then check things still work + */ + g_dbus_object_manager_server_set_connection (manager, NULL); + info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed", loop); + g_assert_cmpint (count_interfaces (info), ==, 0); /* nothing */ + g_dbus_node_info_unref (info); + g_dbus_object_manager_server_set_connection (manager, c); + om_check_get_all (c, loop, + "({objectpath '/managed/first': {'com.acme.Coyote': {'Mood': <''>}}, '/managed/second': {'org.project.Bar': {'y': , 'b': , 'n': , 'q': , 'i': <0>, 'u': , 'x': , 't': , 'd': <0.0>, 's': <''>, 'o': , 'g': , 'ay': , 'as': <@as []>, 'aay': <@aay []>, 'ao': <@ao []>, 'ag': <@ag []>, 'FinallyNormalName': <''>, 'ReadonlyProperty': <''>, 'unset_i': <0>, 'unset_d': <0.0>, 'unset_s': <''>, 'unset_o': , 'unset_g': , 'unset_ay': , 'unset_as': <@as []>, 'unset_ao': <@ao []>, 'unset_ag': <@ag []>, 'unset_struct': <(0, 0.0, '', objectpath '/', signature '', @ay [], @as [], @ao [], @ag [])>}, 'org.project.Bat': {'force_i': <0>, 'force_s': <''>, 'force_ay': <@ay []>, 'force_struct': <(0,)>}}},)"); + /* Also check that the ObjectManagerClient returns these objects - and * that they are of the right GType cf. what was requested via * the generated ::get-proxy-type signal handler