[glib/wip/gsettings-list: 2/2] list stuff
- From: Ryan Lortie <ryanl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/wip/gsettings-list: 2/2] list stuff
- Date: Tue, 12 Oct 2010 14:53:54 +0000 (UTC)
commit b12b0a26c2172e79fbe6ce16a19b97e11c1b1f06
Author: Ryan Lortie <desrt desrt ca>
Date: Mon Sep 13 13:19:09 2010 -0400
list stuff
gio/gio.symbols | 5 +
gio/gmemorysettingsbackend.c | 117 +++++++++++++++-
gio/gsettings.c | 309 ++++++++++++++++++++++++++++------------
gio/gsettings.h | 27 +++-
gio/gsettingsbackend.c | 45 ++++++
gio/gsettingsbackend.h | 19 ++-
gio/gsettingsbackendinternal.h | 34 +++++
7 files changed, 453 insertions(+), 103 deletions(-)
---
diff --git a/gio/gio.symbols b/gio/gio.symbols
index fa5d623..ad700e9 100644
--- a/gio/gio.symbols
+++ b/gio/gio.symbols
@@ -1558,6 +1558,11 @@ g_settings_sync
g_settings_list_keys
g_settings_list_children
g_settings_get_mapped
+g_settings_add_child
+g_settings_can_add_child
+g_settings_can_remove_child
+g_settings_remove_child
+g_settings_get_destroyed
#endif
#endif
diff --git a/gio/gmemorysettingsbackend.c b/gio/gmemorysettingsbackend.c
index 6b60058..50c2f41 100644
--- a/gio/gmemorysettingsbackend.c
+++ b/gio/gmemorysettingsbackend.c
@@ -32,11 +32,42 @@
G_TYPE_MEMORY_SETTINGS_BACKEND, \
GMemorySettingsBackend))
+typedef struct
+{
+ GHashTable/*<string, GVariant>*/ *values;
+ GHashTable/*<string, GHashTable<string, TablePair>*/ *lists;
+} TablePair;
+
+static void
+table_pair_free (gpointer data)
+{
+ TablePair *pair = data;
+
+ g_hash_table_unref (pair->values);
+ g_hash_table_unref (pair->list);
+}
+
+static TablePair *
+table_pair_new (void)
+{
+ TablePair *pair;
+
+ pair = g_slice_new (TablePair);
+ pair->values = g_hash_table_new (g_str_hash, g_str_equal, g_free,
+ (GDestroyNotify) g_variant_unref);
+ pair->lists = g_hash_table_new (g_str_hash, g_str_equal, g_free,
+ (GDestroyNotify) g_hash_table_unref);
+
+ return pair;
+}
+
+
+
typedef GSettingsBackendClass GMemorySettingsBackendClass;
typedef struct
{
GSettingsBackend parent_instance;
- GHashTable *table;
+ TablePair *root;
} GMemorySettingsBackend;
G_DEFINE_TYPE_WITH_CODE (GMemorySettingsBackend,
@@ -45,6 +76,90 @@ G_DEFINE_TYPE_WITH_CODE (GMemorySettingsBackend,
g_io_extension_point_implement (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME,
g_define_type_id, "memory", 10))
+static GHashTable *
+g_memory_settings_backend_get_table (GHashTable *table,
+ const gchar **key_ptr)
+{
+ const gchar *key = *key_ptr;
+ gchar *prefix;
+ gchar *name;
+ gint i, j;
+
+ for (i = 2; key[i - 2] != ':' || key[i - 1] != '/'; i++)
+ if (key[i - 2] == '\0')
+ /* no :/ in the string -- pass through */
+ return table;
+
+ for (j = i + 1; key[j - 1] != '/'; j++)
+ if (key[j - 1] == '\0')
+ /* string of form /some/path:/child -- definitely invalid */
+ return NULL;
+
+ /* We now have this situation:
+ *
+ * /some/path:/child/item
+ * ^0 ^i ^j
+ *
+ * So we can split the string into 3 parts:
+ *
+ * prefix = /some/path:/
+ * child = child/
+ * *key_ptr = item
+ */
+ prefix = g_strndup (key, i);
+ name = g_strndup (key + i, j - i);
+
+ /* name is either like 'foo' or ':foo'
+ *
+ * If it doesn't start with a colon, it's in the schema.
+ */
+ if (name[0] == ':')
+ {
+ table = g_hash_table_lookup (table, prefix);
+ if (table)
+ table = g_hash_table_lookup (table, name);
+ }
+ else
+ {
+ gpointer value;
+
+ if (!g_hash_table_lookup_extended (table, prefix, NULL, &value))
+ g_hash_table_insert (table, prefix,
+ value = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, g_hash_table_unref));
+
+ table = value;
+
+ if (!g_hash_table_lookup_extended (table, prefix, NULL, &value))
+ g_hash_table_insert (table, prefix,
+ value = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, g_hash_table_unref));
+ }
+
+ if (key[i] == ':' && key[i + 1] == '/')
+ {
+ gchar *prefix;
+ gchar *name;
+ gint j;
+
+ i += 2;
+
+ for (j = i; (*key)[j] != '/'; j++)
+ /* found a path of the form /a:/b
+ * which is never a valid spot for a key.
+ */
+ if ((*key)[j] == '\0')
+ return NULL;
+
+ name = g_strndup (*key + i, j - i);
+ prefix = g_strndup (*key, i);
+ table = g_hash_table_lookup (table, prefix);
+ g_free (prefix);
+ }
+
+ return table;
+}
+
static GVariant *
g_memory_settings_backend_read (GSettingsBackend *backend,
const gchar *key,
diff --git a/gio/gsettings.c b/gio/gsettings.c
index eb4370c..365ddd1 100644
--- a/gio/gsettings.c
+++ b/gio/gsettings.c
@@ -195,6 +195,7 @@ struct _GSettingsPrivate
gchar *path;
GDelayedSettingsBackend *delayed;
+ gboolean destroyed;
};
enum
@@ -465,6 +466,10 @@ g_settings_constructed (GObject *object)
settings->priv->main_context);
g_settings_backend_subscribe (settings->priv->backend,
settings->priv->path);
+
+ settings->priv->destroyed =
+ !g_settings_backend_check (settings->priv->backend,
+ settings->priv->path);
}
static void
@@ -1975,7 +1980,7 @@ g_settings_get_has_unapplied (GSettings *settings)
G_DELAYED_SETTINGS_BACKEND (settings->priv->backend));
}
-/* Extra API (reset, sync, get_child, is_writable, list_*) {{{1 */
+/* Extra API (reset, sync, get_child, is_writable) {{{1 */
/**
* g_settings_reset:
* @settings: a #GSettings object
@@ -2089,95 +2094,6 @@ g_settings_get_child (GSettings *settings,
return child;
}
-/**
- * g_settings_list_keys:
- * @settings: a #GSettings object
- * @returns: a list of the keys on @settings
- *
- * Introspects the list of keys on @settings.
- *
- * You should probably not be calling this function from "normal" code
- * (since you should already know what keys are in your schema). This
- * function is intended for introspection reasons.
- *
- * You should free the return value with g_strfreev() when you are done
- * with it.
- */
-gchar **
-g_settings_list_keys (GSettings *settings)
-{
- const GQuark *keys;
- gchar **strv;
- gint n_keys;
- gint i, j;
-
- keys = g_settings_schema_list (settings->priv->schema, &n_keys);
- strv = g_new (gchar *, n_keys + 1);
- for (i = j = 0; i < n_keys; i++)
- {
- const gchar *key = g_quark_to_string (keys[i]);
-
- if (!g_str_has_suffix (key, "/"))
- strv[j++] = g_strdup (key);
- }
- strv[j] = NULL;
-
- return strv;
-}
-
-/**
- * g_settings_list_children:
- * @settings: a #GSettings object
- * @returns: a list of the children on @settings
- *
- * Gets the list of children on @settings.
- *
- * The list is exactly the list of strings for which it is not an error
- * to call g_settings_get_child().
- *
- * For GSettings objects that are lists, this value can change at any
- * time and you should connect to the "children-changed" signal to watch
- * for those changes. Note that there is a race condition here: you may
- * request a child after listing it only for it to have been destroyed
- * in the meantime. For this reason, g_settings_get_chuld() may return
- * %NULL even for a child that was listed by this function.
- *
- * For GSettings objects that are not lists, you should probably not be
- * calling this function from "normal" code (since you should already
- * know what children are in your schema). This function may still be
- * useful there for introspection reasons, however.
- *
- * You should free the return value with g_strfreev() when you are done
- * with it.
- */
-gchar **
-g_settings_list_children (GSettings *settings)
-{
- const GQuark *keys;
- gchar **strv;
- gint n_keys;
- gint i, j;
-
- keys = g_settings_schema_list (settings->priv->schema, &n_keys);
- strv = g_new (gchar *, n_keys + 1);
- for (i = j = 0; i < n_keys; i++)
- {
- const gchar *key = g_quark_to_string (keys[i]);
-
- if (g_str_has_suffix (key, "/"))
- {
- gint length = strlen (key);
-
- strv[j] = g_memdup (key, length);
- strv[j][length - 1] = '\0';
- j++;
- }
- }
- strv[j] = NULL;
-
- return strv;
-}
-
/* Binding {{{1 */
typedef struct
{
@@ -2736,6 +2652,219 @@ g_settings_unbind (gpointer object,
g_object_set_qdata (object, binding_quark, NULL);
}
+/* Children (add, remove, can_{add,remove}, list, get_destroyed) {{{1 */
+
+/**
+ * g_settings_add_child:
+ * @settings: a list #GSettings
+ * @prefix: the prefix of the new child name
+ * @name: return location for the new child name
+ * @returns: %TRUE if the child was added
+ *
+ * Adds a child to a list.
+ *
+ * The child will be created with a new unique name that starts with
+ * @prefix. For example, if @prefix is "item" then the child's name may
+ * end up looking like "item0", "item1", or so on. No particular format
+ * is specified -- only that the resulting name will have the given
+ * prefix.
+ *
+ * If the creation was successful then @name (if non-%NULL) is set to
+ * the name of the new child and %TRUE is returned.
+ *
+ * If the creation fails then %FALSE is returned and @name is untouched.
+ **/
+gboolean
+g_settings_add_child (GSettings *settings,
+ const gchar *prefix,
+ gchar **name)
+{
+ g_return_val_if_fail (G_IS_SETTINGS (settings), FALSE);
+ g_return_val_if_fail (prefix != NULL, FALSE);
+
+ return g_settings_backend_insert (settings->priv->backend,
+ settings->priv->path,
+ -1, prefix, name);
+}
+
+/**
+ * g_settings_remove_child:
+ * @settings: a list #GSettings
+ * @id: the id of the child to remove
+ * @returns: %TRUE if the child was successfully removed
+ *
+ * Removes a child from the list.
+ *
+ * In the case that the removal was successful then %TRUE is returned.
+ * In the case that it failed, %FALSE is returned.
+ *
+ * The return value of this function is not particularly useful, since
+ * it is not specified if the non-operation resulting from the request
+ * to remove a non-existent child is considered to be a success (and
+ * this situation can easily arise as a race condition). Most usually
+ * you will actually probably want to ignore the return value here and
+ * just monitor the "children-changed" signal and make changes to your
+ * user interface accordingly.
+ **/
+gboolean
+g_settings_remove_child (GSettings *settings,
+ const gchar *id)
+{
+ g_return_val_if_fail (G_IS_SETTINGS (settings), FALSE);
+ g_return_val_if_fail (id != NULL, FALSE);
+
+ return g_settings_backend_remove (settings->priv->backend,
+ settings->priv->path,
+ id);
+}
+
+/**
+ * g_settings_can_add_child:
+ * @settings: a #GSettings object
+ * @returns: %TRUE if a call to g_settings_add_child() would succeed
+ *
+ * Checks if it is valid to add children to @settings.
+ **/
+gboolean
+g_settings_can_add_child (GSettings *settings)
+{
+ g_return_val_if_fail (G_IS_SETTINGS (settings), FALSE);
+
+ return g_settings_backend_can_insert (settings->priv->backend,
+ settings->priv->path);
+}
+
+/**
+ * g_settings_can_remove_child:
+ * @settings: a #GSettings object
+ * @id: the identifier of an existing child
+ * @returns: %TRUE if a call to g_settings_remove_child() would succeed
+ *
+ * Checks if it is valid to remove @id from @settings.
+ *
+ * The return value of this function is unspecified for the case that
+ * @id does not exist.
+ **/
+gboolean
+g_settings_can_remove_child (GSettings *settings,
+ const gchar *id)
+{
+ g_return_val_if_fail (G_IS_SETTINGS (settings), FALSE);
+
+ return g_settings_backend_can_remove (settings->priv->backend,
+ settings->priv->path, id);
+}
+
+/**
+ * g_settings_get_destroyed:
+ * @settings: a #GSettings
+ * @returns: %TRUE if @settings has been destroyed
+ *
+ * Checks if @settings has been destroyed.
+ *
+ * If @settings is a member of a list (or a child thereof) and has since
+ * been removed from the list then it will be considered as having been
+ * destroyed. The "notify" signal will be emitted on the "destroyed"
+ * property and this function will return %TRUE thereafter.
+ *
+ * A destroyed #GSettings object is never revived and nearly all
+ * operations performed on it will be meaningless.
+ **/
+gboolean
+g_settings_get_destroyed (GSettings *settings)
+{
+ return settings->priv->destroyed;
+}
+
+/**
+ * g_settings_list_keys:
+ * @settings: a #GSettings object
+ * @returns: a list of the keys on @settings
+ *
+ * Introspects the list of keys on @settings.
+ *
+ * You should probably not be calling this function from "normal" code
+ * (since you should already know what keys are in your schema). This
+ * function is intended for introspection reasons.
+ *
+ * You should free the return value with g_strfreev() when you are done
+ * with it.
+ */
+gchar **
+g_settings_list_keys (GSettings *settings)
+{
+ const GQuark *keys;
+ gchar **strv;
+ gint n_keys;
+ gint i, j;
+
+ keys = g_settings_schema_list (settings->priv->schema, &n_keys);
+ strv = g_new (gchar *, n_keys + 1);
+ for (i = j = 0; i < n_keys; i++)
+ {
+ const gchar *key = g_quark_to_string (keys[i]);
+
+ if (!g_str_has_suffix (key, "/"))
+ strv[j++] = g_strdup (key);
+ }
+ strv[j] = NULL;
+
+ return strv;
+}
+
+/**
+ * g_settings_list_children:
+ * @settings: a #GSettings object
+ * @returns: a list of the children on @settings
+ *
+ * Gets the list of children on @settings.
+ *
+ * The list is exactly the list of strings for which it is not an error
+ * to call g_settings_get_child().
+ *
+ * For GSettings objects that are lists, this value can change at any
+ * time and you should connect to the "children-changed" signal to watch
+ * for those changes. Note that there is a race condition here: you may
+ * request a child after listing it only for it to have been destroyed
+ * in the meantime. For this reason, g_settings_get_chuld() may return
+ * %NULL even for a child that was listed by this function.
+ *
+ * For GSettings objects that are not lists, you should probably not be
+ * calling this function from "normal" code (since you should already
+ * know what children are in your schema). This function may still be
+ * useful there for introspection reasons, however.
+ *
+ * You should free the return value with g_strfreev() when you are done
+ * with it.
+ */
+gchar **
+g_settings_list_children (GSettings *settings)
+{
+ const GQuark *keys;
+ gchar **strv;
+ gint n_keys;
+ gint i, j;
+
+ keys = g_settings_schema_list (settings->priv->schema, &n_keys);
+ strv = g_new (gchar *, n_keys + 1);
+ for (i = j = 0; i < n_keys; i++)
+ {
+ const gchar *key = g_quark_to_string (keys[i]);
+
+ if (g_str_has_suffix (key, "/"))
+ {
+ gint length = strlen (key);
+
+ strv[j] = g_memdup (key, length);
+ strv[j][length - 1] = '\0';
+ j++;
+ }
+ }
+ strv[j] = NULL;
+
+ return strv;
+}
+
/* Epilogue {{{1 */
/* vim:set foldmethod=marker: */
diff --git a/gio/gsettings.h b/gio/gsettings.h
index 294d885..c051ac2 100644
--- a/gio/gsettings.h
+++ b/gio/gsettings.h
@@ -58,7 +58,10 @@ struct _GSettingsClass
const GQuark *keys,
gint n_keys);
- gpointer padding[20];
+ void (*can_remove_changed) (GSettings *settings);
+ void (*children_changed) (GSettings *settings);
+
+ gpointer padding[18];
};
struct _GSettings
@@ -79,11 +82,6 @@ GSettings * g_settings_new_with_backend (const g
GSettings * g_settings_new_with_backend_and_path (const gchar *schema,
GSettingsBackend *backend,
const gchar *path);
-gchar ** g_settings_list_children (GSettings *settings);
-gchar ** g_settings_list_keys (GSettings *settings);
-
-gboolean g_settings_get_destroyed (GSettings *settings);
-GPermission * g_settings_get_permission (GSettings *settings);
gboolean g_settings_set_value (GSettings *settings,
const gchar *key,
@@ -256,6 +254,23 @@ gpointer g_settings_get_mapped (GSettin
GSettingsGetMapping mapping,
gpointer user_data);
+gchar ** g_settings_list_children (GSettings *settings);
+gchar ** g_settings_list_keys (GSettings *settings);
+
+gboolean g_settings_can_add_child (GSettings *settings);
+
+gboolean g_settings_can_remove_child (GSettings *settings,
+ const gchar *id);
+
+gboolean g_settings_add_child (GSettings *settings,
+ const gchar *prefix,
+ gchar **name);
+
+gboolean g_settings_remove_child (GSettings *settings,
+ const gchar *id);
+
+gboolean g_settings_get_destroyed (GSettings *settings);
+
G_END_DECLS
#endif /* __G_SETTINGS_H__ */
diff --git a/gio/gsettingsbackend.c b/gio/gsettingsbackend.c
index 8485cd3..3414d73 100644
--- a/gio/gsettingsbackend.c
+++ b/gio/gsettingsbackend.c
@@ -1050,3 +1050,48 @@ g_settings_backend_sync_default (void)
if (class->sync)
class->sync (backend);
}
+
+gboolean
+g_settings_backend_can_insert (GSettingsBackend *backend,
+ const gchar *path)
+{
+ return G_SETTINGS_BACKEND_GET_CLASS (backend)
+ ->can_insert (backend, path);
+}
+
+gboolean
+g_settings_backend_can_remove (GSettingsBackend *backend,
+ const gchar *path,
+ const gchar *id)
+{
+ return G_SETTINGS_BACKEND_GET_CLASS (backend)
+ ->can_remove (backend, path, id);
+}
+
+gboolean
+g_settings_backend_insert (GSettingsBackend *backend,
+ const gchar *path,
+ gint index_,
+ const gchar *prefix,
+ gchar **name)
+{
+ return G_SETTINGS_BACKEND_GET_CLASS (backend)
+ ->insert (backend, path, index_, prefix, name);
+}
+
+gboolean
+g_settings_backend_remove (GSettingsBackend *backend,
+ const gchar *path,
+ const gchar *id)
+{
+ return G_SETTINGS_BACKEND_GET_CLASS (backend)
+ ->remove (backend, path, id);
+}
+
+gboolean
+g_settings_backend_check (GSettingsBackend *backend,
+ const gchar *path)
+{
+ return G_SETTINGS_BACKEND_GET_CLASS (backend)
+ ->check (backend, path);
+}
diff --git a/gio/gsettingsbackend.h b/gio/gsettingsbackend.h
index 781874e..2f4aeaa 100644
--- a/gio/gsettingsbackend.h
+++ b/gio/gsettingsbackend.h
@@ -96,16 +96,23 @@ struct _GSettingsBackendClass
gchar ** (*list) (GSettingsBackend *backend,
const gchar *path,
const gchar * const *schema_items);
- gchar * (*add) (GSettingsBackend *backend,
+ gboolean (*check) (GSettingsBackend *backend,
+ const gchar *path);
+ gboolean (*can_insert) (GSettingsBackend *backend,
+ const gchar *path);
+ gboolean (*can_remove) (GSettingsBackend *backend,
+ const gchar *path,
+ const gchar *id);
+ gboolean (*insert) (GSettingsBackend *backend,
const gchar *path,
- const gchar *hint);
+ gint index_,
+ const gchar *prefix,
+ gchar **name);
gboolean (*remove) (GSettingsBackend *backend,
const gchar *path,
- const gchar *name);
- gboolean (*check) (GSettingsBackend *backend,
- const gchar *path);
+ const gchar *id);
- gpointer padding[20];
+ gpointer padding[18];
};
struct _GSettingsBackend
diff --git a/gio/gsettingsbackendinternal.h b/gio/gsettingsbackendinternal.h
index 68a61a8..ea284e9 100644
--- a/gio/gsettingsbackendinternal.h
+++ b/gio/gsettingsbackendinternal.h
@@ -41,12 +41,24 @@ typedef struct
const gchar *prefix,
const gchar * const *names,
gpointer origin_tag);
+
void (* writable_changed) (GObject *target,
GSettingsBackend *backend,
const gchar *key);
void (* path_writable_changed) (GObject *target,
GSettingsBackend *backend,
const gchar *path);
+
+ void (* children_changed) (GObject *target,
+ GSettingsBackend *backend,
+ const gchar *path,
+ gpointer origin_tag);
+ void (* can_add_changed) (GObject *target,
+ GSettingsBackend *backend,
+ const gchar *path);
+ void (* can_remove_changed) (GObject *target,
+ GSettingsBackend *backend,
+ const gchar *path);
} GSettingsListenerVTable;
G_GNUC_INTERNAL
@@ -91,6 +103,28 @@ void g_settings_backend_subscribe (GSettin
G_GNUC_INTERNAL
GPermission * g_settings_backend_get_permission (GSettingsBackend *backend,
const gchar *path);
+
+G_GNUC_INTERNAL
+gboolean g_settings_backend_check (GSettingsBackend *backend,
+ const gchar *path);
+G_GNUC_INTERNAL
+gboolean g_settings_backend_insert (GSettingsBackend *backend,
+ const gchar *path,
+ gint index,
+ const gchar *prefix,
+ gchar **name);
+G_GNUC_INTERNAL
+gboolean g_settings_backend_remove (GSettingsBackend *backend,
+ const gchar *path,
+ const gchar *id);
+G_GNUC_INTERNAL
+gboolean g_settings_backend_can_insert (GSettingsBackend *backend,
+ const gchar *path);
+G_GNUC_INTERNAL
+gboolean g_settings_backend_can_remove (GSettingsBackend *backend,
+ const gchar *path,
+ const gchar *id);
+
G_GNUC_INTERNAL
GMainContext * g_settings_backend_get_active_context (void);
G_GNUC_INTERNAL
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]