fix rules for optional plugins.
[galan.git] / src / prefs.c
blobca3f58f8090cb7360b72c1032ea672da0567ab7c
1 /* gAlan - Graphical Audio Language
2 * Copyright (C) 1999 Tony Garnock-Jones
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program 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
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
23 #include <gdk/gdk.h>
24 #include <gtk/gtk.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <ctype.h>
32 #include "global.h"
33 #include "msgbox.h"
34 #include "prefs.h"
36 #define HOMEDIR_GALANDIR "/.galan"
37 #define HOMEDIR_SUFFIX "/.galan/prefs"
38 #define SITE_PREFS_PATH SITE_PKGLIB_DIR "/prefs"
40 typedef struct PrefEntry {
41 char *key;
42 union {
43 char *value;
44 GList *list;
45 } d;
46 } PrefEntry;
48 PRIVATE GHashTable *prefs = NULL;
49 PRIVATE GHashTable *options = NULL;
51 PRIVATE void clone_prefs_entry(gpointer key, gpointer value, gpointer user_data) {
52 GHashTable *newtab = user_data;
53 PrefEntry *entry = value;
54 PrefEntry *newentry = safe_malloc(sizeof(PrefEntry));
56 newentry->key = safe_string_dup(entry->key);
57 newentry->d.value = safe_string_dup(entry->d.value);
58 g_hash_table_insert(newtab, newentry->key, newentry);
61 PRIVATE GHashTable *clone_prefs_table(GHashTable *tab) {
62 GHashTable *newtab = g_hash_table_new(g_str_hash, g_str_equal);
64 g_hash_table_foreach(tab, clone_prefs_entry, newtab);
65 return newtab;
68 PRIVATE void free_prefs_entry(gpointer key, gpointer value, gpointer user_data) {
69 PrefEntry *entry = value;
70 free(entry->key);
71 free(entry->d.value);
72 free(entry);
75 PRIVATE void kill_prefs_table(GHashTable *tab) {
76 g_hash_table_foreach(tab, free_prefs_entry, NULL);
79 PUBLIC char *prefs_get_item(const char *key) {
80 PrefEntry *entry = g_hash_table_lookup(prefs, key);
81 return entry ? entry->d.value : NULL;
84 PUBLIC void prefs_set_item(const char *key, const char *value) {
85 PrefEntry *entry = safe_malloc(sizeof(PrefEntry));
86 entry->key = safe_string_dup(key);
87 entry->d.value = safe_string_dup(value);
88 prefs_clear_item(key);
89 g_hash_table_insert(prefs, entry->key, entry);
92 PUBLIC void prefs_clear_item(const char *key) {
93 PrefEntry *entry = g_hash_table_lookup(prefs, key);
95 if (entry != NULL) {
96 g_hash_table_remove(prefs, key);
97 free(entry->key);
98 free(entry->d.value);
99 free(entry);
103 PUBLIC void prefs_register_option(const char *key, const char *value) {
104 PrefEntry *entry = g_hash_table_lookup(options, key);
106 if (entry == NULL) {
107 entry = safe_malloc(sizeof(PrefEntry));
108 entry->key = safe_string_dup(key);
109 entry->d.list = NULL;
112 entry->d.list = g_list_append(entry->d.list, safe_string_dup(value));
113 g_hash_table_insert(options, entry->key, entry);
116 PRIVATE void add_option_to_optlist(gpointer key, gpointer value, gpointer user_data) {
117 PrefEntry *entry = value;
118 GtkCList *list = user_data;
119 char *texts[2] = { NULL, NULL };
121 texts[0] = entry->key;
122 gtk_clist_append(list, texts);
125 PRIVATE gboolean optlist_row_selected(GtkCList *optlist, gint row, gint column,
126 GdkEventButton *event, gpointer user_data) {
127 GtkCombo *droplist = gtk_object_get_data(GTK_OBJECT(optlist), "droplist");
128 PrefEntry *entry;
129 gchar *option_name;
131 gtk_clist_get_text(optlist, row, column, &option_name);
132 entry = g_hash_table_lookup(options, option_name);
134 if (entry != NULL) {
135 gchar *current_value = prefs_get_item(option_name);
137 /* Remove the data so that setting the text doesn't update the variable */
138 gtk_object_remove_data(GTK_OBJECT(droplist->entry), "option_name");
139 gtk_combo_set_popdown_strings(droplist, entry->d.list);
140 gtk_entry_set_text(GTK_ENTRY(droplist->entry), current_value ? current_value : "");
142 /* Reinstate it so that changes from now on take effect */
143 gtk_object_set_data(GTK_OBJECT(droplist->entry), "option_name", option_name);
145 return FALSE;
148 PRIVATE gboolean droplist_entry_changed(GtkEntry *entry, gpointer data) {
149 gchar *option_name = gtk_object_get_data(GTK_OBJECT(entry), "option_name");
151 if (option_name != NULL) {
152 const gchar *value_text = gtk_entry_get_text(entry);
154 if (value_text[0] == '\0')
155 prefs_clear_item(option_name);
156 else
157 prefs_set_item(option_name, value_text);
159 return TRUE;
162 PUBLIC void prefs_edit_prefs(void) {
163 GHashTable *backup_prefs = clone_prefs_table(prefs);
164 GtkWidget *ob = gtk_vbox_new(FALSE, 5);
165 GtkWidget *ib = gtk_vbox_new(FALSE, 5);
166 GtkWidget *hb;
167 GtkWidget *label = gtk_label_new("[Note: Quit and restart to put changes into effect]");
168 GtkWidget *frame = gtk_frame_new("Options");
169 GtkWidget *optlist = gtk_clist_new(1);
170 GtkWidget *droplist = gtk_combo_new();
171 GtkWidget *scrollwin = gtk_scrolled_window_new(NULL,NULL);
173 /* Configure the widgets */
174 //gtk_widget_set_usize(optlist, 200, 100);
175 gtk_clist_set_selection_mode(GTK_CLIST(optlist), GTK_SELECTION_SINGLE);
176 gtk_clist_column_titles_hide(GTK_CLIST(optlist));
177 gtk_clist_set_column_width(GTK_CLIST(optlist), 0, 200);
178 g_hash_table_foreach(options, add_option_to_optlist, optlist);
180 gtk_box_pack_start(GTK_BOX(ob), label, FALSE, FALSE, 5);
181 gtk_box_pack_start(GTK_BOX(ob), frame, TRUE, TRUE, 0);
182 gtk_widget_show(label);
183 gtk_widget_show(frame);
185 /* Nest and display the widgets */
186 gtk_container_add(GTK_CONTAINER(frame), ib);
187 gtk_widget_show(ib);
189 gtk_container_add( GTK_CONTAINER( scrollwin ), optlist );
190 gtk_box_pack_start(GTK_BOX(ib), scrollwin, TRUE, TRUE, 0);
191 gtk_widget_show(optlist);
192 gtk_widget_show(scrollwin);
194 hb = gtk_hbox_new(FALSE, 5);
195 gtk_box_pack_start(GTK_BOX(ib), hb, FALSE, FALSE, 0);
196 gtk_widget_show(hb);
198 label = gtk_label_new("Value:");
199 gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
200 gtk_box_pack_start(GTK_BOX(hb), label, FALSE, TRUE, 0);
201 gtk_widget_show(label);
203 gtk_box_pack_start(GTK_BOX(hb), droplist, FALSE, FALSE, 0);
204 gtk_widget_show(droplist);
206 /* Configure the data and signals */
207 gtk_object_set_data(GTK_OBJECT(optlist), "droplist", droplist);
209 gtk_signal_connect(GTK_OBJECT(optlist), "select_row",
210 GTK_SIGNAL_FUNC(optlist_row_selected), NULL);
211 gtk_signal_connect(GTK_OBJECT(GTK_COMBO(droplist)->entry), "changed",
212 GTK_SIGNAL_FUNC(droplist_entry_changed), NULL);
214 if (popup_dialog("Adjust Preferences", MSGBOX_ACCEPT | MSGBOX_DISMISS, 0, MSGBOX_NONE,
215 ob, NULL, NULL) != MSGBOX_ACCEPT) {
216 kill_prefs_table(prefs);
217 prefs = backup_prefs;
221 #define LINELEN 2048
222 PRIVATE void load_prefs_from(char *filename) {
223 FILE *f = fopen(filename, "rt");
224 char line[LINELEN]; /* %%% Yuck, a fixed size buffer */
226 if (f == NULL)
227 return;
229 while (!feof(f)) {
230 if (fgets(line, LINELEN, f) != NULL) {
231 char *valpos = strchr(line, '=');
232 int len;
234 if (line[0] == '#' || valpos == NULL)
235 continue;
237 /* Extract value string + trim leading whitespace */
238 *valpos = '\0';
239 do {
240 valpos++;
241 } while (isspace(*valpos) && *valpos != '\0');
243 /* Trim trailing whitespace */
244 len = strlen(valpos);
245 while (isspace(valpos[len-1])) {
246 valpos[len-1] = '\0';
247 len--;
250 prefs_set_item(line, valpos);
254 fclose(f);
257 PRIVATE void save_pref_entry(gpointer key, gpointer value, gpointer user_data) {
258 FILE *f = user_data;
259 PrefEntry *entry = value;
261 fprintf(f, "%s=%s\n", entry->key, entry->d.value);
264 PRIVATE gboolean save_prefs_to(char *filename) {
265 FILE *f = fopen(filename, "wt");
267 if (f == NULL)
268 return FALSE;
270 g_hash_table_foreach(prefs, save_pref_entry, f);
271 return TRUE;
274 PRIVATE char *build_userprefs_path(char *homedir) {
275 char *userprefs = safe_malloc(strlen(homedir) + strlen(HOMEDIR_SUFFIX) + 1);
277 strcpy(userprefs, homedir);
278 strcat(userprefs, HOMEDIR_SUFFIX);
279 return userprefs;
282 PRIVATE void load_prefs(void) {
283 char *homedir = getenv("HOME");
285 load_prefs_from(SITE_PREFS_PATH);
287 if (homedir != NULL) {
288 char *userprefs = build_userprefs_path(homedir);
289 load_prefs_from(userprefs);
290 free(userprefs);
294 PRIVATE void save_prefs(void) {
295 #ifdef G_OS_WIN32
296 if (!save_prefs_to(SITE_PREFS_PATH))
297 g_warning("Could not save preferences to %s", SITE_PREFS_PATH);
298 #else
299 char *homedir = getenv("HOME");
301 if (homedir != NULL) {
302 char *userprefs = build_userprefs_path(homedir);
304 if (!save_prefs_to(userprefs)) {
305 char *usergalandir = safe_malloc(strlen(homedir) + strlen(HOMEDIR_GALANDIR) + 1);
306 strcpy(usergalandir, homedir);
307 strcat(usergalandir, HOMEDIR_GALANDIR);
308 mkdir(usergalandir, 0777);
309 free(usergalandir);
310 if (!save_prefs_to(userprefs))
311 g_warning("Could not save preferences to %s", userprefs);
314 free(userprefs);
316 #endif
319 PUBLIC void init_prefs(void) {
320 prefs = g_hash_table_new(g_str_hash, g_str_equal);
321 options = g_hash_table_new(g_str_hash, g_str_equal);
323 load_prefs();
326 PRIVATE void free_options_entry(gpointer key, gpointer value, gpointer user_data) {
327 PrefEntry *entry = value;
328 free(entry->key);
329 g_list_foreach(entry->d.list, (GFunc) free, NULL);
330 g_list_free(entry->d.list);
331 free(entry);
334 PUBLIC void done_prefs(void) {
335 save_prefs();
337 g_hash_table_foreach(options, free_options_entry, NULL);
338 kill_prefs_table(prefs);
340 g_hash_table_destroy(options);
341 g_hash_table_destroy(prefs);