r156: Fixed some compiler warnings for systems with signed char types.
[rox-filer/ma.git] / ROX-Filer / src / options.c
bloba63f7d72bd2b0e11e03f8ad7e424f93773032d75
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 1999, Thomas Leonard, <tal197@ecs.soton.ac.uk>.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
22 /* options.c - code for handling user choices */
24 #include <stdio.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <glib.h>
28 #include <gtk/gtk.h>
30 #include "gui_support.h"
31 #include "choices.h"
32 #include "options.h"
34 /* Add OptionsSection structs to this list in your _init() functions */
35 GSList *options_sections = NULL;
37 static GtkWidget *window, *sections_vbox;
38 static FILE *save_file = NULL;
39 static GHashTable *option_hash = NULL;
41 /* Static prototypes */
42 static void save_options(GtkWidget *widget, gpointer data);
43 static char *process_option_line(guchar *line);
45 void options_init()
47 GtkWidget *tl_vbox, *scrolled_area;
48 GtkWidget *border, *label;
49 GtkWidget *actions, *button;
50 char *string, *save_path;
52 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
53 gtk_window_set_title(GTK_WINDOW(window), "ROX-Filer options");
54 gtk_signal_connect(GTK_OBJECT(window), "delete_event",
55 GTK_SIGNAL_FUNC(hide_dialog_event), window);
56 gtk_container_set_border_width(GTK_CONTAINER(window), 4);
57 gtk_window_set_default_size(GTK_WINDOW(window), 400, 400);
59 tl_vbox = gtk_vbox_new(FALSE, 4);
60 gtk_container_add(GTK_CONTAINER(window), tl_vbox);
62 scrolled_area = gtk_scrolled_window_new(NULL, NULL);
63 gtk_container_set_border_width(GTK_CONTAINER(scrolled_area), 4);
64 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_area),
65 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
66 gtk_box_pack_start(GTK_BOX(tl_vbox), scrolled_area, TRUE, TRUE, 0);
68 border = gtk_frame_new(NULL);
69 gtk_frame_set_shadow_type(GTK_FRAME(border), GTK_SHADOW_NONE);
70 gtk_container_set_border_width(GTK_CONTAINER(border), 4);
71 gtk_scrolled_window_add_with_viewport(
72 GTK_SCROLLED_WINDOW(scrolled_area), border);
74 sections_vbox = gtk_vbox_new(FALSE, 4);
75 gtk_container_add(GTK_CONTAINER(border), sections_vbox);
77 save_path = choices_find_path_save("...");
78 if (save_path)
80 string = g_strconcat("Choices will be saved as ",
81 save_path,
82 NULL);
83 label = gtk_label_new(string);
84 g_free(string);
86 else
87 label = gtk_label_new("Choices saving is disabled by "
88 "CHOICESPATH variable");
89 gtk_box_pack_start(GTK_BOX(tl_vbox), label, FALSE, TRUE, 0);
91 actions = gtk_hbox_new(TRUE, 16);
92 gtk_box_pack_start(GTK_BOX(tl_vbox), actions, FALSE, TRUE, 0);
94 button = gtk_button_new_with_label("Save");
95 gtk_box_pack_start(GTK_BOX(actions), button, FALSE, TRUE, 0);
96 if (!save_path)
97 gtk_widget_set_sensitive(button, FALSE);
98 gtk_signal_connect(GTK_OBJECT(button), "clicked",
99 GTK_SIGNAL_FUNC(save_options), (gpointer) TRUE);
101 button = gtk_button_new_with_label("OK");
102 gtk_box_pack_start(GTK_BOX(actions), button, FALSE, TRUE, 0);
103 gtk_signal_connect(GTK_OBJECT(button), "clicked",
104 GTK_SIGNAL_FUNC(save_options), (gpointer) FALSE);
106 button = gtk_button_new_with_label("Cancel");
107 gtk_box_pack_start(GTK_BOX(actions), button, FALSE, TRUE, 0);
108 gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
109 GTK_SIGNAL_FUNC(gtk_widget_hide), GTK_OBJECT(window));
112 void options_load(void)
114 static gboolean need_init = TRUE;
115 char *path;
117 if (need_init)
119 GtkWidget *group;
120 GSList *next = options_sections;
122 while (next)
124 OptionsSection *section = (OptionsSection *) next->data;
126 group = gtk_frame_new(section->name);
127 gtk_box_pack_start(GTK_BOX(sections_vbox), group,
128 FALSE, TRUE, 0);
129 gtk_container_add(GTK_CONTAINER(group),
130 section->create());
131 next = next->next;
134 need_init = FALSE;
137 path = choices_find_path_load("options");
138 if (!path)
139 return; /* Nothing to load */
141 parse_file(path, process_option_line);
144 void parse_file(char *path, ParseFunc *parse_line)
146 char *data;
147 long length;
149 if (load_file(path, &data, &length))
151 char *eol, *error;
152 char *line = data;
153 int line_number = 1;
155 while (line && *line)
157 eol = strchr(line, '\n');
158 if (eol)
159 *eol = '\0';
161 error = parse_line(line);
163 if (error)
165 GString *message;
167 message = g_string_new(NULL);
168 g_string_sprintf(message,
169 "Error in options file at "
170 "line %d: %s", line_number,
171 error);
172 delayed_error("ROX-Filer", message->str);
173 g_string_free(message, TRUE);
174 break;
177 if (!eol)
178 break;
179 line = eol + 1;
180 line_number++;
182 g_free(data);
186 /* Call this on init to register a handler for a key (thing before the = in
187 * the config file).
188 * The function returns a pointer to an error messages (which will
189 * NOT be free()d), or NULL on success.
191 void option_register(char *key, OptionFunc *func)
193 if (!option_hash)
194 option_hash = g_hash_table_new(g_str_hash, g_str_equal);
195 g_hash_table_insert(option_hash, key, func);
198 /* Process one line from the options file (\0 term'd).
199 * Returns NULL on success, or a pointer to an error message.
200 * The line is modified.
202 static char *process_option_line(guchar *line)
204 guchar *eq, *c;
205 OptionFunc *func;
207 g_return_val_if_fail(option_hash != NULL, "No registered functions!");
209 eq = strchr(line, '=');
210 if (!eq)
211 return "Missing '='";
213 c = eq - 1;
214 while (c > line && (*c == ' ' || *c == '\t'))
215 c--;
216 c[1] = '\0';
217 c = eq + 1;
218 while (*c == ' ' || *c == '\t')
219 c++;
221 func = (OptionFunc *) g_hash_table_lookup(option_hash, line);
222 if (!func)
223 return "Bad key (no such option name)";
225 return func(c);
228 static void save_options(GtkWidget *widget, gpointer data)
230 gboolean save = (gboolean) data;
231 GSList *next = options_sections;
233 while (next)
235 OptionsSection *section = (OptionsSection *) next->data;
236 section->set();
237 next = next->next;
240 if (save)
242 char *path;
244 path = choices_find_path_save("options");
245 g_return_if_fail(path != NULL);
247 save_file = fopen(path, "wb");
248 if (!save_file)
250 char *str;
251 str = g_strconcat("Unable to open '", path,
252 "' for writing: ",
253 g_strerror(errno),
254 NULL);
255 report_error("ROX-Filer", str);
256 g_free(str);
257 return;
260 next = options_sections;
261 while (next)
263 OptionsSection *section = (OptionsSection *) next->data;
264 section->save();
265 next = next->next;
268 if (save_file && fclose(save_file) == EOF)
270 report_error("ROX-Filer", g_strerror(errno));
271 return;
275 gtk_widget_hide(window);
278 void options_show(FilerWindow *filer_window)
280 GSList *next = options_sections;
282 if (GTK_WIDGET_MAPPED(window))
283 gtk_widget_hide(window);
285 while (next)
287 OptionsSection *section = (OptionsSection *) next->data;
288 section->update();
289 next = next->next;
292 gtk_widget_show_all(window);
295 void option_write(char *name, char *value)
297 char *string;
298 int len;
300 if (!save_file)
301 return; /* Error already reported hopefully */
303 string = g_strconcat(name, " = ", value, "\n", NULL);
304 len = strlen(string);
305 if (fwrite(string, sizeof(char), len, save_file) < len)
307 delayed_error("Saving options", g_strerror(errno));
308 fclose(save_file);
309 save_file = NULL;
311 g_free(string);