rename gsettingsschema.h to -internal.h
[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-internal.h"
23 #include "gsettings.h"
24
25 #include "gvdb/gvdb-reader.h"
26
27 #include <glibintl.h>
28
29 struct _GSettingsSchema
30 {
31   const gchar *gettext_domain;
32   const gchar *path;
33   GQuark *items;
34   gint n_items;
35   GvdbTable *table;
36   gchar *name;
37
38   gint ref_count;
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 GSettingsSchema *
220 g_settings_schema_ref (GSettingsSchema *schema)
221 {
222   g_atomic_int_inc (&schema->ref_count);
223
224   return schema;
225 }
226
227 void
228 g_settings_schema_unref (GSettingsSchema *schema)
229 {
230   if (g_atomic_int_dec_and_test (&schema->ref_count))
231     {
232       gvdb_table_unref (schema->table);
233       g_free (schema->items);
234       g_free (schema->name);
235
236       g_slice_free (GSettingsSchema, schema);
237     }
238 }
239
240 const gchar *
241 g_settings_schema_get_string (GSettingsSchema *schema,
242                               const gchar     *key)
243 {
244   const gchar *result = NULL;
245   GVariant *value;
246
247   if ((value = gvdb_table_get_raw_value (schema->table, key)))
248     {
249       result = g_variant_get_string (value, NULL);
250       g_variant_unref (value);
251     }
252
253   return result;
254 }
255
256 GSettingsSchema *
257 g_settings_schema_new (const gchar *name)
258 {
259   GSettingsSchema *schema;
260   GvdbTable *table = NULL;
261   GSList *source;
262
263   g_return_val_if_fail (name != NULL, NULL);
264
265   initialise_schema_sources ();
266
267   for (source = schema_sources; source; source = source->next)
268     {
269       GvdbTable *file = source->data;
270
271       if ((table = gvdb_table_get_table (file, name)))
272         break;
273     }
274
275   if (table == NULL)
276     g_error ("Settings schema '%s' is not installed\n", name);
277
278   schema = g_slice_new0 (GSettingsSchema);
279   schema->ref_count = 1;
280   schema->name = g_strdup (name);
281   schema->table = table;
282   schema->path =
283     g_settings_schema_get_string (schema, ".path");
284   schema->gettext_domain =
285     g_settings_schema_get_string (schema, ".gettext-domain");
286
287   if (schema->gettext_domain)
288     bind_textdomain_codeset (schema->gettext_domain, "UTF-8");
289
290   return schema;
291 }
292
293 GVariantIter *
294 g_settings_schema_get_value (GSettingsSchema *schema,
295                              const gchar     *key)
296 {
297   GVariantIter *iter;
298   GVariant *value;
299
300   value = gvdb_table_get_raw_value (schema->table, key);
301
302   if G_UNLIKELY (value == NULL)
303     g_error ("Settings schema '%s' does not contain a key named '%s'",
304              schema->name, key);
305
306   iter = g_variant_iter_new (value);
307   g_variant_unref (value);
308
309   return iter;
310 }
311
312 const gchar *
313 g_settings_schema_get_path (GSettingsSchema *schema)
314 {
315   return schema->path;
316 }
317
318 const gchar *
319 g_settings_schema_get_gettext_domain (GSettingsSchema *schema)
320 {
321   return schema->gettext_domain;
322 }
323
324 gboolean
325 g_settings_schema_has_key (GSettingsSchema *schema,
326                            const gchar     *key)
327 {
328   return gvdb_table_has_value (schema->table, key);
329 }
330
331 const GQuark *
332 g_settings_schema_list (GSettingsSchema *schema,
333                         gint            *n_items)
334 {
335   gint i, j;
336
337   if (schema->items == NULL)
338     {
339       gchar **list;
340       gint len;
341
342       list = gvdb_table_list (schema->table, "");
343       len = list ? g_strv_length (list) : 0;
344
345       schema->items = g_new (GQuark, len);
346       j = 0;
347
348       for (i = 0; i < len; i++)
349         if (list[i][0] != '.')
350           schema->items[j++] = g_quark_from_string (list[i]);
351       schema->n_items = j;
352
353       g_strfreev (list);
354     }
355
356   *n_items = schema->n_items;
357   return schema->items;
358 }