967 lines
26 KiB
C
967 lines
26 KiB
C
/*
|
|
* mooutils/mooprefs.c
|
|
*
|
|
* Copyright (C) 2004-2005 by Yevgen Muntyan <muntyan@math.tamu.edu>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* See COPYING file that comes with this distribution.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "mooutils/mooprefs.h"
|
|
#include "mooutils/moocompat.h"
|
|
#include "mooutils/eggregex.h"
|
|
#include "mooutils/moomarshals.h"
|
|
#include <string.h>
|
|
|
|
|
|
static MooPrefs *instance (void)
|
|
{
|
|
static MooPrefs *p = NULL;
|
|
if (!p)
|
|
p = MOO_PREFS (g_object_new (MOO_TYPE_PREFS, NULL));
|
|
return p;
|
|
}
|
|
|
|
|
|
/* MOO_TYPE_PREFS */
|
|
G_DEFINE_TYPE (MooPrefs, moo_prefs, G_TYPE_OBJECT)
|
|
|
|
|
|
typedef struct {
|
|
char *value;
|
|
guint changed : 1;
|
|
} Item;
|
|
|
|
static Item *item_new (const char *val,
|
|
gboolean changed)
|
|
{
|
|
Item *item = g_new (Item, 1);
|
|
item->value = g_strdup (val);
|
|
item->changed = changed;
|
|
return item;
|
|
}
|
|
|
|
static void item_free (Item *item)
|
|
{
|
|
if (!item) return;
|
|
g_free (item->value);
|
|
g_free (item);
|
|
}
|
|
|
|
|
|
typedef union {
|
|
char *key;
|
|
EggRegex *regex;
|
|
} Pattern;
|
|
|
|
static void pattern_free (Pattern p,
|
|
MooPrefsMatchType type);
|
|
|
|
|
|
typedef struct {
|
|
guint id;
|
|
MooPrefsMatchType type;
|
|
Pattern pattern;
|
|
guint prefix_len;
|
|
MooPrefsNotify callback;
|
|
gpointer data;
|
|
guint blocked : 1;
|
|
} Closure;
|
|
|
|
static Closure *closure_new (MooPrefs *prefs,
|
|
const char *pattern,
|
|
MooPrefsMatchType match_type,
|
|
MooPrefsNotify callback,
|
|
gpointer data);
|
|
static void closure_free (Closure *closure);
|
|
static gboolean closure_match (Closure *closure,
|
|
const char *key);
|
|
static void closure_invoke (Closure *closure,
|
|
const char *key,
|
|
const char *value);
|
|
|
|
|
|
struct _MooPrefsPrivate {
|
|
GHashTable *data; /* char* -> Item* */
|
|
guint last_notify_id;
|
|
GList *closures;
|
|
GHashTable *closures_map; /* guint -> closures list link */
|
|
};
|
|
|
|
|
|
static void prefs_set (MooPrefs *prefs,
|
|
const char *key,
|
|
const char *val,
|
|
gboolean changed);
|
|
|
|
static Item *prefs_get (MooPrefs *prefs,
|
|
const char *key);
|
|
|
|
static void prefs_change (MooPrefs *prefs,
|
|
const char *key,
|
|
Item *item,
|
|
const char *val,
|
|
gboolean changed);
|
|
static void prefs_create (MooPrefs *prefs,
|
|
const char *key,
|
|
const char *val,
|
|
gboolean changed);
|
|
static void prefs_remove (MooPrefs *prefs,
|
|
const char *key);
|
|
|
|
static void emit_notify (MooPrefs *prefs,
|
|
const char *key,
|
|
const char *val);
|
|
|
|
|
|
static void moo_prefs_finalize (GObject *object);
|
|
|
|
enum {
|
|
CHANGED,
|
|
SET,
|
|
UNSET,
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
static guint signals[LAST_SIGNAL];
|
|
|
|
|
|
static void moo_prefs_class_init (MooPrefsClass *klass)
|
|
{
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
gobject_class->finalize = moo_prefs_finalize;
|
|
|
|
signals[CHANGED] =
|
|
g_signal_new ("changed",
|
|
G_OBJECT_CLASS_TYPE (klass),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (MooPrefsClass, changed),
|
|
NULL, NULL,
|
|
_moo_marshal_VOID__STRING_STRING,
|
|
G_TYPE_NONE, 2,
|
|
G_TYPE_STRING, G_TYPE_STRING);
|
|
|
|
signals[SET] =
|
|
g_signal_new ("set",
|
|
G_OBJECT_CLASS_TYPE (klass),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (MooPrefsClass, changed),
|
|
NULL, NULL,
|
|
_moo_marshal_VOID__STRING_STRING,
|
|
G_TYPE_NONE, 2,
|
|
G_TYPE_STRING, G_TYPE_STRING);
|
|
|
|
signals[UNSET] =
|
|
g_signal_new ("unset",
|
|
G_OBJECT_CLASS_TYPE (klass),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (MooPrefsClass, changed),
|
|
NULL, NULL,
|
|
_moo_marshal_VOID__STRING,
|
|
G_TYPE_NONE, 1,
|
|
G_TYPE_STRING);
|
|
}
|
|
|
|
|
|
static void moo_prefs_init (MooPrefs *prefs)
|
|
{
|
|
prefs->priv = g_new0 (MooPrefsPrivate, 1);
|
|
|
|
prefs->priv->data = g_hash_table_new (g_str_hash, g_str_equal);
|
|
prefs->priv->last_notify_id = 0;
|
|
prefs->priv->closures = NULL;
|
|
prefs->priv->closures_map = g_hash_table_new (g_direct_hash, NULL);
|
|
}
|
|
|
|
|
|
static void free_key_and_item (char *key,
|
|
Item *item)
|
|
{
|
|
g_free (key);
|
|
item_free (item);
|
|
}
|
|
|
|
|
|
static void moo_prefs_finalize (GObject *obj)
|
|
{
|
|
MooPrefs *prefs = MOO_PREFS (obj);
|
|
|
|
g_hash_table_foreach (prefs->priv->data,
|
|
(GHFunc) free_key_and_item,
|
|
NULL);
|
|
g_hash_table_destroy (prefs->priv->data);
|
|
|
|
g_hash_table_destroy (prefs->priv->closures_map);
|
|
|
|
g_list_foreach (prefs->priv->closures,
|
|
(GFunc) closure_free,
|
|
NULL);
|
|
g_list_free (prefs->priv->closures);
|
|
}
|
|
|
|
|
|
static void prefs_set (MooPrefs *prefs,
|
|
const char *key,
|
|
const char *val,
|
|
gboolean changed)
|
|
{
|
|
g_return_if_fail (MOO_IS_PREFS (prefs));
|
|
g_return_if_fail (key != NULL);
|
|
|
|
if (!val)
|
|
{
|
|
prefs_remove (prefs, key);
|
|
}
|
|
else
|
|
{
|
|
Item *item = prefs_get (prefs, key);
|
|
if (item)
|
|
prefs_change (prefs, key, item, val, changed);
|
|
else
|
|
prefs_create (prefs, key, val, changed);
|
|
}
|
|
}
|
|
|
|
|
|
static Item *prefs_get (MooPrefs *prefs,
|
|
const char *key)
|
|
{
|
|
return g_hash_table_lookup (prefs->priv->data, key);
|
|
}
|
|
|
|
|
|
static void prefs_change (MooPrefs *prefs,
|
|
const char *key,
|
|
Item *item,
|
|
const char *val,
|
|
gboolean changed)
|
|
{
|
|
g_free (item->value);
|
|
item->value = g_strdup (val);
|
|
if (changed)
|
|
item->changed = TRUE;
|
|
emit_notify (prefs, key, val);
|
|
}
|
|
|
|
|
|
static void prefs_create (MooPrefs *prefs,
|
|
const char *key,
|
|
const char *val,
|
|
gboolean changed)
|
|
{
|
|
Item *item = item_new (val, changed);
|
|
g_hash_table_insert (prefs->priv->data,
|
|
g_strdup (key),
|
|
item);
|
|
emit_notify (prefs, key, val);
|
|
}
|
|
|
|
|
|
static void prefs_remove (MooPrefs *prefs,
|
|
const char *key)
|
|
{
|
|
Item *item = NULL;
|
|
char *orig_key = NULL;
|
|
gboolean found;
|
|
|
|
found = g_hash_table_lookup_extended (prefs->priv->data,
|
|
key,
|
|
(gpointer*) &orig_key,
|
|
(gpointer*) &item);
|
|
if (!found) return;
|
|
|
|
g_free (orig_key);
|
|
item_free (item);
|
|
g_hash_table_remove (prefs->priv->data, key);
|
|
|
|
emit_notify (prefs, key, NULL);
|
|
}
|
|
|
|
|
|
static void emit_notify (MooPrefs *prefs,
|
|
const char *key,
|
|
const char *val)
|
|
{
|
|
GList *l;
|
|
|
|
g_object_ref (prefs);
|
|
|
|
for (l = prefs->priv->closures; l != NULL; l = l->next)
|
|
{
|
|
Closure *closure = l->data;
|
|
if (!closure->blocked && closure_match (closure, key))
|
|
closure_invoke (closure, key, val);
|
|
}
|
|
|
|
g_object_unref (prefs);
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
/* Closure
|
|
*/
|
|
|
|
static Closure *closure_new (MooPrefs *prefs,
|
|
const char *pattern,
|
|
MooPrefsMatchType match_type,
|
|
MooPrefsNotify callback,
|
|
gpointer data)
|
|
{
|
|
EggRegex *regex;
|
|
Closure *closure;
|
|
GError *err = NULL;
|
|
|
|
closure = g_new (Closure, 1);
|
|
closure->type = match_type;
|
|
closure->callback = callback;
|
|
closure->data = data;
|
|
closure->blocked = FALSE;
|
|
|
|
closure->id = ++prefs->priv->last_notify_id;
|
|
|
|
switch (match_type) {
|
|
case MOO_PREFS_MATCH_REGEX:
|
|
regex = egg_regex_new (pattern, EGG_REGEX_EXTENDED, 0, &err);
|
|
if (err)
|
|
{
|
|
g_warning ("%s: %s", G_STRLOC, err->message);
|
|
g_error_free (err);
|
|
egg_regex_free (regex);
|
|
g_free (closure);
|
|
return NULL;
|
|
}
|
|
egg_regex_optimize (regex, &err);
|
|
if (err)
|
|
{
|
|
g_warning ("%s: %s", G_STRLOC, err->message);
|
|
g_error_free (err);
|
|
}
|
|
|
|
closure->pattern.regex = regex;
|
|
break;
|
|
|
|
case MOO_PREFS_MATCH_PREFIX:
|
|
closure->pattern.key = g_strdup (pattern);
|
|
closure->prefix_len = strlen (pattern);
|
|
break;
|
|
|
|
case MOO_PREFS_MATCH_KEY:
|
|
closure->pattern.key = g_strdup (pattern);
|
|
break;
|
|
|
|
default:
|
|
g_assert_not_reached ();
|
|
}
|
|
|
|
return closure;
|
|
}
|
|
|
|
|
|
static void closure_free (Closure *closure)
|
|
{
|
|
if (!closure) return;
|
|
pattern_free (closure->pattern, closure->type);
|
|
g_free (closure);
|
|
}
|
|
|
|
|
|
static gboolean closure_match (Closure *closure,
|
|
const char *key)
|
|
{
|
|
switch (closure->type) {
|
|
case MOO_PREFS_MATCH_KEY:
|
|
return !strcmp (key, closure->pattern.key);
|
|
|
|
case MOO_PREFS_MATCH_PREFIX:
|
|
if (closure->prefix_len)
|
|
return !strncmp (key, closure->pattern.key,
|
|
closure->prefix_len);
|
|
else
|
|
return TRUE;
|
|
|
|
case MOO_PREFS_MATCH_REGEX:
|
|
egg_regex_clear (closure->pattern.regex);
|
|
return egg_regex_match (closure->pattern.regex,
|
|
key, -1, 0) > 0;
|
|
|
|
default:
|
|
#ifndef G_DISABLE_ASSERT
|
|
g_assert_not_reached ();
|
|
#else
|
|
g_critical ("%s: should not be reached", G_STRLOC);
|
|
return FALSE;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
static void closure_invoke (Closure *closure,
|
|
const char *key,
|
|
const char *value)
|
|
{
|
|
closure->callback (key, value, closure->data);
|
|
}
|
|
|
|
|
|
static void pattern_free (Pattern p,
|
|
MooPrefsMatchType type)
|
|
{
|
|
if (!p.key) return;
|
|
if (type == MOO_PREFS_MATCH_REGEX)
|
|
egg_regex_free (p.regex);
|
|
else
|
|
g_free (p.key);
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
/* MooPrefs
|
|
*/
|
|
|
|
guint moo_prefs_notify_connect (const char *pattern,
|
|
MooPrefsMatchType match_type,
|
|
MooPrefsNotify callback,
|
|
gpointer data)
|
|
{
|
|
Closure *closure;
|
|
MooPrefs *prefs = instance ();
|
|
|
|
g_return_val_if_fail (pattern != NULL, 0);
|
|
g_return_val_if_fail (match_type == MOO_PREFS_MATCH_KEY ||
|
|
match_type == MOO_PREFS_MATCH_PREFIX ||
|
|
match_type == MOO_PREFS_MATCH_REGEX, 0);
|
|
g_return_val_if_fail (callback != NULL, 0);
|
|
|
|
closure = closure_new (prefs, pattern, match_type, callback, data);
|
|
g_return_val_if_fail (closure != NULL, 0);
|
|
|
|
prefs->priv->closures = g_list_prepend (prefs->priv->closures, closure);
|
|
g_hash_table_insert (prefs->priv->closures_map,
|
|
GUINT_TO_POINTER (closure->id),
|
|
prefs->priv->closures);
|
|
|
|
return closure->id;
|
|
}
|
|
|
|
|
|
static Closure *find_closure (MooPrefs *prefs,
|
|
guint id)
|
|
{
|
|
GList *l;
|
|
|
|
l = g_hash_table_lookup (prefs->priv->closures_map,
|
|
GUINT_TO_POINTER (id));
|
|
if (l)
|
|
return l->data;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
|
|
gboolean moo_prefs_notify_block (guint id)
|
|
{
|
|
Closure *c;
|
|
|
|
g_return_val_if_fail (id != 0, FALSE);
|
|
|
|
c = find_closure (instance(), id);
|
|
g_return_val_if_fail (c != NULL, FALSE);
|
|
|
|
c->blocked = TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
gboolean moo_prefs_notify_unblock (guint id)
|
|
{
|
|
Closure *c;
|
|
|
|
g_return_val_if_fail (id != 0, FALSE);
|
|
|
|
c = find_closure (instance(), id);
|
|
g_return_val_if_fail (c != NULL, FALSE);
|
|
|
|
c->blocked = FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
gboolean moo_prefs_notify_disconnect (guint id)
|
|
{
|
|
GList *l;
|
|
MooPrefs *prefs = instance ();
|
|
|
|
g_return_val_if_fail (id != 0, FALSE);
|
|
|
|
l = g_hash_table_lookup (prefs->priv->closures_map,
|
|
GUINT_TO_POINTER (id));
|
|
g_return_val_if_fail (l != NULL, FALSE);
|
|
|
|
g_hash_table_remove (prefs->priv->closures_map,
|
|
GUINT_TO_POINTER (id));
|
|
|
|
closure_free (l->data);
|
|
prefs->priv->closures =
|
|
g_list_delete_link (prefs->priv->closures, l);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void moo_prefs_set (const char *key,
|
|
const char *val)
|
|
{
|
|
g_return_if_fail (key != NULL);
|
|
prefs_set (instance(), key, val, TRUE);
|
|
}
|
|
|
|
void moo_prefs_set_ignore_change (const char *key,
|
|
const char *val)
|
|
{
|
|
g_return_if_fail (key != NULL);
|
|
prefs_set (instance(), key, val, FALSE);
|
|
}
|
|
|
|
|
|
const gchar *moo_prefs_get (const char *key)
|
|
{
|
|
Item *item;
|
|
|
|
g_return_val_if_fail (key != NULL, NULL);
|
|
|
|
item = prefs_get (instance(), key);
|
|
if (item)
|
|
return item->value;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
/* Loading abd saving
|
|
*/
|
|
|
|
gboolean moo_prefs_load (const char *file)
|
|
{
|
|
GError *err = NULL;
|
|
char *content = NULL;
|
|
gsize len = 0;
|
|
char** lines;
|
|
guint i;
|
|
|
|
g_return_val_if_fail (file != NULL, FALSE);
|
|
|
|
if (!g_file_get_contents (file, &content, &len, &err))
|
|
{
|
|
g_critical ("%s: could not load file '%s'", G_STRLOC, file);
|
|
if (err) {
|
|
g_critical ("%s: %s", G_STRLOC, err->message);
|
|
g_error_free (err);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
if (!len) {
|
|
g_free (content);
|
|
return TRUE;
|
|
}
|
|
|
|
g_strdelimit (content, "\r\f", '\n');
|
|
lines = g_strsplit (content, "\n", 0);
|
|
|
|
for (i = 0; lines[i]; ++i)
|
|
{
|
|
char **keyval = g_strsplit (lines[i], "=", 2);
|
|
|
|
if (keyval[0])
|
|
{
|
|
if (keyval[1])
|
|
moo_prefs_set (keyval[0], keyval[1]);
|
|
else
|
|
g_critical ("%s: error in file '%s' "
|
|
"on line %d", G_STRLOC, file, i);
|
|
}
|
|
|
|
g_strfreev (keyval);
|
|
}
|
|
|
|
g_free (content);
|
|
g_strfreev (lines);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
#ifdef __WIN32__
|
|
#define LINE_SEPARATOR "\r\n"
|
|
#define LINE_SEPARATOR_LEN 2
|
|
#elif defined(OS_DARWIN)
|
|
#define LINE_SEPARATOR "\r"
|
|
#define LINE_SEPARATOR_LEN 1
|
|
#else
|
|
#define LINE_SEPARATOR "\n"
|
|
#define LINE_SEPARATOR_LEN 1
|
|
#endif
|
|
|
|
typedef struct {
|
|
const char *filename;
|
|
GIOChannel *file;
|
|
gboolean error;
|
|
} Stuff;
|
|
|
|
static void write_item (const char *key,
|
|
Item *item,
|
|
Stuff *stuff)
|
|
{
|
|
gsize written;
|
|
GIOStatus status;
|
|
GError *err = NULL;
|
|
|
|
if (!(item->value && item->changed) || stuff->error)
|
|
return;
|
|
|
|
if (!stuff->file)
|
|
{
|
|
stuff->file = g_io_channel_new_file (stuff->filename, "w", &err);
|
|
if (!stuff->file)
|
|
{
|
|
g_critical ("%s: could not open file '%s' "
|
|
"for writing", G_STRLOC, stuff->filename);
|
|
if (err)
|
|
{
|
|
g_critical ("%s: %s", G_STRLOC, err->message);
|
|
g_error_free (err);
|
|
}
|
|
|
|
stuff->error = TRUE;
|
|
return;
|
|
}
|
|
}
|
|
|
|
status = g_io_channel_write_chars (stuff->file,
|
|
key, strlen (key),
|
|
&written, &err);
|
|
if (status == G_IO_STATUS_NORMAL)
|
|
status = g_io_channel_write_chars (stuff->file,
|
|
"=", 1,
|
|
&written, &err);
|
|
if (status == G_IO_STATUS_NORMAL)
|
|
status = g_io_channel_write_chars (stuff->file,
|
|
item->value,
|
|
strlen (item->value),
|
|
&written, &err);
|
|
if (status == G_IO_STATUS_NORMAL)
|
|
status = g_io_channel_write_chars (stuff->file,
|
|
LINE_SEPARATOR,
|
|
LINE_SEPARATOR_LEN,
|
|
&written, &err);
|
|
|
|
if (status != G_IO_STATUS_NORMAL)
|
|
{
|
|
g_critical ("%s: could not write to file '%s'",
|
|
G_STRLOC, stuff->filename);
|
|
|
|
if (err)
|
|
{
|
|
g_critical ("%s: %s", G_STRLOC, err->message);
|
|
g_error_free (err);
|
|
err = NULL;
|
|
}
|
|
|
|
g_io_channel_shutdown (stuff->file, TRUE, &err);
|
|
|
|
if (err)
|
|
{
|
|
g_critical ("%s: %s", G_STRLOC, err->message);
|
|
g_error_free (err);
|
|
err = NULL;
|
|
}
|
|
|
|
g_io_channel_unref (stuff->file);
|
|
stuff->file = NULL;
|
|
stuff->error = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
gboolean moo_prefs_save (const char *file)
|
|
{
|
|
GError *err = NULL;
|
|
Stuff stuff;
|
|
MooPrefs *prefs = instance ();
|
|
|
|
g_return_val_if_fail (file != NULL, FALSE);
|
|
|
|
stuff.file = NULL;
|
|
stuff.error = FALSE;
|
|
stuff.filename = file;
|
|
|
|
g_hash_table_foreach (prefs->priv->data,
|
|
(GHFunc) write_item,
|
|
&stuff);
|
|
|
|
if (stuff.file)
|
|
{
|
|
g_io_channel_shutdown (stuff.file, TRUE, &err);
|
|
if (err) {
|
|
g_critical ("%s: %s", G_STRLOC, err->message);
|
|
g_error_free (err);
|
|
}
|
|
g_io_channel_unref (stuff.file);
|
|
}
|
|
|
|
return !err && !stuff.error;
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
/* Helpers
|
|
*/
|
|
|
|
gboolean moo_prefs_get_bool (const char *key)
|
|
{
|
|
const char *val = moo_prefs_get (key);
|
|
|
|
if (!val) return FALSE;
|
|
|
|
return ! g_ascii_strcasecmp (val, "1") ||
|
|
! g_ascii_strcasecmp (val, "yes") ||
|
|
! g_ascii_strcasecmp (val, "true");
|
|
}
|
|
|
|
|
|
gdouble moo_prefs_get_double (const char *key)
|
|
{
|
|
const char *strval = moo_prefs_get (key);
|
|
if (!strval)
|
|
return 0;
|
|
else return g_ascii_strtod (strval, NULL);
|
|
}
|
|
|
|
|
|
const GdkColor *moo_prefs_get_color (const char *key)
|
|
{
|
|
static GdkColormap *sys_colormap = NULL;
|
|
static GdkColor color;
|
|
|
|
const char *strval = moo_prefs_get (key);
|
|
|
|
if (!strval)
|
|
return NULL;
|
|
|
|
if (!sys_colormap)
|
|
sys_colormap = gdk_colormap_get_system ();
|
|
|
|
if (gdk_color_parse (strval, &color) &&
|
|
gdk_colormap_alloc_color (sys_colormap, &color, TRUE, TRUE))
|
|
return &color;
|
|
|
|
g_warning ("%s: invalid color string '%s' in key '%s'",
|
|
G_STRLOC, strval, key);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
int moo_prefs_get_enum (const char *key,
|
|
GType type)
|
|
{
|
|
gpointer klass;
|
|
GEnumClass *enum_class;
|
|
const char *sval;
|
|
guint i;
|
|
int val;
|
|
|
|
sval = moo_prefs_get (key);
|
|
if (!sval || !sval[0])
|
|
return 0;
|
|
|
|
klass = g_type_class_peek (type);
|
|
g_return_val_if_fail (G_IS_ENUM_CLASS (klass), 0);
|
|
enum_class = G_ENUM_CLASS (klass);
|
|
|
|
for (i = 0; i < enum_class->n_values; ++i)
|
|
{
|
|
if (!strcmp (sval, enum_class->values[i].value_name))
|
|
return enum_class->values[i].value;
|
|
}
|
|
|
|
val = moo_prefs_get_int (key);
|
|
if (val < enum_class->minimum || val > enum_class->maximum)
|
|
g_warning ("%s: value %d is illegal for type %s", G_STRLOC,
|
|
val, g_type_name (type));
|
|
return val;
|
|
}
|
|
|
|
|
|
void moo_prefs_set_if_not_set (const char *key,
|
|
const char *val)
|
|
{
|
|
if (!moo_prefs_get (key))
|
|
prefs_set (instance(), key, val, TRUE);
|
|
}
|
|
|
|
void moo_prefs_set_if_not_set_ignore_change
|
|
(const char *key,
|
|
const char *val)
|
|
{
|
|
if (!moo_prefs_get (key))
|
|
prefs_set (instance(), key, val, FALSE);
|
|
}
|
|
|
|
|
|
static void set_double (const char *key,
|
|
double val,
|
|
gboolean ignore_change)
|
|
{
|
|
char value[G_ASCII_DTOSTR_BUF_SIZE];
|
|
g_ascii_dtostr (value, G_ASCII_DTOSTR_BUF_SIZE, val);
|
|
prefs_set (instance(), key, value, !ignore_change);
|
|
}
|
|
|
|
|
|
void moo_prefs_set_double (const char *key,
|
|
double val)
|
|
{
|
|
set_double (key, val, FALSE);
|
|
}
|
|
|
|
void moo_prefs_set_double_ignore_change
|
|
(const char *key,
|
|
double val)
|
|
{
|
|
set_double (key, val, TRUE);
|
|
}
|
|
|
|
void moo_prefs_set_double_if_not_set
|
|
(const char *key,
|
|
double val)
|
|
{
|
|
if (!moo_prefs_get (key))
|
|
set_double (key, val, FALSE);
|
|
}
|
|
|
|
void moo_prefs_set_double_if_not_set_ignore_change
|
|
(const char *key,
|
|
double val)
|
|
{
|
|
if (!moo_prefs_get (key))
|
|
set_double (key, val, TRUE);
|
|
}
|
|
|
|
|
|
static void set_bool (const char *key,
|
|
gboolean val,
|
|
gboolean ignore_change)
|
|
{
|
|
prefs_set (instance(), key,
|
|
val ? "TRUE" : "FALSE",
|
|
!ignore_change);
|
|
}
|
|
|
|
void moo_prefs_set_bool (const char *key,
|
|
gboolean val)
|
|
{
|
|
set_bool (key, val, FALSE);
|
|
}
|
|
|
|
void moo_prefs_set_bool_ignore_change
|
|
(const char *key,
|
|
gboolean val)
|
|
{
|
|
set_bool (key, val, TRUE);
|
|
}
|
|
|
|
void moo_prefs_set_bool_if_not_set
|
|
(const char *key,
|
|
gboolean val)
|
|
{
|
|
if (!moo_prefs_get (key))
|
|
set_bool (key, val, FALSE);
|
|
}
|
|
|
|
void moo_prefs_set_bool_if_not_set_ignore_change
|
|
(const char *key,
|
|
gboolean val)
|
|
{
|
|
if (!moo_prefs_get (key))
|
|
set_bool (key, val, TRUE);
|
|
}
|
|
|
|
|
|
static void set_color (const char *key,
|
|
const GdkColor *val,
|
|
gboolean ignore_change)
|
|
{
|
|
char sval[14];
|
|
|
|
if (!val)
|
|
{
|
|
moo_prefs_set (key, NULL);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
g_snprintf (sval, 8, "#%02x%02x%02x",
|
|
val->red >> 8,
|
|
val->green >> 8,
|
|
val->blue >> 8);
|
|
prefs_set (instance(), key, sval, !ignore_change);
|
|
}
|
|
}
|
|
|
|
void moo_prefs_set_color (const char *key,
|
|
const GdkColor *val)
|
|
{
|
|
set_color (key, val, FALSE);
|
|
}
|
|
|
|
void moo_prefs_set_color_ignore_change
|
|
(const char *key,
|
|
const GdkColor *val)
|
|
{
|
|
set_color (key, val, TRUE);
|
|
}
|
|
|
|
void moo_prefs_set_color_if_not_set
|
|
(const char *key,
|
|
const GdkColor *val)
|
|
{
|
|
if (!moo_prefs_get (key))
|
|
set_color (key, val, FALSE);
|
|
}
|
|
|
|
void moo_prefs_set_color_if_not_set_ignore_change
|
|
(const char *key,
|
|
const GdkColor *val)
|
|
{
|
|
if (!moo_prefs_get (key))
|
|
set_color (key, val, TRUE);
|
|
}
|
|
|
|
|
|
GType moo_prefs_match_type_get_type (void)
|
|
{
|
|
static GType type = 0;
|
|
|
|
if (!type)
|
|
{
|
|
static const GFlagsValue values[] = {
|
|
{ MOO_PREFS_MATCH_KEY, (char*)"MOO_PREFS_MATCH_KEY", (char*)"match-key" },
|
|
{ MOO_PREFS_MATCH_PREFIX, (char*)"MOO_PREFS_MATCH_PREFIX", (char*)"match-prefix" },
|
|
{ MOO_PREFS_MATCH_REGEX, (char*)"MOO_PREFS_MATCH_REGEX", (char*)"match-regex" },
|
|
{ 0, NULL, NULL }
|
|
};
|
|
type = g_flags_register_static ("MooPrefsMatchType", values);
|
|
}
|
|
|
|
return type;
|
|
}
|