2 * Routines for handling preferences
4 * $Id: prefs_dlg.c,v 1.32 2001/10/24 06:13:07 guy Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
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.
29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
44 #ifdef HAVE_SYS_STAT_H
48 #include <epan/filesystem.h>
51 #include "gtkglobals.h"
55 #include "column_prefs.h"
57 #include "prefs_dlg.h"
58 #include "print_prefs.h"
59 #include "stream_prefs.h"
60 #include "gui_prefs.h"
62 #include "dlg_utils.h"
63 #include "simple_dialog.h"
65 #include "prefs-int.h"
67 static void prefs_main_ok_cb(GtkWidget *, gpointer);
68 static void prefs_main_apply_cb(GtkWidget *, gpointer);
69 static void prefs_main_save_cb(GtkWidget *, gpointer);
70 static void prefs_main_cancel_cb(GtkWidget *, gpointer);
71 static gboolean prefs_main_delete_cb(GtkWidget *, gpointer);
72 static void prefs_main_destroy_cb(GtkWidget *, gpointer);
73 static void prefs_tree_select_cb(GtkCTree *, GtkCTreeNode *, gint, gpointer);
75 #define E_PRINT_PAGE_KEY "printer_options_page"
76 #define E_COLUMN_PAGE_KEY "column_options_page"
77 #define E_STREAM_PAGE_KEY "tcp_stream_options_page"
78 #define E_GUI_PAGE_KEY "gui_options_page"
80 #define FIRST_PROTO_PREFS_PAGE 4
83 * Keep a static pointer to the notebook to be able to choose the
86 static GtkWidget *notebook;
89 * Keep a static pointer to the current "Preferences" window, if any, so that
90 * if somebody tries to do "Edit:Preferences" while there's already a
91 * "Preferences" window up, we just pop up the existing one, rather than
94 static GtkWidget *prefs_w;
97 * Save the value of the preferences as of when the preferences dialog
98 * box was first popped up, so we can revert to those values if the
99 * user selects "Cancel".
101 static e_prefs saved_prefs;
111 pref_show(pref_t *pref, gpointer user_data)
113 GtkWidget *main_tb = user_data;
116 GtkWidget *label, *menu, *menu_item, *widget, *button;
119 const enum_val_t *enum_valp;
120 int menu_index, index;
122 /* Give this preference a label which is its title, followed by a colon,
123 and left-align it. */
125 label_string = g_malloc(strlen(title) + 2);
126 strcpy(label_string, title);
127 strcat(label_string, ":");
128 label = gtk_label_new(label_string);
129 g_free(label_string);
130 gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
132 /* Attach it to the table. */
133 gtk_table_attach_defaults(GTK_TABLE(main_tb), label, 0, 1, pref->ordinal,
136 /* Save the current value of the preference, so that we can revert it if
137 the user does "Apply" and then "Cancel", and create the control for
138 editing the preference. */
139 switch (pref->type) {
142 pref->saved_val.uint = *pref->varp.uint;
144 /* XXX - there are no uint spinbuttons, so we can't use a spinbutton.
145 Even more annoyingly, even if there were, GLib doesn't define
146 G_MAXUINT - but I think ANSI C may define UINT_MAX, so we could
148 widget = gtk_entry_new();
149 switch (pref->info.base) {
152 sprintf(uint_str, "%u", pref->saved_val.uint);
156 sprintf(uint_str, "%o", pref->saved_val.uint);
160 sprintf(uint_str, "%x", pref->saved_val.uint);
163 gtk_entry_set_text(GTK_ENTRY(widget), uint_str);
164 pref->control = widget;
168 pref->saved_val.bool = *pref->varp.bool;
169 widget = gtk_check_button_new();
170 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(widget), pref->saved_val.bool);
171 pref->control = widget;
175 pref->saved_val.enumval = *pref->varp.enump;
176 if (pref->info.enum_info.radio_buttons) {
177 /* Show it as radio buttons. */
178 widget = gtk_hbox_new(FALSE, 0);
180 for (enum_valp = pref->info.enum_info.enumvals, index = 0;
181 enum_valp->name != NULL; enum_valp++, index++) {
182 button = gtk_radio_button_new_with_label(rb_group, enum_valp->name);
183 if (rb_group == NULL)
184 rb_group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
185 gtk_box_pack_start(GTK_BOX(widget), button, FALSE, FALSE, 10);
186 if (enum_valp->value == pref->saved_val.enumval)
187 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), TRUE);
188 pref->control = button;
191 /* Show it as an option menu. */
192 menu = gtk_menu_new();
194 for (enum_valp = pref->info.enum_info.enumvals, index = 0;
195 enum_valp->name != NULL; enum_valp++, index++) {
196 menu_item = gtk_menu_item_new_with_label(enum_valp->name);
197 gtk_menu_append(GTK_MENU(menu), menu_item);
198 if (enum_valp->value == pref->saved_val.enumval)
200 gtk_widget_show(menu_item);
203 /* Create the option menu from the option */
204 widget = gtk_option_menu_new();
205 gtk_option_menu_set_menu(GTK_OPTION_MENU(widget), menu);
207 /* Set its current value to the variable's current value */
208 if (menu_index != -1)
209 gtk_option_menu_set_history(GTK_OPTION_MENU(widget), menu_index);
210 pref->control = widget;
215 widget = gtk_entry_new();
216 if (pref->saved_val.string != NULL)
217 g_free(pref->saved_val.string);
218 pref->saved_val.string = g_strdup(*pref->varp.string);
219 gtk_entry_set_text(GTK_ENTRY(widget), pref->saved_val.string);
220 pref->control = widget;
224 g_assert_not_reached();
229 gtk_table_attach_defaults(GTK_TABLE(main_tb), widget, 1, 2, pref->ordinal,
233 #define MAX_TREE_NODE_NAME_LEN 64
235 module_prefs_show(module_t *module, gpointer user_data)
237 struct ct_struct *cts = user_data;
238 GtkWidget *main_vb, *main_tb, *frame;
239 gchar label_str[MAX_TREE_NODE_NAME_LEN], *label_ptr = label_str;
240 GtkCTreeNode *ct_node;
243 frame = gtk_frame_new(module->title);
244 gtk_widget_show(frame);
246 /* Main vertical box */
247 main_vb = gtk_vbox_new(FALSE, 5);
248 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
249 gtk_container_add(GTK_CONTAINER(frame), main_vb);
252 main_tb = gtk_table_new(module->numprefs, 2, FALSE);
253 gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0);
254 gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10);
255 gtk_table_set_col_spacings(GTK_TABLE(main_tb), 15);
257 /* Add items for each of the preferences */
258 prefs_pref_foreach(module, pref_show, main_tb);
260 gtk_notebook_append_page(GTK_NOTEBOOK(cts->notebook), frame, NULL);
261 strcpy(label_str, module->title);
262 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts->ctree), cts->node, NULL,
263 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
264 gtk_ctree_node_set_row_data(GTK_CTREE(cts->ctree), ct_node,
265 GINT_TO_POINTER(cts->page));
268 /* Show 'em what we got */
269 gtk_widget_show_all(main_vb);
273 prefs_cb(GtkWidget *w, gpointer dummy) {
274 GtkWidget *main_vb, *top_hb, *bbox, *prefs_nb, *ct_sb, *frame,
275 *ok_bt, *apply_bt, *save_bt, *cancel_bt;
276 GtkWidget *print_pg, *column_pg, *stream_pg, *gui_pg;
277 gchar label_str[MAX_TREE_NODE_NAME_LEN], *label_ptr = label_str;
278 GtkCTreeNode *ct_node;
279 struct ct_struct cts;
282 if (prefs_w != NULL) {
283 /* There's already a "Preferences" dialog box; reactivate it. */
284 reactivate_window(prefs_w);
288 /* Save the current preferences, so we can revert to those values
289 if the user presses "Cancel". */
290 copy_prefs(&saved_prefs, &prefs);
292 prefs_w = dlg_window_new("Ethereal: Preferences");
293 gtk_signal_connect(GTK_OBJECT(prefs_w), "delete_event",
294 GTK_SIGNAL_FUNC(prefs_main_delete_cb), NULL);
295 gtk_signal_connect(GTK_OBJECT(prefs_w), "destroy",
296 GTK_SIGNAL_FUNC(prefs_main_destroy_cb), NULL);
298 /* Container for each row of widgets */
299 main_vb = gtk_vbox_new(FALSE, 5);
300 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
301 gtk_container_add(GTK_CONTAINER(prefs_w), main_vb);
302 gtk_widget_show(main_vb);
304 /* Top row: Preferences tree and notebook */
305 top_hb = gtk_hbox_new(FALSE, 10);
306 gtk_container_add(GTK_CONTAINER(main_vb), top_hb);
307 gtk_widget_show(top_hb);
309 /* Place a Ctree on the left for preference categories */
310 ct_sb = gtk_scrolled_window_new(NULL, NULL);
311 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ct_sb),
312 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
313 set_scrollbar_placement_scrollw(ct_sb, prefs.gui_scrollbar_on_right);
314 remember_scrolled_window(ct_sb);
315 gtk_container_add(GTK_CONTAINER(top_hb), ct_sb);
316 gtk_widget_show(ct_sb);
318 cts.ctree = gtk_ctree_new(1, 0);
320 gtk_container_add(GTK_CONTAINER(ct_sb), cts.ctree);
322 /* Be consistent with our line/expander styles */
323 g_assert(prefs.gui_ptree_line_style >= GTK_CTREE_LINES_NONE &&
324 prefs.gui_ptree_line_style <= GTK_CTREE_LINES_TABBED);
325 gtk_ctree_set_line_style(GTK_CTREE(cts.ctree), prefs.gui_ptree_line_style);
326 g_assert(prefs.gui_ptree_expander_style >= GTK_CTREE_EXPANDER_NONE &&
327 prefs.gui_ptree_expander_style <= GTK_CTREE_EXPANDER_CIRCULAR);
328 gtk_ctree_set_expander_style(GTK_CTREE(cts.ctree),
329 prefs.gui_ptree_expander_style);
331 gtk_clist_set_column_auto_resize(GTK_CLIST(cts.ctree), 0, TRUE);
332 gtk_signal_connect(GTK_OBJECT(cts.ctree), "tree-select-row",
333 GTK_SIGNAL_FUNC(prefs_tree_select_cb), NULL);
334 gtk_widget_show(cts.ctree);
336 /* A notebook widget sans tabs is used to flip between prefs */
337 notebook = prefs_nb = gtk_notebook_new();
338 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE);
339 gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook), FALSE);
340 gtk_container_add(GTK_CONTAINER(top_hb), prefs_nb);
341 gtk_widget_show(prefs_nb);
344 frame = gtk_frame_new("Printing");
345 gtk_widget_show(GTK_WIDGET(frame));
346 print_pg = printer_prefs_show();
347 gtk_container_add(GTK_CONTAINER(frame), print_pg);
348 gtk_object_set_data(GTK_OBJECT(prefs_w), E_PRINT_PAGE_KEY, print_pg);
349 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
350 strcpy(label_str, "Printing");
351 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.ctree), NULL, NULL,
352 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
353 gtk_ctree_node_set_row_data(GTK_CTREE(cts.ctree), ct_node,
354 GINT_TO_POINTER(cts.page));
358 frame = gtk_frame_new("Columns");
359 gtk_widget_show(GTK_WIDGET(frame));
360 column_pg = column_prefs_show();
361 gtk_container_add(GTK_CONTAINER(frame), column_pg);
362 gtk_object_set_data(GTK_OBJECT(prefs_w), E_COLUMN_PAGE_KEY, column_pg);
363 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
364 strcpy(label_str, "Columns");
365 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.ctree), NULL, NULL,
366 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
367 gtk_ctree_node_set_row_data(GTK_CTREE(cts.ctree), ct_node,
368 GINT_TO_POINTER(cts.page));
371 /* TCP Streams prefs */
372 frame = gtk_frame_new("TCP Streams");
373 gtk_widget_show(GTK_WIDGET(frame));
374 stream_pg = stream_prefs_show();
375 gtk_container_add(GTK_CONTAINER(frame), stream_pg);
376 gtk_object_set_data(GTK_OBJECT(prefs_w), E_STREAM_PAGE_KEY, stream_pg);
377 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
378 strcpy(label_str, "TCP Streams");
379 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.ctree), NULL, NULL,
380 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
381 gtk_ctree_node_set_row_data(GTK_CTREE(cts.ctree), ct_node,
382 GINT_TO_POINTER(cts.page));
386 frame = gtk_frame_new("User Interface");
387 gtk_widget_show(GTK_WIDGET(frame));
388 gui_pg = gui_prefs_show();
389 gtk_container_add(GTK_CONTAINER(frame), gui_pg);
390 gtk_object_set_data(GTK_OBJECT(prefs_w), E_GUI_PAGE_KEY, gui_pg);
391 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
392 strcpy(label_str, "User Interface");
393 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.ctree), NULL, NULL,
394 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
395 gtk_ctree_node_set_row_data(GTK_CTREE(cts.ctree), ct_node,
396 GINT_TO_POINTER(cts.page));
400 /* Registered prefs */
401 cts.notebook = prefs_nb;
402 strcpy(label_str, "Protocols");
403 cts.node = gtk_ctree_insert_node(GTK_CTREE(cts.ctree), NULL, NULL,
404 &label_ptr, 5, NULL, NULL, NULL, NULL, FALSE, FALSE);
405 gtk_ctree_node_set_row_data(GTK_CTREE(cts.ctree), cts.node,
406 GINT_TO_POINTER(-1));
407 gtk_ctree_node_set_selectable(GTK_CTREE(cts.ctree), cts.node, FALSE);
409 prefs_module_foreach(module_prefs_show, &cts);
412 /* Button row: OK and cancel buttons */
413 bbox = gtk_hbutton_box_new();
414 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
415 gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
416 gtk_container_add(GTK_CONTAINER(main_vb), bbox);
417 gtk_widget_show(bbox);
419 ok_bt = gtk_button_new_with_label ("OK");
420 gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
421 GTK_SIGNAL_FUNC(prefs_main_ok_cb), GTK_OBJECT(prefs_w));
422 GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT);
423 gtk_box_pack_start (GTK_BOX (bbox), ok_bt, TRUE, TRUE, 0);
424 gtk_widget_grab_default(ok_bt);
425 gtk_widget_show(ok_bt);
427 apply_bt = gtk_button_new_with_label ("Apply");
428 gtk_signal_connect(GTK_OBJECT(apply_bt), "clicked",
429 GTK_SIGNAL_FUNC(prefs_main_apply_cb), GTK_OBJECT(prefs_w));
430 GTK_WIDGET_SET_FLAGS(apply_bt, GTK_CAN_DEFAULT);
431 gtk_box_pack_start(GTK_BOX (bbox), apply_bt, TRUE, TRUE, 0);
432 gtk_widget_show(apply_bt);
434 save_bt = gtk_button_new_with_label ("Save");
435 gtk_signal_connect(GTK_OBJECT(save_bt), "clicked",
436 GTK_SIGNAL_FUNC(prefs_main_save_cb), GTK_OBJECT(prefs_w));
437 GTK_WIDGET_SET_FLAGS(save_bt, GTK_CAN_DEFAULT);
438 gtk_box_pack_start (GTK_BOX (bbox), save_bt, TRUE, TRUE, 0);
439 gtk_widget_show(save_bt);
441 cancel_bt = gtk_button_new_with_label ("Cancel");
442 gtk_signal_connect(GTK_OBJECT(cancel_bt), "clicked",
443 GTK_SIGNAL_FUNC(prefs_main_cancel_cb), GTK_OBJECT(prefs_w));
444 GTK_WIDGET_SET_FLAGS(cancel_bt, GTK_CAN_DEFAULT);
445 gtk_box_pack_start (GTK_BOX (bbox), cancel_bt, TRUE, TRUE, 0);
446 gtk_widget_show(cancel_bt);
448 /* Catch the "key_press_event" signal in the window, so that we can catch
449 the ESC key being pressed and act as if the "Cancel" button had
451 dlg_set_cancel(prefs_w, cancel_bt);
453 gtk_widget_show(prefs_w);
457 pref_fetch(pref_t *pref, gpointer user_data)
468 gboolean *pref_changed_p = user_data;
470 /* Fetch the value of the preference, and set the appropriate variable
472 switch (pref->type) {
475 str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
476 uval = strtoul(str_val, &p, pref->info.base);
478 if (p == value || *p != '\0')
479 return PREFS_SET_SYNTAX_ERR; /* number was bad */
481 if (*pref->varp.uint != uval) {
482 *pref_changed_p = TRUE;
483 *pref->varp.uint = uval;
488 bval = GTK_TOGGLE_BUTTON(pref->control)->active;
489 if (*pref->varp.bool != bval) {
490 *pref_changed_p = TRUE;
491 *pref->varp.bool = bval;
496 if (pref->info.enum_info.radio_buttons) {
497 /* Go through the list of of radio buttons in the group, and find
498 the first one that's active. */
500 for (rb_entry = gtk_radio_button_group(GTK_RADIO_BUTTON(pref->control));
502 rb_entry = g_slist_next(rb_entry)) {
503 button = rb_entry->data;
504 if (GTK_TOGGLE_BUTTON(button)->active)
507 /* OK, now find that button's label. */
508 label = GTK_BIN(button)->child;
510 /* Get the label for the currently active entry in the option menu.
511 Yes, this is how you do it. See FAQ 6.8 in the GTK+ FAQ. */
512 label = GTK_BIN(pref->control)->child;
515 /* Get the label, and translate it to a value. */
516 gtk_label_get(GTK_LABEL(label), &label_string);
517 enumval = find_val_for_string(label_string,
518 pref->info.enum_info.enumvals, 1);
519 if (*pref->varp.enump != enumval) {
520 *pref_changed_p = TRUE;
521 *pref->varp.enump = enumval;
526 str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
527 if (*pref->varp.string == NULL || strcmp(*pref->varp.string, str_val) != 0) {
528 *pref_changed_p = TRUE;
529 if (*pref->varp.string != NULL)
530 g_free(*pref->varp.string);
531 *pref->varp.string = g_strdup(str_val);
538 module_prefs_fetch(module_t *module, gpointer user_data)
540 gboolean *must_redissect_p = user_data;
542 /* For all preferences in this module, fetch its value from this
543 module's notebook page. Find out whether any of them changed. */
544 module->prefs_changed = FALSE; /* assume none of them changed */
545 prefs_pref_foreach(module, pref_fetch, &module->prefs_changed);
547 /* If any of them changed, indicate that we must redissect and refilter
548 the current capture (if we have one), as the preference change
549 could cause packets to be dissected differently. */
550 if (module->prefs_changed)
551 *must_redissect_p = TRUE;
555 pref_clean(pref_t *pref, gpointer user_data)
557 switch (pref->type) {
569 if (pref->saved_val.string != NULL) {
570 g_free(pref->saved_val.string);
571 pref->saved_val.string = NULL;
578 module_prefs_clean(module_t *module, gpointer user_data)
580 /* For all preferences in this module, clean up any cruft allocated for
581 use by the GUI code. */
582 prefs_pref_foreach(module, pref_clean, NULL);
586 prefs_main_ok_cb(GtkWidget *ok_bt, gpointer parent_w)
588 gboolean must_redissect = FALSE;
590 /* Fetch the preferences (i.e., make sure all the values set in all of
591 the preferences panes have been copied to "prefs" and the registered
593 printer_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_PRINT_PAGE_KEY));
594 column_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
595 stream_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
596 gui_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
597 prefs_module_foreach(module_prefs_fetch, &must_redissect);
599 /* Now apply those preferences. */
600 printer_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_PRINT_PAGE_KEY));
601 column_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
602 stream_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
603 gui_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
606 /* Now destroy the "Preferences" dialog. */
607 gtk_widget_destroy(GTK_WIDGET(parent_w));
609 if (must_redissect) {
610 /* Redissect all the packets, and re-evaluate the display filter. */
611 redissect_packets(&cfile);
616 prefs_main_apply_cb(GtkWidget *apply_bt, gpointer parent_w)
618 gboolean must_redissect = FALSE;
620 /* Fetch the preferences (i.e., make sure all the values set in all of
621 the preferences panes have been copied to "prefs" and the registered
623 printer_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_PRINT_PAGE_KEY));
624 column_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
625 stream_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
626 gui_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
627 prefs_module_foreach(module_prefs_fetch, &must_redissect);
629 /* Now apply those preferences. */
630 printer_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_PRINT_PAGE_KEY));
631 column_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
632 stream_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
633 gui_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
634 prefs_module_foreach(module_prefs_fetch, &must_redissect);
637 if (must_redissect) {
638 /* Redissect all the packets, and re-evaluate the display filter. */
639 redissect_packets(&cfile);
644 prefs_main_save_cb(GtkWidget *save_bt, gpointer parent_w)
646 gboolean must_redissect = FALSE;
651 /* Fetch the preferences (i.e., make sure all the values set in all of
652 the preferences panes have been copied to "prefs" and the registered
654 printer_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_PRINT_PAGE_KEY));
655 column_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
656 stream_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
657 gui_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
658 prefs_module_foreach(module_prefs_fetch, &must_redissect);
660 /* Create the directory that holds personal configuration files, if
662 if (create_persconffile_dir(&pf_dir_path) == -1) {
663 simple_dialog(ESD_TYPE_WARN, NULL,
664 "Can't create directory\n\"%s\"\nfor preferences file: %s.", pf_dir_path,
668 /* Write the preferencs out. */
669 err = write_prefs(&pf_path);
671 simple_dialog(ESD_TYPE_WARN, NULL,
672 "Can't open preferences file\n\"%s\": %s.", pf_path,
677 /* Now apply those preferences.
678 XXX - should we do this? The user didn't click "OK" or "Apply".
681 1) by saving the preferences they presumably indicate that they
684 2) the next time they fire Ethereal up, those preferences will
687 3) we'd have to buffer "must_redissect" so that if they do
688 "Apply" after this, we know we have to redissect;
690 4) we did apply the protocol preferences, at least, in the past. */
691 printer_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_PRINT_PAGE_KEY));
692 column_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
693 stream_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
694 gui_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
695 prefs_module_foreach(module_prefs_fetch, &must_redissect);
698 if (must_redissect) {
699 /* Redissect all the packets, and re-evaluate the display filter. */
700 redissect_packets(&cfile);
705 pref_revert(pref_t *pref, gpointer user_data)
707 gboolean *pref_changed_p = user_data;
709 /* Revert the preference to its saved value. */
710 switch (pref->type) {
713 if (*pref->varp.uint != pref->saved_val.uint) {
714 *pref_changed_p = TRUE;
715 *pref->varp.uint = pref->saved_val.uint;
720 if (*pref->varp.bool != pref->saved_val.bool) {
721 *pref_changed_p = TRUE;
722 *pref->varp.bool = pref->saved_val.bool;
727 if (*pref->varp.enump != pref->saved_val.enumval) {
728 *pref_changed_p = TRUE;
729 *pref->varp.enump = pref->saved_val.enumval;
734 if (*pref->varp.string != pref->saved_val.string &&
735 (*pref->varp.string == NULL ||
736 pref->saved_val.string == NULL ||
737 strcmp(*pref->varp.string, pref->saved_val.string) != 0)) {
738 *pref_changed_p = TRUE;
739 if (*pref->varp.string != NULL)
740 g_free(*pref->varp.string);
741 *pref->varp.string = g_strdup(pref->saved_val.string);
748 module_prefs_revert(module_t *module, gpointer user_data)
750 gboolean *must_redissect_p = user_data;
752 /* For all preferences in this module, revert its value to the value
753 it had when we popped up the Preferences dialog. Find out whether
754 this changes any of them. */
755 module->prefs_changed = FALSE; /* assume none of them changed */
756 prefs_pref_foreach(module, pref_revert, &module->prefs_changed);
758 /* If any of them changed, indicate that we must redissect and refilter
759 the current capture (if we have one), as the preference change
760 could cause packets to be dissected differently. */
761 if (module->prefs_changed)
762 *must_redissect_p = TRUE;
766 prefs_main_cancel_cb(GtkWidget *cancel_bt, gpointer parent_w)
768 gboolean must_redissect = FALSE;
770 /* Free up the current preferences and copy the saved preferences to the
771 current preferences. */
773 copy_prefs(&prefs, &saved_prefs);
775 /* Now revert the registered preferences. */
776 prefs_module_foreach(module_prefs_revert, &must_redissect);
778 /* Now apply the reverted-to preferences. */
779 printer_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_PRINT_PAGE_KEY));
780 column_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
781 stream_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
782 gui_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
785 gtk_widget_destroy(GTK_WIDGET(parent_w));
787 if (must_redissect) {
788 /* Redissect all the packets, and re-evaluate the display filter. */
789 redissect_packets(&cfile);
793 /* Treat this as a cancel, by calling "prefs_main_cancel_cb()".
794 XXX - that'll destroy the Preferences dialog; will that upset
795 a higher-level handler that says "OK, we've been asked to delete
796 this, so destroy it"? */
798 prefs_main_delete_cb(GtkWidget *prefs_w, gpointer dummy)
800 prefs_main_cancel_cb(NULL, prefs_w);
805 prefs_main_destroy_cb(GtkWidget *win, gpointer user_data)
807 /* Let the preference tabs clean up anything they've done. */
808 printer_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w), E_PRINT_PAGE_KEY));
809 column_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w), E_COLUMN_PAGE_KEY));
810 stream_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w), E_STREAM_PAGE_KEY));
811 gui_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w), E_GUI_PAGE_KEY));
813 /* Free up the saved preferences (both for "prefs" and for registered
815 free_prefs(&saved_prefs);
816 prefs_module_foreach(module_prefs_clean, NULL);
818 /* Note that we no longer have a "Preferences" dialog box. */
822 struct properties_data {
828 /* XXX this way of searching the correct page number is really ugly ... */
830 module_search_properties(module_t *module, gpointer user_data)
832 struct properties_data *p = (struct properties_data *)user_data;
834 if (p->title == NULL) return;
835 if (strcmp(module->title, p->title) == 0) {
837 gtk_notebook_set_page(GTK_NOTEBOOK(p->w), p->page_num);
845 properties_cb(GtkWidget *w, gpointer dummy)
848 struct properties_data p;
850 if (finfo_selected) {
851 header_field_info *hfinfo = finfo_selected->hfinfo;
852 if (hfinfo->parent == -1) {
853 title = (gchar *)prefs_get_title_by_name(hfinfo->abbrev);
856 prefs_get_title_by_name(proto_registrar_get_abbrev(hfinfo->parent));
864 if (prefs_w != NULL) {
865 reactivate_window(prefs_w);
871 p.page_num = FIRST_PROTO_PREFS_PAGE;
874 prefs_module_foreach(module_search_properties, &p);
878 /* Prefs tree selection callback. The node data has been loaded with
879 the proper notebook page to load. */
881 prefs_tree_select_cb(GtkCTree *ct, GtkCTreeNode *node, gint col, gpointer dummy)
883 gint page = GPOINTER_TO_INT(gtk_ctree_node_get_row_data(ct, node));
886 gtk_notebook_set_page(GTK_NOTEBOOK(notebook), page);