a lot of code cleanup
[obnox/wireshark/wip.git] / gtk / gui_prefs.c
1 /* gui_prefs.c
2  * Dialog box for GUI preferences
3  *
4  * $Id: gui_prefs.c,v 1.71 2004/05/27 16:50:15 ulfl Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include <gtk/gtk.h>
30
31 #include <string.h>
32
33 #include "globals.h"
34 #include "gui_prefs.h"
35 #include "gtkglobals.h"
36 #include "help_dlg.h"
37 #include "supported_protos_dlg.h"
38 #include "prefs.h"
39 #include "prefs_dlg.h"
40 #include "ui_util.h"
41 #include "simple_dialog.h"
42 #include "dlg_utils.h"
43 #include "proto_draw.h"
44 #include "main.h"
45 #include "packet_list.h"
46 #include "compat_macros.h"
47 #include "toolbar.h"
48 #include "recent.h"
49
50 static gint fetch_enum_value(gpointer control, const enum_val_t *enumvals);
51 static gint fileopen_dir_changed_cb(GtkWidget *myentry _U_, GdkEvent *event, gpointer parent_w);
52 static void fileopen_selected_cb(GtkWidget *mybutton_rb _U_, gpointer parent_w);
53 static gint recent_files_count_changed_cb(GtkWidget *recent_files_entry _U_, 
54                                           GdkEvent *event _U_, gpointer parent_w);
55
56 #define SCROLLBAR_PLACEMENT_KEY         "scrollbar_placement"
57 #define PLIST_SEL_BROWSE_KEY            "plist_sel_browse"
58 #define PTREE_SEL_BROWSE_KEY            "ptree_sel_browse"
59 #if GTK_MAJOR_VERSION < 2
60 #define PTREE_LINE_STYLE_KEY            "ptree_line_style"
61 #define PTREE_EXPANDER_STYLE_KEY        "ptree_expander_style"
62 #else
63 #define ALTERN_COLORS_KEY               "altern_colors"
64 #endif
65 #define FILTER_TOOLBAR_PLACEMENT_KEY    "filter_toolbar_show_in_statusbar"
66 #define HEX_DUMP_HIGHLIGHT_STYLE_KEY    "hex_dump_highlight_style"
67 #define GEOMETRY_POSITION_KEY           "geometry_position"
68 #define GEOMETRY_SIZE_KEY               "geometry_size"
69 #define GEOMETRY_MAXIMIZED_KEY          "geometry_maximized"
70
71 #define GUI_CONSOLE_OPEN_KEY "console_open"
72 #define GUI_FILEOPEN_KEY        "fileopen_behavior"
73 #define GUI_RECENT_FILES_COUNT_KEY "recent_files_count"
74 #define GUI_FILEOPEN_DIR_KEY    "fileopen_directory"
75
76 #define GUI_TOOLBAR_STYLE_KEY   "toolbar_style"
77
78 static const enum_val_t scrollbar_placement_vals[] = {
79         { "FALSE", "Left", FALSE },
80         { "TRUE",  "Right", TRUE },
81         { NULL,    NULL,    0 }
82 };
83
84 static const enum_val_t selection_mode_vals[] = {
85         { "FALSE", "Selects", FALSE },
86         { "TRUE",  "Browses", TRUE },
87         { NULL,    NULL,      0 }
88 };
89
90 #if GTK_MAJOR_VERSION < 2
91 static const enum_val_t line_style_vals[] = {
92         { "NONE",   "None",   0 },
93         { "SOLID",  "Solid",  1 },
94         { "DOTTED", "Dotted", 2 },
95         { "TABBED", "Tabbed", 3 },
96         { NULL,     NULL,     0 }
97 };
98
99 static const enum_val_t expander_style_vals[] = {
100         { "NONE",     "None",     0 },
101         { "SQUARE",   "Square",   1 },
102         { "TRIANGLE", "Triangle", 2 },
103         { "CIRCULAR", "Circular", 3 },
104         { NULL,       NULL,       0 }
105 };
106 #else
107 static const enum_val_t altern_colors_vals[] = {
108         { "FALSE", "No",  FALSE },
109         { "TRUE",  "Yes", TRUE },
110         { NULL,    NULL,  0 }
111 };
112 #endif
113
114 static const enum_val_t filter_toolbar_placement_vals[] = {
115         { "FALSE", "Below the main toolbar", FALSE },
116         { "TRUE",  "Insert into statusbar",  TRUE },
117         { NULL,    NULL,                     0 }
118 };
119
120 static const enum_val_t highlight_style_vals[] = {
121         { "FALSE", "Bold",     FALSE },
122         { "TRUE",  "Inverse",  TRUE },
123         { NULL,    NULL,       0 }
124 };
125
126 static const enum_val_t toolbar_style_vals[] = {
127         { "ICONS", "Icons only",     TB_STYLE_ICONS },
128         { "TEXT",  "Text only",      TB_STYLE_TEXT },
129         { "BOTH",  "Icons & Text",   TB_STYLE_BOTH },
130         { NULL,    NULL,             0 }
131 };
132
133 #ifdef _WIN32
134 static const enum_val_t gui_console_open_vals[] = {
135         { "NEVER",     "Never",                      console_open_never },
136         { "AUTOMATIC", "Automatic (advanced user)",  console_open_auto },
137         { "ALWAYS",    "Always (debugging)",         console_open_always },
138         { NULL,        NULL,                         0 }
139 };
140 #endif
141
142 static const enum_val_t gui_fileopen_vals[] = {
143         { "LAST_OPENED", "Remember last directory", FO_STYLE_LAST_OPENED },
144         { "SPECIFIED",   "Always start in:",        FO_STYLE_SPECIFIED },
145         { NULL,          NULL,                      0 }
146 };
147
148 /* Set to FALSE initially; set to TRUE if the user ever hits "OK" on
149    the "Font..." dialog, so that we know that they (probably) changed
150    the font, and therefore that the "apply" function needs to take care
151    of that */
152 static gboolean font_changed;
153
154 /* Font name from the font dialog box; if "font_changed" is TRUE, this
155    has been set to the name of the font the user selected. */
156 static gchar *new_font_name;
157
158 static GtkWidget *font_browse_w;
159
160 /* Used to contain the string from the Recent Files Count Max pref item */
161 static char recent_files_count_max_str[128] = "";
162
163 #if GTK_MAJOR_VERSION < 2
164 #define GUI_TABLE_ROWS 10
165 #else
166 #define GUI_TABLE_ROWS 9
167 #endif
168
169 GtkWidget*
170 gui_prefs_show(void)
171 {
172         GtkWidget *main_tb, *main_vb, *hbox;
173         GtkWidget *scrollbar_om, *plist_browse_om;
174         GtkWidget *ptree_browse_om, *highlight_style_om;
175 #ifdef _WIN32
176         GtkWidget *console_open_om;
177 #endif
178         GtkWidget *fileopen_rb, *fileopen_dir_te, *toolbar_style_om;
179     GtkWidget *filter_toolbar_placement_om;
180         GtkWidget *recent_files_count_max_te;
181         GtkWidget *save_position_cb, *save_size_cb, *save_maximized_cb;
182 #if GTK_MAJOR_VERSION < 2
183         GtkWidget *expander_style_om, *line_style_om;
184 #else
185         GtkWidget *altern_colors_om;
186 #endif
187         int        pos = 0;
188         char       current_val_str[128];
189
190         /* The font haven't been changed yet. */
191         font_changed = FALSE;
192
193         /* Main vertical box */
194         main_vb = gtk_vbox_new(FALSE, 7);
195         gtk_container_border_width( GTK_CONTAINER(main_vb), 5 );
196
197         /* Main horizontal box  */
198         /* XXX - Is there a better way to center the table? */
199         hbox = gtk_hbox_new(FALSE, 7);
200         gtk_box_pack_start (GTK_BOX(main_vb), hbox, TRUE, FALSE, 0);
201
202         /* Main table */
203         main_tb = gtk_table_new(GUI_TABLE_ROWS, 2, FALSE);
204         gtk_box_pack_start( GTK_BOX(hbox), main_tb, TRUE, FALSE, 0 );
205         gtk_table_set_row_spacings( GTK_TABLE(main_tb), 10 );
206         gtk_table_set_col_spacings( GTK_TABLE(main_tb), 15 );
207         gtk_table_set_col_spacing( GTK_TABLE(main_tb), 0, 50 );
208
209         /* Scrollbar placement */
210         scrollbar_om = create_preference_option_menu(main_tb, pos++,
211             "Vertical scrollbar placement:", NULL, scrollbar_placement_vals,
212             prefs.gui_scrollbar_on_right);
213         OBJECT_SET_DATA(main_vb, SCROLLBAR_PLACEMENT_KEY, scrollbar_om);
214
215         /* Packet list selection browseable */
216         plist_browse_om = create_preference_option_menu(main_tb, pos++,
217             "Packet list selection mode:", NULL, selection_mode_vals,
218             prefs.gui_plist_sel_browse);
219         OBJECT_SET_DATA(main_vb, PLIST_SEL_BROWSE_KEY, plist_browse_om);
220
221         /* Proto tree selection browseable */
222         ptree_browse_om = create_preference_option_menu(main_tb, pos++,
223             "Protocol tree selection mode:", NULL, selection_mode_vals,
224             prefs.gui_ptree_sel_browse);
225         OBJECT_SET_DATA(main_vb, PTREE_SEL_BROWSE_KEY, ptree_browse_om);
226
227 #if GTK_MAJOR_VERSION < 2
228         /* Tree line style */
229         line_style_om = create_preference_option_menu(main_tb, pos++,
230             "Tree line style:", NULL, line_style_vals,
231             prefs.gui_ptree_line_style);
232         OBJECT_SET_DATA(main_vb, PTREE_LINE_STYLE_KEY, line_style_om);
233
234         /* Tree expander style */
235         expander_style_om = create_preference_option_menu(main_tb, pos++,
236             "Tree expander style:", NULL, expander_style_vals,
237             prefs.gui_ptree_expander_style);
238         OBJECT_SET_DATA(main_vb, PTREE_EXPANDER_STYLE_KEY, expander_style_om);
239 #else
240         /* Alternating row colors in list and tree views */
241         altern_colors_om = create_preference_option_menu(main_tb, pos++,
242             "Alternating row colors in lists and trees:", NULL,
243             altern_colors_vals, prefs.gui_altern_colors);
244         OBJECT_SET_DATA(main_vb, ALTERN_COLORS_KEY, altern_colors_om);
245 #endif
246
247         /* Hex Dump highlight style */
248         highlight_style_om = create_preference_option_menu(main_tb, pos++,
249             "Hex display highlight style:", NULL, highlight_style_vals,
250             prefs.gui_hex_dump_highlight_style);
251         OBJECT_SET_DATA(main_vb, HEX_DUMP_HIGHLIGHT_STYLE_KEY,
252             highlight_style_om);
253
254         /* Toolbar prefs */
255         toolbar_style_om = create_preference_option_menu(main_tb, pos++,
256             "Toolbar style:", NULL, toolbar_style_vals,
257             prefs.gui_toolbar_main_style);
258         OBJECT_SET_DATA(main_vb, GUI_TOOLBAR_STYLE_KEY,
259             toolbar_style_om);
260
261     /* Placement of Filter toolbar */
262     filter_toolbar_placement_om = create_preference_option_menu(main_tb, pos++,
263        "Filter toolbar placement:", NULL,
264        filter_toolbar_placement_vals, prefs.filter_toolbar_show_in_statusbar);
265     OBJECT_SET_DATA(main_vb, FILTER_TOOLBAR_PLACEMENT_KEY, filter_toolbar_placement_om);
266
267         /* Geometry prefs */
268         save_position_cb = create_preference_check_button(main_tb, pos++,
269             "Save window position:", NULL, prefs.gui_geometry_save_position);
270         OBJECT_SET_DATA(main_vb, GEOMETRY_POSITION_KEY, save_position_cb);
271
272         save_size_cb = create_preference_check_button(main_tb, pos++,
273             "Save window size:", NULL, prefs.gui_geometry_save_size);
274         OBJECT_SET_DATA(main_vb, GEOMETRY_SIZE_KEY, save_size_cb);
275
276         save_maximized_cb = create_preference_check_button(main_tb, pos++,
277             "Save maximized state:", NULL, prefs.gui_geometry_save_maximized);
278         OBJECT_SET_DATA(main_vb, GEOMETRY_MAXIMIZED_KEY, save_maximized_cb);
279
280 #ifdef _WIN32
281         /* How the console window should be opened */
282     console_open_om = create_preference_option_menu(main_tb, pos++,
283        "Open a console window", NULL,
284        gui_console_open_vals, prefs.gui_console_open);
285         OBJECT_SET_DATA(main_vb, GUI_CONSOLE_OPEN_KEY, console_open_om);
286 #endif
287
288         /* Allow user to select where they want the File Open dialog to open to
289          * by default */
290         fileopen_rb = create_preference_radio_buttons(main_tb, pos++,
291             "\"File Open\" dialog behavior:", NULL, gui_fileopen_vals,
292             prefs.gui_fileopen_style);
293
294         /* Directory to default File Open dialog to */
295         fileopen_dir_te = create_preference_entry(main_tb, pos++, 
296         "Directory:", NULL, prefs.gui_fileopen_dir);
297         OBJECT_SET_DATA(main_vb, GUI_FILEOPEN_KEY, fileopen_rb);
298         OBJECT_SET_DATA(main_vb, GUI_FILEOPEN_DIR_KEY, fileopen_dir_te);
299         SIGNAL_CONNECT(fileopen_rb, "clicked", fileopen_selected_cb, main_vb);
300         SIGNAL_CONNECT(fileopen_dir_te, "focus-out-event",
301             fileopen_dir_changed_cb, main_vb);
302
303         /* Number of entries in the recent_files list ... */
304         recent_files_count_max_te = create_preference_entry(main_tb, pos++,
305             "\"Open Recent\" max. list entries:", "Maximum number of recent files", recent_files_count_max_str);
306         g_snprintf(current_val_str, 128, "%d", prefs.gui_recent_files_count_max);
307         gtk_entry_set_text(GTK_ENTRY(recent_files_count_max_te), current_val_str);
308         OBJECT_SET_DATA(main_vb, GUI_RECENT_FILES_COUNT_KEY, recent_files_count_max_te);
309         SIGNAL_CONNECT(recent_files_count_max_te, "focus_out_event", recent_files_count_changed_cb, main_vb);
310
311         fileopen_selected_cb(NULL, main_vb);        
312
313         /* Show 'em what we got */
314         gtk_widget_show_all(main_vb);
315
316         return(main_vb);
317 }
318
319
320 /* Create a font widget for browsing. */
321 GtkWidget *
322 gui_font_prefs_show(void)
323 {
324         /* Create the font selection widget. */
325         font_browse_w = (GtkWidget *) gtk_font_selection_new();
326         gtk_widget_show(font_browse_w);
327
328         return font_browse_w;
329 }
330
331
332 static gboolean
333 font_fetch(void)
334 {
335         gchar   *font_name;
336 #if GTK_MAJOR_VERSION < 2
337         gchar   *bold_font_name;
338         GdkFont *new_r_font, *new_b_font;
339 #else
340         PangoFontDescription *new_r_font, *new_b_font;
341 #endif
342
343         font_name = g_strdup(gtk_font_selection_get_font_name(
344               GTK_FONT_SELECTION(font_browse_w)));
345         if (font_name == NULL) {
346                 /* No font was selected; let the user know, but don't
347                    tear down the font selection dialog, so they can
348                    try again. */
349                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
350                    "You have not selected a font.");
351                 return FALSE;
352         }
353
354 #if GTK_MAJOR_VERSION < 2
355         /* Get the name that the boldface version of that font would have. */
356         bold_font_name = font_boldify(font_name);
357
358         /* Now load those fonts, just to make sure we can. */
359         new_r_font = gdk_font_load(font_name);
360 #else
361         new_r_font = pango_font_description_from_string(font_name);
362 #endif
363         if (new_r_font == NULL) {
364                 /* Oops, that font didn't work.
365                    Tell the user, but don't tear down the font selection
366                    dialog, so that they can try again. */
367                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
368                    "The font you selected cannot be loaded.");
369
370                 g_free(font_name);
371 #if GTK_MAJOR_VERSION < 2
372                 g_free(bold_font_name);
373 #endif
374                 return FALSE;
375         }
376
377 #if GTK_MAJOR_VERSION < 2
378         new_b_font = gdk_font_load(bold_font_name);
379 #else
380         new_b_font = pango_font_description_copy(new_r_font);
381         pango_font_description_set_weight(new_b_font, PANGO_WEIGHT_BOLD);
382 #endif
383         if (new_b_font == NULL) {
384                 /* Oops, that font didn't work.
385                    Tell the user, but don't tear down the font selection
386                    dialog, so that they can try again. */
387                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
388                    "The font you selected doesn't have a boldface version.");
389
390                 g_free(font_name);
391 #if GTK_MAJOR_VERSION < 2
392                 g_free(bold_font_name);
393                 gdk_font_unref(new_r_font);
394 #else
395                 pango_font_description_free(new_r_font);
396 #endif
397                 return FALSE;
398         }
399
400         new_font_name = font_name;
401         return TRUE;
402 }
403
404
405 static gint
406 fetch_enum_value(gpointer control, const enum_val_t *enumvals)
407 {
408         return fetch_preference_option_menu_val(GTK_WIDGET(control), enumvals);
409 }
410
411 void
412 gui_prefs_fetch(GtkWidget *w)
413 {
414         prefs.gui_scrollbar_on_right = fetch_enum_value(
415             OBJECT_GET_DATA(w, SCROLLBAR_PLACEMENT_KEY),
416             scrollbar_placement_vals);
417         prefs.gui_plist_sel_browse = fetch_enum_value(
418             OBJECT_GET_DATA(w, PLIST_SEL_BROWSE_KEY), selection_mode_vals);
419         prefs.gui_ptree_sel_browse = fetch_enum_value(
420             OBJECT_GET_DATA(w, PTREE_SEL_BROWSE_KEY), selection_mode_vals);
421 #if GTK_MAJOR_VERSION < 2
422         prefs.gui_ptree_line_style = fetch_enum_value(
423             OBJECT_GET_DATA(w, PTREE_LINE_STYLE_KEY), line_style_vals);
424         prefs.gui_ptree_expander_style = fetch_enum_value(
425             OBJECT_GET_DATA(w, PTREE_EXPANDER_STYLE_KEY), expander_style_vals);
426 #else
427         prefs.gui_altern_colors = fetch_enum_value(
428             OBJECT_GET_DATA(w, ALTERN_COLORS_KEY), altern_colors_vals);
429 #endif
430     prefs.filter_toolbar_show_in_statusbar = fetch_enum_value(
431         OBJECT_GET_DATA(w, FILTER_TOOLBAR_PLACEMENT_KEY), filter_toolbar_placement_vals);
432         prefs.gui_hex_dump_highlight_style = fetch_enum_value(
433             OBJECT_GET_DATA(w, HEX_DUMP_HIGHLIGHT_STYLE_KEY),
434             highlight_style_vals);
435         prefs.gui_toolbar_main_style = fetch_enum_value(
436             OBJECT_GET_DATA(w, GUI_TOOLBAR_STYLE_KEY),
437             toolbar_style_vals);        
438         prefs.gui_geometry_save_position =
439             gtk_toggle_button_get_active(OBJECT_GET_DATA(w,
440                 GEOMETRY_POSITION_KEY));
441         prefs.gui_geometry_save_size =
442             gtk_toggle_button_get_active(OBJECT_GET_DATA(w, GEOMETRY_SIZE_KEY));
443         prefs.gui_geometry_save_maximized =
444             gtk_toggle_button_get_active(OBJECT_GET_DATA(w, GEOMETRY_MAXIMIZED_KEY));
445 #ifdef _WIN32
446         prefs.gui_console_open = fetch_enum_value(
447             OBJECT_GET_DATA(w, GUI_CONSOLE_OPEN_KEY), gui_console_open_vals);
448 #endif
449         prefs.gui_fileopen_style = fetch_preference_radio_buttons_val(
450             OBJECT_GET_DATA(w, GUI_FILEOPEN_KEY), gui_fileopen_vals);
451             
452         if (prefs.gui_fileopen_dir != NULL)
453                 g_free(prefs.gui_fileopen_dir);
454         prefs.gui_fileopen_dir = g_strdup(gtk_entry_get_text(
455                 GTK_ENTRY(OBJECT_GET_DATA(w, GUI_FILEOPEN_DIR_KEY))));
456
457         /*
458          * XXX - we need to have a way to fetch the preferences into
459          * local storage and only set the permanent preferences if there
460          * weren't any errors in those fetches, as there are several
461          * places where there *can* be a bad preference value.
462          */
463         if (font_fetch()) {
464                 if (strcmp(new_font_name, prefs.PREFS_GUI_FONT_NAME) != 0) {
465                         font_changed = TRUE;
466                         if (prefs.PREFS_GUI_FONT_NAME != NULL)
467                                 g_free(prefs.PREFS_GUI_FONT_NAME);
468                         prefs.PREFS_GUI_FONT_NAME = g_strdup(new_font_name);
469                 }
470         }
471 }
472
473
474
475 void
476 gui_prefs_apply(GtkWidget *w _U_)
477 {
478
479 #ifdef _WIN32
480     /* user immediately wants to see a console */
481     if (prefs.gui_console_open == console_open_always) {
482         create_console();
483     }
484 #endif
485
486         if (font_changed) {
487                 /* This redraws the hex dump windows. */
488                 switch (font_apply()) {
489
490                 case FA_SUCCESS:
491                         break;
492
493                 case FA_FONT_NOT_RESIZEABLE:
494                         /* "font_apply()" popped up an alert box. */
495                         /* turn off zooming - font can't be resized */
496                         recent.gui_zoom_level = 0;
497                         break;
498
499                 case FA_FONT_NOT_AVAILABLE:
500                         /* We assume this means that the specified size
501                            isn't available. */
502                         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
503                             "That font isn't available at the specified zoom level;\n"
504                             "turning zooming off.");
505                         recent.gui_zoom_level = 0;
506                         break;
507                 }
508         } else {
509                 /* Redraw the hex dump windows, in case the
510                    highlight style changed.
511                    XXX - do it only if the highlight style *did* change. */
512                 redraw_hex_dump_all();
513         }
514
515         /* Redraw the help window(s). */
516         supported_redraw();
517         help_redraw();
518
519         /* XXX: redraw the toolbar only, if style changed */
520         toolbar_redraw_all();
521         
522         set_scrollbar_placement_all();
523         set_plist_sel_browse(prefs.gui_plist_sel_browse);
524         set_ptree_sel_browse_all(prefs.gui_ptree_sel_browse);
525         set_tree_styles_all();
526     main_widgets_rearrange();
527 }
528
529 void
530 gui_prefs_destroy(GtkWidget *w _U_)
531 {
532         /* Free up any saved font name. */
533         if (new_font_name != NULL) {
534                 g_free(new_font_name);
535                 new_font_name = NULL;
536         }
537 }
538
539
540 static gint
541 recent_files_count_changed_cb(GtkWidget *recent_files_entry _U_, 
542                               GdkEvent *event _U_, gpointer parent_w)
543 {
544     GtkWidget   *recent_files_count_te;
545     guint newval;
546     
547     recent_files_count_te = (GtkWidget *)OBJECT_GET_DATA(parent_w, GUI_RECENT_FILES_COUNT_KEY);
548
549     /*
550      * Now, just convert the string to a number and store it in the prefs
551      * filed ...
552      */
553
554     newval = strtol(gtk_entry_get_text (GTK_ENTRY(recent_files_count_te)), NULL, 10);
555
556     if (newval > 0) {
557       prefs.gui_recent_files_count_max = newval;
558     }
559
560     /* We really should pop up a nasty dialog box if newval <= 0 */
561
562     return TRUE;
563 }
564
565 static gint
566 fileopen_dir_changed_cb(GtkWidget *fileopen_entry _U_, GdkEvent *event _U_, gpointer parent_w)
567 {
568     GtkWidget   *fileopen_dir_te;
569     char *lastchar;
570     gint fileopen_dir_te_length;
571     
572     fileopen_dir_te = (GtkWidget *)OBJECT_GET_DATA(parent_w, GUI_FILEOPEN_DIR_KEY);
573     fileopen_dir_te_length = strlen(gtk_entry_get_text (GTK_ENTRY(fileopen_entry)));
574     if (fileopen_dir_te_length == 0)
575         return FALSE;
576     lastchar = gtk_editable_get_chars(GTK_EDITABLE(fileopen_entry), fileopen_dir_te_length-1, -1);
577     if (strcmp(lastchar, G_DIR_SEPARATOR_S) != 0)
578         gtk_entry_append_text(GTK_ENTRY(fileopen_entry), G_DIR_SEPARATOR_S);
579     return FALSE;
580 }
581
582 static void
583 fileopen_selected_cb(GtkWidget *mybutton_rb _U_, gpointer parent_w)
584 {
585     GtkWidget   *fileopen_rb, *fileopen_dir_te;
586     
587     fileopen_rb = (GtkWidget *)OBJECT_GET_DATA(parent_w, GUI_FILEOPEN_KEY);
588     fileopen_dir_te = (GtkWidget *)OBJECT_GET_DATA(parent_w, GUI_FILEOPEN_DIR_KEY);
589     
590     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(fileopen_rb)))
591     {
592         gtk_widget_set_sensitive(GTK_WIDGET(fileopen_dir_te), TRUE);
593     }
594     else
595     {
596         gtk_widget_set_sensitive(GTK_WIDGET(fileopen_dir_te), FALSE);
597     }
598     return;
599 }