X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Fgdelayedsettingsbackend.c;h=22a42ebdaeed409c28f7e9e4e7f1835a69ca42a3;hb=9da85c7262325478e8730ae9f3e76bd0528a9a8c;hp=644e92e8294d4ab797dc5b901ace741f40ed1c23;hpb=118ae129bc24597d937f30998e643ba83db908f4;p=platform%2Fupstream%2Fglib.git diff --git a/gio/gdelayedsettingsbackend.c b/gio/gdelayedsettingsbackend.c index 644e92e..22a42eb 100644 --- a/gio/gdelayedsettingsbackend.c +++ b/gio/gdelayedsettingsbackend.c @@ -12,9 +12,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. + * License along with this library; if not, see . * * Author: Ryan Lortie */ @@ -26,33 +24,110 @@ #include -#include "gioalias.h" struct _GDelayedSettingsBackendPrivate { GSettingsBackend *backend; + GMutex lock; GTree *delayed; + + GMainContext *owner_context; gpointer owner; }; -G_DEFINE_TYPE (GDelayedSettingsBackend, - g_delayed_settings_backend, - G_TYPE_SETTINGS_BACKEND) +G_DEFINE_TYPE_WITH_PRIVATE (GDelayedSettingsBackend, + g_delayed_settings_backend, + G_TYPE_SETTINGS_BACKEND) + +static gboolean +invoke_notify_unapplied (gpointer data) +{ + g_object_notify (data, "has-unapplied"); + g_object_unref (data); + + return FALSE; +} + +static void +g_delayed_settings_backend_notify_unapplied (GDelayedSettingsBackend *delayed) +{ + GMainContext *target_context; + GObject *target; + + g_mutex_lock (&delayed->priv->lock); + if (delayed->priv->owner) + { + target_context = delayed->priv->owner_context; + target = g_object_ref (delayed->priv->owner); + } + else + { + target_context = NULL; + target = NULL; + } + g_mutex_unlock (&delayed->priv->lock); + + if (target != NULL) + g_main_context_invoke (target_context, invoke_notify_unapplied, target); +} + static GVariant * g_delayed_settings_backend_read (GSettingsBackend *backend, const gchar *key, - const GVariantType *expected_type) + const GVariantType *expected_type, + gboolean default_value) { GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (backend); - GVariant *result; + gpointer result = NULL; + + if (!default_value) + { + g_mutex_lock (&delayed->priv->lock); + if (g_tree_lookup_extended (delayed->priv->delayed, key, NULL, &result)) + { + /* NULL in the tree means we should consult the default value */ + if (result != NULL) + g_variant_ref (result); + else + default_value = TRUE; + } + g_mutex_unlock (&delayed->priv->lock); + } - if ((result = g_tree_lookup (delayed->priv->delayed, key))) - return g_variant_ref (result); + if (result == NULL) + result = g_settings_backend_read (delayed->priv->backend, key, + expected_type, default_value); - return g_settings_backend_read (delayed->priv->backend, - key, expected_type); + return result; } + +static GVariant * +g_delayed_settings_backend_read_user_value (GSettingsBackend *backend, + const gchar *key, + const GVariantType *expected_type) +{ + GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (backend); + gboolean value_found = FALSE; + gpointer result = NULL; + + /* If we find an explicit NULL in our changeset then we want to return + * NULL (because the user value has been reset). + * + * Otherwise, chain up. + */ + g_mutex_lock (&delayed->priv->lock); + value_found = g_tree_lookup_extended (delayed->priv->delayed, key, NULL, &result); + if (result) + g_variant_ref (result); + g_mutex_unlock (&delayed->priv->lock); + + if (value_found) + return result; + + return g_settings_backend_read_user_value (delayed->priv->backend, key, expected_type); +} + static gboolean g_delayed_settings_backend_write (GSettingsBackend *backend, const gchar *key, @@ -62,13 +137,16 @@ g_delayed_settings_backend_write (GSettingsBackend *backend, GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (backend); gboolean was_empty; + g_mutex_lock (&delayed->priv->lock); was_empty = g_tree_nnodes (delayed->priv->delayed) == 0; g_tree_insert (delayed->priv->delayed, g_strdup (key), g_variant_ref_sink (value)); + g_mutex_unlock (&delayed->priv->lock); + g_settings_backend_changed (backend, key, origin_tag); - if (was_empty && delayed->priv->owner) - g_object_notify (delayed->priv->owner, "has-unapplied"); + if (was_empty) + g_delayed_settings_backend_notify_unapplied (delayed); return TRUE; } @@ -83,21 +161,23 @@ add_to_tree (gpointer key, } static gboolean -g_delayed_settings_backend_write_keys (GSettingsBackend *backend, +g_delayed_settings_backend_write_tree (GSettingsBackend *backend, GTree *tree, gpointer origin_tag) { GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (backend); gboolean was_empty; + g_mutex_lock (&delayed->priv->lock); was_empty = g_tree_nnodes (delayed->priv->delayed) == 0; g_tree_foreach (tree, add_to_tree, delayed->priv->delayed); + g_mutex_unlock (&delayed->priv->lock); g_settings_backend_changed_tree (backend, tree, origin_tag); - if (was_empty && delayed->priv->owner) - g_object_notify (delayed->priv->owner, "has-unapplied"); + if (was_empty) + g_delayed_settings_backend_notify_unapplied (delayed); return TRUE; } @@ -116,15 +196,16 @@ g_delayed_settings_backend_reset (GSettingsBackend *backend, const gchar *key, gpointer origin_tag) { - /* deal with this... */ -} + GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (backend); + gboolean was_empty; -static void -g_delayed_settings_backend_reset_path (GSettingsBackend *backend, - const gchar *path, - gpointer origin_tag) -{ - /* deal with this... */ + g_mutex_lock (&delayed->priv->lock); + was_empty = g_tree_nnodes (delayed->priv->delayed) == 0; + g_tree_insert (delayed->priv->delayed, g_strdup (key), NULL); + g_mutex_unlock (&delayed->priv->lock); + + if (was_empty) + g_delayed_settings_backend_notify_unapplied (delayed); } static void @@ -145,11 +226,22 @@ g_delayed_settings_backend_unsubscribe (GSettingsBackend *backend, g_settings_backend_unsubscribe (delayed->priv->backend, name); } +static GPermission * +g_delayed_settings_backend_get_permission (GSettingsBackend *backend, + const gchar *path) +{ + GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (backend); + + return g_settings_backend_get_permission (delayed->priv->backend, path); +} + /* method calls */ gboolean g_delayed_settings_backend_get_has_unapplied (GDelayedSettingsBackend *delayed) { + /* we don't need to lock for this... */ + return g_tree_nnodes (delayed->priv->delayed) > 0; } @@ -161,10 +253,12 @@ g_delayed_settings_backend_apply (GDelayedSettingsBackend *delayed) gboolean success; GTree *tmp; + g_mutex_lock (&delayed->priv->lock); tmp = delayed->priv->delayed; delayed->priv->delayed = g_settings_backend_create_tree (); - success = g_settings_backend_write_keys (delayed->priv->backend, + success = g_settings_backend_write_tree (delayed->priv->backend, tmp, delayed->priv); + g_mutex_unlock (&delayed->priv->lock); if (!success) g_settings_backend_changed_tree (G_SETTINGS_BACKEND (delayed), @@ -172,8 +266,7 @@ g_delayed_settings_backend_apply (GDelayedSettingsBackend *delayed) g_tree_unref (tmp); - if (delayed->priv->owner) - g_object_notify (delayed->priv->owner, "has-unapplied"); + g_delayed_settings_backend_notify_unapplied (delayed); } } @@ -184,24 +277,25 @@ g_delayed_settings_backend_revert (GDelayedSettingsBackend *delayed) { GTree *tmp; + g_mutex_lock (&delayed->priv->lock); tmp = delayed->priv->delayed; delayed->priv->delayed = g_settings_backend_create_tree (); + g_mutex_unlock (&delayed->priv->lock); g_settings_backend_changed_tree (G_SETTINGS_BACKEND (delayed), tmp, NULL); g_tree_unref (tmp); - if (delayed->priv->owner) - g_object_notify (delayed->priv->owner, "has-unapplied"); + g_delayed_settings_backend_notify_unapplied (delayed); } } /* change notification */ static void -delayed_backend_changed (GSettingsBackend *backend, +delayed_backend_changed (GObject *target, + GSettingsBackend *backend, const gchar *key, - gpointer origin_tag, - gpointer user_data) + gpointer origin_tag) { - GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (user_data); + GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (target); if (origin_tag != delayed->priv) g_settings_backend_changed (G_SETTINGS_BACKEND (delayed), @@ -209,13 +303,13 @@ delayed_backend_changed (GSettingsBackend *backend, } static void -delayed_backend_keys_changed (GSettingsBackend *backend, +delayed_backend_keys_changed (GObject *target, + GSettingsBackend *backend, const gchar *path, - const gchar * const *items, gpointer origin_tag, - gpointer user_data) + const gchar * const *items) { - GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (user_data); + GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (target); if (origin_tag != delayed->priv) g_settings_backend_keys_changed (G_SETTINGS_BACKEND (delayed), @@ -223,12 +317,12 @@ delayed_backend_keys_changed (GSettingsBackend *backend, } static void -delayed_backend_path_changed (GSettingsBackend *backend, - const gchar *path, - gpointer origin_tag, - gpointer user_data) +delayed_backend_path_changed (GObject *target, + GSettingsBackend *backend, + const gchar *path, + gpointer origin_tag) { - GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (user_data); + GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (target); if (origin_tag != delayed->priv) g_settings_backend_path_changed (G_SETTINGS_BACKEND (delayed), @@ -236,26 +330,37 @@ delayed_backend_path_changed (GSettingsBackend *backend, } static void -delayed_backend_writable_changed (GSettingsBackend *backend, - const gchar *key, - gpointer user_data) +delayed_backend_writable_changed (GObject *target, + GSettingsBackend *backend, + const gchar *key) { - GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (user_data); + GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (target); + gboolean last_one = FALSE; + + g_mutex_lock (&delayed->priv->lock); - if (g_tree_lookup (delayed->priv->delayed, key) && + if (g_tree_lookup (delayed->priv->delayed, key) != NULL && !g_settings_backend_get_writable (delayed->priv->backend, key)) { /* drop the key from our changeset if it just became read-only. - * no need to signal this since the writable change implies it. + * no need to signal since the writable change below implies it. + * + * note that the item in the tree may very well be set to NULL in + * the case that the user stored a reset. we intentionally don't + * drop the key in this case since a reset will always succeed + * (even against a non-writable key). */ g_tree_remove (delayed->priv->delayed, key); /* if that was the only key... */ - if (delayed->priv->owner && - g_tree_nnodes (delayed->priv->delayed) == 0) - g_object_notify (delayed->priv->owner, "has-unapplied"); + last_one = g_tree_nnodes (delayed->priv->delayed) == 0; } + g_mutex_unlock (&delayed->priv->lock); + + if (last_one) + g_delayed_settings_backend_notify_unapplied (delayed); + g_settings_backend_writable_changed (G_SETTINGS_BACKEND (delayed), key); } @@ -282,13 +387,16 @@ check_prefix (gpointer key, } static void -delayed_backend_path_writable_changed (GSettingsBackend *backend, - const gchar *path, - gpointer user_data) +delayed_backend_path_writable_changed (GObject *target, + GSettingsBackend *backend, + const gchar *path) { - GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (user_data); + GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (target); + gboolean last_one = FALSE; gsize n_keys; + g_mutex_lock (&delayed->priv->lock); + n_keys = g_tree_nnodes (delayed->priv->delayed); if (n_keys > 0) @@ -299,19 +407,25 @@ delayed_backend_path_writable_changed (GSettingsBackend *backend, /* collect a list of possibly-affected keys (ie: matching the path) */ g_tree_foreach (delayed->priv->delayed, check_prefix, &state); - /* drop the keys that have been affected */ + /* drop the keys that have been affected. + * + * don't drop 'reset' keys (see above) */ for (i = 0; i < state.index; i++) - if (!g_settings_backend_get_writable (delayed->priv->backend, + if (g_tree_lookup (delayed->priv->delayed, state.keys[i]) != NULL && + !g_settings_backend_get_writable (delayed->priv->backend, state.keys[i])) g_tree_remove (delayed->priv->delayed, state.keys[i]); g_free (state.keys); - if (delayed->priv->owner && - g_tree_nnodes (delayed->priv->delayed) == 0) - g_object_notify (delayed->priv->owner, "has-unapplied"); + last_one = g_tree_nnodes (delayed->priv->delayed) == 0; } + g_mutex_unlock (&delayed->priv->lock); + + if (last_one) + g_delayed_settings_backend_notify_unapplied (delayed); + g_settings_backend_path_writable_changed (G_SETTINGS_BACKEND (delayed), path); } @@ -321,8 +435,15 @@ g_delayed_settings_backend_finalize (GObject *object) { GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (object); - g_settings_backend_unwatch (delayed->priv->backend, delayed); + g_mutex_clear (&delayed->priv->lock); g_object_unref (delayed->priv->backend); + g_tree_unref (delayed->priv->delayed); + + /* if our owner is still alive, why are we finalizing? */ + g_assert (delayed->priv->owner == NULL); + + G_OBJECT_CLASS (g_delayed_settings_backend_parent_class) + ->finalize (object); } static void @@ -331,16 +452,15 @@ g_delayed_settings_backend_class_init (GDelayedSettingsBackendClass *class) GSettingsBackendClass *backend_class = G_SETTINGS_BACKEND_CLASS (class); GObjectClass *object_class = G_OBJECT_CLASS (class); - g_type_class_add_private (class, sizeof (GDelayedSettingsBackendPrivate)); - backend_class->read = g_delayed_settings_backend_read; + backend_class->read_user_value = g_delayed_settings_backend_read_user_value; backend_class->write = g_delayed_settings_backend_write; - backend_class->write_keys = g_delayed_settings_backend_write_keys; + backend_class->write_tree = g_delayed_settings_backend_write_tree; backend_class->reset = g_delayed_settings_backend_reset; - backend_class->reset_path = g_delayed_settings_backend_reset_path; backend_class->get_writable = g_delayed_settings_backend_get_writable; backend_class->subscribe = g_delayed_settings_backend_subscribe; backend_class->unsubscribe = g_delayed_settings_backend_unsubscribe; + backend_class->get_permission = g_delayed_settings_backend_get_permission; object_class->finalize = g_delayed_settings_backend_finalize; } @@ -348,30 +468,46 @@ g_delayed_settings_backend_class_init (GDelayedSettingsBackendClass *class) static void g_delayed_settings_backend_init (GDelayedSettingsBackend *delayed) { - delayed->priv = - G_TYPE_INSTANCE_GET_PRIVATE (delayed, G_TYPE_DELAYED_SETTINGS_BACKEND, - GDelayedSettingsBackendPrivate); - + delayed->priv = g_delayed_settings_backend_get_instance_private (delayed); delayed->priv->delayed = g_settings_backend_create_tree (); + g_mutex_init (&delayed->priv->lock); +} + +static void +g_delayed_settings_backend_disown (gpointer data, + GObject *where_the_object_was) +{ + GDelayedSettingsBackend *delayed = data; + + g_mutex_lock (&delayed->priv->lock); + delayed->priv->owner_context = NULL; + delayed->priv->owner = NULL; + g_mutex_unlock (&delayed->priv->lock); } GDelayedSettingsBackend * g_delayed_settings_backend_new (GSettingsBackend *backend, - gpointer owner) + gpointer owner, + GMainContext *owner_context) { + static GSettingsListenerVTable vtable = { + delayed_backend_changed, + delayed_backend_path_changed, + delayed_backend_keys_changed, + delayed_backend_writable_changed, + delayed_backend_path_writable_changed + }; GDelayedSettingsBackend *delayed; delayed = g_object_new (G_TYPE_DELAYED_SETTINGS_BACKEND, NULL); delayed->priv->backend = g_object_ref (backend); + delayed->priv->owner_context = owner_context; delayed->priv->owner = owner; + g_object_weak_ref (owner, g_delayed_settings_backend_disown, delayed); + g_settings_backend_watch (delayed->priv->backend, - delayed_backend_changed, - delayed_backend_path_changed, - delayed_backend_keys_changed, - delayed_backend_writable_changed, - delayed_backend_path_writable_changed, - delayed); + &vtable, G_OBJECT (delayed), NULL); return delayed; }