create a generic tokenizer/sectionizer for the config file. pass off the token to...
[dana/openbox.git] / openbox / config.c
1 #include "config.h"
2
3 #ifdef HAVE_STDIO_H
4 #  include <stdio.h>
5 #endif
6
7 static void config_free_entry(ConfigEntry *entry);
8 static void config_set_entry(char *name, ConfigValueType type,
9                              ConfigValue value);
10 static void config_def_free(ConfigDefEntry *entry);
11
12 static GData *config = NULL;
13 static GData *config_def = NULL;
14
15 /* provided by cparse.l */
16 void cparse_go(char *filename, FILE *);
17
18
19 void config_startup()
20 {
21     ConfigValue val;
22
23     /* set up options exported by the kernel */
24     config_def_set(config_def_new("engine", Config_String,
25                                   "Engine",
26                                   "The name of the theming engine to be used "
27                                   "to decorate windows."));
28
29     config_def_set(config_def_new("theme", Config_String,
30                                   "Theme",
31                                   "The name of the theme to load with the "
32                                   "chosen engine."));
33
34     config_def_set(config_def_new("font", Config_String,
35                                   "Titlebar Font",
36                                   "The fontstring specifying the font to "
37                                   "be used in window titlebars."));
38     val.string = "Sans-7";
39     config_set("font", Config_String, val);
40
41     config_def_set(config_def_new("font.shadow", Config_Bool,
42                                   "Titlebar Font Shadow",
43                                   "Whether or not the text in the window "
44                                   "titlebars gets a drop shadow."));
45     val.bool = FALSE;
46     config_set("font.shadow", Config_Bool, val);
47
48     config_def_set(config_def_new("font.shadow.offset", Config_Integer,
49                                   "Titlebar Font Shadow Offset",
50                                   "The offset of the drop shadow for text "
51                                   "in the window titlebars."));
52     val.integer = 1;
53     config_set("font.shadow.offset", Config_Integer, val);
54
55     config_def_set(config_def_new("font.shadow.tint", Config_Integer,
56                                   "Titlebar Font Shadow Tint",
57                                   "The percentage of tint/opacity to give the "
58                                   "the shadow(from -100(white) to "
59                                   "100(black))."));
60     val.integer = 25;
61     config_set("font.shadow.tint", Config_Integer, val);
62
63     config_def_set(config_def_new("titlebar.layout", Config_String,
64                                   "Titlebar Layout",
65                                   "The ordering of the elements in the "
66                                   "window titlebars."));
67     val.string = "NDSLIMC";
68     config_set("titlebar.layout", Config_String, val);
69
70     config_def_set(config_def_new("focusNew", Config_Bool,
71                                   "Focus New Windows",
72                                   "Focus windows when they first appear."));
73     val.bool = TRUE;
74     config_set("focusNew", Config_Bool, val);
75
76     config_def_set(config_def_new("focusFollowsMouse", Config_Bool,
77                                   "Focus Follows Mouse",
78                                   "Focus windows when the mouse pointer "
79                                   "enters them."));
80     val.bool = TRUE;
81     config_set("focusFollowsMouse", Config_Bool, val);
82 }
83
84 void config_shutdown()
85 {
86     g_datalist_clear(&config);
87     g_datalist_clear(&config_def);
88 }
89
90 gboolean config_set(char *name, ConfigValueType type, ConfigValue value)
91 {
92     ConfigDefEntry *def;
93     gboolean ret = FALSE;
94
95     name = g_ascii_strdown(name, -1);
96
97     def = g_datalist_get_data(&config_def, name);
98
99     if (def == NULL) {
100         g_warning("Invalid config option '%s'", name);
101     } else {
102         if (def->hasList) {
103             gboolean found = FALSE;
104             GSList *it;
105
106             it = def->values;
107             g_assert(it != NULL);
108             do {
109                 if (g_ascii_strcasecmp(it->data, value.string) == 0) {
110                     found = TRUE;
111                     break;
112                 }
113             } while ((it = it->next));
114
115             if (!found)
116                 g_warning("Invalid value '%s' for config option '%s'",
117                           value.string, name);
118             else
119                 ret = TRUE;
120         } else if (type != def->type) {
121             g_warning("Incorrect type of value for config option '%s'", name);
122         } else
123             ret = TRUE;
124
125     }
126
127     if (ret)
128         config_set_entry(name, type, value);
129     else
130         g_free(name);
131
132     return ret;
133 }
134
135 gboolean config_get(char *name, ConfigValueType type, ConfigValue *value)
136 {
137     ConfigEntry *entry;
138     gboolean ret = FALSE;
139
140     name = g_ascii_strdown(name, -1);
141     entry = g_datalist_get_data(&config, name);
142     if (entry != NULL && entry->type == type) {
143         *value = entry->value;
144         ret = TRUE;
145     }
146     g_free(name);
147     return ret;
148 }
149
150 static void config_set_entry(char *name, ConfigValueType type,
151                              ConfigValue value)
152 {
153     ConfigEntry *entry = NULL;
154
155     entry = g_new(ConfigEntry, 1);
156     entry->name = name;
157     entry->type = type;
158     if (type == Config_String)
159         entry->value.string = g_strdup(value.string);
160     else
161         entry->value = value;
162
163     g_datalist_set_data_full(&config, name, entry,
164                              (GDestroyNotify)config_free_entry);
165 }
166
167 static void config_free_entry(ConfigEntry *entry)
168 {
169     g_free(entry->name);
170     entry->name = NULL;
171     if(entry->type == Config_String) {
172         g_free(entry->value.string);
173         entry->value.string = NULL;
174     }
175     g_free(entry);
176 }
177
178 ConfigDefEntry *config_def_new(char *name, ConfigValueType type,
179                                 char *descriptive_name, char *long_description)
180 {
181     ConfigDefEntry *entry;
182
183     entry = g_new(ConfigDefEntry, 1);
184     entry->name = g_ascii_strdown(name, -1);
185     entry->descriptive_name = g_strdup(descriptive_name);
186     entry->long_description = g_strdup(long_description);
187     entry->hasList = FALSE;
188     entry->type = type;
189     entry->values = NULL;
190     return entry;
191 }
192
193 static void config_def_free(ConfigDefEntry *entry)
194 {
195     GSList *it;
196
197     g_free(entry->name);
198     g_free(entry->descriptive_name);
199     g_free(entry->long_description);
200     if (entry->hasList) {
201         for (it = entry->values; it != NULL; it = it->next)
202             g_free(it->data);
203         g_slist_free(entry->values);
204     }
205     g_free(entry);
206 }
207
208 gboolean config_def_add_value(ConfigDefEntry *entry, char *value)
209 {
210     if (entry->type != Config_String) {
211         g_warning("Tried adding value to non-string config definition");
212         return FALSE;
213     }
214
215     entry->hasList = TRUE;
216     entry->values = g_slist_append(entry->values, g_ascii_strdown(value, -1));
217     return TRUE;
218 }
219
220 gboolean config_def_set(ConfigDefEntry *entry)
221 {
222     gboolean ret = FALSE;
223     ConfigDefEntry *def;
224
225     if ((def = g_datalist_get_data(&config_def, entry->name))) {
226         g_assert(def != entry); /* adding it twice!? */
227         g_warning("Definition already set for config option '%s'. ",
228                   entry->name);
229         config_def_free(entry);
230     } else {
231         g_datalist_set_data_full(&config_def, entry->name, entry,
232                                  (GDestroyNotify)config_def_free);
233         ret = TRUE;
234     }
235
236     return ret;
237 }