2 * Dialog box for GUI preferences
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
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.
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.
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.
32 #include <epan/prefs.h>
34 #include "../globals.h"
35 #include "../simple_dialog.h"
37 #include "gtk/prefs_gui.h"
38 #include "gtk/gtkglobals.h"
39 #include "gtk/help_dlg.h"
40 #include "gtk/supported_protos_dlg.h"
41 #include "gtk/prefs_dlg.h"
42 #include "gtk/gui_utils.h"
43 #include "gtk/dlg_utils.h"
45 #include "gtk/main_packet_list.h"
46 #include "gtk/main_proto_draw.h"
47 #include "gtk/main_toolbar.h"
48 #include "gtk/font_utils.h"
49 #include "gtk/recent.h"
50 #include "gtk/webbrowser.h"
53 static gint fetch_enum_value(gpointer control, const enum_val_t *enumvals);
54 static gint fileopen_dir_changed_cb(GtkWidget *myentry _U_, GdkEvent *event, gpointer parent_w);
55 static gint fileopen_preview_changed_cb(GtkWidget *myentry _U_, GdkEvent *event, gpointer parent_w);
56 static void fileopen_selected_cb(GtkWidget *mybutton_rb _U_, gpointer parent_w);
57 static gint recent_files_count_changed_cb(GtkWidget *recent_files_entry _U_,
58 GdkEvent *event _U_, gpointer parent_w);
59 #define PLIST_SEL_BROWSE_KEY "plist_sel_browse"
60 #define PTREE_SEL_BROWSE_KEY "ptree_sel_browse"
61 #define GEOMETRY_POSITION_KEY "geometry_position"
62 #define GEOMETRY_SIZE_KEY "geometry_size"
63 #define GEOMETRY_MAXIMIZED_KEY "geometry_maximized"
64 #define GEOMETRY_COLUMN_WIDTH_KEY "geometry_column_width"
66 #define GUI_CONSOLE_OPEN_KEY "console_open"
67 #define GUI_FILEOPEN_KEY "fileopen_behavior"
68 #define GUI_FILEOPEN_PREVIEW_KEY "fileopen_preview_timeout"
69 #define GUI_RECENT_FILES_COUNT_KEY "recent_files_count"
70 #define GUI_FILEOPEN_DIR_KEY "fileopen_directory"
71 #define GUI_ASK_UNSAVED_KEY "ask_unsaved"
72 #define GUI_WEBBROWSER_KEY "webbrowser"
73 #define GUI_FIND_WRAP_KEY "find_wrap"
74 #define GUI_USE_PREF_SAVE_KEY "use_pref_save"
76 static const enum_val_t scrollbar_placement_vals[] _U_ = {
77 { "FALSE", "Left", FALSE },
78 { "TRUE", "Right", TRUE },
82 static const enum_val_t selection_mode_vals[] = {
83 { "FALSE", "Selects", FALSE },
84 { "TRUE", "Browses", TRUE },
88 static const enum_val_t altern_colors_vals[] _U_ = {
89 { "FALSE", "No", FALSE },
90 { "TRUE", "Yes", TRUE },
94 static const enum_val_t filter_toolbar_placement_vals[] _U_ = {
95 { "FALSE", "Below the main toolbar", FALSE },
96 { "TRUE", "Insert into statusbar", TRUE },
100 static const enum_val_t highlight_style_vals[] _U_ = {
101 { "FALSE", "Bold", FALSE },
102 { "TRUE", "Inverse", TRUE },
107 static const enum_val_t toolbar_style_vals[] _U_ = {
108 { "ICONS", "Icons only", TB_STYLE_ICONS },
109 { "TEXT", "Text only", TB_STYLE_TEXT },
110 { "BOTH", "Icons & Text", TB_STYLE_BOTH },
115 static const enum_val_t gui_console_open_vals[] = {
116 { "NEVER", "Never", console_open_never },
117 { "AUTOMATIC", "Automatic (advanced user)", console_open_auto },
118 { "ALWAYS", "Always (debugging)", console_open_always },
123 static const enum_val_t gui_fileopen_vals[] = {
124 { "LAST_OPENED", "Remember last directory", FO_STYLE_LAST_OPENED },
125 { "SPECIFIED", "Always start in:", FO_STYLE_SPECIFIED },
129 /* Set to FALSE initially; set to TRUE if the user ever hits "OK" on
130 the "Font..." dialog, so that we know that they (probably) changed
131 the font, and therefore that the "apply" function needs to take care
133 static gboolean font_changed;
135 /* Font name from the font dialog box; if "font_changed" is TRUE, this
136 has been set to the name of the font the user selected. */
137 static gchar *new_font_name;
139 static GtkWidget *font_browse_w;
141 /* Used to contain the string from the Recent Files Count Max pref item */
142 static char recent_files_count_max_str[128] = "";
144 /* Used to contain the string from the Open File preview timeout pref item */
145 static char open_file_preview_str[128] = "";
147 #define GUI_TABLE_ROWS 4
152 GtkWidget *main_tb, *main_vb;
153 GtkWidget *plist_browse_om;
154 GtkWidget *ptree_browse_om;
156 GtkWidget *console_open_om;
158 GtkWidget *fileopen_rb, *fileopen_dir_te, *fileopen_preview_te;
159 GtkWidget *recent_files_count_max_te, *ask_unsaved_cb, *find_wrap_cb;
160 GtkWidget *use_pref_save_cb;
161 GtkWidget *webbrowser_te;
162 GtkWidget *save_position_cb, *save_size_cb, *save_maximized_cb, *save_column_width_cb;
164 GtkTooltips *tooltips = gtk_tooltips_new();
167 char current_val_str[128];
169 /* The font haven't been changed yet. */
170 font_changed = FALSE;
172 /* The columns haven't been changed yet */
173 cfile.cinfo.columns_changed = FALSE;
175 /* Main vertical box */
176 main_vb = gtk_vbox_new(FALSE, 7);
177 gtk_container_border_width( GTK_CONTAINER(main_vb), 5 );
180 main_tb = gtk_table_new(GUI_TABLE_ROWS, 2, FALSE);
181 gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0);
182 gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10);
183 gtk_table_set_col_spacings(GTK_TABLE(main_tb), 15);
185 /* Packet list selection browseable */
186 plist_browse_om = create_preference_option_menu(main_tb, pos++,
187 "Packet list selection mode:", NULL, selection_mode_vals,
188 prefs.gui_plist_sel_browse);
189 gtk_tooltips_set_tip(tooltips, plist_browse_om, "Choose to browse "
190 "or select a packet for detailed dissection.", NULL);
191 g_object_set_data(G_OBJECT(main_vb), PLIST_SEL_BROWSE_KEY, plist_browse_om);
193 /* Proto tree selection browseable */
194 ptree_browse_om = create_preference_option_menu(main_tb, pos++,
195 "Protocol tree selection mode:", NULL, selection_mode_vals,
196 prefs.gui_ptree_sel_browse);
197 gtk_tooltips_set_tip(tooltips, ptree_browse_om, "Choose to browse "
199 g_object_set_data(G_OBJECT(main_vb), PTREE_SEL_BROWSE_KEY, ptree_browse_om);
202 save_position_cb = create_preference_check_button(main_tb, pos++,
203 "Save window position:", NULL, prefs.gui_geometry_save_position);
204 gtk_tooltips_set_tip(tooltips, save_position_cb, "Whether to save the "
205 "position of the main window.", NULL);
206 g_object_set_data(G_OBJECT(main_vb), GEOMETRY_POSITION_KEY, save_position_cb);
208 save_size_cb = create_preference_check_button(main_tb, pos++,
209 "Save window size:", NULL, prefs.gui_geometry_save_size);
210 gtk_tooltips_set_tip(tooltips, save_size_cb, "Whether to save the "
211 "size of the main window.", NULL);
212 g_object_set_data(G_OBJECT(main_vb), GEOMETRY_SIZE_KEY, save_size_cb);
214 save_maximized_cb = create_preference_check_button(main_tb, pos++,
215 "Save maximized state:", NULL, prefs.gui_geometry_save_maximized);
216 gtk_tooltips_set_tip(tooltips, save_maximized_cb, "Whether to save the "
217 "maximed state of the main window.", NULL);
218 g_object_set_data(G_OBJECT(main_vb), GEOMETRY_MAXIMIZED_KEY, save_maximized_cb);
220 save_column_width_cb = create_preference_check_button(main_tb, pos++,
221 "Save column widths:", NULL, prefs.gui_geometry_save_column_width);
222 gtk_tooltips_set_tip(tooltips, save_column_width_cb, "Whether to save the "
223 "column widths.", NULL);
224 g_object_set_data(G_OBJECT(main_vb), GEOMETRY_COLUMN_WIDTH_KEY, save_column_width_cb);
227 /* How the console window should be opened */
228 console_open_om = create_preference_option_menu(main_tb, pos++,
229 "Open a console window", NULL, gui_console_open_vals,
230 prefs.gui_console_open);
231 gtk_tooltips_set_tip(tooltips, console_open_om, "Whether to open a console window "
232 "(Automatic will open a console if messages appear).", NULL);
233 g_object_set_data(G_OBJECT(main_vb), GUI_CONSOLE_OPEN_KEY, console_open_om);
236 /* Allow user to select where they want the File Open dialog to open to
238 fileopen_rb = create_preference_radio_buttons(main_tb, pos++,
239 "\"File Open\" dialog behavior:",
240 "Which directory the \"File Open\" dialog should start with.", gui_fileopen_vals,
241 prefs.gui_fileopen_style);
243 /* Directory to default File Open dialog to */
244 fileopen_dir_te = create_preference_entry(main_tb, pos++,
245 "Directory:", NULL, prefs.gui_fileopen_dir);
246 gtk_tooltips_set_tip(tooltips, fileopen_dir_te,
247 "The \"File Open\" dialog defaults always to this directory.", NULL);
248 g_object_set_data(G_OBJECT(main_vb), GUI_FILEOPEN_KEY, fileopen_rb);
249 g_object_set_data(G_OBJECT(main_vb), GUI_FILEOPEN_DIR_KEY, fileopen_dir_te);
250 g_signal_connect(fileopen_rb, "clicked", G_CALLBACK(fileopen_selected_cb), main_vb);
251 g_signal_connect(fileopen_dir_te, "focus-out-event",
252 G_CALLBACK(fileopen_dir_changed_cb), main_vb);
254 /* File Open dialog preview timeout */
255 fileopen_preview_te = create_preference_entry(main_tb, pos++,
256 "\"File Open\" preview timeout:", "Timeout, until preview gives up scanning the capture file content.", open_file_preview_str);
257 g_snprintf(current_val_str, 128, "%d", prefs.gui_fileopen_preview);
258 gtk_entry_set_text(GTK_ENTRY(fileopen_preview_te), current_val_str);
259 gtk_tooltips_set_tip(tooltips, fileopen_preview_te,
260 "Reading preview data in the \"File Open\" dialog will be stopped after given seconds.", NULL);
261 g_object_set_data(G_OBJECT(main_vb), GUI_FILEOPEN_PREVIEW_KEY, fileopen_preview_te);
262 g_signal_connect(fileopen_preview_te, "focus_out_event", G_CALLBACK(fileopen_preview_changed_cb), main_vb);
264 /* Number of entries in the recent_files list ... */
265 recent_files_count_max_te = create_preference_entry(main_tb, pos++,
266 "\"Open Recent\" max. list entries:", "Maximum number of recent files", recent_files_count_max_str);
267 g_snprintf(current_val_str, 128, "%d", prefs.gui_recent_files_count_max);
268 gtk_entry_set_text(GTK_ENTRY(recent_files_count_max_te), current_val_str);
269 gtk_tooltips_set_tip(tooltips, recent_files_count_max_te,
270 "Maximum number of entries in the \"File/Open Recent\" list.", NULL);
271 g_object_set_data(G_OBJECT(main_vb), GUI_RECENT_FILES_COUNT_KEY, recent_files_count_max_te);
272 g_signal_connect(recent_files_count_max_te, "focus_out_event", G_CALLBACK(recent_files_count_changed_cb), main_vb);
274 fileopen_selected_cb(NULL, main_vb);
276 /* ask for unsaved capture files? */
277 ask_unsaved_cb = create_preference_check_button(main_tb, pos++,
278 "Ask for unsaved capture files:", NULL, prefs.gui_ask_unsaved);
279 gtk_tooltips_set_tip(tooltips, ask_unsaved_cb, "Whether a dialog should "
280 "pop up in case of an unsaved capture file.", NULL);
281 g_object_set_data(G_OBJECT(main_vb), GUI_ASK_UNSAVED_KEY, ask_unsaved_cb);
283 /* do we want to wrap when searching for data? */
284 find_wrap_cb = create_preference_check_button(main_tb, pos++,
285 "Wrap to end/beginning of file during a find:", NULL, prefs.gui_find_wrap);
286 gtk_tooltips_set_tip(tooltips, find_wrap_cb, "Whether a search should "
287 "wrap in a capture file.", NULL);
288 g_object_set_data(G_OBJECT(main_vb), GUI_FIND_WRAP_KEY, find_wrap_cb);
290 /* show an explicit Save button for settings dialogs (preferences and alike)? */
291 use_pref_save_cb = create_preference_check_button(main_tb, pos++,
292 "Settings dialogs show a save button:", NULL, prefs.gui_use_pref_save);
293 gtk_tooltips_set_tip(tooltips, use_pref_save_cb,
294 "Whether the various settings dialogs (e.g. Preferences) should "
295 "use an explicit save button - for advanced users.", NULL);
296 g_object_set_data(G_OBJECT(main_vb), GUI_USE_PREF_SAVE_KEY, use_pref_save_cb);
299 if (browser_needs_pref()) {
300 webbrowser_te = create_preference_entry(main_tb, pos++,
301 "Web browser command:", NULL, prefs.gui_webbrowser);
302 gtk_entry_set_text(GTK_ENTRY(webbrowser_te), prefs.gui_webbrowser);
303 gtk_tooltips_set_tip(tooltips, webbrowser_te, "Command line to "
304 "desired browser.", NULL);
305 g_object_set_data(G_OBJECT(main_vb), GUI_WEBBROWSER_KEY, webbrowser_te);
308 /* Show 'em what we got */
309 gtk_widget_show_all(main_vb);
315 /* Create a font widget for browsing. */
317 gui_font_prefs_show(void)
319 /* Create the font selection widget. */
320 font_browse_w = (GtkWidget *) gtk_font_selection_new();
321 gtk_widget_show(font_browse_w);
323 return font_browse_w;
332 font_name = g_strdup(gtk_font_selection_get_font_name(
333 GTK_FONT_SELECTION(font_browse_w)));
334 if (font_name == NULL) {
335 /* No font was selected; let the user know, but don't
336 tear down the font selection dialog, so they can
338 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
339 "You have not selected a font.");
343 if (!user_font_test(font_name)) {
344 /* The font isn't usable; "user_font_test()" has already
345 told the user why. Don't tear down the font selection
350 new_font_name = font_name;
356 fetch_enum_value(gpointer control, const enum_val_t *enumvals)
358 return fetch_preference_option_menu_val(GTK_WIDGET(control), enumvals);
362 gui_prefs_fetch(GtkWidget *w)
364 prefs.gui_plist_sel_browse = fetch_enum_value(
365 g_object_get_data(G_OBJECT(w), PLIST_SEL_BROWSE_KEY), selection_mode_vals);
366 prefs.gui_ptree_sel_browse = fetch_enum_value(
367 g_object_get_data(G_OBJECT(w), PTREE_SEL_BROWSE_KEY), selection_mode_vals);
368 prefs.gui_geometry_save_position =
369 gtk_toggle_button_get_active(g_object_get_data(G_OBJECT(w), GEOMETRY_POSITION_KEY));
370 prefs.gui_geometry_save_size =
371 gtk_toggle_button_get_active(g_object_get_data(G_OBJECT(w), GEOMETRY_SIZE_KEY));
372 prefs.gui_geometry_save_maximized =
373 gtk_toggle_button_get_active(g_object_get_data(G_OBJECT(w), GEOMETRY_MAXIMIZED_KEY));
374 prefs.gui_geometry_save_column_width =
375 gtk_toggle_button_get_active(g_object_get_data(G_OBJECT(w), GEOMETRY_COLUMN_WIDTH_KEY));
377 prefs.gui_console_open = fetch_enum_value(
378 g_object_get_data(G_OBJECT(w), GUI_CONSOLE_OPEN_KEY), gui_console_open_vals);
380 prefs.gui_fileopen_style = fetch_preference_radio_buttons_val(
381 g_object_get_data(G_OBJECT(w), GUI_FILEOPEN_KEY), gui_fileopen_vals);
383 if (prefs.gui_fileopen_dir != NULL)
384 g_free(prefs.gui_fileopen_dir);
385 prefs.gui_fileopen_dir = g_strdup(gtk_entry_get_text(
386 GTK_ENTRY(g_object_get_data(G_OBJECT(w), GUI_FILEOPEN_DIR_KEY))));
388 prefs.gui_ask_unsaved =
389 gtk_toggle_button_get_active(g_object_get_data(G_OBJECT(w), GUI_ASK_UNSAVED_KEY));
391 prefs.gui_find_wrap =
392 gtk_toggle_button_get_active(g_object_get_data(G_OBJECT(w), GUI_FIND_WRAP_KEY));
394 prefs.gui_use_pref_save =
395 gtk_toggle_button_get_active(g_object_get_data(G_OBJECT(w), GUI_USE_PREF_SAVE_KEY));
397 if (browser_needs_pref()) {
398 g_free(prefs.gui_webbrowser);
399 prefs.gui_webbrowser = g_strdup(gtk_entry_get_text(
400 GTK_ENTRY(g_object_get_data(G_OBJECT(w), GUI_WEBBROWSER_KEY))));
403 * XXX - we need to have a way to fetch the preferences into
404 * local storage and only set the permanent preferences if there
405 * weren't any errors in those fetches, as there are several
406 * places where there *can* be a bad preference value.
409 if (strcmp(new_font_name, prefs.gui_font_name) != 0) {
411 if (prefs.gui_font_name != NULL)
412 g_free(prefs.gui_font_name);
413 prefs.gui_font_name = g_strdup(new_font_name);
421 gui_prefs_apply(GtkWidget *w _U_ , gboolean redissect)
425 /* user immediately wants to see a console */
426 if (prefs.gui_console_open == console_open_always) {
432 /* This redraws the hex dump windows. */
433 switch (user_font_apply(FALSE)) {
438 case FA_FONT_NOT_RESIZEABLE:
439 /* "user_font_apply()" popped up an alert box. */
440 /* turn off zooming - font can't be resized */
441 recent.gui_zoom_level = 0;
444 case FA_FONT_NOT_AVAILABLE:
445 /* We assume this means that the specified size
447 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
448 "That font isn't available at the specified zoom level;\n"
449 "turning zooming off.");
450 recent.gui_zoom_level = 0;
453 } else if (!redissect) {
454 /* Redraw the hex dump windows, in case the
455 highlight style changed, only if we aren't redissecting the whole file.
456 XXX - do it only if the highlight style *did* change. */
457 redraw_hex_dump_all();
460 /* Redraw the help window(s). */
464 /* XXX: redraw the toolbar only, if style changed */
465 toolbar_redraw_all();
467 set_scrollbar_placement_all();
468 packet_list_set_sel_browse(prefs.gui_plist_sel_browse, FALSE);
469 set_ptree_sel_browse_all(prefs.gui_ptree_sel_browse);
470 set_tree_styles_all();
471 main_widgets_rearrange();
475 gui_prefs_destroy(GtkWidget *w _U_)
477 /* Free up any saved font name. */
478 if (new_font_name != NULL) {
479 g_free(new_font_name);
480 new_font_name = NULL;
486 recent_files_count_changed_cb(GtkWidget *recent_files_entry _U_,
487 GdkEvent *event _U_, gpointer parent_w)
489 GtkWidget *recent_files_count_te;
492 recent_files_count_te = (GtkWidget *)g_object_get_data(G_OBJECT(parent_w), GUI_RECENT_FILES_COUNT_KEY);
495 * Now, just convert the string to a number and store it in the prefs
499 newval = strtol(gtk_entry_get_text (GTK_ENTRY(recent_files_count_te)), NULL, 10);
502 prefs.gui_recent_files_count_max = newval;
505 /* We really should pop up a nasty dialog box if newval <= 0 */
511 fileopen_preview_changed_cb(GtkWidget *recent_files_entry _U_,
512 GdkEvent *event _U_, gpointer parent_w)
514 GtkWidget *fileopen_preview_te;
517 fileopen_preview_te = (GtkWidget *)g_object_get_data(G_OBJECT(parent_w), GUI_FILEOPEN_PREVIEW_KEY);
520 * Now, just convert the string to a number and store it in the prefs
524 newval = strtol(gtk_entry_get_text (GTK_ENTRY(fileopen_preview_te)), NULL, 10);
527 prefs.gui_fileopen_preview = newval;
530 /* We really should pop up a nasty dialog box if newval <= 0 */
536 fileopen_dir_changed_cb(GtkWidget *fileopen_entry _U_, GdkEvent *event _U_, gpointer parent_w)
538 GtkWidget *fileopen_dir_te;
540 gint fileopen_dir_te_length;
542 fileopen_dir_te = (GtkWidget *)g_object_get_data(G_OBJECT(parent_w), GUI_FILEOPEN_DIR_KEY);
543 fileopen_dir_te_length = strlen(gtk_entry_get_text (GTK_ENTRY(fileopen_entry)));
544 if (fileopen_dir_te_length == 0)
546 lastchar = gtk_editable_get_chars(GTK_EDITABLE(fileopen_entry), fileopen_dir_te_length-1, -1);
547 if (strcmp(lastchar, G_DIR_SEPARATOR_S) != 0)
548 gtk_entry_append_text(GTK_ENTRY(fileopen_entry), G_DIR_SEPARATOR_S);
553 fileopen_selected_cb(GtkWidget *mybutton_rb _U_, gpointer parent_w)
555 GtkWidget *fileopen_rb, *fileopen_dir_te;
557 fileopen_rb = (GtkWidget *)g_object_get_data(G_OBJECT(parent_w), GUI_FILEOPEN_KEY);
558 fileopen_dir_te = (GtkWidget *)g_object_get_data(G_OBJECT(parent_w), GUI_FILEOPEN_DIR_KEY);
560 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(fileopen_rb)))
562 gtk_widget_set_sensitive(GTK_WIDGET(fileopen_dir_te), TRUE);
566 gtk_widget_set_sensitive(GTK_WIDGET(fileopen_dir_te), FALSE);