2 * Routines for handling preferences
4 * $Id: prefs_dlg.c,v 1.29 2001/10/13 12:05:32 sharpe 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
49 #include "gtkglobals.h"
53 #include "column_prefs.h"
55 #include "prefs_dlg.h"
56 #include "print_prefs.h"
57 #include "stream_prefs.h"
58 #include "gui_prefs.h"
60 #include "dlg_utils.h"
61 #include "simple_dialog.h"
63 #include "prefs-int.h"
65 static void prefs_main_ok_cb(GtkWidget *, gpointer);
66 static void prefs_main_apply_cb(GtkWidget *, gpointer);
67 static void prefs_main_save_cb(GtkWidget *, gpointer);
68 static void prefs_main_cancel_cb(GtkWidget *, gpointer);
69 static gboolean prefs_main_delete_cb(GtkWidget *, gpointer);
70 static void prefs_main_destroy_cb(GtkWidget *, gpointer);
71 static void prefs_tree_select_cb(GtkCTree *, GtkCTreeNode *, gint, gpointer);
73 #define E_PRINT_PAGE_KEY "printer_options_page"
74 #define E_COLUMN_PAGE_KEY "column_options_page"
75 #define E_STREAM_PAGE_KEY "tcp_stream_options_page"
76 #define E_GUI_PAGE_KEY "gui_options_page"
78 #define FIRST_PROTO_PREFS_PAGE 4
81 * Keep a static pointer to the notebook to be able to choose the
84 static GtkWidget *notebook;
87 * Keep a static pointer to the current "Preferences" window, if any, so that
88 * if somebody tries to do "Edit:Preferences" while there's already a
89 * "Preferences" window up, we just pop up the existing one, rather than
92 static GtkWidget *prefs_w;
95 * Save the value of the preferences as of when the preferences dialog
96 * box was first popped up, so we can revert to those values if the
97 * user selects "Cancel".
99 static e_prefs saved_prefs;
109 pref_show(pref_t *pref, gpointer user_data)
111 GtkWidget *main_tb = user_data;
114 GtkWidget *label, *menu, *menu_item, *widget, *button;
117 const enum_val_t *enum_valp;
118 int menu_index, index;
120 /* Give this preference a label which is its title, followed by a colon,
121 and left-align it. */
123 label_string = g_malloc(strlen(title) + 2);
124 strcpy(label_string, title);
125 strcat(label_string, ":");
126 label = gtk_label_new(label_string);
127 g_free(label_string);
128 gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
130 /* Attach it to the table. */
131 gtk_table_attach_defaults(GTK_TABLE(main_tb), label, 0, 1, pref->ordinal,
134 /* Save the current value of the preference, so that we can revert it if
135 the user does "Apply" and then "Cancel", and create the control for
136 editing the preference. */
137 switch (pref->type) {
140 pref->saved_val.uint = *pref->varp.uint;
142 /* XXX - there are no uint spinbuttons, so we can't use a spinbutton.
143 Even more annoyingly, even if there were, GLib doesn't define
144 G_MAXUINT - but I think ANSI C may define UINT_MAX, so we could
146 widget = gtk_entry_new();
147 switch (pref->info.base) {
150 sprintf(uint_str, "%u", pref->saved_val.uint);
154 sprintf(uint_str, "%o", pref->saved_val.uint);
158 sprintf(uint_str, "%x", pref->saved_val.uint);
161 gtk_entry_set_text(GTK_ENTRY(widget), uint_str);
162 pref->control = widget;
166 pref->saved_val.bool = *pref->varp.bool;
167 widget = gtk_check_button_new();
168 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(widget), pref->saved_val.bool);
169 pref->control = widget;
173 pref->saved_val.enumval = *pref->varp.enump;
174 if (pref->info.enum_info.radio_buttons) {
175 /* Show it as radio buttons. */
176 widget = gtk_hbox_new(FALSE, 0);
178 for (enum_valp = pref->info.enum_info.enumvals, index = 0;
179 enum_valp->name != NULL; enum_valp++, index++) {
180 button = gtk_radio_button_new_with_label(rb_group, enum_valp->name);
181 if (rb_group == NULL)
182 rb_group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
183 gtk_box_pack_start(GTK_BOX(widget), button, FALSE, FALSE, 10);
184 if (enum_valp->value == pref->saved_val.enumval)
185 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), TRUE);
186 pref->control = button;
189 /* Show it as an option menu. */
190 menu = gtk_menu_new();
192 for (enum_valp = pref->info.enum_info.enumvals, index = 0;
193 enum_valp->name != NULL; enum_valp++, index++) {
194 menu_item = gtk_menu_item_new_with_label(enum_valp->name);
195 gtk_menu_append(GTK_MENU(menu), menu_item);
196 if (enum_valp->value == pref->saved_val.enumval)
198 gtk_widget_show(menu_item);
201 /* Create the option menu from the option */
202 widget = gtk_option_menu_new();
203 gtk_option_menu_set_menu(GTK_OPTION_MENU(widget), menu);
205 /* Set its current value to the variable's current value */
206 if (menu_index != -1)
207 gtk_option_menu_set_history(GTK_OPTION_MENU(widget), menu_index);
208 pref->control = widget;
213 widget = gtk_entry_new();
214 if (pref->saved_val.string != NULL)
215 g_free(pref->saved_val.string);
216 pref->saved_val.string = g_strdup(*pref->varp.string);
217 gtk_entry_set_text(GTK_ENTRY(widget), pref->saved_val.string);
218 pref->control = widget;
222 g_assert_not_reached();
227 gtk_table_attach_defaults(GTK_TABLE(main_tb), widget, 1, 2, pref->ordinal,
231 #define MAX_TREE_NODE_NAME_LEN 64
233 module_prefs_show(module_t *module, gpointer user_data)
235 struct ct_struct *cts = user_data;
236 GtkWidget *main_vb, *main_tb, *frame;
237 gchar label_str[MAX_TREE_NODE_NAME_LEN], *label_ptr = label_str;
238 GtkCTreeNode *ct_node;
241 frame = gtk_frame_new(module->title);
242 gtk_widget_show(frame);
244 /* Main vertical box */
245 main_vb = gtk_vbox_new(FALSE, 5);
246 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
247 gtk_container_add(GTK_CONTAINER(frame), main_vb);
250 main_tb = gtk_table_new(module->numprefs, 2, FALSE);
251 gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0);
252 gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10);
253 gtk_table_set_col_spacings(GTK_TABLE(main_tb), 15);
255 /* Add items for each of the preferences */
256 prefs_pref_foreach(module, pref_show, main_tb);
258 gtk_notebook_append_page(GTK_NOTEBOOK(cts->notebook), frame, NULL);
259 strcpy(label_str, module->title);
260 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts->ctree), cts->node, NULL,
261 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
262 gtk_ctree_node_set_row_data(GTK_CTREE(cts->ctree), ct_node,
263 GINT_TO_POINTER(cts->page));
266 /* Show 'em what we got */
267 gtk_widget_show_all(main_vb);
271 prefs_cb(GtkWidget *w, gpointer dummy) {
272 GtkWidget *main_vb, *top_hb, *bbox, *prefs_nb, *ct_sb, *frame,
273 *ok_bt, *apply_bt, *save_bt, *cancel_bt;
274 GtkWidget *print_pg, *column_pg, *stream_pg, *gui_pg;
275 gchar label_str[MAX_TREE_NODE_NAME_LEN], *label_ptr = label_str;
276 GtkCTreeNode *ct_node;
277 struct ct_struct cts;
280 if (prefs_w != NULL) {
281 /* There's already a "Preferences" dialog box; reactivate it. */
282 reactivate_window(prefs_w);
286 /* Save the current preferences, so we can revert to those values
287 if the user presses "Cancel". */
288 copy_prefs(&saved_prefs, &prefs);
290 prefs_w = dlg_window_new("Ethereal: Preferences");
291 gtk_signal_connect(GTK_OBJECT(prefs_w), "delete_event",
292 GTK_SIGNAL_FUNC(prefs_main_delete_cb), NULL);
293 gtk_signal_connect(GTK_OBJECT(prefs_w), "destroy",
294 GTK_SIGNAL_FUNC(prefs_main_destroy_cb), NULL);
296 /* Container for each row of widgets */
297 main_vb = gtk_vbox_new(FALSE, 5);
298 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
299 gtk_container_add(GTK_CONTAINER(prefs_w), main_vb);
300 gtk_widget_show(main_vb);
302 /* Top row: Preferences tree and notebook */
303 top_hb = gtk_hbox_new(FALSE, 10);
304 gtk_container_add(GTK_CONTAINER(main_vb), top_hb);
305 gtk_widget_show(top_hb);
307 /* Place a Ctree on the left for preference categories */
308 ct_sb = gtk_scrolled_window_new(NULL, NULL);
309 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ct_sb),
310 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
311 set_scrollbar_placement_scrollw(ct_sb, prefs.gui_scrollbar_on_right);
312 remember_scrolled_window(ct_sb);
313 gtk_container_add(GTK_CONTAINER(top_hb), ct_sb);
314 gtk_widget_show(ct_sb);
316 cts.ctree = gtk_ctree_new(1, 0);
318 gtk_container_add(GTK_CONTAINER(ct_sb), cts.ctree);
320 /* Be consistent with our line/expander styles */
321 g_assert(prefs.gui_ptree_line_style >= GTK_CTREE_LINES_NONE &&
322 prefs.gui_ptree_line_style <= GTK_CTREE_LINES_TABBED);
323 gtk_ctree_set_line_style(GTK_CTREE(cts.ctree), prefs.gui_ptree_line_style);
324 g_assert(prefs.gui_ptree_expander_style >= GTK_CTREE_EXPANDER_NONE &&
325 prefs.gui_ptree_expander_style <= GTK_CTREE_EXPANDER_CIRCULAR);
326 gtk_ctree_set_expander_style(GTK_CTREE(cts.ctree),
327 prefs.gui_ptree_expander_style);
329 gtk_clist_set_column_auto_resize(GTK_CLIST(cts.ctree), 0, TRUE);
330 gtk_signal_connect(GTK_OBJECT(cts.ctree), "tree-select-row",
331 GTK_SIGNAL_FUNC(prefs_tree_select_cb), NULL);
332 gtk_widget_show(cts.ctree);
334 /* A notebook widget sans tabs is used to flip between prefs */
335 notebook = prefs_nb = gtk_notebook_new();
336 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE);
337 gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook), FALSE);
338 gtk_container_add(GTK_CONTAINER(top_hb), prefs_nb);
339 gtk_widget_show(prefs_nb);
342 frame = gtk_frame_new("Printing");
343 gtk_widget_show(GTK_WIDGET(frame));
344 print_pg = printer_prefs_show();
345 gtk_container_add(GTK_CONTAINER(frame), print_pg);
346 gtk_object_set_data(GTK_OBJECT(prefs_w), E_PRINT_PAGE_KEY, print_pg);
347 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
348 strcpy(label_str, "Printing");
349 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.ctree), NULL, NULL,
350 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
351 gtk_ctree_node_set_row_data(GTK_CTREE(cts.ctree), ct_node,
352 GINT_TO_POINTER(cts.page));
356 frame = gtk_frame_new("Columns");
357 gtk_widget_show(GTK_WIDGET(frame));
358 column_pg = column_prefs_show();
359 gtk_container_add(GTK_CONTAINER(frame), column_pg);
360 gtk_object_set_data(GTK_OBJECT(prefs_w), E_COLUMN_PAGE_KEY, column_pg);
361 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
362 strcpy(label_str, "Columns");
363 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.ctree), NULL, NULL,
364 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
365 gtk_ctree_node_set_row_data(GTK_CTREE(cts.ctree), ct_node,
366 GINT_TO_POINTER(cts.page));
369 /* TCP Streams prefs */
370 frame = gtk_frame_new("TCP Streams");
371 gtk_widget_show(GTK_WIDGET(frame));
372 stream_pg = stream_prefs_show();
373 gtk_container_add(GTK_CONTAINER(frame), stream_pg);
374 gtk_object_set_data(GTK_OBJECT(prefs_w), E_STREAM_PAGE_KEY, stream_pg);
375 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
376 strcpy(label_str, "TCP Streams");
377 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.ctree), NULL, NULL,
378 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
379 gtk_ctree_node_set_row_data(GTK_CTREE(cts.ctree), ct_node,
380 GINT_TO_POINTER(cts.page));
384 frame = gtk_frame_new("User Interface");
385 gtk_widget_show(GTK_WIDGET(frame));
386 gui_pg = gui_prefs_show();
387 gtk_container_add(GTK_CONTAINER(frame), gui_pg);
388 gtk_object_set_data(GTK_OBJECT(prefs_w), E_GUI_PAGE_KEY, gui_pg);
389 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
390 strcpy(label_str, "User Interface");
391 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.ctree), NULL, NULL,
392 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
393 gtk_ctree_node_set_row_data(GTK_CTREE(cts.ctree), ct_node,
394 GINT_TO_POINTER(cts.page));
398 /* Registered prefs */
399 cts.notebook = prefs_nb;
400 strcpy(label_str, "Protocols");
401 cts.node = gtk_ctree_insert_node(GTK_CTREE(cts.ctree), NULL, NULL,
402 &label_ptr, 5, NULL, NULL, NULL, NULL, FALSE, FALSE);
403 gtk_ctree_node_set_row_data(GTK_CTREE(cts.ctree), cts.node,
404 GINT_TO_POINTER(-1));
405 gtk_ctree_node_set_selectable(GTK_CTREE(cts.ctree), cts.node, FALSE);
407 prefs_module_foreach(module_prefs_show, &cts);
410 /* Button row: OK and cancel buttons */
411 bbox = gtk_hbutton_box_new();
412 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
413 gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
414 gtk_container_add(GTK_CONTAINER(main_vb), bbox);
415 gtk_widget_show(bbox);
417 ok_bt = gtk_button_new_with_label ("OK");
418 gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
419 GTK_SIGNAL_FUNC(prefs_main_ok_cb), GTK_OBJECT(prefs_w));
420 GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT);
421 gtk_box_pack_start (GTK_BOX (bbox), ok_bt, TRUE, TRUE, 0);
422 gtk_widget_grab_default(ok_bt);
423 gtk_widget_show(ok_bt);
425 apply_bt = gtk_button_new_with_label ("Apply");
426 gtk_signal_connect(GTK_OBJECT(apply_bt), "clicked",
427 GTK_SIGNAL_FUNC(prefs_main_apply_cb), GTK_OBJECT(prefs_w));
428 GTK_WIDGET_SET_FLAGS(apply_bt, GTK_CAN_DEFAULT);
429 gtk_box_pack_start(GTK_BOX (bbox), apply_bt, TRUE, TRUE, 0);
430 gtk_widget_show(apply_bt);
432 save_bt = gtk_button_new_with_label ("Save");
433 gtk_signal_connect(GTK_OBJECT(save_bt), "clicked",
434 GTK_SIGNAL_FUNC(prefs_main_save_cb), GTK_OBJECT(prefs_w));
435 GTK_WIDGET_SET_FLAGS(save_bt, GTK_CAN_DEFAULT);
436 gtk_box_pack_start (GTK_BOX (bbox), save_bt, TRUE, TRUE, 0);
437 gtk_widget_show(save_bt);
439 cancel_bt = gtk_button_new_with_label ("Cancel");
440 gtk_signal_connect(GTK_OBJECT(cancel_bt), "clicked",
441 GTK_SIGNAL_FUNC(prefs_main_cancel_cb), GTK_OBJECT(prefs_w));
442 GTK_WIDGET_SET_FLAGS(cancel_bt, GTK_CAN_DEFAULT);
443 gtk_box_pack_start (GTK_BOX (bbox), cancel_bt, TRUE, TRUE, 0);
444 gtk_widget_show(cancel_bt);
446 /* Catch the "key_press_event" signal in the window, so that we can catch
447 the ESC key being pressed and act as if the "Cancel" button had
449 dlg_set_cancel(prefs_w, cancel_bt);
451 gtk_widget_show(prefs_w);
455 pref_fetch(pref_t *pref, gpointer user_data)
466 gboolean *pref_changed_p = user_data;
468 /* Fetch the value of the preference, and set the appropriate variable
470 switch (pref->type) {
473 str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
474 uval = strtoul(str_val, &p, pref->info.base);
476 if (p == value || *p != '\0')
477 return PREFS_SET_SYNTAX_ERR; /* number was bad */
479 if (*pref->varp.uint != uval) {
480 *pref_changed_p = TRUE;
481 *pref->varp.uint = uval;
486 bval = GTK_TOGGLE_BUTTON(pref->control)->active;
487 if (*pref->varp.bool != bval) {
488 *pref_changed_p = TRUE;
489 *pref->varp.bool = bval;
494 if (pref->info.enum_info.radio_buttons) {
495 /* Go through the list of of radio buttons in the group, and find
496 the first one that's active. */
498 for (rb_entry = gtk_radio_button_group(GTK_RADIO_BUTTON(pref->control));
500 rb_entry = g_slist_next(rb_entry)) {
501 button = rb_entry->data;
502 if (GTK_TOGGLE_BUTTON(button)->active)
505 /* OK, now find that button's label. */
506 label = GTK_BIN(button)->child;
508 /* Get the label for the currently active entry in the option menu.
509 Yes, this is how you do it. See FAQ 6.8 in the GTK+ FAQ. */
510 label = GTK_BIN(pref->control)->child;
513 /* Get the label, and translate it to a value. */
514 gtk_label_get(GTK_LABEL(label), &label_string);
515 enumval = find_val_for_string(label_string,
516 pref->info.enum_info.enumvals, 1);
517 if (*pref->varp.enump != enumval) {
518 *pref_changed_p = TRUE;
519 *pref->varp.enump = enumval;
524 str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
525 if (*pref->varp.string == NULL || strcmp(*pref->varp.string, str_val) != 0) {
526 *pref_changed_p = TRUE;
527 if (*pref->varp.string != NULL)
528 g_free(*pref->varp.string);
529 *pref->varp.string = g_strdup(str_val);
536 module_prefs_fetch(module_t *module, gpointer user_data)
538 gboolean *must_redissect_p = user_data;
540 /* For all preferences in this module, fetch its value from this
541 module's notebook page. Find out whether any of them changed. */
542 module->prefs_changed = FALSE; /* assume none of them changed */
543 prefs_pref_foreach(module, pref_fetch, &module->prefs_changed);
545 /* If any of them changed, indicate that we must redissect and refilter
546 the current capture (if we have one), as the preference change
547 could cause packets to be dissected differently. */
548 if (module->prefs_changed)
549 *must_redissect_p = TRUE;
553 pref_clean(pref_t *pref, gpointer user_data)
555 switch (pref->type) {
567 if (pref->saved_val.string != NULL) {
568 g_free(pref->saved_val.string);
569 pref->saved_val.string = NULL;
576 module_prefs_clean(module_t *module, gpointer user_data)
578 /* For all preferences in this module, clean up any cruft allocated for
579 use by the GUI code. */
580 prefs_pref_foreach(module, pref_clean, NULL);
584 prefs_main_ok_cb(GtkWidget *ok_bt, gpointer parent_w)
586 gboolean must_redissect = FALSE;
588 /* Fetch the preferences (i.e., make sure all the values set in all of
589 the preferences panes have been copied to "prefs" and the registered
591 printer_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_PRINT_PAGE_KEY));
592 column_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
593 stream_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
594 gui_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
595 prefs_module_foreach(module_prefs_fetch, &must_redissect);
597 /* Now apply those preferences. */
598 printer_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_PRINT_PAGE_KEY));
599 column_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
600 stream_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
601 gui_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
604 /* Now destroy the "Preferences" dialog. */
605 gtk_widget_destroy(GTK_WIDGET(parent_w));
607 if (must_redissect) {
608 /* Redissect all the packets, and re-evaluate the display filter. */
609 redissect_packets(&cfile);
614 prefs_main_apply_cb(GtkWidget *apply_bt, gpointer parent_w)
616 gboolean must_redissect = FALSE;
618 /* Fetch the preferences (i.e., make sure all the values set in all of
619 the preferences panes have been copied to "prefs" and the registered
621 printer_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_PRINT_PAGE_KEY));
622 column_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
623 stream_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
624 gui_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
625 prefs_module_foreach(module_prefs_fetch, &must_redissect);
627 /* Now apply those preferences. */
628 printer_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_PRINT_PAGE_KEY));
629 column_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
630 stream_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
631 gui_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
632 prefs_module_foreach(module_prefs_fetch, &must_redissect);
635 if (must_redissect) {
636 /* Redissect all the packets, and re-evaluate the display filter. */
637 redissect_packets(&cfile);
642 prefs_main_save_cb(GtkWidget *save_bt, gpointer parent_w)
644 gboolean must_redissect = FALSE;
648 /* Fetch the preferences (i.e., make sure all the values set in all of
649 the preferences panes have been copied to "prefs" and the registered
651 printer_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_PRINT_PAGE_KEY));
652 column_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
653 stream_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
654 gui_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
655 prefs_module_foreach(module_prefs_fetch, &must_redissect);
657 /* Write the preferencs out. */
658 err = write_prefs(&pf_path);
660 simple_dialog(ESD_TYPE_WARN, NULL,
661 "Can't open preferences file\n\"%s\": %s.", pf_path,
665 /* Now apply those preferences.
666 XXX - should we do this? The user didn't click "OK" or "Apply".
669 1) by saving the preferences they presumably indicate that they
672 2) the next time they fire Ethereal up, those preferences will
675 3) we'd have to buffer "must_redissect" so that if they do
676 "Apply" after this, we know we have to redissect;
678 4) we did apply the protocol preferences, at least, in the past. */
679 printer_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_PRINT_PAGE_KEY));
680 column_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
681 stream_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
682 gui_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
683 prefs_module_foreach(module_prefs_fetch, &must_redissect);
686 if (must_redissect) {
687 /* Redissect all the packets, and re-evaluate the display filter. */
688 redissect_packets(&cfile);
693 pref_revert(pref_t *pref, gpointer user_data)
695 gboolean *pref_changed_p = user_data;
697 /* Revert the preference to its saved value. */
698 switch (pref->type) {
701 if (*pref->varp.uint != pref->saved_val.uint) {
702 *pref_changed_p = TRUE;
703 *pref->varp.uint = pref->saved_val.uint;
708 if (*pref->varp.bool != pref->saved_val.bool) {
709 *pref_changed_p = TRUE;
710 *pref->varp.bool = pref->saved_val.bool;
715 if (*pref->varp.enump != pref->saved_val.enumval) {
716 *pref_changed_p = TRUE;
717 *pref->varp.enump = pref->saved_val.enumval;
722 if (*pref->varp.string != pref->saved_val.string &&
723 (*pref->varp.string == NULL ||
724 pref->saved_val.string == NULL ||
725 strcmp(*pref->varp.string, pref->saved_val.string) != 0)) {
726 *pref_changed_p = TRUE;
727 if (*pref->varp.string != NULL)
728 g_free(*pref->varp.string);
729 *pref->varp.string = g_strdup(pref->saved_val.string);
736 module_prefs_revert(module_t *module, gpointer user_data)
738 gboolean *must_redissect_p = user_data;
740 /* For all preferences in this module, revert its value to the value
741 it had when we popped up the Preferences dialog. Find out whether
742 this changes any of them. */
743 module->prefs_changed = FALSE; /* assume none of them changed */
744 prefs_pref_foreach(module, pref_revert, &module->prefs_changed);
746 /* If any of them changed, indicate that we must redissect and refilter
747 the current capture (if we have one), as the preference change
748 could cause packets to be dissected differently. */
749 if (module->prefs_changed)
750 *must_redissect_p = TRUE;
754 prefs_main_cancel_cb(GtkWidget *cancel_bt, gpointer parent_w)
756 gboolean must_redissect = FALSE;
758 /* Free up the current preferences and copy the saved preferences to the
759 current preferences. */
761 copy_prefs(&prefs, &saved_prefs);
763 /* Now revert the registered preferences. */
764 prefs_module_foreach(module_prefs_revert, &must_redissect);
766 /* Now apply the reverted-to preferences. */
767 printer_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_PRINT_PAGE_KEY));
768 column_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
769 stream_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
770 gui_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
773 gtk_widget_destroy(GTK_WIDGET(parent_w));
775 if (must_redissect) {
776 /* Redissect all the packets, and re-evaluate the display filter. */
777 redissect_packets(&cfile);
781 /* Treat this as a cancel, by calling "prefs_main_cancel_cb()".
782 XXX - that'll destroy the Preferences dialog; will that upset
783 a higher-level handler that says "OK, we've been asked to delete
784 this, so destroy it"? */
786 prefs_main_delete_cb(GtkWidget *prefs_w, gpointer dummy)
788 prefs_main_cancel_cb(NULL, prefs_w);
793 prefs_main_destroy_cb(GtkWidget *win, gpointer user_data)
795 /* Let the preference tabs clean up anything they've done. */
796 printer_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w), E_PRINT_PAGE_KEY));
797 column_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w), E_COLUMN_PAGE_KEY));
798 stream_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w), E_STREAM_PAGE_KEY));
799 gui_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w), E_GUI_PAGE_KEY));
801 /* Free up the saved preferences (both for "prefs" and for registered
803 free_prefs(&saved_prefs);
804 prefs_module_foreach(module_prefs_clean, NULL);
806 /* Note that we no longer have a "Preferences" dialog box. */
810 struct properties_data {
816 /* XXX this way of searching the correct page number is really ugly ... */
818 module_search_properties(module_t *module, gpointer user_data)
820 struct properties_data *p = (struct properties_data *)user_data;
822 if (p->title == NULL) return;
823 if (strcmp(module->title, p->title) == 0) {
825 gtk_notebook_set_page(GTK_NOTEBOOK(p->w), p->page_num);
833 properties_cb(GtkWidget *w, gpointer dummy)
836 struct properties_data p;
838 if (finfo_selected) {
839 header_field_info *hfinfo = finfo_selected->hfinfo;
840 if (hfinfo->parent == -1) {
841 title = (gchar *)prefs_get_title_by_name(hfinfo->abbrev);
844 prefs_get_title_by_name(proto_registrar_get_abbrev(hfinfo->parent));
852 if (prefs_w != NULL) {
853 reactivate_window(prefs_w);
859 p.page_num = FIRST_PROTO_PREFS_PAGE;
862 prefs_module_foreach(module_search_properties, &p);
866 /* Prefs tree selection callback. The node data has been loaded with
867 the proper notebook page to load. */
869 prefs_tree_select_cb(GtkCTree *ct, GtkCTreeNode *node, gint col, gpointer dummy)
871 gint page = GPOINTER_TO_INT(gtk_ctree_node_get_row_data(ct, node));
874 gtk_notebook_set_page(GTK_NOTEBOOK(notebook), page);