From a9293624e12e60aeea72dd046407207d96948d3d Mon Sep 17 00:00:00 2001 From: Thomas Leonard Date: Thu, 5 Aug 1999 15:00:19 +0000 Subject: [PATCH] r44: Greatly improved the options system. Choice of xterm process is now saved. --- ROX-Filer/src/dnd.c | 49 ------------- ROX-Filer/src/gui_support.c | 52 +++++++++++++ ROX-Filer/src/gui_support.h | 1 + ROX-Filer/src/main.c | 2 + ROX-Filer/src/menu.c | 81 +++++++++++++++++--- ROX-Filer/src/menu.h | 7 +- ROX-Filer/src/options.c | 175 +++++++++++++++++++++++++++++++++++++++----- ROX-Filer/src/options.h | 5 ++ 8 files changed, 293 insertions(+), 79 deletions(-) diff --git a/ROX-Filer/src/dnd.c b/ROX-Filer/src/dnd.c index 62166082..6d9d104f 100644 --- a/ROX-Filer/src/dnd.c +++ b/ROX-Filer/src/dnd.c @@ -79,7 +79,6 @@ static void got_data_raw(GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint32 time); -static gboolean load_file(char *pathname, char **data_out, long *length_out); static GSList *uri_list_to_gslist(char *uri_list); static void got_uri_list(GtkWidget *widget, GdkDragContext *context, @@ -380,54 +379,6 @@ void drag_data_get(GtkWidget *widget, g_free(to_send); } -/* Load the file into memory. Return TRUE on success. */ -static gboolean load_file(char *pathname, char **data_out, long *length_out) -{ - FILE *file; - long length; - char *buffer; - gboolean retval = FALSE; - - file = fopen(pathname, "r"); - - if (!file) - { - delayed_error("Opening file for DND", g_strerror(errno)); - return FALSE; - } - - fseek(file, 0, SEEK_END); - length = ftell(file); - - buffer = malloc(length); - if (buffer) - { - fseek(file, 0, SEEK_SET); - fread(buffer, 1, length, file); - - if (ferror(file)) - { - delayed_error("Loading file for DND", - g_strerror(errno)); - g_free(buffer); - } - else - { - *data_out = buffer; - *length_out = length; - retval = TRUE; - } - } - else - delayed_error("Loading file for DND", - "Can't allocate memory for buffer to " - "transfer this file"); - - fclose(file); - - return retval; -} - /* DRAGGING TO US */ /* Set up this filer window as a drop target. Called once, when the diff --git a/ROX-Filer/src/gui_support.c b/ROX-Filer/src/gui_support.c index f1ed333e..0f0d4a0e 100644 --- a/ROX-Filer/src/gui_support.c +++ b/ROX-Filer/src/gui_support.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -198,3 +199,54 @@ void delayed_error(char *title, char *error) number_of_windows++; } + +/* Load the file into memory. Return TRUE on success. + * Block is zero terminated (but this is not included in the length). + */ +gboolean load_file(char *pathname, char **data_out, long *length_out) +{ + FILE *file; + long length; + char *buffer; + gboolean retval = FALSE; + + file = fopen(pathname, "r"); + + if (!file) + { + delayed_error("Opening file for DND", g_strerror(errno)); + return FALSE; + } + + fseek(file, 0, SEEK_END); + length = ftell(file); + + buffer = malloc(length + 1); + if (buffer) + { + fseek(file, 0, SEEK_SET); + fread(buffer, 1, length, file); + + if (ferror(file)) + { + delayed_error("Loading file for DND", + g_strerror(errno)); + g_free(buffer); + } + else + { + *data_out = buffer; + *length_out = length; + buffer[length] = '\0'; + retval = TRUE; + } + } + else + delayed_error("Loading file for DND", + "Can't allocate memory for buffer to " + "transfer this file"); + + fclose(file); + + return retval; +} diff --git a/ROX-Filer/src/gui_support.h b/ROX-Filer/src/gui_support.h index d26a1cc8..a558e5b8 100644 --- a/ROX-Filer/src/gui_support.h +++ b/ROX-Filer/src/gui_support.h @@ -24,5 +24,6 @@ void set_cardinal_property(GdkWindow *window, GdkAtom prop, guint32 value); void make_panel_window(GdkWindow *window); gint hide_dialog_event(GtkWidget *widget, GdkEvent *event, gpointer window); void delayed_error(char *title, char *error); +gboolean load_file(char *pathname, char **data_out, long *length_out); #endif /* _GUI_SUPPORT_H */ diff --git a/ROX-Filer/src/main.c b/ROX-Filer/src/main.c index 194ed446..38b6f527 100644 --- a/ROX-Filer/src/main.c +++ b/ROX-Filer/src/main.c @@ -69,6 +69,8 @@ int main(int argc, char **argv) savebox_init(); type_init(); + options_load(); + signal(SIGCHLD, child_died); if (argc < 2) diff --git a/ROX-Filer/src/menu.c b/ROX-Filer/src/menu.c index 85dfe59c..737c0e99 100644 --- a/ROX-Filer/src/menu.c +++ b/ROX-Filer/src/menu.c @@ -34,10 +34,15 @@ GtkAccelGroup *filer_keys; GtkAccelGroup *panel_keys; +/* Options */ +static GtkWidget *xterm_here_entry; +static char *xterm_here_value; + /* Static prototypes */ static void position_menu(GtkMenu *menu, gint *x, gint *y, gpointer data); static void menu_closed(GtkWidget *widget); static void items_sensitive(GtkWidget *menu, int from, int n, gboolean state); +static char *load_xterm_here(char *data); static void refresh(gpointer data, guint action, GtkWidget *widget); @@ -118,7 +123,6 @@ static GtkItemFactoryEntry panel_menu_def[] = { {"/Close panel", NULL, close_panel, 0, NULL}, }; - void menu_init() { GtkItemFactory *item_factory; @@ -165,8 +169,71 @@ void menu_init() GTK_SIGNAL_FUNC(menu_closed), NULL); gtk_accel_group_lock(panel_keys); + + xterm_here_value = g_strdup("xterm"); + option_register("xterm_here", load_xterm_here); } +/* Build up some option widgets to go in the options dialog, but don't + * fill them in yet. + */ +GtkWidget *create_menu_options() +{ + GtkWidget *table, *label; + + table = gtk_table_new(2, 2, FALSE); + gtk_container_set_border_width(GTK_CONTAINER(table), 4); + + label = gtk_label_new("To set the keyboard short-cuts you simply open " + "the menu over a filer window, move the pointer over " + "the item you want to use and press a key. The key " + "will appear next to the menu item and you can just " + "press that key without opening the menu in future. " + "To save the current menu short-cuts for next time, " + "click the Save button at the bottom of this window."); + gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 2, 0, 1); + + label = gtk_label_new("'Xterm here' program:"); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2); + xterm_here_entry = gtk_entry_new(); + gtk_table_attach_defaults(GTK_TABLE(table), xterm_here_entry, + 1, 2, 1, 2); + + return table; +} + +static char *load_xterm_here(char *data) +{ + g_free(xterm_here_value); + xterm_here_value = g_strdup(data); + return NULL; +} + +void menu_update_options() +{ + gtk_entry_set_text(GTK_ENTRY(xterm_here_entry), xterm_here_value); +} + +void menu_set_options() +{ + g_free(xterm_here_value); + xterm_here_value = g_strdup(gtk_entry_get_text( + GTK_ENTRY(xterm_here_entry))); +} + +void menu_save_options() +{ + char *menurc; + + menurc = choices_find_path_save("menus"); + if (menurc) + gtk_item_factory_dump_rc(menurc, NULL, TRUE); + + option_write("xterm_here", xterm_here_value); +} + + static void items_sensitive(GtkWidget *menu, int from, int n, gboolean state) { GList *items, *item; @@ -183,16 +250,6 @@ static void items_sensitive(GtkWidget *menu, int from, int n, gboolean state) g_list_free(items); } -/* Save the keybindings... */ -void menu_save() -{ - char *menurc; - - menurc = choices_find_path_save("menus"); - if (menurc) - gtk_item_factory_dump_rc(menurc, NULL, TRUE); -} - static void position_menu(GtkMenu *menu, gint *x, gint *y, gpointer data) { int *pos = (int *) data; @@ -562,7 +619,7 @@ static void new_directory(gpointer data, guint action, GtkWidget *widget) static void xterm_here(gpointer data, guint action, GtkWidget *widget) { - char *argv[] = {"gnome-terminal", NULL}; /* XXX: Bad default */ + char *argv[] = {xterm_here_value, NULL}; g_return_if_fail(window_with_focus != NULL); diff --git a/ROX-Filer/src/menu.h b/ROX-Filer/src/menu.h index d7002949..40dd2eea 100644 --- a/ROX-Filer/src/menu.h +++ b/ROX-Filer/src/menu.h @@ -13,7 +13,12 @@ extern GtkAccelGroup *filer_keys; void menu_init(void); -void menu_save(void); + +GtkWidget *create_menu_options(void); +void menu_update_options(void); +void menu_set_options(void); +void menu_save_options(void); + void show_filer_menu(FilerWindow *filer_window, GdkEventButton *event, int item); #endif /* _MENU_H */ diff --git a/ROX-Filer/src/options.c b/ROX-Filer/src/options.c index 01bf266a..e037b661 100644 --- a/ROX-Filer/src/options.c +++ b/ROX-Filer/src/options.c @@ -7,6 +7,9 @@ /* options.c - code for handling user choices */ +#include +#include +#include #include #include @@ -15,10 +18,14 @@ #include "menu.h" #include "options.h" + static GtkWidget *window; +static FILE *save_file = NULL; +static GHashTable *option_hash = NULL; /* Static prototypes */ static void save_options(GtkWidget *widget, gpointer data); +static char *process_option_line(char *line); void options_init() { @@ -57,22 +64,10 @@ void options_init() label = gtk_label_new("There are no copy options yet..."); gtk_container_add(GTK_CONTAINER(group), label); - group = gtk_frame_new("External programs"); - gtk_box_pack_start(GTK_BOX(vbox), group, FALSE, TRUE, 0); - label = gtk_label_new("There are no external program options yet..."); - gtk_container_add(GTK_CONTAINER(group), label); - group = gtk_frame_new("Short-cut keys"); + group = gtk_frame_new("Menu options"); gtk_box_pack_start(GTK_BOX(vbox), group, FALSE, TRUE, 0); - label = gtk_label_new("To set the keyboard short-cuts you simply open " - "the menu over a filer window, move the pointer over " - "the item you want to use and press a key. The key " - "will appear next to the menu item and you can just " - "press that key without opening the menu in future. " - "To save the current menu short-cuts for next time, " - "click the Save button at the bottom of this window."); - gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); - gtk_container_add(GTK_CONTAINER(group), label); + gtk_container_add(GTK_CONTAINER(group), create_menu_options()); save_path = choices_find_path_save("..."); if (save_path) @@ -96,17 +91,143 @@ void options_init() if (!save_path) gtk_widget_set_sensitive(button, FALSE); gtk_signal_connect(GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(save_options), NULL); + GTK_SIGNAL_FUNC(save_options), (gpointer) TRUE); + + button = gtk_button_new_with_label("OK"); + gtk_box_pack_start(GTK_BOX(actions), button, FALSE, TRUE, 0); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(save_options), (gpointer) FALSE); - button = gtk_button_new_with_label("Dismiss"); + button = gtk_button_new_with_label("Cancel"); gtk_box_pack_start(GTK_BOX(actions), button, FALSE, TRUE, 0); gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_hide), GTK_OBJECT(window)); } +void options_load(void) +{ + char *path; + char *data; + long length; + + path = choices_find_path_load("options"); + if (!path) + return; /* Nothing to load */ + + if (load_file(path, &data, &length)) + { + char *eol, *error; + char *line = data; + int line_number = 1; + + while (line && *line) + { + eol = strchr(line, '\n'); + if (eol) + *eol = '\0'; + + error = process_option_line(line); + + if (error) + { + GString *message; + + message = g_string_new(NULL); + g_string_sprintf(message, + "Error in options file at " + "line %d: %s", line_number, + error); + delayed_error("ROX-Filer", message->str); + g_string_free(message, TRUE); + break; + } + + if (!eol) + break; + line = eol + 1; + line_number++; + } + g_free(data); + } + +} + +/* Call this on init to register a handler for a key. + * The function returns a pointer to an error messages (which will + * NOT be free()d, or NULL on success. + */ +void option_register(char *key, OptionFunc *func) +{ + if (!option_hash) + option_hash = g_hash_table_new(g_str_hash, g_str_equal); + g_hash_table_insert(option_hash, key, func); +} + +/* Process one line from the options file (\0 term'd). + * Returns NULL on success, or a pointer to an error message. + * The line is modified. + */ +static char *process_option_line(char *line) +{ + char *eq, *c; + OptionFunc *func; + + g_return_val_if_fail(option_hash != NULL, "No registered functions!"); + + eq = strchr(line, '='); + if (!eq) + return "Missing '='"; + + c = eq - 1; + while (c > line && (*c == ' ' || *c == '\t')) + c--; + c[1] = '\0'; + c = eq + 1; + while (*c == ' ' || *c == '\t') + c++; + + func = (OptionFunc *) g_hash_table_lookup(option_hash, line); + if (!func) + return "Bad key (no such option name)"; + + return func(c); +} + static void save_options(GtkWidget *widget, gpointer data) { - menu_save(); + gboolean save = (gboolean) data; + + menu_set_options(); + + if (save) + { + char *path; + + path = choices_find_path_save("options"); + g_return_if_fail(path != NULL); + + save_file = fopen(path, "wb"); + if (!save_file) + { + char *str; + str = g_strconcat("Unable to open '", path, + "' for writing: ", + g_strerror(errno), + NULL); + report_error("ROX-Filer", str); + g_free(str); + return; + } + + menu_save_options(); + + if (save_file && fclose(save_file) == EOF) + { + report_error("ROX-Filer", g_strerror(errno)); + return; + } + } + gtk_widget_hide(window); } @@ -114,5 +235,25 @@ void options_show(FilerWindow *filer_window) { if (GTK_WIDGET_MAPPED(window)) gtk_widget_hide(window); + menu_update_options(); gtk_widget_show_all(window); } + +void option_write(char *name, char *value) +{ + char *string; + int len; + + if (!save_file) + return; /* Error already reported hopefully */ + + string = g_strconcat(name, " = ", value, "\n", NULL); + len = strlen(string); + if (fwrite(string, sizeof(char), len, save_file) < len) + { + delayed_error("Saving options", g_strerror(errno)); + fclose(save_file); + save_file = NULL; + } + g_free(string); +} diff --git a/ROX-Filer/src/options.h b/ROX-Filer/src/options.h index 12653914..c28a6e6b 100644 --- a/ROX-Filer/src/options.h +++ b/ROX-Filer/src/options.h @@ -8,11 +8,16 @@ #ifndef _OPTIONS_H #define _OPTIONS_H +typedef char *OptionFunc(char *value); + #include "filer.h" /* Prototypes */ void options_init(void); +void option_register(char *key, OptionFunc *func); +void options_load(void); void options_show(FilerWindow *filer_window); +void option_write(char *name, char *value); #endif /* _OPTIONS_H */ -- 2.11.4.GIT