[glib/gsettings] add GSettingsList
- From: Ryan Lortie <ryanl src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [glib/gsettings] add GSettingsList
- Date: Tue, 1 Sep 2009 23:18:54 +0000 (UTC)
commit 58fe5bb7e7e2093e93d5238032ea9265242dbb1d
Author: Ryan Lortie <desrt desrt ca>
Date: Tue Sep 1 19:18:02 2009 -0400
add GSettingsList
gio/Makefile.am | 2 +
gio/gio.symbols | 11 ++
gio/gsettings.c | 6 +-
gio/gsettingslist.c | 432 +++++++++++++++++++++++++++++++++++++++++++++++++++
gio/gsettingslist.h | 71 +++++++++
5 files changed, 518 insertions(+), 4 deletions(-)
---
diff --git a/gio/Makefile.am b/gio/Makefile.am
index 91d3007..57a9665 100644
--- a/gio/Makefile.am
+++ b/gio/Makefile.am
@@ -239,6 +239,7 @@ libgio_2_0_la_SOURCES = \
gseekable.c \
gsettingsbackend.c \
gsettingsdelayedbackend.c \
+ gsettingslist.c \
gsettingsschema.c \
gsettings.c \
gsimpleasyncresult.c \
@@ -371,6 +372,7 @@ gio_headers = \
gseekable.h \
gsettingsbackend.h \
gsettingsdelayedbackend.h \
+ gsettingslist.h \
gsettingsschema.h \
gsettings.h \
gsimpleasyncresult.h \
diff --git a/gio/gio.symbols b/gio/gio.symbols
index d7b663a..3f3265f 100644
--- a/gio/gio.symbols
+++ b/gio/gio.symbols
@@ -1317,3 +1317,14 @@ g_settings_set_delay_apply
g_settings_set_value
#endif
#endif
+
+#if IN_HEADER(_gsettingslist_h_)
+#if IN_FILE(_gsettingslist_c_)
+g_settings_get_list
+g_settings_list_add
+g_settings_list_get
+g_settings_list_get_type
+g_settings_list_list
+g_settings_list_remove
+#endif
+#endif
diff --git a/gio/gsettings.c b/gio/gsettings.c
index d621506..f20ff91 100644
--- a/gio/gsettings.c
+++ b/gio/gsettings.c
@@ -11,6 +11,7 @@
#include "gsettings.h"
#include "gsettingsdelayedbackend.h"
+#include "gsettingslist.h"
#include "gio-marshal.h"
#include "gsettingsschema.h"
@@ -383,7 +384,6 @@ g_settings_new_from_path (const gchar *path)
static GType
g_settings_get_gtype_for_schema (GSettingsSchema *schema)
{
- //extern GType g_settings_list_get_type (void);
GVariantIter iter;
const gchar *item;
GVariant *list;
@@ -392,11 +392,9 @@ g_settings_get_gtype_for_schema (GSettingsSchema *schema)
g_variant_iter_init (&iter, list);
g_variant_unref (list);
- /*
while (g_variant_iter_next (&iter, "s", &item))
if (strcmp (item, "list") == 0)
- return g_settings_list_get_type ();
- */
+ return G_TYPE_SETTINGS_LIST;
return G_TYPE_SETTINGS;
}
diff --git a/gio/gsettingslist.c b/gio/gsettingslist.c
new file mode 100644
index 0000000..8c540f6
--- /dev/null
+++ b/gio/gsettingslist.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright © 2009 Codethink Limited
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 3 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * See the included COPYING file for more information.
+ */
+
+#include "gsettingslist.h"
+
+#include "gsettingsschema.h"
+#include <string.h>
+
+#include "gioalias.h"
+
+typedef struct _ListItem ListItem;
+struct _ListItem
+{
+ gchar *string;
+ GSettingsList *owner;
+ GSList *children;
+ gint index;
+
+ ListItem *next;
+};
+
+struct _GSettingsListPrivate {
+ ListItem *list;
+ ListItem **array;
+ gint n_items;
+
+ gint tables;
+};
+
+G_DEFINE_TYPE (GSettingsList, g_settings_list, G_TYPE_SETTINGS)
+
+enum
+{
+ SIGNAL_ADDED,
+ SIGNAL_REMOVED,
+ SIGNAL_MOVED,
+ NR_SIGNALS
+};
+
+static guint g_settings_list_signals[NR_SIGNALS];
+
+static void
+g_settings_list_init (GSettingsList *list)
+{
+ list->priv = G_TYPE_INSTANCE_GET_PRIVATE (list,
+ G_TYPE_SETTINGS_LIST,
+ GSettingsListPrivate);
+}
+
+static void
+g_settings_list_rebuild_array (GSettingsList *list)
+{
+ ListItem *item;
+ gint index;
+
+ g_assert (list->priv->array == NULL);
+
+ list->priv->array = g_new (ListItem *, list->priv->n_items);
+ index = 0;
+
+ for (item = list->priv->list; item; item = item->next)
+ list->priv->array[index++] = item;
+}
+
+static void
+g_settings_list_free_array (GSettingsList *list)
+{
+ g_free (list->priv->array);
+ list->priv->array = NULL;
+}
+
+static void
+g_settings_list_constructed (GObject *object)
+{
+ GSettingsList *list = G_SETTINGS_LIST (object);
+ const gchar *string;
+ GVariantIter iter;
+ ListItem **item;
+
+ G_OBJECT_CLASS (g_settings_list_parent_class)
+ ->constructed (object);
+
+ g_settings_get (G_SETTINGS (list), "list", &iter, NULL);
+ item = &list->priv->list;
+
+ while (g_variant_iter_next (&iter, "s", &string))
+ {
+ (*item) = g_slice_new (ListItem);
+ (*item)->children = NULL;
+ (*item)->index = list->priv->n_items++;
+ (*item)->owner = list;
+ (*item)->string = g_strdup (string);
+ item = &(*item)->next;
+ }
+ *item = NULL;
+
+ g_settings_list_rebuild_array (list);
+}
+
+static void
+g_settings_list_child_finalized (gpointer user_data,
+ GObject *where_object_was)
+{
+ ListItem *item = user_data;
+
+ item->children = g_slist_remove (item->children, where_object_was);
+ g_object_unref (item->owner);
+}
+
+static void
+g_settings_list_remove_items (GSettingsList *list,
+ GVariant *new_list)
+{
+ ListItem **item;
+ gint index;
+
+ index = 0;
+ item = &list->priv->list;
+ while (*item)
+ {
+ GVariantIter iter;
+ const gchar *str;
+
+ g_variant_iter_init (&iter, new_list);
+ while (g_variant_iter_next (&iter, "s", &str))
+ if (strcmp (str, (*item)->string) == 0)
+ g_variant_iter_cancel (&iter);
+
+ if (g_variant_iter_was_cancelled (&iter))
+ {
+ (*item)->index = index++;
+ item = &(*item)->next;
+ }
+ else
+ {
+ ListItem *tmp;
+ GSList *node;
+
+ tmp = (*item);
+ *item = (*item)->next;
+ list->priv->n_items--;
+
+ g_signal_emit (list, g_settings_list_signals[SIGNAL_REMOVED],
+ 0, tmp->string, tmp->index);
+
+ for (node = tmp->children; node; node = node->next)
+ {
+ g_object_ref (node->data);
+ g_settings_destroy (node->data);
+ g_object_weak_unref (node->data,
+ g_settings_list_child_finalized,
+ tmp);
+ g_object_unref (node->data);
+ g_object_unref (list);
+ }
+
+ g_slist_free (tmp->children);
+ g_free (tmp->string);
+
+ g_slice_free (ListItem, tmp);
+ }
+ }
+}
+
+static void
+g_settings_list_insert_and_move_items (GSettingsList *list,
+ GVariant *new_items)
+{
+ const gchar *new_item;
+ GVariantIter iter;
+ gint index;
+ ListItem **item;
+
+ g_variant_iter_init (&iter, new_items);
+
+ index = 0;
+ item = &list->priv->list;
+ while (g_variant_iter_next (&iter, "s", &new_item))
+ {
+ ListItem **node;
+
+ /* find the nearest instance of the item with this name */
+ for (node = item; (*node); node = &(*node)->next)
+ if (strcmp ((*node)->string, new_item) == 0)
+ break;
+
+ if (*node)
+ {
+ /* if it's not already here... */
+ if (node != item)
+ {
+ /* move it. */
+ ListItem *tmp = *node;
+ *node = (*node)->next;
+
+ tmp->next = (*item);
+ *item = tmp;
+
+ g_signal_emit (list, g_settings_list_signals[SIGNAL_MOVED],
+ 0, tmp->string, tmp->index, index);
+ }
+
+ (*item)->index = index++;
+ item = &(*item)->next;
+ }
+ else
+ {
+ /* double check to ensure that the item isn't already in the
+ * list (ie: we got a bogus input that contains an item twice)
+ */
+ for (node = &list->priv->list; node != item; node = &(*node)->next)
+ if (strcmp ((*node)->string, new_item) == 0)
+ break;
+
+ if (node != item)
+ break;
+
+ /* not found. insert here */
+ ListItem *tmp = g_slice_new (ListItem);
+ tmp->next = *item;
+ tmp->string = g_strdup (new_item);
+ tmp->index = index++;
+ tmp->owner = list;
+ tmp->children = NULL;
+ *item = tmp;
+ item = &tmp->next;
+
+ list->priv->n_items++;
+
+ g_signal_emit (list, g_settings_list_signals[SIGNAL_ADDED],
+ 0, tmp->string, tmp->index);
+ }
+ }
+}
+
+static void
+g_settings_list_changed (GSettings *settings,
+ const gchar *key)
+{
+ GSettingsList *list = G_SETTINGS_LIST (settings);
+ GVariant *new_list;
+
+ new_list = g_settings_get_value (settings, "list");
+
+ g_settings_list_free_array (list);
+ g_settings_list_remove_items (list, new_list);
+ g_settings_list_insert_and_move_items (list, new_list);
+ g_settings_list_rebuild_array (list);
+}
+
+static void
+g_settings_list_finalize (GObject *object)
+{
+ GSettingsList *list = G_SETTINGS_LIST (object);
+ ListItem *item;
+
+ while ((item = list->priv->list))
+ {
+ list->priv->list = item->next;
+
+ g_free (item->string);
+ g_slice_free (ListItem, item);
+ }
+
+ g_free (list->priv->array);
+}
+
+static GSettings *
+g_settings_list_get_settings (GSettings *settings,
+ const gchar *name)
+{
+ GSettingsClass *parent_class = G_SETTINGS_CLASS (g_settings_list_parent_class);
+ GSettingsList *list = G_SETTINGS_LIST (settings);
+ GSettings *child;
+ ListItem *item;
+
+ for (item = list->priv->list; item; item = item->next)
+ if (strcmp (item->string, name) == 0)
+ break;
+
+ if (item == NULL)
+ g_error ("No such list item %s\n", name);
+
+ child = parent_class->get_settings (settings, name);
+
+ item->children = g_slist_prepend (item->children, child);
+ g_object_weak_ref (G_OBJECT (child), g_settings_list_child_finalized, item);
+ g_object_ref (list);
+
+ return child;
+}
+
+static void
+g_settings_list_class_init (GSettingsListClass *class)
+{
+ GSettingsClass *settings_class = G_SETTINGS_CLASS (class);
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ settings_class->get_settings = g_settings_list_get_settings;
+ settings_class->changed = g_settings_list_changed;
+
+ object_class->constructed = g_settings_list_constructed;
+ object_class->finalize = g_settings_list_finalize;
+
+ g_type_class_add_private (class, sizeof (GSettingsListPrivate));
+}
+
+GSettingsList *
+g_settings_get_list (GSettings *settings,
+ const gchar *name)
+{
+ GSettings *list;
+
+ list = g_settings_get_settings (settings, name);
+ g_assert (G_IS_SETTINGS_LIST (list));
+
+ return G_SETTINGS_LIST (list);
+}
+
+gchar **
+g_settings_list_list (GSettingsList *list,
+ gint *n_items)
+{
+ const gchar *item;
+ GVariantIter iter;
+ GVariant *value;
+ gchar **result;
+ gchar **ptr;
+ gint n;
+
+ if (!n_items)
+ n_items = &n;
+
+ value = g_settings_get_value (G_SETTINGS (list), "list");
+ *n_items = g_variant_iter_init (&iter, value);
+ result = g_new (gchar *, *n_items + 1);
+ g_variant_unref (value);
+
+ ptr = result;
+ while (g_variant_iter_next (&iter, "s", &item))
+ *ptr++ = g_strdup (item);
+ *ptr = NULL;
+
+ return result;
+}
+
+GSettings *
+g_settings_list_get (GSettingsList *list,
+ const gchar *id)
+{
+ return g_settings_get_settings (G_SETTINGS (list), id);
+}
+
+gchar *
+g_settings_list_add (GSettingsList *list,
+ const gchar *prefix,
+ gint before)
+{
+ GVariantBuilder *builder;
+ gboolean already_in;
+ GVariant *old_list;
+ gint i, length;
+ gboolean in;
+
+ builder = g_variant_builder_new (G_VARIANT_TYPE_CLASS_ARRAY,
+ G_VARIANT_TYPE ("as"));
+ old_list = g_settings_get_value (G_SETTINGS (list), "list");
+ length = g_variant_n_children (old_list);
+ already_in = FALSE;
+ in = FALSE;
+
+ for (i = 0; i < length; i++)
+ {
+ GVariant *item;
+
+ if (before == i)
+ {
+ g_variant_builder_add (builder, "s", prefix);
+ in = TRUE;
+ }
+
+ item = g_variant_get_child_value (old_list, i);
+ g_variant_builder_add_value (builder, item);
+
+ if (strcmp (g_variant_get_string (item, NULL), prefix) == 0)
+ already_in = TRUE;
+
+ g_variant_unref (item);
+ }
+
+ g_variant_unref (old_list);
+
+ if (!in)
+ g_variant_builder_add (builder, "s", prefix);
+
+ if (!already_in)
+ g_settings_set_value (G_SETTINGS (list), "list",
+ g_variant_builder_end (builder));
+ else
+ g_variant_builder_cancel (builder);
+
+ return g_strdup (prefix);
+}
+
+void
+g_settings_list_remove (GSettingsList *list,
+ const gchar *id)
+{
+ GVariantBuilder *new_list;
+ GVariantIter old_list;
+ GVariant *value;
+
+ new_list = g_variant_builder_new (G_VARIANT_TYPE_CLASS_ARRAY,
+ G_VARIANT_TYPE ("as"));
+ g_settings_get (G_SETTINGS (list), "list", &old_list);
+
+ while ((value = g_variant_iter_next_value (&old_list)))
+ if (strcmp (g_variant_get_string (value, NULL), id))
+ g_variant_builder_add_value (new_list, value);
+
+ g_settings_set (G_SETTINGS (list), "list", new_list);
+}
+
+#define _gsettingslist_c_
+#include "gioaliasdef.c"
diff --git a/gio/gsettingslist.h b/gio/gsettingslist.h
new file mode 100644
index 0000000..7e926a2
--- /dev/null
+++ b/gio/gsettingslist.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright © 2009 Codethink Limited
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 3 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * See the included COPYING file for more information.
+ */
+
+#ifndef _gsettingslist_h_
+#define _gsettingslist_h_
+
+#include "gsettings.h"
+
+#define G_TYPE_SETTINGS_LIST (g_settings_list_get_type ())
+#define G_SETTINGS_LIST(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
+ G_TYPE_SETTINGS_LIST, GSettingsList))
+#define G_SETTINGS_LIST_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), \
+ G_TYPE_SETTINGS_LIST, GSettingsListClass))
+#define G_IS_SETTINGS_LIST(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
+ G_TYPE_SETTINGS_LIST))
+#define G_IS_SETTINGS_LIST_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), \
+ G_TYPE_SETTINGS_LIST))
+#define G_SETTINGS_LIST_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), \
+ G_TYPE_SETTINGS_LIST, GSettingsListClass))
+
+typedef struct _GSettingsListPrivate GSettingsListPrivate;
+typedef struct _GSettingsListClass GSettingsListClass;
+typedef struct _GSettingsList GSettingsList;
+
+struct _GSettingsListClass
+{
+ GSettingsClass parent_class;
+};
+
+struct _GSettingsList
+{
+ GSettings parent_instance;
+ GSettingsListPrivate *priv;
+};
+
+G_BEGIN_DECLS
+
+
+GType g_settings_list_get_type (void);
+
+gchar ** g_settings_list_list (GSettingsList *list,
+ gint *n_items);
+
+GSettings * g_settings_list_get (GSettingsList *list,
+ const gchar *id);
+
+gchar * g_settings_list_add (GSettingsList *list,
+ const gchar *prefix,
+ gint before);
+
+void g_settings_list_remove (GSettingsList *list,
+ const gchar *id);
+
+gboolean g_settings_list_move_item (GSettingsList *list,
+ const gchar *id,
+ gint new_index);
+
+/* avoid header pain -- put this here */
+GSettingsList * g_settings_get_list (GSettings *settings,
+ const gchar *name);
+
+G_END_DECLS
+
+#endif /* _gsettingslist_h_ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]