~ubuntu-branches/ubuntu/natty/tilda/natty

« back to all changes in this revision

Viewing changes to src/configsys.c

  • Committer: Bazaar Package Importer
  • Author(s): Davide Truffa
  • Date: 2007-11-11 21:28:51 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20071111212851-r7en873eocdv85bj
Tags: 0.09.4+cvs20071012-1
* New upstream release from CVS snapshot 20071012 (Closes: #446745, #432111)
  - removed old patch
  - added 01_general-fixes.patch to debianize this CVS snapshot
  - new build depends on: automake, cvs, flex, libglade2-dev
  - updated copyright file
  - updated README.Debian
* Added Italian translation (02_italian-translation.dpatch)
* Updated menu structure

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// vim: set ts=8 sts=8 sw=8 noexpandtab textwidth=112:
 
2
 
 
3
#include <tilda-config.h>
 
4
#include <debug.h>
 
5
 
 
6
#include <confuse.h>
 
7
#include <glib.h>
 
8
#include <stdio.h>
 
9
#include <stdlib.h> /* atoi */
 
10
#include <unistd.h> /* fsync */
 
11
 
 
12
#include <configsys.h>
 
13
#include <translation.h>
 
14
#include <key_converter.h>
 
15
 
 
16
 
 
17
static cfg_t *tc;
 
18
 
 
19
/* CONFIGURATION OPTIONS */
 
20
static cfg_opt_t config_opts[] = {
 
21
 
 
22
    /* strings */
 
23
    CFG_STR("tilda_config_version", PACKAGE_VERSION, CFGF_NONE),
 
24
    CFG_STR("image", NULL, CFGF_NONE),
 
25
    CFG_STR("command", "", CFGF_NONE),
 
26
    CFG_STR("font", "Monospace 13", CFGF_NONE),
 
27
    CFG_STR("key", NULL, CFGF_NONE),
 
28
    CFG_STR("title", "Tilda", CFGF_NONE),
 
29
    CFG_STR("background_color", "white", CFGF_NONE),
 
30
    CFG_STR("working_dir", NULL, CFGF_NONE),
 
31
    CFG_STR("web_browser", "firefox", CFGF_NONE),
 
32
 
 
33
    /* ints */
 
34
    CFG_INT("lines", 100, CFGF_NONE),
 
35
    CFG_INT("max_width", 600, CFGF_NONE),
 
36
    CFG_INT("max_height", 150, CFGF_NONE),
 
37
    CFG_INT("min_width", 1, CFGF_NONE),
 
38
    CFG_INT("min_height", 1, CFGF_NONE),
 
39
    CFG_INT("transparency", 0, CFGF_NONE),
 
40
    CFG_INT("x_pos", 0, CFGF_NONE),
 
41
    CFG_INT("y_pos", 0, CFGF_NONE),
 
42
    CFG_INT("tab_pos", 0, CFGF_NONE),
 
43
    CFG_INT("backspace_key", 0, CFGF_NONE),
 
44
    CFG_INT("delete_key", 1, CFGF_NONE),
 
45
    CFG_INT("d_set_title", 3, CFGF_NONE),
 
46
    CFG_INT("command_exit", 0, CFGF_NONE),
 
47
    CFG_INT("scheme", 3, CFGF_NONE),
 
48
    CFG_INT("slide_sleep_usec", 15000, CFGF_NONE),
 
49
    CFG_INT("animation_orientation", 0, CFGF_NONE),
 
50
 
 
51
    /* guint16 */
 
52
    CFG_INT("scrollbar_pos", 1, CFGF_NONE),
 
53
    CFG_INT("back_red", 0x0000, CFGF_NONE),
 
54
    CFG_INT("back_green", 0x0000, CFGF_NONE),
 
55
    CFG_INT("back_blue", 0x0000, CFGF_NONE),
 
56
    CFG_INT("text_red", 0xffff, CFGF_NONE),
 
57
    CFG_INT("text_green", 0xffff, CFGF_NONE),
 
58
    CFG_INT("text_blue", 0xffff, CFGF_NONE),
 
59
 
 
60
    /* booleans */
 
61
    CFG_BOOL("scroll_background", TRUE, CFGF_NONE),
 
62
    CFG_BOOL("scroll_on_output", FALSE, CFGF_NONE),
 
63
    CFG_BOOL("notebook_border", FALSE, CFGF_NONE),
 
64
    CFG_BOOL("antialias", TRUE, CFGF_NONE),
 
65
    CFG_BOOL("scrollbar", FALSE, CFGF_NONE),
 
66
    CFG_BOOL("use_image", FALSE, CFGF_NONE),
 
67
    CFG_BOOL("grab_focus", TRUE, CFGF_NONE),
 
68
    CFG_BOOL("above", TRUE, CFGF_NONE),
 
69
    CFG_BOOL("notaskbar", TRUE, CFGF_NONE),
 
70
    CFG_BOOL("bold", TRUE, CFGF_NONE),
 
71
    CFG_BOOL("blinks", TRUE, CFGF_NONE),
 
72
    CFG_BOOL("scroll_on_key", TRUE, CFGF_NONE),
 
73
    CFG_BOOL("bell", FALSE, CFGF_NONE),
 
74
    CFG_BOOL("run_command", FALSE, CFGF_NONE),
 
75
    CFG_BOOL("pinned", TRUE, CFGF_NONE),
 
76
    CFG_BOOL("animation", TRUE, CFGF_NONE),
 
77
    CFG_BOOL("hidden", FALSE, CFGF_NONE),
 
78
    CFG_BOOL("centered_horizontally", FALSE, CFGF_NONE),
 
79
    CFG_BOOL("centered_vertically", FALSE, CFGF_NONE),
 
80
    CFG_BOOL("enable_transparency", FALSE, CFGF_NONE),
 
81
    CFG_BOOL("double_buffer", FALSE, CFGF_NONE),
 
82
    CFG_END()
 
83
};
 
84
 
 
85
static gboolean config_writing_disabled = FALSE;
 
86
 
 
87
/* Define these here, so that we can enable a non-threadsafe version
 
88
 * without changing the code below. */
 
89
#ifndef NO_THREADSAFE
 
90
        static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
 
91
        #define config_mutex_lock() g_static_mutex_lock (&mutex)
 
92
        #define config_mutex_unlock() g_static_mutex_unlock (&mutex)
 
93
#else
 
94
        #define config_mutex_lock()
 
95
        #define config_mutex_unlock()
 
96
#endif
 
97
 
 
98
#define CONFIG1_OLDER -1
 
99
#define CONFIGS_SAME   0
 
100
#define CONFIG1_NEWER  1
 
101
 
 
102
static void try_to_update_config_file (const gchar *config_file);
 
103
static gboolean compare_config_versions (const gchar *config1, const gchar *config2);
 
104
 
 
105
 
 
106
 
 
107
/**
 
108
 * Start up the configuration system, using the configuration file given
 
109
 * to get the current values. If the configuration file given does not exist,
 
110
 * go ahead and write out the default config to the file.
 
111
 */
 
112
gint config_init (const gchar *config_file)
 
113
{
 
114
        gint ret = 0;
 
115
 
 
116
        tc = cfg_init (config_opts, 0);
 
117
 
 
118
        /* I know that this is racy, but I can't think of a good
 
119
         * way to fix it ... */
 
120
        if (g_file_test (config_file, G_FILE_TEST_IS_REGULAR)) {
 
121
                /* Read the file, and try to upgrade it */
 
122
                ret = cfg_parse (tc, config_file);
 
123
 
 
124
                if (ret == CFG_SUCCESS)
 
125
                        try_to_update_config_file (config_file);
 
126
                else {
 
127
                        DEBUG_ERROR ("Problem parsing config");
 
128
                        g_printerr (_("Problem parsing config file\n"));
 
129
                        return 1;
 
130
                }
 
131
        }
 
132
        /* This is commented out because we don't want to do this. Basically, there
 
133
         * is no need to write the config until we have shown the wizard, which is
 
134
         * automatically shown on the first run. */
 
135
#if 0
 
136
        else {
 
137
                /* Write out the defaults */
 
138
                config_write (config_file);
 
139
        }
 
140
#endif
 
141
 
 
142
        return 0;
 
143
}
 
144
 
 
145
/* Note: set config_file to NULL to just free the
 
146
 * data structures, and not write out the state to
 
147
 * a file. */
 
148
gint config_free (const gchar *config_file)
 
149
{
 
150
        gint ret = 0;
 
151
 
 
152
        if (config_file != NULL)
 
153
                ret = config_write (config_file);
 
154
 
 
155
        cfg_free (tc);
 
156
 
 
157
        return ret;
 
158
}
 
159
 
 
160
gint config_setint (const gchar *key, const gint val)
 
161
{
 
162
        config_mutex_lock ();
 
163
        cfg_setint (tc, key, val);
 
164
        config_mutex_unlock ();
 
165
 
 
166
        return 0;
 
167
}
 
168
 
 
169
gint config_setstr (const gchar *key, const gchar *val)
 
170
{
 
171
        config_mutex_lock ();
 
172
        cfg_setstr (tc, key, val);
 
173
        config_mutex_unlock ();
 
174
 
 
175
        return 0;
 
176
}
 
177
 
 
178
gint config_setbool(const gchar *key, const gboolean val)
 
179
{
 
180
        config_mutex_lock ();
 
181
        cfg_setbool (tc, key, val);
 
182
        config_mutex_unlock ();
 
183
 
 
184
        return 0;
 
185
}
 
186
 
 
187
gint config_getint (const gchar *key)
 
188
{
 
189
        gint temp;
 
190
 
 
191
        config_mutex_lock ();
 
192
        temp = cfg_getint (tc, key);
 
193
        config_mutex_unlock ();
 
194
 
 
195
        return temp;
 
196
}
 
197
 
 
198
gchar* config_getstr (const gchar *key)
 
199
{
 
200
        gchar *temp;
 
201
 
 
202
        config_mutex_lock ();
 
203
        temp = cfg_getstr (tc, key);
 
204
        config_mutex_unlock ();
 
205
 
 
206
        return temp;
 
207
}
 
208
 
 
209
gboolean config_getbool(const gchar *key)
 
210
{
 
211
        gboolean temp;
 
212
 
 
213
        config_mutex_lock ();
 
214
        temp = cfg_getbool (tc, key);
 
215
        config_mutex_unlock ();
 
216
 
 
217
        return temp;
 
218
}
 
219
 
 
220
/* This will write out the current state of the config file to the disk.
 
221
 * It's use is generally discouraged, since config_free() will also write
 
222
 * out the configuration to disk. */
 
223
gint config_write (const gchar *config_file)
 
224
{
 
225
    DEBUG_FUNCTION ("config_write");
 
226
    DEBUG_ASSERT (config_file != NULL);
 
227
 
 
228
    gint ret = 0;
 
229
    FILE *fp;
 
230
 
 
231
    /* Check to see if writing is disabled. Leave early if it is. */
 
232
    if (config_writing_disabled)
 
233
        return 1;
 
234
 
 
235
    fp = fopen(config_file, "w");
 
236
 
 
237
    if (fp != NULL)
 
238
    {
 
239
        config_mutex_lock ();
 
240
        cfg_print (tc, fp);
 
241
        config_mutex_unlock ();
 
242
 
 
243
        if (fsync (fileno(fp)))
 
244
        {
 
245
            // Error occurred during sync
 
246
            TILDA_PERROR ();
 
247
            DEBUG_ERROR ("Unable to sync file");
 
248
 
 
249
            g_printerr (_("Unable to sync the config file to disk\n"));
 
250
            ret = 2;
 
251
        }
 
252
 
 
253
        if (fclose (fp))
 
254
        {
 
255
            // An error occurred
 
256
            TILDA_PERROR ();
 
257
            DEBUG_ERROR ("Unable to close config file");
 
258
 
 
259
            g_printerr (_("Unable to close the config file\n"));
 
260
            ret = 3;
 
261
        }
 
262
    }
 
263
    else
 
264
    {
 
265
        TILDA_PERROR ();
 
266
        DEBUG_ERROR ("Unable to write config file");
 
267
 
 
268
        g_printerr (_("Unable to write the config file to %s\n"), config_file);
 
269
        ret = 4;
 
270
    }
 
271
 
 
272
    return ret;
 
273
}
 
274
 
 
275
/*
 
276
 * Compares two config versions together.
 
277
 *
 
278
 * Returns -1 if config1 is older than config2 (UPDATE REQUIRED)
 
279
 * Returns  0 if config1 is equal to   config2 (NORMAL USAGE)
 
280
 * Returns  1 if config1 is newer than config2 (DISABLE WRITE)
 
281
 */
 
282
static gboolean compare_config_versions (const gchar *config1, const gchar *config2)
 
283
{
 
284
    DEBUG_FUNCTION ("compare_config_versions");
 
285
    DEBUG_ASSERT (config1 != NULL);
 
286
    DEBUG_ASSERT (config2 != NULL);
 
287
 
 
288
    /*
 
289
     * 1) Split apart both strings using the .'s
 
290
     * 2) Compare the major-major version
 
291
     * 3) Compare the major version
 
292
     * 4) Compare the minor version
 
293
     */
 
294
 
 
295
    gchar **config1_tokens;
 
296
    gchar **config2_tokens;
 
297
    gint  config1_version[3];
 
298
    gint  config2_version[3];
 
299
    gint  i;
 
300
 
 
301
    config1_tokens = g_strsplit (config1, ".", 3);
 
302
    config2_tokens = g_strsplit (config2, ".", 3);
 
303
 
 
304
    for (i=0; i<3; i++)
 
305
    {
 
306
        config1_version[i] = atoi (config1_tokens[i]);
 
307
        config2_version[i] = atoi (config2_tokens[i]);
 
308
    }
 
309
 
 
310
    g_strfreev (config1_tokens);
 
311
    g_strfreev (config2_tokens);
 
312
 
 
313
    /* We're done splitting things, so compare now */
 
314
    for (i=0; i<3; i++)
 
315
    {
 
316
        if (config1_version[i] > config2_version[i])
 
317
            return CONFIG1_NEWER;
 
318
 
 
319
        if (config1_version[i] < config2_version[i])
 
320
            return CONFIG1_OLDER;
 
321
    }
 
322
 
 
323
    return CONFIGS_SAME;
 
324
}
 
325
 
 
326
/*
 
327
 * Compare config file versions and see if we know about a new version.
 
328
 *
 
329
 * If we have a version newer than what we know about, we need to stop
 
330
 * anything from writing to the config file.
 
331
 *
 
332
 * If we are at the same config version, we're done, so exit early.
 
333
 *
 
334
 * If the config is older than we are now, update it and then write
 
335
 * it to disk.
 
336
 */
 
337
static void try_to_update_config_file (const gchar *config_file)
 
338
{
 
339
    DEBUG_FUNCTION ("try_to_update_config_file");
 
340
    DEBUG_ASSERT (config_file != NULL);
 
341
 
 
342
    gboolean changed = FALSE;
 
343
    gchar *current_config = config_getstr ("tilda_config_version");
 
344
 
 
345
    if (compare_config_versions (current_config, PACKAGE_VERSION) == CONFIGS_SAME)
 
346
        return; // Same version as ourselves, we're done!
 
347
 
 
348
    if (compare_config_versions (current_config, PACKAGE_VERSION) == CONFIG1_NEWER)
 
349
    {
 
350
        // We have a version newer than ourselves!
 
351
        // Disable writing to the config for safety.
 
352
        config_writing_disabled = TRUE;
 
353
        return; // Out early, since we won't be able to update anyway!
 
354
    }
 
355
 
 
356
    /* NOTE: Start with the oldest config version first, and work our way up to the
 
357
     * NOTE: newest that we support, updating our current version each time.
 
358
     *
 
359
     * NOTE: You may need to re-read the config each time! Probably not though,
 
360
     * NOTE: since you should be updating VALUES not names directly in the config.
 
361
     * NOTE: Try to rely on libconfuse to generate the configs :) */
 
362
 
 
363
    /* Below is a template for creating new entries in the updater. If you ever
 
364
     * change anything between versions, copy this, replacing YOUR_VERSION
 
365
     * with the new version that you are making. */
 
366
#if 0
 
367
    if (compare_config_versions (current_config, YOUR_VERSION) == CONFIG1_OLDER)
 
368
    {
 
369
        // TODO: Add things here to migrate from whatever we are to YOUR_VERSION
 
370
        current_config = YOUR_VERSION;
 
371
        changed = TRUE;
 
372
    }
 
373
#endif
 
374
 
 
375
    if (compare_config_versions (current_config, "0.09.4") == CONFIG1_OLDER)
 
376
    {
 
377
        /* Nothing to update here. All we did was add an option, there is no
 
378
         * need to rewrite the config file here, since the writer at the end
 
379
         * will automatically add the default value of the new option. */
 
380
        current_config = "0.09.4";
 
381
        changed = TRUE;
 
382
    }
 
383
 
 
384
    if (compare_config_versions (current_config, "0.9.5") == CONFIG1_OLDER)
 
385
    {
 
386
        char *old_key;
 
387
        char *new_key;
 
388
 
 
389
        old_key = config_getstr ("key");
 
390
        new_key = upgrade_key_to_095 (old_key);
 
391
 
 
392
        config_setstr ("key", new_key);
 
393
        free (new_key);
 
394
 
 
395
        current_config = "0.9.5";
 
396
        changed = TRUE;
 
397
    }
 
398
 
 
399
    /* We've run through all the updates, so set our config file version to the
 
400
     * version we're at now, then write out the config file.
 
401
     *
 
402
     * NOTE: this only happens if we upgraded the config, due to some early-exit
 
403
     * logic above.
 
404
     */
 
405
 
 
406
    if (changed)
 
407
    {
 
408
        config_setstr ("tilda_config_version", current_config);
 
409
        config_write (config_file);
 
410
    }
 
411
}
 
412