gio static fixups
[platform/upstream/glib.git] / gio / gsettingsschema.c
1 /*
2  * Copyright © 2010 Codethink Limited
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the licence, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21
22 #include "gsettingsschema.h"
23 #include "gsettings.h"
24
25 #include "gvdb/gvdb-reader.h"
26
27 #include <glibintl.h>
28
29 G_DEFINE_TYPE (GSettingsSchema, g_settings_schema, G_TYPE_OBJECT)
30
31 struct _GSettingsSchemaPrivate
32 {
33   const gchar *gettext_domain;
34   const gchar *path;
35   GQuark *items;
36   gint n_items;
37   GvdbTable *table;
38   gchar *name;
39 };
40
41 static GSList *schema_sources;
42
43 static void
44 initialise_schema_sources (void)
45 {
46   static gsize initialised;
47
48   if G_UNLIKELY (g_once_init_enter (&initialised))
49     {
50       const gchar * const *dir;
51       const gchar *path;
52
53       for (dir = g_get_system_data_dirs (); *dir; dir++)
54         {
55           gchar *filename;
56           GvdbTable *table;
57
58           filename = g_build_filename (*dir, "glib-2.0", "schemas",
59                                        "gschemas.compiled", NULL);
60           table = gvdb_table_new (filename, TRUE, NULL);
61
62           if (table != NULL)
63             schema_sources = g_slist_prepend (schema_sources, table);
64
65           g_free (filename);
66         }
67
68       schema_sources = g_slist_reverse (schema_sources);
69
70       if ((path = g_getenv ("GSETTINGS_SCHEMA_DIR")) != NULL)
71         {
72           gchar *filename;
73           GvdbTable *table;
74
75           filename = g_build_filename (path, "gschemas.compiled", NULL);
76           table = gvdb_table_new (filename, TRUE, NULL);
77
78           if (table != NULL)
79             schema_sources = g_slist_prepend (schema_sources, table);
80
81           g_free (filename);
82         }
83
84       g_once_init_leave (&initialised, TRUE);
85     }
86 }
87
88 static gboolean
89 steal_item (gpointer key,
90             gpointer value,
91             gpointer user_data)
92 {
93   gchar ***ptr = user_data;
94
95   *(*ptr)++ = (gchar *) key;
96
97   return TRUE;
98 }
99
100 static const gchar * const *non_relocatable_schema_list;
101 static const gchar * const *relocatable_schema_list;
102 static gsize schema_lists_initialised;
103
104 static void
105 ensure_schema_lists (void)
106 {
107   if (g_once_init_enter (&schema_lists_initialised))
108     {
109       GHashTable *single, *reloc;
110       const gchar **ptr;
111       GSList *source;
112       gchar **list;
113       gint i;
114
115       initialise_schema_sources ();
116
117       /* We use hash tables to avoid duplicate listings for schemas that
118        * appear in more than one file.
119        */
120       single = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
121       reloc = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
122
123       for (source = schema_sources; source; source = source->next)
124         {
125           list = gvdb_table_list (source->data, "");
126
127           g_assert (list != NULL);
128
129           for (i = 0; list[i]; i++)
130             {
131               if (!g_hash_table_lookup (single, list[i]) &&
132                   !g_hash_table_lookup (reloc, list[i]))
133                 {
134                   GvdbTable *table;
135
136                   table = gvdb_table_get_table (source->data, list[i]);
137                   g_assert (table != NULL);
138
139                   if (gvdb_table_has_value (table, ".path"))
140                     g_hash_table_insert (single, g_strdup (list[i]), NULL);
141                   else
142                     g_hash_table_insert (reloc, g_strdup (list[i]), NULL);
143
144                   gvdb_table_unref (table);
145                 }
146             }
147
148           g_strfreev (list);
149         }
150
151       ptr = g_new (const gchar *, g_hash_table_size (single) + 1);
152       non_relocatable_schema_list = ptr;
153       g_hash_table_foreach_steal (single, steal_item, &ptr);
154       g_hash_table_unref (single);
155       *ptr = NULL;
156
157       ptr = g_new (const gchar *, g_hash_table_size (reloc) + 1);
158       relocatable_schema_list = ptr;
159       g_hash_table_foreach_steal (reloc, steal_item, &ptr);
160       g_hash_table_unref (reloc);
161       *ptr = NULL;
162
163       g_once_init_leave (&schema_lists_initialised, TRUE);
164     }
165 }
166
167 /**
168  * g_settings_list_schemas:
169  *
170  * Gets a list of the #GSettings schemas installed on the system.  The
171  * returned list is exactly the list of schemas for which you may call
172  * g_settings_new() without adverse effects.
173  *
174  * This function does not list the schemas that do not provide their own
175  * paths (ie: schemas for which you must use
176  * g_settings_new_with_path()).  See
177  * g_settings_list_relocatable_schemas() for that.
178  *
179  * Returns: (element-type utf8) (transfer none):  a list of #GSettings
180  *   schemas that are available.  The list must not be modified or
181  *   freed.
182  *
183  * Since: 2.26
184  **/
185 const gchar * const *
186 g_settings_list_schemas (void)
187 {
188   ensure_schema_lists ();
189
190   return non_relocatable_schema_list;
191 }
192
193 /**
194  * g_settings_list_relocatable_schemas:
195  *
196  * Gets a list of the relocatable #GSettings schemas installed on the
197  * system.  These are schemas that do not provide their own path.  It is
198  * usual to instantiate these schemas directly, but if you want to you
199  * can use g_settings_new_with_path() to specify the path.
200  *
201  * The output of this function, tTaken together with the output of
202  * g_settings_list_schemas() represents the complete list of all
203  * installed schemas.
204  *
205  * Returns: (element-type utf8) (transfer none): a list of relocatable
206  *   #GSettings schemas that are available.  The list must not be
207  *   modified or freed.
208  *
209  * Since: 2.28
210  **/
211 const gchar * const *
212 g_settings_list_relocatable_schemas (void)
213 {
214   ensure_schema_lists ();
215
216   return relocatable_schema_list;
217 }
218
219 static void
220 g_settings_schema_finalize (GObject *object)
221 {
222   GSettingsSchema *schema = G_SETTINGS_SCHEMA (object);
223
224   gvdb_table_unref (schema->priv->table);
225   g_free (schema->priv->items);
226   g_free (schema->priv->name);
227
228   G_OBJECT_CLASS (g_settings_schema_parent_class)
229     ->finalize (object);
230 }
231
232 static void
233 g_settings_schema_init (GSettingsSchema *schema)
234 {
235   schema->priv = G_TYPE_INSTANCE_GET_PRIVATE (schema, G_TYPE_SETTINGS_SCHEMA,
236                                               GSettingsSchemaPrivate);
237 }
238
239 static void
240 g_settings_schema_class_init (GSettingsSchemaClass *class)
241 {
242   GObjectClass *object_class = G_OBJECT_CLASS (class);
243
244   object_class->finalize = g_settings_schema_finalize;
245
246   g_type_class_add_private (class, sizeof (GSettingsSchemaPrivate));
247 }
248
249 const gchar *
250 g_settings_schema_get_string (GSettingsSchema *schema,
251                               const gchar     *key)
252 {
253   const gchar *result = NULL;
254   GVariant *value;
255
256   if ((value = gvdb_table_get_raw_value (schema->priv->table, key)))
257     {
258       result = g_variant_get_string (value, NULL);
259       g_variant_unref (value);
260     }
261
262   return result;
263 }
264
265 GSettingsSchema *
266 g_settings_schema_new (const gchar *name)
267 {
268   GSettingsSchema *schema;
269   GvdbTable *table = NULL;
270   GSList *source;
271
272   g_return_val_if_fail (name != NULL, NULL);
273
274   initialise_schema_sources ();
275
276   for (source = schema_sources; source; source = source->next)
277     {
278       GvdbTable *file = source->data;
279
280       if ((table = gvdb_table_get_table (file, name)))
281         break;
282     }
283
284   if (table == NULL)
285     g_error ("Settings schema '%s' is not installed\n", name);
286
287   schema = g_object_new (G_TYPE_SETTINGS_SCHEMA, NULL);
288   schema->priv->name = g_strdup (name);
289   schema->priv->table = table;
290   schema->priv->path =
291     g_settings_schema_get_string (schema, ".path");
292   schema->priv->gettext_domain =
293     g_settings_schema_get_string (schema, ".gettext-domain");
294
295   if (schema->priv->gettext_domain)
296     bind_textdomain_codeset (schema->priv->gettext_domain, "UTF-8");
297
298   return schema;
299 }
300
301 GVariantIter *
302 g_settings_schema_get_value (GSettingsSchema *schema,
303                              const gchar     *key)
304 {
305   GVariantIter *iter;
306   GVariant *value;
307
308   value = gvdb_table_get_raw_value (schema->priv->table, key);
309
310   if G_UNLIKELY (value == NULL)
311     g_error ("Settings schema '%s' does not contain a key named '%s'",
312              schema->priv->name, key);
313
314   iter = g_variant_iter_new (value);
315   g_variant_unref (value);
316
317   return iter;
318 }
319
320 const gchar *
321 g_settings_schema_get_path (GSettingsSchema *schema)
322 {
323   return schema->priv->path;
324 }
325
326 const gchar *
327 g_settings_schema_get_gettext_domain (GSettingsSchema *schema)
328 {
329   return schema->priv->gettext_domain;
330 }
331
332 gboolean
333 g_settings_schema_has_key (GSettingsSchema *schema,
334                            const gchar     *key)
335 {
336   return gvdb_table_has_value (schema->priv->table, key);
337 }
338
339 const GQuark *
340 g_settings_schema_list (GSettingsSchema *schema,
341                         gint            *n_items)
342 {
343   gint i, j;
344
345   if (schema->priv->items == NULL)
346     {
347       gchar **list;
348       gint len;
349
350       list = gvdb_table_list (schema->priv->table, "");
351       len = list ? g_strv_length (list) : 0;
352
353       schema->priv->items = g_new (GQuark, len);
354       j = 0;
355
356       for (i = 0; i < len; i++)
357         if (list[i][0] != '.')
358           schema->priv->items[j++] = g_quark_from_string (list[i]);
359       schema->priv->n_items = j;
360
361       g_strfreev (list);
362     }
363
364   *n_items = schema->priv->n_items;
365   return schema->priv->items;
366 }