~ubuntu-branches/ubuntu/oneiric/avant-window-navigator/oneiric

« back to all changes in this revision

Viewing changes to libawn/awn-config-client-gkeyfile.c

  • Committer: Bazaar Package Importer
  • Author(s): Julien Lavergne
  • Date: 2008-05-24 14:42:01 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20080524144201-r3v8e4g2hv2q1i9x
Tags: 0.2.6-6
* debian/patches/04-fix-colormap.patch
 - Fix crash in awn-manager if colormap == None. Thanks Emme for the 
   patch. (Closes: #482030) 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  Copyright (C) 2007, 2008 Mark Lee <avant-wn@lazymalevolence.com>
 
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 License, 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
 *  Author : Mark Lee <avant-wn@lazymalevolence.com>
 
20
 */
 
21
 
 
22
#ifdef HAVE_CONFIG_H
 
23
#include <config.h>
 
24
#endif
 
25
 
 
26
#include <glib.h>
 
27
#ifdef HAVE_UNISTD_H
 
28
#include <unistd.h>
 
29
#endif
 
30
#include <string.h>
 
31
 
 
32
#include <glib/gstdio.h>
 
33
#include <glib/gutils.h>
 
34
 
 
35
/**
 
36
 * SECTION: awn-config-client
 
37
 * @short_description: The configuration API for both Awn proper and
 
38
 * Awn applets.
 
39
 * @include libawn/awn-config-client.h
 
40
 *
 
41
 * A configuration wrapper API that supports both a GConf backend, as well as
 
42
 * a GKeyFile-based backend.  Used for both Awn proper and its applets.
 
43
 */
 
44
#include "libawn/awn-config-client.h"
 
45
#include "libawn/awn-vfs.h"
 
46
#include "awn-config-client-shared.c"
 
47
 
 
48
struct _AwnConfigClient
 
49
{
 
50
        GKeyFile *client;
 
51
        GData *notify_funcs;
 
52
        AwnVfsMonitor *file_monitor;
 
53
        gchar *checksum;
 
54
        GKeyFile *schema;
 
55
        gchar *path; /* .ini path */
 
56
};
 
57
 
 
58
/**
 
59
 * AwnConfigClientNotifyData:
 
60
 * @callback: The notification callback.
 
61
 * @data: Extra data passed to the callback, as defined in the call
 
62
 * to awn_config_client_notify_add().
 
63
 *
 
64
 * A utility structure used to pass callback metadata in the configuration
 
65
 * backend implementations.
 
66
 */
 
67
typedef struct {
 
68
        AwnConfigClientNotifyFunc callback;
 
69
        gpointer data;
 
70
} AwnConfigClientNotifyData;
 
71
 
 
72
static void awn_config_client_gkeyfile_new_schema (AwnConfigClient *client, gchar *base_name);
 
73
static void awn_config_client_load_data (AwnConfigClient *client);
 
74
static void awn_config_client_save (AwnConfigClient *client, GError **err);
 
75
static void awn_config_client_reload (AwnVfsMonitor *monitor, gchar *monitor_path, gchar *event_path, AwnVfsMonitorEvent event, AwnConfigClient *client);
 
76
 
 
77
static AwnConfigClient *awn_config_client_new_with_path (gchar *path, gchar *name)
 
78
{
 
79
        AwnConfigClient *client = g_new (AwnConfigClient, 1);
 
80
        client->path = path;
 
81
        client->client = g_key_file_new ();
 
82
        awn_config_client_gkeyfile_new_schema (client, name);
 
83
        GError *err = NULL;
 
84
        if (g_file_test (client->path, G_FILE_TEST_EXISTS)) {
 
85
                awn_config_client_load_data (client);
 
86
        } else {
 
87
                g_message ("Creating the config file for you.");
 
88
                awn_config_client_load_defaults_from_schema (client, &err);
 
89
                if (err) {
 
90
                        g_error ("Error loading the schema: '%s'", err->message);
 
91
                        g_error_free (err);
 
92
                }
 
93
                awn_config_client_save (client, &err);
 
94
                if (err) {
 
95
                        g_warning ("Error loading the config file: '%s'", err->message);
 
96
                        g_error_free (err);
 
97
                }
 
98
        }
 
99
        client->file_monitor = awn_vfs_monitor_add (client->path, AWN_VFS_MONITOR_FILE,
 
100
                                                    (AwnVfsMonitorFunc)awn_config_client_reload, client);
 
101
        g_datalist_init (&(client->notify_funcs));
 
102
        return client;
 
103
}
 
104
 
 
105
/**
 
106
 * awn_config_client_new:
 
107
 *
 
108
 * Retrieves the configuration client for Awn proper.  If none exists,
 
109
 * one is created.
 
110
 * Returns: a singleton instance of #AwnConfigClient.
 
111
 */
 
112
AwnConfigClient *awn_config_client_new ()
 
113
{
 
114
        static AwnConfigClient *awn_dock_config = NULL;
 
115
        if (!awn_dock_config) {
 
116
                gchar *config_path = g_build_filename (g_get_user_config_dir (), "awn", "awn.ini", NULL);
 
117
                awn_dock_config = awn_config_client_new_with_path (g_strdup (config_path), NULL);
 
118
                g_free (config_path);
 
119
        }
 
120
        return awn_dock_config;
 
121
}
 
122
 
 
123
/**
 
124
 * awn_config_client_new_for_applet:
 
125
 * @name: The name of the applet.
 
126
 * @uid: The unique identifier for the applet (used for positioning on the
 
127
 * dock).  Optional value (i.e., may be %NULL).
 
128
 *
 
129
 * Creates a configuration client for the applet named in the parameter.  If
 
130
 * @uid is not defined, it is implied that the applet is a singleton.
 
131
 * Returns: an instance of #AwnConfigClient for the specified applet.
 
132
 */
 
133
AwnConfigClient *awn_config_client_new_for_applet (gchar *name, gchar *uid)
 
134
{
 
135
        AwnConfigClient *client;
 
136
        gchar *config_dir = g_build_filename (g_get_user_config_dir (), "awn", "applets", NULL);
 
137
        if (!g_file_test (client->path, G_FILE_TEST_EXISTS)) {
 
138
                g_mkdir (config_dir, 0755);
 
139
        }
 
140
        gchar *config_file;
 
141
        if (uid) {
 
142
                config_file = g_strconcat (uid, ".ini", NULL);
 
143
        } else {
 
144
                config_file = g_strconcat (name, ".ini", NULL);
 
145
        }
 
146
        gchar *config_path = g_build_filename (config_dir, config_file, NULL);
 
147
        client = awn_config_client_new_with_path (g_strdup (config_path), name);
 
148
        g_free (config_path);
 
149
        g_free (config_file);
 
150
        g_free (config_dir);
 
151
        return client;
 
152
}
 
153
 
 
154
/* returns a newly allocated string */
 
155
static gchar *awn_config_client_generate_key (AwnConfigClient *client, const gchar *group, const gchar *key)
 
156
{
 
157
        if (key == NULL) {
 
158
                return g_strconcat (client->path, "/", group, NULL);
 
159
        } else {
 
160
                return g_strconcat (client->path, "/", group, "/", key, NULL);
 
161
        }
 
162
}
 
163
 
 
164
/**
 
165
 * Generic function to free both the elements of a GSList and the GSList itself.
 
166
 */
 
167
static void awn_config_client_free_gslist (GSList *list)
 
168
{
 
169
        g_slist_foreach (list, (GFunc)g_free, NULL);
 
170
        g_slist_free (list);
 
171
}
 
172
/* if base_name is NULL, base_name defaults to "awn" */
 
173
static void awn_config_client_gkeyfile_new_schema (AwnConfigClient *client, gchar *base_name)
 
174
{
 
175
        if (!base_name) {
 
176
                base_name = "awn";
 
177
        }
 
178
        client->schema = g_key_file_new ();
 
179
        gchar *file_name = g_strconcat(base_name, ".schema-ini", NULL);
 
180
        gchar *schema_path = g_build_filename (DATADIR, "avant-window-navigator", "schemas", file_name, NULL);
 
181
        GError *err = NULL;
 
182
        if (!g_key_file_load_from_file (client->schema, schema_path,
 
183
                                        (G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS),
 
184
                                        &err)) {
 
185
                if (err) {
 
186
                        g_error ("Error loading the schema file '%s': '%s'", schema_path, err->message);
 
187
                        g_error_free (err);
 
188
                } else {
 
189
                        g_error ("Error loading the schema file.");
 
190
                }
 
191
        }
 
192
        g_free (schema_path);
 
193
        g_free (file_name);
 
194
}
 
195
static GSList *awn_config_client_get_gkeyfile_list_value (GKeyFile *client, const gchar *group, const gchar *key, AwnConfigListType list_type, GError **err)
 
196
{
 
197
        GSList *slist = NULL;
 
198
        gsize list_len;
 
199
        switch (list_type) {
 
200
                case AWN_CONFIG_CLIENT_LIST_TYPE_BOOL: {
 
201
                        gboolean *list = g_key_file_get_boolean_list (client, group, key, &list_len, err);
 
202
                        if (list) {
 
203
                                gsize i;
 
204
                                for (i = 0; i < list_len; i++) {
 
205
                                        slist = g_slist_append (slist, (gpointer)(&list[i]));
 
206
                                }
 
207
                        }
 
208
                        break;
 
209
                } case AWN_CONFIG_CLIENT_LIST_TYPE_FLOAT: {
 
210
                        gdouble *list = g_key_file_get_double_list (client, group, key, &list_len, err);
 
211
                        if (list) {
 
212
                                gsize i;
 
213
                                for (i = 0; i < list_len; i++) {
 
214
                                        slist = g_slist_append (slist, (gpointer)(&list[i]));
 
215
                                }
 
216
                        }
 
217
                        break;
 
218
                } case AWN_CONFIG_CLIENT_LIST_TYPE_INT: {
 
219
                        gint *list = g_key_file_get_integer_list (client, group, key, &list_len, err);
 
220
                        if (list) {
 
221
                                gsize i;
 
222
                                for (i = 0; i < list_len; i++) {
 
223
                                        slist = g_slist_append (slist, (gpointer)(&list[i]));
 
224
                                }
 
225
                        }
 
226
                        break;
 
227
                } case AWN_CONFIG_CLIENT_LIST_TYPE_STRING: {
 
228
                        gchar **list = g_key_file_get_string_list (client, group, key, &list_len, err);
 
229
                        if (list) {
 
230
                                gsize i;
 
231
                                for (i = 0; i < list_len; i++) {
 
232
                                        slist = g_slist_append (slist, (gpointer)(list[i]));
 
233
                                }
 
234
                        }
 
235
                        break;
 
236
                }
 
237
        }
 
238
        return slist;
 
239
}
 
240
static void awn_config_client_load_data (AwnConfigClient *client)
 
241
{
 
242
        GError *err = NULL;
 
243
        if (!g_key_file_load_from_file (client->client, client->path,
 
244
                                        (G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS),
 
245
                                        &err)) {
 
246
                if (err) {
 
247
                        g_warning ("Error loading the config file: '%s'", err->message);
 
248
                        g_error_free (err);
 
249
                } else {
 
250
                        g_message ("Config file not found.  It will be created for you.");
 
251
                }
 
252
        }
 
253
        gchar *data;
 
254
        gsize len;
 
255
        data = g_key_file_to_data (client->client, &len, &err);
 
256
        if (err) {
 
257
                g_warning ("Could not serialize the loaded configuration data: '%s'", err->message);
 
258
                g_error_free (err);
 
259
                client->checksum = g_compute_checksum_for_string (G_CHECKSUM_SHA256, "", 0);
 
260
        } else {
 
261
                client->checksum = g_compute_checksum_for_string (G_CHECKSUM_SHA256, data, len);
 
262
                g_free (data);
 
263
        }
 
264
}
 
265
static void awn_config_client_save (AwnConfigClient *client, GError **err)
 
266
{
 
267
        gchar *data;
 
268
        gsize len;
 
269
        data = g_key_file_to_data (client->client, &len, err);
 
270
        if (!err || !*err) {
 
271
                g_file_set_contents (client->path, data, len, err);
 
272
                g_free (data);
 
273
        }
 
274
}
 
275
/* free the returned value when done */
 
276
static gchar **awn_config_client_string_lists_merge (gchar **list1, gsize list1_len, gchar **list2, gsize list2_len, gsize *ret_len)
 
277
{
 
278
        gchar **ret_list = g_malloc (sizeof(gchar*) * (list1_len + list2_len));
 
279
        gsize i, j;
 
280
        for (i = 0; i < list1_len; i++) {
 
281
                ret_list[i] = g_strdup (list1[i]);
 
282
        }
 
283
        *ret_len = list1_len;
 
284
        for (i = 0; i < list2_len; i++) {
 
285
                gchar *value = list2[i];
 
286
                gboolean value_exists = FALSE;
 
287
                for (j = 0; j < *ret_len; j++) {
 
288
                        if (strcmp (value, ret_list[j]) == 0) {
 
289
                                value_exists = TRUE;
 
290
                                break;
 
291
                        }
 
292
                }
 
293
                if (!value_exists) {
 
294
                        ret_list[(*ret_len)++] = g_strdup (value);
 
295
                }
 
296
        }
 
297
        ret_list[*ret_len] = NULL;
 
298
        return ret_list;
 
299
}
 
300
static void awn_config_client_do_notify (AwnConfigClient *client, const gchar *group, const gchar *key)
 
301
{
 
302
        if (g_key_file_has_group (client->client, group) && g_key_file_has_key (client->client, group, key, NULL)) {
 
303
                AwnConfigClientNotifyEntry *entry = g_new0 (AwnConfigClientNotifyEntry, 1);
 
304
                entry->client = client;
 
305
                entry->group = (gchar*)group;
 
306
                entry->key = (gchar*)key;
 
307
                AwnConfigClientValue *value = g_malloc (sizeof (AwnConfigClientValue));
 
308
                GError *err = NULL;
 
309
                switch (awn_config_client_get_value_type (client, group, key, &err)) {
 
310
                        case AWN_CONFIG_VALUE_TYPE_BOOL:
 
311
                                value->bool_val = g_key_file_get_boolean (client->client, group, key, NULL);
 
312
                                break;
 
313
                        case AWN_CONFIG_VALUE_TYPE_FLOAT:
 
314
                                value->float_val = (gfloat)g_key_file_get_double (client->client, group, key, NULL);
 
315
                                break;
 
316
                        case AWN_CONFIG_VALUE_TYPE_INT:
 
317
                                value->int_val = g_key_file_get_integer (client->client, group, key, NULL);
 
318
                                break;
 
319
                        case AWN_CONFIG_VALUE_TYPE_STRING:
 
320
                                value->str_val = g_key_file_get_string (client->client, group, key, NULL);
 
321
                                break;
 
322
                        case AWN_CONFIG_VALUE_TYPE_LIST_BOOL:
 
323
                                value->list_val = awn_config_client_get_gkeyfile_list_value (client->client, group, key, AWN_CONFIG_CLIENT_LIST_TYPE_BOOL, NULL);
 
324
                                break;
 
325
                        case AWN_CONFIG_VALUE_TYPE_LIST_FLOAT:
 
326
                                value->list_val = awn_config_client_get_gkeyfile_list_value (client->client, group, key, AWN_CONFIG_CLIENT_LIST_TYPE_FLOAT, NULL);
 
327
                                break;
 
328
                        case AWN_CONFIG_VALUE_TYPE_LIST_INT:
 
329
                                value->list_val = awn_config_client_get_gkeyfile_list_value (client->client, group, key, AWN_CONFIG_CLIENT_LIST_TYPE_INT, NULL);
 
330
                                break;
 
331
                        case AWN_CONFIG_VALUE_TYPE_LIST_STRING:
 
332
                                value->list_val = awn_config_client_get_gkeyfile_list_value (client->client, group, key, AWN_CONFIG_CLIENT_LIST_TYPE_STRING, NULL);
 
333
                                break;
 
334
                        default: /* NULL */
 
335
                                return;
 
336
                                break;
 
337
                }
 
338
                entry->value = *value;
 
339
                gchar *full_key = awn_config_client_generate_key (client, group, key);
 
340
                GSList *callbacks = g_datalist_get_data (&(client->notify_funcs), full_key);
 
341
                GSList *notify_iter;
 
342
                for (notify_iter = callbacks; notify_iter != NULL; notify_iter = g_slist_next (notify_iter)) {
 
343
                        AwnConfigClientNotifyData *notify = (AwnConfigClientNotifyData*)notify_iter->data;
 
344
                        if (notify->callback) {
 
345
                                (notify->callback) (entry, notify->data);
 
346
                        }
 
347
                }
 
348
                g_free (full_key);
 
349
                g_free (value);
 
350
                g_free (entry);
 
351
        } else {
 
352
        }
 
353
}
 
354
static void awn_config_client_reload (AwnVfsMonitor *monitor, gchar *monitor_path, gchar *event_path, AwnVfsMonitorEvent event, AwnConfigClient *client)
 
355
{
 
356
        switch (event) {
 
357
                case AWN_VFS_MONITOR_EVENT_CREATED:
 
358
                case AWN_VFS_MONITOR_EVENT_CHANGED: {
 
359
                        gchar *old_checksum = client->checksum;
 
360
                        GKeyFile *old_client = client->client;
 
361
                        client->client = g_key_file_new ();
 
362
                        awn_config_client_load_data (client);
 
363
                        if (!old_checksum || strcmp (old_checksum, client->checksum) != 0) {
 
364
                                /* iterate through all of the groups/keys to see if anything's changed */
 
365
                                /* merge groups into one array */
 
366
                                gsize og_len, ng_len, i, groups_len;
 
367
                                gchar **old_groups = g_key_file_get_groups (old_client, &og_len);
 
368
                                gchar **new_groups = g_key_file_get_groups (client->client, &ng_len);
 
369
                                gchar **all_groups = awn_config_client_string_lists_merge (old_groups, og_len, new_groups, ng_len, &groups_len);
 
370
                                for (i = 0; i < groups_len; i++) {
 
371
                                        gchar *group = all_groups[i];
 
372
                                        if (!g_key_file_has_group (old_client, group)) {
 
373
                                                /* group added */
 
374
                                                gsize keys_len, j;
 
375
                                                gchar **keys = g_key_file_get_keys (client->client, group, &keys_len, NULL);
 
376
                                                for (j = 0; j < keys_len; j++) {
 
377
                                                        awn_config_client_do_notify (client, group, keys[j]);
 
378
                                                }
 
379
                                                g_strfreev (keys);
 
380
                                        } else if (!g_key_file_has_group (client->client, group)) {
 
381
                                                /* group removed */
 
382
                                                gsize keys_len, j;
 
383
                                                gchar **keys = g_key_file_get_keys (old_client, group, &keys_len, NULL);
 
384
                                                for (j = 0; j < keys_len; j++) {
 
385
                                                        awn_config_client_do_notify (client, group, keys[j]);
 
386
                                                }
 
387
                                                g_strfreev (keys);
 
388
                                        } else {
 
389
                                                /* check for added/deleted/changed keys */
 
390
                                                gsize ok_len, nk_len, j, keys_len;
 
391
                                                gchar **okeys = g_key_file_get_keys (old_client, group, &ok_len, NULL);
 
392
                                                gchar **nkeys = g_key_file_get_keys (client->client, group, &nk_len, NULL);
 
393
                                                gchar **all_keys = awn_config_client_string_lists_merge (okeys, ok_len, nkeys, nk_len, &keys_len);
 
394
                                                for (j = 0; j < keys_len; j++) {
 
395
                                                        gchar *key = all_keys[j];
 
396
                                                        if (!g_key_file_has_key (old_client, group, key, NULL)) {
 
397
                                                                /* key added */
 
398
                                                                awn_config_client_do_notify (client, group, key);
 
399
                                                        } else if (!g_key_file_has_key (client->client, group, key, NULL)) {
 
400
                                                                /* key removed */
 
401
                                                                awn_config_client_do_notify (client, group, key);
 
402
                                                        } else {
 
403
                                                                gchar *old_value = g_key_file_get_value (old_client, group, key, NULL);
 
404
                                                                gchar *new_value = g_key_file_get_value (client->client, group, key, NULL);
 
405
                                                                if (strcmp (old_value, new_value) != 0) {
 
406
                                                                        awn_config_client_do_notify (client, group, key);
 
407
                                                                }
 
408
                                                                g_free (new_value);
 
409
                                                                g_free (old_value);
 
410
                                                        }
 
411
                                                }
 
412
                                                g_strfreev (nkeys);
 
413
                                                g_strfreev (okeys);
 
414
                                        }
 
415
                                }
 
416
                                g_strfreev (new_groups);
 
417
                                g_strfreev (old_groups);
 
418
                        }
 
419
                        g_key_file_free (old_client);
 
420
                        g_free (old_checksum);
 
421
                        break;
 
422
                } case AWN_VFS_MONITOR_EVENT_DELETED: {
 
423
                        g_warning ("Your configuration file was deleted.");
 
424
                        break;
 
425
                }
 
426
        }
 
427
}
 
428
 
 
429
/**
 
430
 * awn_config_client_clear:
 
431
 * @client: The configuration client that is to be used.
 
432
 * @err: The pointer to the #GError structure that contains an error
 
433
 * message on failure.
 
434
 *
 
435
 * Removes all of the configuration entries from the client.
 
436
 */
 
437
void awn_config_client_clear (AwnConfigClient *client, GError **err)
 
438
{
 
439
        gsize i, group_len;
 
440
        gchar **group_list = g_key_file_get_groups (client->client, &group_len);
 
441
        for (i = 0; i < group_len; i++) {
 
442
                gsize j, key_len;
 
443
                gchar **key_list = g_key_file_get_keys (client->client, group_list[i], &key_len, NULL);
 
444
                for (j = 0; j < key_len; j++) {
 
445
                        g_key_file_remove_key (client->client, group_list[i], key_list[j], NULL);
 
446
                }
 
447
                g_strfreev (key_list);
 
448
                g_key_file_remove_group (client->client, group_list[i], NULL);
 
449
        }
 
450
        g_strfreev (group_list);
 
451
        awn_config_client_save (client, err);
 
452
}
 
453
 
 
454
/**
 
455
 * awn_config_client_ensure_group:
 
456
 * @client: The configuration client to be queried.
 
457
 * @group: The name of the group.
 
458
 *
 
459
 * Ensures that the @group named has been created in the configuration backend.
 
460
 */
 
461
void awn_config_client_ensure_group (AwnConfigClient *client, const gchar *group)
 
462
{
 
463
        if (!g_key_file_has_group (client->client, group)) {
 
464
                g_warning ("The configuration file does not currently contain the group '%s'.  It will be created when a configuration option is set in that group.", group);
 
465
        }
 
466
}
 
467
 
 
468
/**
 
469
 * awn_config_client_notify_add:
 
470
 * @client: The configuration client that is to be used.
 
471
 * @group: The name of the group.
 
472
 * @key: The name of the key.
 
473
 * @callback: The function that is called when the key value has been modified.
 
474
 * @data: Extra data that is passed to the callback.
 
475
 *
 
476
 * Associates a callback function with a group and a key, which is called
 
477
 * when that key's value has been modified in some way.
 
478
 */
 
479
void awn_config_client_notify_add (AwnConfigClient *client, const gchar *group, 
 
480
                                   const gchar *key, AwnConfigClientNotifyFunc callback,
 
481
                                   gpointer data)
 
482
{
 
483
        AwnConfigClientNotifyData *notify = g_new0 (AwnConfigClientNotifyData, 1);
 
484
        notify->callback = callback;
 
485
        notify->data = data;
 
486
        gchar *full_key = awn_config_client_generate_key (client, group, key);
 
487
        GQuark quark = g_quark_from_string (full_key);
 
488
        GSList *funcs = g_datalist_id_get_data (&(client->notify_funcs), quark);
 
489
        funcs = g_slist_append (funcs, notify);
 
490
        g_datalist_id_set_data_full (&(client->notify_funcs), quark, funcs, (GDestroyNotify)awn_config_client_free_gslist);
 
491
        g_free (full_key);
 
492
}
 
493
 
 
494
/**
 
495
 * awn_config_client_entry_exists:
 
496
 * @client: The configuration client that is to be queried.
 
497
 * @group: The name of the group.
 
498
 * @key: The name of the key.
 
499
 *
 
500
 * Determines whether the group and key exists in the configuration backend.
 
501
 * Returns: %TRUE on success, %FALSE otherwise.
 
502
 */
 
503
gboolean awn_config_client_entry_exists (AwnConfigClient *client, const gchar *group, const gchar *key)
 
504
{
 
505
        return g_key_file_has_key (client->client, group, key, NULL);
 
506
}
 
507
 
 
508
/**
 
509
 * awn_config_client_load_defaults_from_schema:
 
510
 * @client: The configuration client that is to be queried.
 
511
 *
 
512
 * Loads the default configuration values from the backend's schema.
 
513
 */
 
514
void awn_config_client_load_defaults_from_schema (AwnConfigClient *client, GError **err)
 
515
{
 
516
        gsize i, key_names_len;
 
517
        gchar **key_names = g_key_file_get_groups (client->schema, &key_names_len);
 
518
        for (i = 0; i < key_names_len; i++) {
 
519
                if (g_key_file_has_key (client->schema, key_names[i], "default", err)) {
 
520
                        gchar *key_name = key_names[i];
 
521
                        gchar **result = g_strsplit (key_name, "/", 2);
 
522
                        if (g_strv_length (result) == 2) {
 
523
                                gchar *group = result[0];
 
524
                                gchar *key = result[1];
 
525
#define SET_DEFAULT(atype, gtype) \
 
526
        awn_config_client_set_##atype (client, group, key, \
 
527
                                       g_key_file_get_##gtype (client->schema, key_name, "default", NULL), \
 
528
                                       NULL)
 
529
#define SET_LIST_DEFAULT(ltype) \
 
530
        awn_config_client_set_list (client, group, key, AWN_CONFIG_CLIENT_LIST_TYPE_##ltype, \
 
531
                                    awn_config_client_get_gkeyfile_list_value (client->schema, group, key, \
 
532
                                                                               AWN_CONFIG_CLIENT_LIST_TYPE_##ltype, NULL), \
 
533
                                    NULL)
 
534
                                switch (awn_config_client_get_value_type (client, group, key, err)) {
 
535
                                        case AWN_CONFIG_VALUE_TYPE_BOOL:
 
536
                                                SET_DEFAULT (bool, boolean);
 
537
                                                break;
 
538
                                        case AWN_CONFIG_VALUE_TYPE_FLOAT:
 
539
                                                awn_config_client_set_float (client, group, key,
 
540
                                                                             (gfloat)g_key_file_get_double (client->schema, key_name, "default", NULL),
 
541
                                                                             NULL);
 
542
                                                break;
 
543
                                        case AWN_CONFIG_VALUE_TYPE_INT:
 
544
                                                SET_DEFAULT (int, integer);
 
545
                                                break;
 
546
                                        case AWN_CONFIG_VALUE_TYPE_STRING:
 
547
                                                SET_DEFAULT (string, string);
 
548
                                                break;
 
549
                                        case AWN_CONFIG_VALUE_TYPE_LIST_BOOL:
 
550
                                                SET_LIST_DEFAULT (BOOL);
 
551
                                                break;
 
552
                                        case AWN_CONFIG_VALUE_TYPE_LIST_FLOAT:
 
553
                                                SET_LIST_DEFAULT (FLOAT);
 
554
                                                break;
 
555
                                        case AWN_CONFIG_VALUE_TYPE_LIST_INT:
 
556
                                                SET_LIST_DEFAULT (INT);
 
557
                                                break;
 
558
                                        case AWN_CONFIG_VALUE_TYPE_LIST_STRING:
 
559
                                                SET_LIST_DEFAULT (STRING);
 
560
                                                break;
 
561
                                        default: /* NULL */
 
562
                                                return;
 
563
                                                break;
 
564
                                }
 
565
                                g_strfreev (result);
 
566
                        } else {
 
567
                                g_error ("The key '%s' has a malformed name.", key_names[i]);
 
568
                                g_strfreev (result);
 
569
                                return;
 
570
                        }
 
571
                } else {
 
572
                        g_error ("The key '%s' does not have a default value.", key_names[i]);
 
573
                        return;
 
574
                }
 
575
        }
 
576
        g_free (key_names);
 
577
}
 
578
 
 
579
/**
 
580
 * awn_config_client_get_value_type:
 
581
 * @client: The configuration client that is to be queried.
 
582
 * @group: The group name of the entry.
 
583
 * @key: The key name of the entry.
 
584
 * @err: A pointer to a #GError structure, which contains an error message
 
585
 * if the function fails.
 
586
 *
 
587
 * Retrieves the type of the entry value as reported by the backend's schema.
 
588
 * Returns: the entry type.
 
589
 */
 
590
AwnConfigValueType awn_config_client_get_value_type (AwnConfigClient *client, const gchar *group, const gchar *key, GError **err)
 
591
{
 
592
        AwnConfigValueType value_type;
 
593
        gchar *schema_group = g_strconcat (group, "/", key, NULL);
 
594
        if (g_key_file_has_group (client->schema, schema_group)) {
 
595
                if (g_key_file_has_key (client->schema, schema_group, "type", err)) {
 
596
                        gchar *value = g_key_file_get_string (client->schema, schema_group, "type", err);
 
597
                        if (err && *err) {
 
598
                                value_type = AWN_CONFIG_VALUE_TYPE_NULL;
 
599
                        } else {
 
600
                                if (g_ascii_strcasecmp (value, "bool") == 0) {
 
601
                                        value_type = AWN_CONFIG_VALUE_TYPE_BOOL;
 
602
                                } else if (g_ascii_strcasecmp (value, "float") == 0) {
 
603
                                        value_type = AWN_CONFIG_VALUE_TYPE_FLOAT;
 
604
                                } else if (g_ascii_strcasecmp (value, "int") == 0) {
 
605
                                        value_type = AWN_CONFIG_VALUE_TYPE_INT;
 
606
                                } else if (g_ascii_strcasecmp (value, "string") == 0) {
 
607
                                        value_type = AWN_CONFIG_VALUE_TYPE_STRING;
 
608
                                } else if (g_ascii_strcasecmp (value, "list-bool") == 0) {
 
609
                                        value_type = AWN_CONFIG_VALUE_TYPE_LIST_BOOL;
 
610
                                } else if (g_ascii_strcasecmp (value, "list-float") == 0) {
 
611
                                        value_type = AWN_CONFIG_VALUE_TYPE_LIST_FLOAT;
 
612
                                } else if (g_ascii_strcasecmp (value, "list-int") == 0) {
 
613
                                        value_type = AWN_CONFIG_VALUE_TYPE_LIST_INT;
 
614
                                } else if (g_ascii_strcasecmp (value, "list-string") == 0) {
 
615
                                        value_type = AWN_CONFIG_VALUE_TYPE_LIST_STRING;
 
616
                                } else {
 
617
                                        value_type = AWN_CONFIG_VALUE_TYPE_NULL;
 
618
                                }
 
619
                        }
 
620
                } else {
 
621
                        g_error ("Invalid schema file for the config file '%s': all keys must have a value type.", client->path);
 
622
                        value_type = AWN_CONFIG_VALUE_TYPE_NULL;
 
623
                }
 
624
        } else {
 
625
                
 
626
                value_type = AWN_CONFIG_VALUE_TYPE_NULL;
 
627
        }
 
628
        g_free (schema_group);
 
629
        return value_type;
 
630
}
 
631
 
 
632
/**
 
633
 * awn_config_client_get_bool:
 
634
 * @client: The configuration client that is to be queried.
 
635
 * @group: The name of the group.
 
636
 * @key: The name of the key.
 
637
 * @err: A pointer to a #GError structure, which contains an error message
 
638
 * if the function fails.
 
639
 *
 
640
 * Retrieves the value (as a boolean) of the specified group and key.
 
641
 * Returns: a boolean value.
 
642
 */
 
643
gboolean awn_config_client_get_bool (AwnConfigClient *client, const gchar *group, const gchar *key, GError **err)
 
644
{
 
645
        return g_key_file_get_boolean (client->client, group, key, err);
 
646
}
 
647
 
 
648
/**
 
649
 * awn_config_client_set_bool:
 
650
 * @client: The configuration client that is to be used.
 
651
 * @group: The name of the group.
 
652
 * @key: The name of the key.
 
653
 * @value: The new value of the key.
 
654
 * @err: A pointer to a #GError structure, which contains an error message
 
655
 * if the function fails.
 
656
 *
 
657
 * Changes the value (as a boolean) of the specified group and key.
 
658
 */
 
659
void awn_config_client_set_bool (AwnConfigClient *client, const gchar *group, const gchar *key, gboolean value, GError **err)
 
660
{
 
661
        gchar *full_key = awn_config_client_generate_key (client, group, key);
 
662
        g_key_file_set_boolean (client->client, group, key, value);
 
663
        awn_config_client_save (client, err);
 
664
        g_free (full_key);
 
665
}
 
666
 
 
667
/**
 
668
 * awn_config_client_get_float:
 
669
 * @client: The configuration client that is to be queried.
 
670
 * @group: The name of the group.
 
671
 * @key: The name of the key.
 
672
 * @err: A pointer to a #GError structure, which contains an error message
 
673
 * if the function fails.
 
674
 *
 
675
 * Retrieves the value (as a float) of the specified group and key.
 
676
 * Returns: a float value.
 
677
 */
 
678
gfloat awn_config_client_get_float (AwnConfigClient *client, const gchar *group, const gchar *key, GError **err)
 
679
{
 
680
        return (gfloat)g_key_file_get_double (client->client, group, key, err);
 
681
}
 
682
 
 
683
/**
 
684
 * awn_config_client_set_float:
 
685
 * @client: The configuration client that is to be used.
 
686
 * @group: The name of the group.
 
687
 * @key: The name of the key.
 
688
 * @value: The new value of the key.
 
689
 * @err: A pointer to a #GError structure, which contains an error message
 
690
 * if the function fails.
 
691
 *
 
692
 * Changes the value (as a float) of the specified group and key.
 
693
 * If you need double precision, use a string.
 
694
 */
 
695
void awn_config_client_set_float (AwnConfigClient *client, const gchar *group, const gchar *key, gfloat value, GError **err)
 
696
{
 
697
        g_key_file_set_double (client->client, group, key, (gdouble)value);
 
698
        awn_config_client_save (client, err);
 
699
}
 
700
 
 
701
/**
 
702
 * awn_config_client_get_int:
 
703
 * @client: The configuration client that is to be queried.
 
704
 * @group: The name of the group.
 
705
 * @key: The name of the key.
 
706
 * @err: A pointer to a #GError structure, which contains an error message
 
707
 * if the function fails.
 
708
 *
 
709
 * Retrieves the value (as an integer) of the specified group and key.
 
710
 * Returns: an integer value.
 
711
 */
 
712
gint awn_config_client_get_int (AwnConfigClient *client, const gchar *group, const gchar *key, GError **err)
 
713
{
 
714
        return g_key_file_get_integer (client->client, group, key, err);
 
715
}
 
716
 
 
717
/**
 
718
 * awn_config_client_set_int:
 
719
 * @client: The configuration client that is to be used.
 
720
 * @group: The name of the group.
 
721
 * @key: The name of the key.
 
722
 * @value: The new value of the key.
 
723
 * @err: A pointer to a #GError structure, which contains an error message
 
724
 * if the function fails.
 
725
 *
 
726
 * Changes the value (as an integer) of the specified group and key.
 
727
 */
 
728
void awn_config_client_set_int (AwnConfigClient *client, const gchar *group, const gchar *key, gint value, GError **err)
 
729
{
 
730
        g_key_file_set_integer (client->client, group, key, value);
 
731
        awn_config_client_save (client, err);
 
732
}
 
733
 
 
734
/**
 
735
 * awn_config_client_get_string:
 
736
 * @client: The configuration client that is to be queried.
 
737
 * @group: The name of the group.
 
738
 * @key: The name of the key.
 
739
 * @err: A pointer to a #GError structure, which contains an error message
 
740
 * if the function fails.
 
741
 *
 
742
 * Retrieves the value (as a string) of the specified group and key.
 
743
 * Returns: a newly allocated string value.  The caller is responsible
 
744
 * for freeing the memory.
 
745
 */
 
746
gchar *awn_config_client_get_string (AwnConfigClient *client, const gchar *group, const gchar *key, GError **err)
 
747
{
 
748
        return g_key_file_get_string (client->client, group, key, err);
 
749
}
 
750
 
 
751
/**
 
752
 * awn_config_client_set_string:
 
753
 * @client: The configuration client that is to be used.
 
754
 * @group: The name of the group.
 
755
 * @key: The name of the key.
 
756
 * @value: The new value of the key.
 
757
 * @err: A pointer to a #GError structure, which contains an error message
 
758
 * if the function fails.
 
759
 *
 
760
 * Changes the value (as a string) of the specified group and key.
 
761
 */
 
762
void awn_config_client_set_string (AwnConfigClient *client, const gchar *group, const gchar *key, gchar *value, GError **err)
 
763
{
 
764
        g_key_file_set_string (client->client, group, key, value);
 
765
        awn_config_client_save (client, err);
 
766
}
 
767
 
 
768
/**
 
769
 * awn_config_client_get_list:
 
770
 * @client: The configuration client that is to be queried.
 
771
 * @group: The name of the group.
 
772
 * @key: The name of the key.
 
773
 * @list_type: The value type of every item in the list.
 
774
 * @err: A pointer to a #GError structure, which contains an error message
 
775
 * if the function fails.
 
776
 *
 
777
 * Retrieves the value (as a #GSList) of the specified group and key.
 
778
 * Returns: a newly allocated list value.  The caller is responsible
 
779
 * for freeing the memory.
 
780
 */
 
781
GSList *awn_config_client_get_list (AwnConfigClient *client, const gchar *group, const gchar *key, AwnConfigListType list_type, GError **err)
 
782
{
 
783
        return awn_config_client_get_gkeyfile_list_value (client->client, group, key, list_type, err);
 
784
}
 
785
 
 
786
/**
 
787
 * awn_config_client_set_list:
 
788
 * @client: The configuration client that is to be used.
 
789
 * @group: The name of the group.
 
790
 * @key: The name of the key.
 
791
 * @value: The new value of the key.
 
792
 * @list_type: The value type of every item in the list.
 
793
 * @err: A pointer to a #GError structure, which contains an error message
 
794
 * if the function fails.
 
795
 *
 
796
 * Changes the value (as a list of values) of the specified group and key.
 
797
 */
 
798
void awn_config_client_set_list (AwnConfigClient *client, const gchar *group, const gchar *key, AwnConfigListType list_type, GSList *value, GError **err)
 
799
{
 
800
        gsize list_len = g_slist_length (value);
 
801
        gsize i;
 
802
        GSList *iter = NULL;
 
803
        gboolean list_set = FALSE;
 
804
        switch (list_type) {
 
805
                case AWN_CONFIG_CLIENT_LIST_TYPE_BOOL: {
 
806
                        gboolean *list = g_malloc (sizeof(gboolean) * list_len);
 
807
                        for (iter = value, i = 0; iter != NULL; iter = g_slist_next(iter), i++) {
 
808
                                list[i] = *(gboolean*)(iter->data);
 
809
                        }
 
810
                        /* GKeyFile doesn't like setting NULL lists */
 
811
                        if (list) {
 
812
                                list_set = TRUE;
 
813
                                g_key_file_set_boolean_list (client->client, group, key, list, list_len);
 
814
                        }
 
815
                        g_free (list);
 
816
                        break;
 
817
                } case AWN_CONFIG_CLIENT_LIST_TYPE_FLOAT: {
 
818
                        gdouble *list = g_malloc (sizeof(gdouble) * list_len);
 
819
                        for (iter = value, i = 0; iter != NULL; iter = g_slist_next(iter), i++) {
 
820
                                list[i] = *(gdouble*)(iter->data);
 
821
                        }
 
822
                        /* GKeyFile doesn't like setting NULL lists */
 
823
                        if (list) {
 
824
                                list_set = TRUE;
 
825
                                g_key_file_set_double_list (client->client, group, key, list, list_len);
 
826
                        }
 
827
                        g_free (list);
 
828
                        break;
 
829
                } case AWN_CONFIG_CLIENT_LIST_TYPE_INT: {
 
830
                        gint *list = g_malloc (sizeof(gint) * list_len);
 
831
                        for (iter = value, i = 0; iter != NULL; iter = g_slist_next(iter), i++) {
 
832
                                list[i] = *(gint*)(iter->data);
 
833
                        }
 
834
                        /* GKeyFile doesn't like setting NULL lists */
 
835
                        if (list) {
 
836
                                list_set = TRUE;
 
837
                                g_key_file_set_integer_list (client->client, group, key, list, list_len);
 
838
                        }
 
839
                        g_free (list);
 
840
                        break;
 
841
                } case AWN_CONFIG_CLIENT_LIST_TYPE_STRING: {
 
842
                        gchar **list = g_malloc (sizeof(gchar*) * list_len);
 
843
                        for (iter = value, i = 0; iter != NULL; iter = g_slist_next(iter), i++) {
 
844
                                list[i] = (gchar*)(iter->data);
 
845
                        }
 
846
                        /* GKeyFile doesn't like setting NULL lists */
 
847
                        if (list) {
 
848
                                list_set = TRUE;
 
849
                                g_key_file_set_string_list (client->client, group, key, (const gchar * const *)list, list_len);
 
850
                        }
 
851
                        g_free (list);
 
852
                        break;
 
853
                }
 
854
        }
 
855
        if (list_set) {
 
856
                awn_config_client_save (client, err);
 
857
        }
 
858
}
 
859
 
 
860
/**
 
861
 * awn_config_client_free:
 
862
 * @client: The configuration client structure to free.
 
863
 *
 
864
 * Frees the configuration client structure from memory.
 
865
 */
 
866
void awn_config_client_free (AwnConfigClient *client)
 
867
{
 
868
        g_key_file_free (client->schema);
 
869
        g_datalist_clear (&(client->notify_funcs));
 
870
        awn_vfs_monitor_remove (client->file_monitor);
 
871
        g_key_file_free (client->client);
 
872
        g_free (client->path);
 
873
        g_free (client);
 
874
}
 
875
 
 
876
/*  vim: set noet ts=8 sw=8 sts=8 : */