| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright © 2009, 2010 Codethink Limited | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 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 of the licence, 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, write to the | 
					
						
							|  |  |  |  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 
					
						
							|  |  |  |  * Boston, MA 02111-1307, USA. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Author: Ryan Lortie <desrt@desrt.ca> | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "config.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "gdelayedsettingsbackend.h"
 | 
					
						
							|  |  |  | #include "gsettingsbackendinternal.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct _GDelayedSettingsBackendPrivate | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   GSettingsBackend *backend; | 
					
						
							| 
									
										
										
										
											2011-09-17 19:26:41 -04:00
										 |  |  |   GMutex lock; | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  |   GTree *delayed; | 
					
						
							| 
									
										
										
										
											2010-05-16 16:56:36 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   GMainContext *owner_context; | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  |   gpointer owner; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | G_DEFINE_TYPE (GDelayedSettingsBackend, | 
					
						
							|  |  |  |                g_delayed_settings_backend, | 
					
						
							|  |  |  |                G_TYPE_SETTINGS_BACKEND) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-16 16:56:36 -04:00
										 |  |  | 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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-17 19:26:41 -04:00
										 |  |  |   g_mutex_lock (&delayed->priv->lock); | 
					
						
							| 
									
										
										
										
											2010-05-16 16:56:36 -04:00
										 |  |  |   if (delayed->priv->owner) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       target_context = delayed->priv->owner_context; | 
					
						
							|  |  |  |       target = g_object_ref (delayed->priv->owner); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       target_context = NULL; | 
					
						
							|  |  |  |       target = NULL; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-09-17 19:26:41 -04:00
										 |  |  |   g_mutex_unlock (&delayed->priv->lock); | 
					
						
							| 
									
										
										
										
											2010-05-16 16:56:36 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (target != NULL) | 
					
						
							| 
									
										
										
										
											2010-10-03 17:30:10 -04:00
										 |  |  |     g_main_context_invoke (target_context, invoke_notify_unapplied, target); | 
					
						
							| 
									
										
										
										
											2010-05-16 16:56:36 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  | static GVariant * | 
					
						
							|  |  |  | g_delayed_settings_backend_read (GSettingsBackend   *backend, | 
					
						
							|  |  |  |                                  const gchar        *key, | 
					
						
							| 
									
										
										
										
											2010-04-25 22:00:28 -05:00
										 |  |  |                                  const GVariantType *expected_type, | 
					
						
							|  |  |  |                                  gboolean            default_value) | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  | { | 
					
						
							|  |  |  |   GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (backend); | 
					
						
							| 
									
										
										
										
											2010-07-22 17:49:40 -04:00
										 |  |  |   gpointer result = NULL; | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-22 17:49:40 -04:00
										 |  |  |   if (!default_value) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2011-09-17 19:26:41 -04:00
										 |  |  |       g_mutex_lock (&delayed->priv->lock); | 
					
						
							| 
									
										
										
										
											2010-07-22 17:49:40 -04:00
										 |  |  |       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; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-09-17 19:26:41 -04:00
										 |  |  |       g_mutex_unlock (&delayed->priv->lock); | 
					
						
							| 
									
										
										
										
											2010-07-22 17:49:40 -04:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-22 17:49:40 -04:00
										 |  |  |   if (result == NULL) | 
					
						
							|  |  |  |     result = g_settings_backend_read (delayed->priv->backend, key, | 
					
						
							|  |  |  |                                       expected_type, default_value); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return result; | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-22 17:49:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  | static gboolean | 
					
						
							|  |  |  | g_delayed_settings_backend_write (GSettingsBackend *backend, | 
					
						
							|  |  |  |                                   const gchar      *key, | 
					
						
							|  |  |  |                                   GVariant         *value, | 
					
						
							|  |  |  |                                   gpointer          origin_tag) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (backend); | 
					
						
							|  |  |  |   gboolean was_empty; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-17 19:26:41 -04:00
										 |  |  |   g_mutex_lock (&delayed->priv->lock); | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  |   was_empty = g_tree_nnodes (delayed->priv->delayed) == 0; | 
					
						
							|  |  |  |   g_tree_insert (delayed->priv->delayed, g_strdup (key), | 
					
						
							|  |  |  |                  g_variant_ref_sink (value)); | 
					
						
							| 
									
										
										
										
											2011-09-17 19:26:41 -04:00
										 |  |  |   g_mutex_unlock (&delayed->priv->lock); | 
					
						
							| 
									
										
										
										
											2010-05-16 16:56:36 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  |   g_settings_backend_changed (backend, key, origin_tag); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-16 16:56:36 -04:00
										 |  |  |   if (was_empty) | 
					
						
							|  |  |  |     g_delayed_settings_backend_notify_unapplied (delayed); | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return TRUE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static gboolean | 
					
						
							|  |  |  | add_to_tree (gpointer key, | 
					
						
							|  |  |  |              gpointer value, | 
					
						
							|  |  |  |              gpointer user_data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   g_tree_insert (user_data, g_strdup (key), g_variant_ref (value)); | 
					
						
							|  |  |  |   return FALSE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static gboolean | 
					
						
							| 
									
										
										
										
											2010-07-22 18:39:50 -04:00
										 |  |  | g_delayed_settings_backend_write_tree (GSettingsBackend *backend, | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  |                                        GTree            *tree, | 
					
						
							|  |  |  |                                        gpointer          origin_tag) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (backend); | 
					
						
							|  |  |  |   gboolean was_empty; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-17 19:26:41 -04:00
										 |  |  |   g_mutex_lock (&delayed->priv->lock); | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  |   was_empty = g_tree_nnodes (delayed->priv->delayed) == 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   g_tree_foreach (tree, add_to_tree, delayed->priv->delayed); | 
					
						
							| 
									
										
										
										
											2011-09-17 19:26:41 -04:00
										 |  |  |   g_mutex_unlock (&delayed->priv->lock); | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   g_settings_backend_changed_tree (backend, tree, origin_tag); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-16 16:56:36 -04:00
										 |  |  |   if (was_empty) | 
					
						
							|  |  |  |     g_delayed_settings_backend_notify_unapplied (delayed); | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return TRUE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static gboolean | 
					
						
							|  |  |  | g_delayed_settings_backend_get_writable (GSettingsBackend *backend, | 
					
						
							|  |  |  |                                          const gchar      *name) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (backend); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return g_settings_backend_get_writable (delayed->priv->backend, name); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | g_delayed_settings_backend_reset (GSettingsBackend *backend, | 
					
						
							|  |  |  |                                   const gchar      *key, | 
					
						
							|  |  |  |                                   gpointer          origin_tag) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-07-22 17:49:40 -04:00
										 |  |  |   GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (backend); | 
					
						
							|  |  |  |   gboolean was_empty; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-17 19:26:41 -04:00
										 |  |  |   g_mutex_lock (&delayed->priv->lock); | 
					
						
							| 
									
										
										
										
											2010-07-22 17:49:40 -04:00
										 |  |  |   was_empty = g_tree_nnodes (delayed->priv->delayed) == 0; | 
					
						
							|  |  |  |   g_tree_insert (delayed->priv->delayed, g_strdup (key), NULL); | 
					
						
							| 
									
										
										
										
											2011-09-17 19:26:41 -04:00
										 |  |  |   g_mutex_unlock (&delayed->priv->lock); | 
					
						
							| 
									
										
										
										
											2010-07-22 17:49:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (was_empty) | 
					
						
							|  |  |  |     g_delayed_settings_backend_notify_unapplied (delayed); | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | g_delayed_settings_backend_subscribe (GSettingsBackend *backend, | 
					
						
							|  |  |  |                                       const char       *name) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (backend); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   g_settings_backend_subscribe (delayed->priv->backend, name); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | g_delayed_settings_backend_unsubscribe (GSettingsBackend *backend, | 
					
						
							|  |  |  |                                         const char       *name) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (backend); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   g_settings_backend_unsubscribe (delayed->priv->backend, name); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-04 23:07:40 +02:00
										 |  |  | 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); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  | /* method calls */ | 
					
						
							|  |  |  | gboolean | 
					
						
							|  |  |  | g_delayed_settings_backend_get_has_unapplied (GDelayedSettingsBackend *delayed) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-05-16 16:56:36 -04:00
										 |  |  |   /* we don't need to lock for this... */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  |   return g_tree_nnodes (delayed->priv->delayed) > 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | g_delayed_settings_backend_apply (GDelayedSettingsBackend *delayed) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (g_tree_nnodes (delayed->priv->delayed) > 0) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2010-04-17 11:39:04 -04:00
										 |  |  |       gboolean success; | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  |       GTree *tmp; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-17 19:26:41 -04:00
										 |  |  |       g_mutex_lock (&delayed->priv->lock); | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  |       tmp = delayed->priv->delayed; | 
					
						
							|  |  |  |       delayed->priv->delayed = g_settings_backend_create_tree (); | 
					
						
							| 
									
										
										
										
											2010-07-22 18:39:50 -04:00
										 |  |  |       success = g_settings_backend_write_tree (delayed->priv->backend, | 
					
						
							| 
									
										
										
										
											2010-04-17 11:39:04 -04:00
										 |  |  |                                                tmp, delayed->priv); | 
					
						
							| 
									
										
										
										
											2011-09-17 19:26:41 -04:00
										 |  |  |       g_mutex_unlock (&delayed->priv->lock); | 
					
						
							| 
									
										
										
										
											2010-04-17 11:39:04 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |       if (!success) | 
					
						
							|  |  |  |         g_settings_backend_changed_tree (G_SETTINGS_BACKEND (delayed), | 
					
						
							|  |  |  |                                          tmp, NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  |       g_tree_unref (tmp); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-16 16:56:36 -04:00
										 |  |  |       g_delayed_settings_backend_notify_unapplied (delayed); | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | g_delayed_settings_backend_revert (GDelayedSettingsBackend *delayed) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (g_tree_nnodes (delayed->priv->delayed) > 0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       GTree *tmp; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-17 19:26:41 -04:00
										 |  |  |       g_mutex_lock (&delayed->priv->lock); | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  |       tmp = delayed->priv->delayed; | 
					
						
							|  |  |  |       delayed->priv->delayed = g_settings_backend_create_tree (); | 
					
						
							| 
									
										
										
										
											2011-09-17 19:26:41 -04:00
										 |  |  |       g_mutex_unlock (&delayed->priv->lock); | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  |       g_settings_backend_changed_tree (G_SETTINGS_BACKEND (delayed), tmp, NULL); | 
					
						
							|  |  |  |       g_tree_unref (tmp); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-16 16:56:36 -04:00
										 |  |  |       g_delayed_settings_backend_notify_unapplied (delayed); | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* change notification */ | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2010-09-09 15:45:53 -04:00
										 |  |  | delayed_backend_changed (GObject          *target, | 
					
						
							|  |  |  |                          GSettingsBackend *backend, | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  |                          const gchar      *key, | 
					
						
							| 
									
										
										
										
											2010-05-16 14:17:34 -04:00
										 |  |  |                          gpointer          origin_tag) | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-05-16 14:17:34 -04:00
										 |  |  |   GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (target); | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (origin_tag != delayed->priv) | 
					
						
							|  |  |  |     g_settings_backend_changed (G_SETTINGS_BACKEND (delayed), | 
					
						
							|  |  |  |                                 key, origin_tag); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2010-09-09 15:45:53 -04:00
										 |  |  | delayed_backend_keys_changed (GObject             *target, | 
					
						
							|  |  |  |                               GSettingsBackend    *backend, | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  |                               const gchar         *path, | 
					
						
							|  |  |  |                               const gchar * const *items, | 
					
						
							| 
									
										
										
										
											2010-05-16 14:17:34 -04:00
										 |  |  |                               gpointer             origin_tag) | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-05-16 14:17:34 -04:00
										 |  |  |   GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (target); | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (origin_tag != delayed->priv) | 
					
						
							|  |  |  |     g_settings_backend_keys_changed (G_SETTINGS_BACKEND (delayed), | 
					
						
							|  |  |  |                                      path, items, origin_tag); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2010-09-09 15:45:53 -04:00
										 |  |  | delayed_backend_path_changed (GObject          *target, | 
					
						
							|  |  |  |                               GSettingsBackend *backend, | 
					
						
							| 
									
										
										
										
											2010-05-16 14:17:34 -04:00
										 |  |  |                               const gchar      *path, | 
					
						
							|  |  |  |                               gpointer          origin_tag) | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-05-16 14:17:34 -04:00
										 |  |  |   GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (target); | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (origin_tag != delayed->priv) | 
					
						
							|  |  |  |     g_settings_backend_path_changed (G_SETTINGS_BACKEND (delayed), | 
					
						
							|  |  |  |                                      path, origin_tag); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2010-09-09 15:45:53 -04:00
										 |  |  | delayed_backend_writable_changed (GObject          *target, | 
					
						
							|  |  |  |                                   GSettingsBackend *backend, | 
					
						
							| 
									
										
										
										
											2010-05-16 14:17:34 -04:00
										 |  |  |                                   const gchar      *key) | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-05-16 14:17:34 -04:00
										 |  |  |   GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (target); | 
					
						
							| 
									
										
										
										
											2010-05-16 16:56:36 -04:00
										 |  |  |   gboolean last_one = FALSE; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-17 19:26:41 -04:00
										 |  |  |   g_mutex_lock (&delayed->priv->lock); | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-07 11:42:46 +02:00
										 |  |  |   if (g_tree_lookup (delayed->priv->delayed, key) != NULL && | 
					
						
							| 
									
										
										
										
											2010-04-17 11:39:04 -04:00
										 |  |  |       !g_settings_backend_get_writable (delayed->priv->backend, key)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       /* drop the key from our changeset if it just became read-only.
 | 
					
						
							| 
									
										
										
										
											2010-05-16 16:56:36 -04:00
										 |  |  |        * no need to signal since the writable change below implies it. | 
					
						
							| 
									
										
										
										
											2011-05-07 11:42:46 +02:00
										 |  |  |        * | 
					
						
							|  |  |  |        * 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). | 
					
						
							| 
									
										
										
										
											2010-04-17 11:39:04 -04:00
										 |  |  |        */ | 
					
						
							|  |  |  |       g_tree_remove (delayed->priv->delayed, key); | 
					
						
							| 
									
										
										
										
											2010-04-17 11:58:52 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |       /* if that was the only key... */ | 
					
						
							| 
									
										
										
										
											2010-05-16 16:56:36 -04:00
										 |  |  |       last_one = g_tree_nnodes (delayed->priv->delayed) == 0; | 
					
						
							| 
									
										
										
										
											2010-04-17 11:39:04 -04:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-17 19:26:41 -04:00
										 |  |  |   g_mutex_unlock (&delayed->priv->lock); | 
					
						
							| 
									
										
										
										
											2010-05-16 16:56:36 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (last_one) | 
					
						
							|  |  |  |     g_delayed_settings_backend_notify_unapplied (delayed); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  |   g_settings_backend_writable_changed (G_SETTINGS_BACKEND (delayed), key); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-17 11:39:04 -04:00
										 |  |  | /* slow method until we get foreach-with-remove in GTree
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | typedef struct | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   const gchar *path; | 
					
						
							|  |  |  |   const gchar **keys; | 
					
						
							|  |  |  |   gsize index; | 
					
						
							|  |  |  | } CheckPrefixState; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static gboolean | 
					
						
							|  |  |  | check_prefix (gpointer key, | 
					
						
							|  |  |  |               gpointer value, | 
					
						
							|  |  |  |               gpointer data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   CheckPrefixState *state = data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (g_str_has_prefix (key, state->path)) | 
					
						
							|  |  |  |     state->keys[state->index++] = key; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return FALSE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  | static void | 
					
						
							| 
									
										
										
										
											2010-09-09 15:45:53 -04:00
										 |  |  | delayed_backend_path_writable_changed (GObject          *target, | 
					
						
							|  |  |  |                                        GSettingsBackend *backend, | 
					
						
							| 
									
										
										
										
											2010-05-16 14:17:34 -04:00
										 |  |  |                                        const gchar      *path) | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-05-16 14:17:34 -04:00
										 |  |  |   GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (target); | 
					
						
							| 
									
										
										
										
											2010-05-16 16:56:36 -04:00
										 |  |  |   gboolean last_one = FALSE; | 
					
						
							| 
									
										
										
										
											2010-04-17 11:58:52 -04:00
										 |  |  |   gsize n_keys; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-17 19:26:41 -04:00
										 |  |  |   g_mutex_lock (&delayed->priv->lock); | 
					
						
							| 
									
										
										
										
											2010-05-16 16:56:36 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-17 11:58:52 -04:00
										 |  |  |   n_keys = g_tree_nnodes (delayed->priv->delayed); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (n_keys > 0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       CheckPrefixState state = { path, g_new (const gchar *, n_keys) }; | 
					
						
							|  |  |  |       gsize i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* collect a list of possibly-affected keys (ie: matching the path) */ | 
					
						
							|  |  |  |       g_tree_foreach (delayed->priv->delayed, check_prefix, &state); | 
					
						
							| 
									
										
										
										
											2010-04-17 11:39:04 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-07 11:42:46 +02:00
										 |  |  |       /* drop the keys that have been affected.
 | 
					
						
							|  |  |  |        * | 
					
						
							|  |  |  |        * don't drop 'reset' keys (see above) */ | 
					
						
							| 
									
										
										
										
											2010-04-17 11:58:52 -04:00
										 |  |  |       for (i = 0; i < state.index; i++) | 
					
						
							| 
									
										
										
										
											2011-05-07 11:42:46 +02:00
										 |  |  |         if (g_tree_lookup (delayed->priv->delayed, state.keys[i]) != NULL && | 
					
						
							|  |  |  |             !g_settings_backend_get_writable (delayed->priv->backend, | 
					
						
							| 
									
										
										
										
											2010-04-17 11:58:52 -04:00
										 |  |  |                                               state.keys[i])) | 
					
						
							|  |  |  |           g_tree_remove (delayed->priv->delayed, state.keys[i]); | 
					
						
							| 
									
										
										
										
											2010-04-17 11:39:04 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-17 11:58:52 -04:00
										 |  |  |       g_free (state.keys); | 
					
						
							| 
									
										
										
										
											2010-04-17 11:39:04 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-16 16:56:36 -04:00
										 |  |  |       last_one = g_tree_nnodes (delayed->priv->delayed) == 0; | 
					
						
							| 
									
										
										
										
											2010-04-17 11:58:52 -04:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-17 19:26:41 -04:00
										 |  |  |   g_mutex_unlock (&delayed->priv->lock); | 
					
						
							| 
									
										
										
										
											2010-05-16 16:56:36 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (last_one) | 
					
						
							|  |  |  |     g_delayed_settings_backend_notify_unapplied (delayed); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  |   g_settings_backend_path_writable_changed (G_SETTINGS_BACKEND (delayed), | 
					
						
							|  |  |  |                                             path); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | g_delayed_settings_backend_finalize (GObject *object) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (object); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-17 19:26:41 -04:00
										 |  |  |   g_mutex_clear (&delayed->priv->lock); | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  |   g_object_unref (delayed->priv->backend); | 
					
						
							| 
									
										
										
										
											2010-06-24 00:38:01 -04:00
										 |  |  |   g_tree_unref (delayed->priv->delayed); | 
					
						
							| 
									
										
										
										
											2010-05-16 16:56:36 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* 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); | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | 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->write = g_delayed_settings_backend_write; | 
					
						
							| 
									
										
										
										
											2010-07-22 18:39:50 -04:00
										 |  |  |   backend_class->write_tree = g_delayed_settings_backend_write_tree; | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  |   backend_class->reset = g_delayed_settings_backend_reset; | 
					
						
							|  |  |  |   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; | 
					
						
							| 
									
										
										
										
											2010-06-04 23:07:40 +02:00
										 |  |  |   backend_class->get_permission = g_delayed_settings_backend_get_permission; | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   object_class->finalize = g_delayed_settings_backend_finalize; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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->delayed = g_settings_backend_create_tree (); | 
					
						
							| 
									
										
										
										
											2011-09-17 19:26:41 -04:00
										 |  |  |   g_mutex_init (&delayed->priv->lock); | 
					
						
							| 
									
										
										
										
											2010-05-16 16:56:36 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | g_delayed_settings_backend_disown (gpointer  data, | 
					
						
							|  |  |  |                                    GObject  *where_the_object_was) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   GDelayedSettingsBackend *delayed = data; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-17 19:26:41 -04:00
										 |  |  |   g_mutex_lock (&delayed->priv->lock); | 
					
						
							| 
									
										
										
										
											2010-05-16 16:56:36 -04:00
										 |  |  |   delayed->priv->owner_context = NULL; | 
					
						
							|  |  |  |   delayed->priv->owner = NULL; | 
					
						
							| 
									
										
										
										
											2011-09-17 19:26:41 -04:00
										 |  |  |   g_mutex_unlock (&delayed->priv->lock); | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | GDelayedSettingsBackend * | 
					
						
							|  |  |  | g_delayed_settings_backend_new (GSettingsBackend *backend, | 
					
						
							| 
									
										
										
										
											2010-05-16 16:56:36 -04:00
										 |  |  |                                 gpointer          owner, | 
					
						
							|  |  |  |                                 GMainContext     *owner_context) | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-09-09 15:45:53 -04:00
										 |  |  |   static GSettingsListenerVTable vtable = { | 
					
						
							|  |  |  |     delayed_backend_changed, | 
					
						
							|  |  |  |     delayed_backend_path_changed, | 
					
						
							|  |  |  |     delayed_backend_keys_changed, | 
					
						
							|  |  |  |     delayed_backend_writable_changed, | 
					
						
							|  |  |  |     delayed_backend_path_writable_changed | 
					
						
							|  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  |   GDelayedSettingsBackend *delayed; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   delayed = g_object_new (G_TYPE_DELAYED_SETTINGS_BACKEND, NULL); | 
					
						
							|  |  |  |   delayed->priv->backend = g_object_ref (backend); | 
					
						
							| 
									
										
										
										
											2010-05-16 16:56:36 -04:00
										 |  |  |   delayed->priv->owner_context = owner_context; | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  |   delayed->priv->owner = owner; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-16 16:56:36 -04:00
										 |  |  |   g_object_weak_ref (owner, g_delayed_settings_backend_disown, delayed); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-09-09 15:45:53 -04:00
										 |  |  |   g_settings_backend_watch (delayed->priv->backend, | 
					
						
							|  |  |  |                             &vtable, G_OBJECT (delayed), NULL); | 
					
						
							| 
									
										
										
										
											2010-04-16 12:02:44 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return delayed; | 
					
						
							|  |  |  | } |