summaryrefslogtreecommitdiff
path: root/eel/eel-preferences.c
diff options
context:
space:
mode:
Diffstat (limited to 'eel/eel-preferences.c')
-rw-r--r--eel/eel-preferences.c1764
1 files changed, 1764 insertions, 0 deletions
diff --git a/eel/eel-preferences.c b/eel/eel-preferences.c
new file mode 100644
index 00000000..7a24ed11
--- /dev/null
+++ b/eel/eel-preferences.c
@@ -0,0 +1,1764 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* eel-preferences.c - Preference peek/poke/notify implementation.
+
+ Copyright (C) 1999, 2000 Eazel, Inc.
+
+ The Mate Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Mate 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Mate Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Authors: Ramiro Estrugo <[email protected]>
+*/
+
+#include <config.h>
+#include "eel-preferences.h"
+
+#include "eel-debug.h"
+#include "eel-mateconf-extensions.h"
+#include "eel-lib-self-check-functions.h"
+#include "eel-enumeration.h"
+#include "eel-glib-extensions.h"
+#include "eel-string.h"
+#include <mateconf/mateconf-client.h>
+#include <mateconf/mateconf.h>
+#include <gtk/gtk.h>
+
+/* An enumeration used for updating auto-storage variables in a type-specific way.
+ * FIXME: there is another enumeration like this in eel-global-preferences.c,
+ * used for different purposes but in a related way. Should we combine them?
+ */
+typedef enum
+{
+ PREFERENCE_BOOLEAN = 1,
+ PREFERENCE_INTEGER,
+ PREFERENCE_STRING,
+ PREFERENCE_STRING_ARRAY,
+ PREFERENCE_STRING_ARRAY_AS_QUARKS
+} PreferenceType;
+
+/*
+ * PreferencesEntry:
+ *
+ * A structure to manage preference hash table nodes.
+ * Preferences are hash tables. The hash key is the preference name
+ * (a string). The hash value is a pointer of the following struct:
+ */
+typedef struct
+{
+ char *name;
+ char *description;
+ PreferenceType type;
+ gboolean invisible;
+ GList *callback_list;
+ GList *auto_storage_list;
+ int mateconf_connection_id;
+ char *enumeration_id;
+ MateConfValue *fallback;
+} PreferencesEntry;
+
+/*
+ * PreferencesCallbackEntry:
+ *
+ * A structure to manage callback lists. A callback list is a GList.
+ * The callback_data in each list node is a pointer to the following
+ * struct:
+ */
+typedef struct
+{
+ EelPreferencesCallback callback;
+ gpointer callback_data;
+} PreferencesCallbackEntry;
+
+static GHashTable *global_table = NULL;
+static char *storage_path = NULL;
+static gboolean initialized = FALSE;
+
+static void preferences_global_table_free (void);
+static char * preferences_key_make (const char *name);
+static void preferences_callback_entry_free (PreferencesCallbackEntry *callback_entry);
+static void preferences_entry_update_auto_storage (PreferencesEntry *entry);
+static PreferencesEntry *preferences_global_table_lookup_or_insert (const char *name);
+
+static int
+preferences_mateconf_value_get_int (const MateConfValue *value)
+{
+ if (value == NULL)
+ {
+ return 0;
+ }
+ g_assert (value->type == MATECONF_VALUE_INT);
+ return mateconf_value_get_int (value);
+}
+
+static gboolean
+preferences_mateconf_value_get_bool (const MateConfValue *value)
+{
+ if (value == NULL)
+ {
+ return FALSE;
+ }
+ g_assert (value->type == MATECONF_VALUE_BOOL);
+ return mateconf_value_get_bool (value);
+}
+
+static char *
+preferences_mateconf_value_get_string (const MateConfValue *value)
+{
+ if (value == NULL)
+ {
+ return g_strdup ("");
+ }
+ g_assert (value->type == MATECONF_VALUE_STRING);
+ return g_strdup (mateconf_value_get_string (value));
+}
+
+static char **
+preferences_mateconf_value_get_string_array (const MateConfValue *value)
+{
+ GSList *slist, *l;
+ GPtrArray *result;
+
+ if (value == NULL)
+ {
+ return NULL;
+ }
+
+ g_assert (value->type == MATECONF_VALUE_LIST);
+ g_assert (mateconf_value_get_list_type (value) == MATECONF_VALUE_STRING);
+
+ slist = eel_mateconf_value_get_string_list (value);
+
+ result = g_ptr_array_new ();
+ for (l = slist; l != NULL; l = l->next)
+ {
+ g_ptr_array_add (result, l->data);
+ }
+ g_slist_free (slist);
+ g_ptr_array_add (result, NULL);
+
+ return (char **) g_ptr_array_free (result, FALSE);
+}
+
+static const char *
+preferences_peek_storage_path (void)
+{
+ g_assert (storage_path != NULL);
+
+ return storage_path;
+}
+
+static void
+preferences_set_storage_path (const char *new_storage_path)
+{
+ g_assert (eel_strlen (new_storage_path) > 0);
+
+ /* Make sure the path is indeed different */
+ if (eel_str_is_equal (new_storage_path, storage_path))
+ {
+ return;
+ }
+
+ /* Free the preference hash table */
+ preferences_global_table_free ();
+
+ /* Stop monitoring the old path */
+ eel_mateconf_monitor_remove (storage_path);
+
+ g_free (storage_path);
+ storage_path = g_strdup (new_storage_path);
+
+ /* Start monitoring the new path */
+ eel_mateconf_monitor_add (storage_path);
+}
+
+static gboolean
+preferences_is_initialized (void)
+{
+ return initialized;
+}
+
+static MateConfValue *
+preferences_get_value (const char *name)
+{
+ MateConfValue *result;
+ char *key;
+ PreferencesEntry *entry;
+
+ g_assert (name != NULL);
+ g_assert (preferences_is_initialized ());
+
+ key = preferences_key_make (name);
+ result = eel_mateconf_get_value (key);
+ g_free (key);
+
+ if (result == NULL)
+ {
+ entry = preferences_global_table_lookup_or_insert (name);
+
+ if (entry->fallback)
+ result = mateconf_value_copy (entry->fallback);
+ }
+
+ return result;
+}
+
+/* If the preference name begind with a "/", we interpret
+ * it as a straight mateconf key. */
+static gboolean
+preferences_preference_is_mateconf_key (const char *name)
+{
+ g_assert (name != NULL);
+
+ if (eel_str_has_prefix (name, "/"))
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static char *
+preferences_key_make (const char *name)
+{
+ g_assert (name != NULL);
+
+ if (!preferences_preference_is_mateconf_key (name))
+ {
+ return g_strdup (name);
+ }
+
+ /* Otherwise, we prefix it with the path */
+ return g_strconcat (preferences_peek_storage_path (), "/",
+ name, NULL);
+}
+
+/* Get default from schema or emergency fallback */
+static MateConfValue *
+preferences_get_default_value (const char *name)
+{
+ MateConfValue *result;
+ PreferencesEntry *entry;
+ char *key;
+
+ g_assert (name != NULL);
+
+ key = preferences_key_make (name);
+
+ result = eel_mateconf_get_default_value (key);
+
+ g_free (key);
+
+ if (result == NULL)
+ {
+ entry = preferences_global_table_lookup_or_insert (name);
+ if (entry && entry->fallback)
+ result = mateconf_value_copy (entry->fallback);
+ }
+
+ return result;
+}
+
+static int
+preferences_callback_entry_compare (gconstpointer a,
+ gconstpointer b)
+{
+ const PreferencesCallbackEntry *a_entry = a;
+ const PreferencesCallbackEntry *b_entry = b;
+
+ if (a_entry->callback < b_entry->callback)
+ {
+ return -1;
+ }
+
+ if (a_entry->callback > b_entry->callback)
+ {
+ return +1;
+ }
+
+ if (a_entry->callback_data < b_entry->callback_data)
+ {
+ return -1;
+ }
+
+ if (a_entry->callback_data > b_entry->callback_data)
+ {
+ return +1;
+ }
+
+ return 0;
+}
+
+/* Public preferences functions */
+
+gboolean
+eel_preferences_get_is_invisible (const char *name)
+{
+ g_assert (name != NULL);
+ g_assert (preferences_is_initialized ());
+
+ return preferences_global_table_lookup_or_insert (name)->invisible;
+}
+
+void
+eel_preferences_set_is_invisible (const char *name,
+ gboolean is_invisible)
+{
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (preferences_is_initialized ());
+
+ preferences_global_table_lookup_or_insert (name)->invisible = is_invisible;
+}
+
+void
+eel_preferences_set_boolean (const char *name,
+ gboolean boolean_value)
+{
+ char *key;
+
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (preferences_is_initialized ());
+
+ key = preferences_key_make (name);
+ eel_mateconf_set_boolean (key, boolean_value);
+ g_free (key);
+
+ eel_mateconf_suggest_sync ();
+}
+
+gboolean
+eel_preferences_get_boolean (const char *name)
+{
+ gboolean result;
+ MateConfValue *value;
+
+ g_return_val_if_fail (name != NULL, 0);
+ g_return_val_if_fail (preferences_is_initialized (), 0);
+
+ value = preferences_get_value (name);
+ result = preferences_mateconf_value_get_bool (value);
+ eel_mateconf_value_free (value);
+
+ return result;
+}
+
+void
+eel_preferences_set_integer (const char *name,
+ int int_value)
+{
+ char *key;
+ int old_value;
+
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (preferences_is_initialized ());
+
+ key = preferences_key_make (name);
+ old_value = eel_preferences_get_integer (name);
+
+ if (int_value != old_value)
+ {
+ eel_mateconf_set_integer (key, int_value);
+ }
+ g_free (key);
+}
+
+int
+eel_preferences_get_integer (const char *name)
+{
+ int result;
+ MateConfValue *value;
+
+ g_return_val_if_fail (name != NULL, 0);
+ g_return_val_if_fail (preferences_is_initialized (), 0);
+
+ value = preferences_get_value (name);
+ result = preferences_mateconf_value_get_int (value);
+ eel_mateconf_value_free (value);
+
+ return result;
+}
+
+/* MateConf has no unsigned store, save as signed and cast */
+guint
+eel_preferences_get_uint (const char *name)
+{
+ return (guint)eel_preferences_get_integer (name);
+}
+void
+eel_preferences_set_uint (const char *name,
+ guint uint_value)
+{
+ eel_preferences_set_integer (name, (int)uint_value);
+}
+
+guint
+eel_preferences_get_enum (const char *name)
+{
+ guint ret_val;
+ char *str_value;
+ MateConfValue *value;
+ const EelEnumeration *enumeration;
+ PreferencesEntry *entry;
+
+ g_return_val_if_fail (name != NULL, 0);
+ g_return_val_if_fail (preferences_is_initialized (), 0);
+
+ entry = preferences_global_table_lookup_or_insert (name);
+ g_return_val_if_fail (entry != NULL, 0);
+
+ enumeration = eel_enumeration_lookup (entry->enumeration_id);
+
+ if (!enumeration)
+ {
+ g_warning ("No enum entry for '%s' (%s)",
+ name, entry->enumeration_id);
+ return 0;
+ }
+
+ value = preferences_get_value (name);
+ if (value->type == MATECONF_VALUE_INT) /* compatibility path */
+ {
+ ret_val = (guint)preferences_mateconf_value_get_int (value);
+ eel_mateconf_value_free (value);
+ return ret_val;
+ }
+
+ str_value = preferences_mateconf_value_get_string (value);
+ eel_mateconf_value_free (value);
+
+ if (str_value == NULL)
+ {
+ g_warning ("No key for '%s' at %s", str_value, name);
+ return 0;
+ }
+
+ ret_val = eel_enumeration_get_value_for_name (enumeration, str_value);
+
+ g_free (str_value);
+
+ return ret_val;
+}
+
+void
+eel_preferences_set_enum (const char *name,
+ guint int_value)
+{
+ const char *str_value;
+ const EelEnumeration *enumeration;
+ PreferencesEntry *entry;
+
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (preferences_is_initialized ());
+
+ entry = preferences_global_table_lookup_or_insert (name);
+ g_return_if_fail (entry != NULL);
+
+ enumeration = eel_enumeration_lookup (entry->enumeration_id);
+
+ if (!enumeration)
+ {
+ g_warning ("No enum entry for '%s' (%s)",
+ name, entry->enumeration_id);
+ return;
+ }
+
+ str_value = eel_enumeration_get_name_for_value (enumeration, int_value);
+
+ if (str_value == NULL)
+ {
+ g_warning ("No enum match for '%d'", int_value);
+ return;
+ }
+
+ eel_preferences_set (name, str_value);
+}
+
+void
+eel_preferences_set (const char *name,
+ const char *string_value)
+{
+ char *key;
+ char *old_value;
+
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (preferences_is_initialized ());
+
+ key = preferences_key_make (name);
+ old_value = eel_preferences_get (name);
+
+ if (strcmp (string_value, old_value) != 0)
+ {
+ eel_mateconf_set_string (key, string_value);
+ }
+ g_free (key);
+ g_free (old_value);
+}
+
+char *
+eel_preferences_get (const char *name)
+{
+ char *result;
+ MateConfValue *value;
+
+ g_return_val_if_fail (name != NULL, NULL);
+ g_return_val_if_fail (preferences_is_initialized (), NULL);
+
+ value = preferences_get_value (name);
+ result = preferences_mateconf_value_get_string (value);
+ eel_mateconf_value_free (value);
+
+ return result;
+}
+
+void
+eel_preferences_set_string_array (const char *name,
+ char **strv_value)
+{
+ GSList *slist;
+ int i;
+ char *key;
+
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (preferences_is_initialized ());
+
+ slist = NULL;
+ if (strv_value != NULL)
+ {
+ for (i = 0; strv_value[i] != NULL; i++)
+ {
+ slist = g_slist_prepend (slist, strv_value[i]);
+ }
+ slist = g_slist_reverse (slist);
+ }
+
+ key = preferences_key_make (name);
+ eel_mateconf_set_string_list (key, slist);
+ g_free (key);
+
+ g_slist_free (slist);
+}
+
+static gboolean
+string_array_is_valid (char **strv, const char *enumeration_id)
+{
+ guint i;
+ gboolean res;
+
+ g_assert (strv != NULL);
+ g_assert (enumeration_id != NULL);
+
+ res = TRUE;
+ for (i = 0; strv[i] != NULL; i++)
+ {
+ const EelEnumeration *enumeration;
+
+ enumeration = eel_enumeration_lookup (enumeration_id);
+ if (!enumeration)
+ {
+ res = FALSE;
+ break;
+ }
+
+ if (!eel_enumeration_contains_name (enumeration, strv[i]))
+ {
+ res = FALSE;
+ break;
+ }
+ }
+
+ return res;
+}
+
+char **
+eel_preferences_get_string_array (const char *name)
+{
+ char **result;
+ MateConfValue *value;
+ PreferencesEntry *entry;
+ MateConfValue *default_value;
+
+ g_return_val_if_fail (name != NULL, NULL);
+ g_return_val_if_fail (preferences_is_initialized (), NULL);
+
+ value = preferences_get_value (name);
+ result = preferences_mateconf_value_get_string_array (value);
+ eel_mateconf_value_free (value);
+
+ entry = preferences_global_table_lookup_or_insert (name);
+ g_assert (entry != NULL);
+
+ /* No enumeration_id so we're done */
+ if (entry->enumeration_id == NULL)
+ {
+ return result;
+ }
+
+ /* Do a sanity check on the validity of the values */
+ if (string_array_is_valid (result, entry->enumeration_id))
+ {
+ return result;
+ }
+
+ /* Forget the bad value and use the default instead */
+ g_strfreev (result);
+
+ default_value = preferences_get_default_value (name);
+ if (default_value)
+ {
+ result = preferences_mateconf_value_get_string_array (default_value);
+ mateconf_value_free (default_value);
+ }
+
+ return result;
+}
+
+void
+eel_preferences_unset (const char *name)
+{
+ char *key;
+
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (preferences_is_initialized ());
+
+ key = preferences_key_make (name);
+
+ eel_mateconf_unset (key);
+
+ g_free (key);
+}
+
+gboolean
+eel_preferences_key_is_writable (const char *name)
+{
+ gboolean result;
+ char *key;
+
+ g_return_val_if_fail (name != NULL, 0);
+ g_return_val_if_fail (preferences_is_initialized (), 0);
+
+ key = preferences_key_make (name);
+ result = eel_mateconf_key_is_writable (key);
+ g_free (key);
+
+ return result;
+}
+
+/**
+ * preferences_callback_entry_invoke_function
+ *
+ * A function that invokes a callback from the given struct. It is meant to be fed to
+ * g_list_foreach ()
+ * @data: The list data privately maintained by the GList.
+ * @callback_data: The callback_data privately maintained by the GList.
+ **/
+static void
+preferences_callback_entry_invoke_function (gpointer data,
+ gpointer callback_data)
+{
+ PreferencesCallbackEntry *callback_entry;
+
+ g_assert (data != NULL);
+
+ callback_entry = data;
+
+ (* callback_entry->callback) (callback_entry->callback_data);
+}
+
+static void
+preferences_entry_invoke_callbacks (PreferencesEntry *entry)
+{
+ g_assert (entry != NULL);
+
+ /* Update the auto storage preferences */
+ if (entry->auto_storage_list != NULL)
+ {
+ preferences_entry_update_auto_storage (entry);
+ }
+
+ /* Invoke callbacks for this entry if any */
+ if (entry->callback_list != NULL)
+ {
+ g_list_foreach (entry->callback_list,
+ preferences_callback_entry_invoke_function,
+ NULL);
+ }
+}
+
+static void
+update_auto_string (gpointer data, gpointer callback_data)
+{
+ char **storage;
+ const char *value;
+
+ g_assert (data != NULL);
+ g_assert (callback_data != NULL);
+
+ storage = (char **)data;
+ value = (const char *)callback_data;
+
+ g_free (*storage);
+ *(char **)storage = g_strdup (value);
+}
+
+static void
+update_auto_string_array (gpointer data, gpointer callback_data)
+{
+ char ***storage;
+ char **value;
+
+ g_assert (data != NULL);
+ g_assert (callback_data != NULL);
+
+ storage = (char ***)data;
+ value = (char **)callback_data;
+
+ g_strfreev (*storage);
+ *(char ***)storage = value ? g_strdupv (value) : NULL;
+}
+
+static void
+update_auto_string_array_as_quarks (gpointer data, gpointer callback_data)
+{
+ GQuark **storage;
+ char **value;
+ int i = 0;
+
+ g_assert (data != NULL);
+ g_assert (callback_data != NULL);
+
+ storage = (GQuark **)data;
+ value = (char **)callback_data;
+
+ g_free (*storage);
+ *storage = g_new (GQuark, g_strv_length (value) + 1);
+
+ if (value != NULL)
+ {
+ for (i = 0; value[i] != NULL; ++i)
+ {
+ (*storage)[i] = g_quark_from_string (value[i]);
+ }
+ }
+ (*storage)[i] = 0;
+}
+
+static void
+update_auto_integer_or_boolean (gpointer data, gpointer callback_data)
+{
+ g_assert (data != NULL);
+
+ *(int *)data = GPOINTER_TO_INT (callback_data);
+}
+
+static void
+preferences_entry_update_auto_storage (PreferencesEntry *entry)
+{
+ char *new_string_value;
+ char **new_string_array_value;
+ int new_int_value;
+ guint new_uint_value;
+ gboolean new_boolean_value;
+
+ switch (entry->type)
+ {
+ case PREFERENCE_STRING:
+ if (entry->enumeration_id != NULL)
+ {
+ new_uint_value = eel_preferences_get_enum (entry->name);
+ g_list_foreach (entry->auto_storage_list,
+ update_auto_integer_or_boolean,
+ GINT_TO_POINTER (new_uint_value));
+ }
+ else
+ {
+ new_string_value = eel_preferences_get (entry->name);
+ g_list_foreach (entry->auto_storage_list,
+ update_auto_string,
+ new_string_value);
+ g_free (new_string_value);
+ }
+ break;
+ case PREFERENCE_STRING_ARRAY:
+ new_string_array_value = eel_preferences_get_string_array (entry->name);
+ g_list_foreach (entry->auto_storage_list,
+ update_auto_string_array,
+ new_string_array_value);
+ g_strfreev (new_string_array_value);
+ break;
+ case PREFERENCE_STRING_ARRAY_AS_QUARKS:
+ new_string_array_value = eel_preferences_get_string_array (entry->name);
+ g_list_foreach (entry->auto_storage_list,
+ update_auto_string_array_as_quarks,
+ new_string_array_value);
+ g_strfreev (new_string_array_value);
+ break;
+ case PREFERENCE_INTEGER:
+ new_int_value = eel_preferences_get_integer (entry->name);
+ g_list_foreach (entry->auto_storage_list,
+ update_auto_integer_or_boolean,
+ GINT_TO_POINTER (new_int_value));
+ break;
+ case PREFERENCE_BOOLEAN:
+ new_boolean_value = eel_preferences_get_boolean (entry->name);
+ g_list_foreach (entry->auto_storage_list,
+ update_auto_integer_or_boolean,
+ GINT_TO_POINTER (new_boolean_value));
+ break;
+ default:
+ g_warning ("unexpected preferences type %d in preferences_entry_update_auto_storage", entry->type);
+ }
+}
+
+static void
+preferences_something_changed_notice (MateConfClient *client,
+ guint connection_id,
+ MateConfEntry *entry,
+ gpointer notice_data)
+{
+ g_assert (entry != NULL);
+ g_assert (entry->key != NULL);
+ g_assert (notice_data != NULL);
+
+ preferences_entry_invoke_callbacks (notice_data);
+}
+
+static void
+preferences_entry_ensure_mateconf_connection (PreferencesEntry *entry)
+{
+ char *key;
+
+ /*
+ * We install only one mateconf notification for each preference entry.
+ * Otherwise, we would invoke the installed callbacks more than once
+ * per registered callback.
+ */
+ if (entry->mateconf_connection_id != EEL_MATECONF_UNDEFINED_CONNECTION)
+ {
+ return;
+ }
+
+ g_assert (entry->name != NULL);
+
+ key = preferences_key_make (entry->name);
+
+ entry->mateconf_connection_id = eel_mateconf_notification_add (key,
+ preferences_something_changed_notice,
+ entry);
+ g_free (key);
+
+ g_assert (entry->mateconf_connection_id != EEL_MATECONF_UNDEFINED_CONNECTION);
+}
+
+/**
+ * preferences_entry_add_callback
+ *
+ * Add a callback to a pref node. Callbacks are fired whenever
+ * the pref value changes.
+ * @preferences_entry: The hash node.
+ * @callback: The user-supplied callback.
+ * @callback_data: The user-supplied closure.
+ **/
+static void
+preferences_entry_add_callback (PreferencesEntry *entry,
+ EelPreferencesCallback callback,
+ gpointer callback_data)
+{
+ PreferencesCallbackEntry *callback_entry;
+ GList *l;
+
+ g_assert (entry != NULL);
+ g_assert (callback != NULL);
+
+ callback_entry = g_new0 (PreferencesCallbackEntry, 1);
+ callback_entry->callback = callback;
+ callback_entry->callback_data = callback_data;
+
+ l = g_list_find_custom (entry->callback_list, callback_entry, preferences_callback_entry_compare);
+ if (l == NULL)
+ {
+ entry->callback_list = g_list_append (entry->callback_list, callback_entry);
+ preferences_entry_ensure_mateconf_connection (entry);
+ }
+ else
+ {
+ g_warning ("Trying to add a callback for %s that already exists.", entry->name);
+ }
+}
+
+/**
+ * preferences_entry_add_auto_storage
+ *
+ * Add an auto-storage variable to a pref node. The variable will
+ * be updated to match the pref value whenever the pref
+ * the pref value changes.
+ * @preferences_entry: The hash node.
+ * @storage: The user-supplied location at which to store the value.
+ * @type: Which type of variable this is.
+ **/
+static void
+preferences_entry_add_auto_storage (PreferencesEntry *entry,
+ gpointer storage,
+ PreferenceType type)
+{
+ g_assert (entry != NULL);
+ g_assert (storage != NULL);
+ g_assert (entry->type == 0 || entry->type == type);
+ if (g_list_find (entry->auto_storage_list, storage) != NULL)
+ {
+ g_warning ("Trying to add an auto storage for %s that already exists.", entry->name);
+ return;
+ }
+
+ entry->type = type;
+
+ entry->auto_storage_list = g_list_append (entry->auto_storage_list, storage);
+
+ preferences_entry_ensure_mateconf_connection (entry);
+}
+
+static void
+preferences_entry_check_remove_connection (PreferencesEntry *entry)
+{
+ /*
+ * If there are no callbacks or auto-storage variables left in the entry,
+ * remove the mateconf notification.
+ */
+ if (entry->callback_list != NULL || entry->auto_storage_list != NULL)
+ {
+ return;
+ }
+
+ eel_mateconf_notification_remove (entry->mateconf_connection_id);
+ entry->mateconf_connection_id = EEL_MATECONF_UNDEFINED_CONNECTION;
+}
+
+/**
+ * preferences_entry_remove_callback
+ *
+ * remove a callback from a pref entry. Both the callback and the callback_data must
+ * match in order for a callback to be removed from the entry.
+ * @preferences_entry: The hash entry.
+ * @callback: The user-supplied callback.
+ * @callback_data: The user-supplied closure.
+ **/
+static void
+preferences_entry_remove_callback (PreferencesEntry *entry,
+ EelPreferencesCallback callback,
+ gpointer callback_data)
+{
+ PreferencesCallbackEntry cb_entry;
+ GList *l;
+
+ g_assert (entry != NULL);
+ g_assert (callback != NULL);
+
+ cb_entry.callback = callback;
+ cb_entry.callback_data = callback_data;
+
+ l = g_list_find_custom (entry->callback_list, &cb_entry, preferences_callback_entry_compare);
+ if (l != NULL)
+ {
+ preferences_callback_entry_free (l->data);
+ entry->callback_list = g_list_delete_link (entry->callback_list, l);
+ preferences_entry_check_remove_connection (entry);
+ }
+ else
+ {
+ g_warning ("Trying to remove a callback for %s without adding it first.", entry->name);
+ }
+
+ g_assert (g_list_find_custom (entry->callback_list, &cb_entry, preferences_callback_entry_compare) == NULL);
+}
+
+/**
+ * preferences_entry_remove_auto_storage
+ *
+ * remove an auto-storage variable from a pref entry.
+ * @preferences_entry: The hash entry.
+ * @storage: The user-supplied location.
+ **/
+static void
+preferences_entry_remove_auto_storage (PreferencesEntry *entry,
+ gpointer storage)
+{
+ GList *new_list;
+ const GList *node;
+ gpointer storage_in_entry;
+
+ g_assert (entry != NULL);
+ g_assert (storage != NULL);
+ g_assert (entry->auto_storage_list != NULL);
+
+ new_list = g_list_copy (entry->auto_storage_list);
+
+ for (node = new_list; node != NULL; node = node->next)
+ {
+ storage_in_entry = node->data;
+
+ g_assert (storage_in_entry != NULL);
+
+ if (storage_in_entry == storage)
+ {
+ entry->auto_storage_list = g_list_remove (entry->auto_storage_list,
+ storage);
+
+ switch (entry->type)
+ {
+ case PREFERENCE_STRING:
+ update_auto_string (storage, NULL);
+ break;
+ case PREFERENCE_STRING_ARRAY:
+ update_auto_string_array (storage, NULL);
+ break;
+ case PREFERENCE_STRING_ARRAY_AS_QUARKS:
+ update_auto_string_array_as_quarks (storage, NULL);
+ break;
+ case PREFERENCE_BOOLEAN:
+ case PREFERENCE_INTEGER:
+ update_auto_integer_or_boolean (storage, NULL);
+ break;
+ default:
+ g_warning ("unexpected preference type %d in preferences_entry_remove_auto_storage", entry->type);
+ }
+ }
+ }
+
+ g_list_free (new_list);
+
+ preferences_entry_check_remove_connection (entry);
+}
+
+/**
+ * preferences_callback_entry_free
+ *
+ * Free a callback info struct.
+ * @preferences_callback_entry: The struct to free.
+ **/
+static void
+preferences_callback_entry_free (PreferencesCallbackEntry *callback_entry)
+{
+ g_assert (callback_entry != NULL);
+
+ callback_entry->callback = NULL;
+ callback_entry->callback_data = NULL;
+
+ g_free (callback_entry);
+}
+
+/**
+ * preferences_callback_entry_free_func
+ *
+ * A function that frees a callback info struct. It is meant to be fed to
+ * g_list_foreach ()
+ * @data: The list data privately maintained by the GList.
+ * @callback_data: The callback_data privately maintained by the GList.
+ **/
+static void
+preferences_callback_entry_free_func (gpointer data,
+ gpointer callback_data)
+{
+ g_assert (data != NULL);
+
+ preferences_callback_entry_free (data);
+}
+
+/**
+ * preferences_entry_free
+ *
+ * Free a preference hash node's members along with the node itself.
+ * @preferences_hash_node: The node to free.
+ **/
+static void
+preferences_entry_free (PreferencesEntry *entry)
+{
+ g_assert (entry != NULL);
+
+ eel_mateconf_notification_remove (entry->mateconf_connection_id);
+ entry->mateconf_connection_id = EEL_MATECONF_UNDEFINED_CONNECTION;
+
+ g_list_free (entry->auto_storage_list);
+ eel_g_list_free_deep_custom (entry->callback_list,
+ preferences_callback_entry_free_func,
+ NULL);
+
+ entry->auto_storage_list = NULL;
+ entry->callback_list = NULL;
+
+ g_free (entry->name);
+ g_free (entry->description);
+ g_free (entry->enumeration_id);
+
+ eel_mateconf_value_free (entry->fallback);
+
+ g_free (entry);
+}
+
+/**
+ * preferences_entry_free_func
+ *
+ * A function that frees a pref hash node. It is meant to be fed to
+ * g_hash_table_foreach ()
+ * @key: The hash key privately maintained by the GHashTable.
+ * @value: The hash value privately maintained by the GHashTable.
+ * @callback_data: The callback_data privately maintained by the GHashTable.
+ **/
+static void
+preferences_entry_free_func (gpointer key,
+ gpointer value,
+ gpointer callback_data)
+{
+ g_assert (value != NULL);
+
+ preferences_entry_free (value);
+}
+
+static void
+preferences_global_table_free (void)
+{
+ if (global_table == NULL)
+ {
+ return;
+ }
+
+ g_hash_table_foreach (global_table, preferences_entry_free_func, NULL);
+ g_hash_table_destroy (global_table);
+ global_table = NULL;
+
+ g_free (storage_path);
+ storage_path = NULL;
+}
+
+static void
+preferences_uninitialize (void)
+{
+ initialized = FALSE;
+}
+
+static GHashTable *
+preferences_global_table_get_global (void)
+{
+ static gboolean at_exit_handler_added = FALSE;
+
+ if (global_table == NULL)
+ {
+ global_table = g_hash_table_new (g_str_hash, g_str_equal);
+
+ if (!at_exit_handler_added)
+ {
+ at_exit_handler_added = TRUE;
+ eel_debug_call_at_shutdown (preferences_global_table_free);
+ /* ensure that we catch calls to preferences functions after eel shutdown */
+ eel_debug_call_at_shutdown (preferences_uninitialize);
+ }
+ }
+
+ return global_table;
+}
+
+static PreferencesEntry *
+preferences_global_table_lookup (const char *name)
+{
+ g_assert (name != NULL);
+ g_assert (preferences_global_table_get_global () != NULL);
+
+ return g_hash_table_lookup (preferences_global_table_get_global (), name);
+}
+
+static PreferencesEntry *
+preferences_global_table_insert (const char *name)
+{
+ PreferencesEntry *entry;
+
+ g_assert (name != NULL);
+ g_assert (preferences_global_table_get_global () != NULL);
+ g_assert (preferences_global_table_lookup (name) == NULL);
+
+ entry = g_new0 (PreferencesEntry, 1);
+ entry->name = g_strdup (name);
+
+ g_hash_table_insert (preferences_global_table_get_global (), entry->name, entry);
+
+ g_assert (entry == preferences_global_table_lookup (name));
+
+ return entry;
+}
+
+static PreferencesEntry *
+preferences_global_table_lookup_or_insert (const char *name)
+{
+ PreferencesEntry *entry;
+
+ g_assert (name != NULL);
+
+ entry = preferences_global_table_lookup (name);
+
+ if (entry != NULL)
+ {
+ return entry;
+ }
+
+ entry = preferences_global_table_insert (name);
+ g_assert (entry != NULL);
+
+ return entry;
+}
+
+void
+eel_preferences_add_callback (const char *name,
+ EelPreferencesCallback callback,
+ gpointer callback_data)
+{
+ PreferencesEntry *entry;
+
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (callback != NULL);
+ g_return_if_fail (preferences_is_initialized ());
+
+ entry = preferences_global_table_lookup_or_insert (name);
+ g_assert (entry != NULL);
+
+ preferences_entry_add_callback (entry, callback, callback_data);
+}
+
+void
+eel_preferences_add_auto_string (const char *name,
+ const char **storage)
+{
+ PreferencesEntry *entry;
+ char *value;
+
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (storage != NULL);
+ g_return_if_fail (preferences_is_initialized ());
+
+ entry = preferences_global_table_lookup_or_insert (name);
+ g_assert (entry != NULL);
+
+ preferences_entry_add_auto_storage (entry, storage, PREFERENCE_STRING);
+
+ value = eel_preferences_get (entry->name);
+ update_auto_string (storage, value);
+ g_free (value);
+}
+
+void
+eel_preferences_add_auto_string_array (const char *name,
+ char ***storage)
+{
+ PreferencesEntry *entry;
+ char **value;
+
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (storage != NULL);
+ g_return_if_fail (preferences_is_initialized ());
+
+ entry = preferences_global_table_lookup_or_insert (name);
+ g_assert (entry != NULL);
+
+ preferences_entry_add_auto_storage (entry, storage, PREFERENCE_STRING_ARRAY);
+
+ value = eel_preferences_get_string_array (entry->name);
+ update_auto_string_array (storage, value);
+ g_strfreev (value);
+}
+
+void
+eel_preferences_add_auto_string_array_as_quarks (const char *name,
+ GQuark **storage)
+{
+ PreferencesEntry *entry;
+ char **value;
+
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (storage != NULL);
+ g_return_if_fail (preferences_is_initialized ());
+
+ entry = preferences_global_table_lookup_or_insert (name);
+ g_assert (entry != NULL);
+
+ preferences_entry_add_auto_storage (entry, storage, PREFERENCE_STRING_ARRAY_AS_QUARKS);
+
+ value = eel_preferences_get_string_array (entry->name);
+ update_auto_string_array_as_quarks (storage, value);
+ g_strfreev (value);
+}
+
+void
+eel_preferences_add_auto_integer (const char *name,
+ int *storage)
+{
+ PreferencesEntry *entry;
+ int value;
+
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (storage != NULL);
+ g_return_if_fail (preferences_is_initialized ());
+
+ entry = preferences_global_table_lookup_or_insert (name);
+ g_assert (entry != NULL);
+
+ preferences_entry_add_auto_storage (entry, storage, PREFERENCE_INTEGER);
+
+ value = eel_preferences_get_integer (entry->name);
+ update_auto_integer_or_boolean (storage, GINT_TO_POINTER (value));
+}
+
+
+void
+eel_preferences_add_auto_enum (const char *name,
+ guint *storage)
+{
+ PreferencesEntry *entry;
+ guint value;
+
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (storage != NULL);
+ g_return_if_fail (preferences_is_initialized ());
+
+ entry = preferences_global_table_lookup_or_insert (name);
+ g_assert (entry != NULL);
+ g_assert (entry->enumeration_id != NULL);
+
+ preferences_entry_add_auto_storage (entry, storage, PREFERENCE_STRING);
+
+ value = eel_preferences_get_enum (entry->name);
+ update_auto_integer_or_boolean (storage, GINT_TO_POINTER (value));
+}
+
+void
+eel_preferences_add_auto_boolean (const char *name,
+ gboolean *storage)
+{
+ PreferencesEntry *entry;
+ gboolean value;
+
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (storage != NULL);
+ g_return_if_fail (preferences_is_initialized ());
+
+ entry = preferences_global_table_lookup_or_insert (name);
+ g_assert (entry != NULL);
+
+ preferences_entry_add_auto_storage (entry, storage, PREFERENCE_BOOLEAN);
+
+ value = eel_preferences_get_boolean (entry->name);
+ update_auto_integer_or_boolean (storage, GINT_TO_POINTER (value));
+}
+
+void
+eel_preferences_remove_auto_string (const char *name,
+ const char **storage)
+{
+ PreferencesEntry *entry;
+
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (storage != NULL);
+ g_return_if_fail (preferences_is_initialized ());
+
+ entry = preferences_global_table_lookup (name);
+ if (entry == NULL)
+ {
+ g_warning ("Trying to remove auto-string for %s without adding it first.", name);
+ return;
+ }
+
+ preferences_entry_remove_auto_storage (entry, storage);
+}
+
+void
+eel_preferences_remove_auto_string_array (const char *name,
+ char ***storage)
+{
+ PreferencesEntry *entry;
+
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (storage != NULL);
+ g_return_if_fail (preferences_is_initialized ());
+
+ entry = preferences_global_table_lookup (name);
+ if (entry == NULL)
+ {
+ g_warning ("Trying to remove auto-string for %s without adding it first.", name);
+ return;
+ }
+
+ preferences_entry_remove_auto_storage (entry, storage);
+}
+
+void
+eel_preferences_remove_auto_integer (const char *name,
+ int *storage)
+{
+ PreferencesEntry *entry;
+
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (storage != NULL);
+ g_return_if_fail (preferences_is_initialized ());
+
+ entry = preferences_global_table_lookup (name);
+ if (entry == NULL)
+ {
+ g_warning ("Trying to remove auto-integer for %s without adding it first.", name);
+ return;
+ }
+
+ preferences_entry_remove_auto_storage (entry, storage);
+}
+
+void
+eel_preferences_remove_auto_boolean (const char *name,
+ gboolean *storage)
+{
+ PreferencesEntry *entry;
+
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (storage != NULL);
+ g_return_if_fail (preferences_is_initialized ());
+
+ entry = preferences_global_table_lookup (name);
+ if (entry == NULL)
+ {
+ g_warning ("Trying to remove auto-boolean for %s without adding it first.", name);
+ return;
+ }
+
+ preferences_entry_remove_auto_storage (entry, storage);
+}
+
+typedef struct
+{
+ char *name;
+ EelPreferencesCallback callback;
+ gpointer callback_data;
+} WhileAliveData;
+
+static void
+preferences_while_alive_disconnector (gpointer callback_data, GObject *where_object_was)
+{
+ WhileAliveData *data;
+
+ g_assert (callback_data != NULL);
+
+ data = callback_data;
+
+ /* we might have survived an eel shutdown, which
+ * already cleared all the callbacks */
+ if (preferences_is_initialized ())
+ {
+ eel_preferences_remove_callback (data->name,
+ data->callback,
+ data->callback_data);
+ }
+
+ g_free (data->name);
+ g_free (data);
+}
+
+void
+eel_preferences_add_callback_while_alive (const char *name,
+ EelPreferencesCallback callback,
+ gpointer callback_data,
+ GObject *alive_object)
+{
+ WhileAliveData *data;
+
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (callback != NULL);
+ g_return_if_fail (G_IS_OBJECT (alive_object));
+ g_return_if_fail (preferences_is_initialized ());
+
+ data = g_new (WhileAliveData, 1);
+ data->name = g_strdup (name);
+ data->callback = callback;
+ data->callback_data = callback_data;
+
+ eel_preferences_add_callback (name, callback, callback_data);
+
+ g_object_weak_ref (alive_object,
+ preferences_while_alive_disconnector,
+ data);
+}
+
+void
+eel_preferences_remove_callback (const char *name,
+ EelPreferencesCallback callback,
+ gpointer callback_data)
+{
+ PreferencesEntry *entry;
+
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (callback != NULL);
+ g_return_if_fail (preferences_is_initialized ());
+
+ entry = preferences_global_table_lookup (name);
+
+ if (entry == NULL)
+ {
+ g_warning ("Trying to remove a callback for %s without adding it first.", name);
+ return;
+ }
+
+ preferences_entry_remove_callback (entry, callback, callback_data);
+}
+
+void
+eel_preferences_set_description (const char *name,
+ const char *description)
+{
+ PreferencesEntry *entry;
+
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (description != NULL);
+ g_return_if_fail (preferences_is_initialized ());
+
+ entry = preferences_global_table_lookup_or_insert (name);
+ g_assert (entry != NULL);
+
+ g_free (entry->description);
+ entry->description = g_strdup (description);
+}
+
+char *
+eel_preferences_get_description (const char *name)
+{
+ PreferencesEntry *entry;
+
+ g_return_val_if_fail (name != NULL, NULL);
+ g_return_val_if_fail (preferences_is_initialized (), NULL);
+
+ entry = preferences_global_table_lookup_or_insert (name);
+
+ return g_strdup (entry->description ? entry->description : "");
+}
+
+void
+eel_preferences_set_enumeration_id (const char *name,
+ const char *enumeration_id)
+{
+ PreferencesEntry *entry;
+
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (enumeration_id != NULL);
+ g_return_if_fail (preferences_is_initialized ());
+
+ entry = preferences_global_table_lookup_or_insert (name);
+ g_assert (entry != NULL);
+
+ g_free (entry->enumeration_id);
+ entry->enumeration_id = g_strdup (enumeration_id);
+}
+
+char *
+eel_preferences_get_enumeration_id (const char *name)
+{
+ PreferencesEntry *entry;
+
+ g_return_val_if_fail (name != NULL, NULL);
+ g_return_val_if_fail (preferences_is_initialized (), NULL);
+
+ entry = preferences_global_table_lookup_or_insert (name);
+
+ return g_strdup (entry->enumeration_id);
+}
+
+static void
+preferences_set_emergency_fallback_stealing_value (const char *name,
+ MateConfValue *value)
+{
+ PreferencesEntry *entry;
+
+ g_assert (name != NULL);
+ g_assert (preferences_is_initialized ());
+
+ entry = preferences_global_table_lookup_or_insert (name);
+ g_assert (entry != NULL);
+
+ if (entry->fallback)
+ mateconf_value_free (entry->fallback);
+ entry->fallback = value; /* steal ownership of value */
+}
+
+void
+eel_preferences_set_emergency_fallback_string (const char *name,
+ const char *value)
+{
+ MateConfValue *mateconf_value;
+
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (value != NULL);
+
+ mateconf_value = mateconf_value_new (MATECONF_VALUE_STRING);
+
+ mateconf_value_set_string (mateconf_value, value);
+
+ preferences_set_emergency_fallback_stealing_value (name, mateconf_value);
+}
+
+void
+eel_preferences_set_emergency_fallback_integer (const char *name,
+ int value)
+{
+ MateConfValue *mateconf_value;
+
+ g_return_if_fail (name != NULL);
+
+ mateconf_value = mateconf_value_new (MATECONF_VALUE_INT);
+
+ mateconf_value_set_int (mateconf_value, value);
+
+ preferences_set_emergency_fallback_stealing_value (name, mateconf_value);
+}
+
+void
+eel_preferences_set_emergency_fallback_boolean (const char *name,
+ gboolean value)
+{
+ MateConfValue *mateconf_value;
+
+ g_return_if_fail (name != NULL);
+
+ mateconf_value = mateconf_value_new (MATECONF_VALUE_BOOL);
+
+ mateconf_value_set_bool (mateconf_value, value);
+
+ preferences_set_emergency_fallback_stealing_value (name, mateconf_value);
+}
+
+
+void
+eel_preferences_set_emergency_fallback_string_array (const char *name,
+ char **value)
+{
+ MateConfValue *mateconf_value;
+ GSList *list;
+ int i;
+
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (value != NULL);
+
+ mateconf_value = mateconf_value_new (MATECONF_VALUE_LIST);
+ mateconf_value_set_list_type (mateconf_value, MATECONF_VALUE_STRING);
+
+ list = NULL;
+ for (i = 0; value[i] != NULL; ++i)
+ {
+ MateConfValue *v;
+
+ v = mateconf_value_new (MATECONF_VALUE_STRING);
+ mateconf_value_set_string (v, value[i]);
+
+ list = g_slist_prepend (list, v);
+ }
+
+ mateconf_value_set_list_nocopy (mateconf_value, g_slist_reverse (list));
+
+ preferences_set_emergency_fallback_stealing_value (name, mateconf_value);
+}
+
+MateConfValue*
+eel_preferences_get_emergency_fallback (const char *name)
+{
+ PreferencesEntry *entry;
+
+ g_return_val_if_fail (name != NULL, NULL);
+ g_return_val_if_fail (preferences_is_initialized (), NULL);
+
+ entry = preferences_global_table_lookup_or_insert (name);
+
+ return entry->fallback ? mateconf_value_copy (entry->fallback) : NULL;
+}
+
+gboolean
+eel_preferences_monitor_directory (const char *directory)
+{
+ g_return_val_if_fail (preferences_is_initialized (), FALSE);
+
+ return eel_mateconf_monitor_add (directory);
+}
+
+gboolean
+eel_preferences_is_visible (const char *name)
+{
+ g_return_val_if_fail (name != NULL, FALSE);
+ g_return_val_if_fail (preferences_is_initialized (), FALSE);
+
+ return !preferences_global_table_lookup_or_insert (name)->invisible;
+}
+
+void
+eel_preferences_init (const char *path)
+{
+ g_return_if_fail (eel_strlen (path) > 0);
+
+ if (initialized)
+ {
+ return;
+ }
+
+ initialized = TRUE;
+
+ preferences_set_storage_path (path);
+}
+
+#if !defined (EEL_OMIT_SELF_CHECK)
+
+#define CHECK_BOOLEAN(name__, value__) \
+G_STMT_START { \
+ eel_preferences_set_boolean ((name__), (value__)); \
+ EEL_CHECK_BOOLEAN_RESULT (eel_preferences_get_boolean (name__), (value__)); \
+} G_STMT_END
+
+#define CHECK_INTEGER(name__, value__) \
+G_STMT_START { \
+ eel_preferences_set_integer ((name__), (value__)); \
+ EEL_CHECK_INTEGER_RESULT (eel_preferences_get_integer (name__), (value__)); \
+} G_STMT_END
+
+#define CHECK_STRING(name__, value__) \
+G_STMT_START { \
+ eel_preferences_set ((name__), (value__)); \
+ EEL_CHECK_STRING_RESULT (eel_preferences_get (name__), (value__)); \
+} G_STMT_END
+
+void
+eel_self_check_preferences (void)
+{
+ /* Disabled until I can debug why these seemingly harmless tests
+ * dont work. -re
+ */
+#if 0
+ int original_user_level;
+
+ original_user_level = eel_preferences_get_user_level ();
+
+ EEL_CHECK_INTEGER_RESULT (eel_preferences_get_integer ("self-check/neverset/i"), 0);
+ EEL_CHECK_STRING_RESULT (eel_preferences_get ("self-check/neverset/s"), "");
+ EEL_CHECK_BOOLEAN_RESULT (eel_preferences_get_boolean ("self-check/neverset/b"), FALSE);
+
+ eel_preferences_set_user_level (0);
+
+ /* FIXME: Fails if you add the commented-out lines. */
+ /* CHECK_INTEGER ("self-check/i", 0); */
+ CHECK_INTEGER ("self-check/i", 666);
+ /* CHECK_BOOLEAN ("self-check/b", FALSE); */
+ CHECK_BOOLEAN ("self-check/b", TRUE);
+ /* CHECK_STRING ("self-check/s", ""); */
+ CHECK_STRING ("self-check/s", "foo");
+
+ /* Restore the original user level */
+ eel_preferences_set_user_level (original_user_level);
+#endif
+}
+
+#endif /* !EEL_OMIT_SELF_CHECK */