2 * Routines for handling preferences
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.
33 #include <epan/filesystem.h>
36 #include <epan/packet.h>
39 #include "column_prefs.h"
41 #include "prefs_dlg.h"
42 #include "print_prefs.h"
43 #include "stream_prefs.h"
44 #include "gui_prefs.h"
45 #include "layout_prefs.h"
46 #include "capture_prefs.h"
47 #include "nameres_prefs.h"
49 #include "dlg_utils.h"
50 #include "simple_dialog.h"
51 #include "compat_macros.h"
53 #include "prefs-int.h"
57 #include "capture-wpcap.h"
59 #endif /* HAVE_LIBPCAP */
61 static void prefs_main_ok_cb(GtkWidget *, gpointer);
62 static void prefs_main_apply_cb(GtkWidget *, gpointer);
63 static void prefs_main_save_cb(GtkWidget *, gpointer);
64 static void prefs_main_cancel_cb(GtkWidget *, gpointer);
65 static gboolean prefs_main_delete_event_cb(GtkWidget *, GdkEvent *, gpointer);
66 static void prefs_main_destroy_cb(GtkWidget *, gpointer);
67 #if GTK_MAJOR_VERSION < 2
68 static void prefs_tree_select_cb(GtkCTree *, GtkCTreeNode *, gint,
71 static void prefs_tree_select_cb(GtkTreeSelection *, gpointer);
74 #define E_GUI_PAGE_KEY "gui_options_page"
75 #define E_GUI_LAYOUT_PAGE_KEY "gui_layout_page"
76 #define E_GUI_COLUMN_PAGE_KEY "gui_column_options_page"
77 #define E_GUI_FONT_PAGE_KEY "gui_font_options_page"
78 #define E_GUI_COLORS_PAGE_KEY "gui_colors_options_page"
79 #define E_CAPTURE_PAGE_KEY "capture_options_page"
80 #define E_PRINT_PAGE_KEY "printer_options_page"
81 #define E_NAMERES_PAGE_KEY "nameres_options_page"
82 #define E_PAGE_MODULE_KEY "page_module"
85 * Keep a static pointer to the notebook to be able to choose the
88 static GtkWidget *notebook;
91 * Keep a static pointer to the current "Preferences" window, if any, so that
92 * if somebody tries to do "Edit:Preferences" while there's already a
93 * "Preferences" window up, we just pop up the existing one, rather than
96 static GtkWidget *prefs_w;
99 * Save the value of the preferences as of when the preferences dialog
100 * box was first popped up, so we can revert to those values if the
101 * user selects "Cancel".
103 static e_prefs saved_prefs;
109 #if GTK_MAJOR_VERSION < 2
114 GtkTooltips *tooltips;
116 gboolean is_protocol;
120 pref_exists(pref_t *pref _U_, gpointer user_data _U_)
125 /* show a single preference on the GtkTable of a preference page */
127 pref_show(pref_t *pref, gpointer user_data)
129 GtkWidget *main_tb = user_data;
134 /* Give this preference a label which is its title, followed by a colon,
135 and left-align it. */
137 label_string = g_malloc(strlen(title) + 2);
138 strcpy(label_string, title);
139 strcat(label_string, ":");
141 /* Save the current value of the preference, so that we can revert it if
142 the user does "Apply" and then "Cancel", and create the control for
143 editing the preference. */
144 switch (pref->type) {
147 pref->saved_val.uint = *pref->varp.uint;
149 /* XXX - there are no uint spinbuttons, so we can't use a spinbutton.
150 Even more annoyingly, even if there were, GLib doesn't define
151 G_MAXUINT - but I think ANSI C may define UINT_MAX, so we could
153 switch (pref->info.base) {
156 g_snprintf(uint_str, 10+1, "%u", pref->saved_val.uint);
160 g_snprintf(uint_str, 10+1, "%o", pref->saved_val.uint);
164 g_snprintf(uint_str, 10+1, "%x", pref->saved_val.uint);
167 pref->control = create_preference_entry(main_tb, pref->ordinal,
168 label_string, pref->description,
173 pref->saved_val.boolval = *pref->varp.boolp;
174 pref->control = create_preference_check_button(main_tb, pref->ordinal,
175 label_string, pref->description,
176 pref->saved_val.boolval);
180 pref->saved_val.enumval = *pref->varp.enump;
181 if (pref->info.enum_info.radio_buttons) {
182 /* Show it as radio buttons. */
183 pref->control = create_preference_radio_buttons(main_tb, pref->ordinal,
184 label_string, pref->description,
185 pref->info.enum_info.enumvals,
186 pref->saved_val.enumval);
188 /* Show it as an option menu. */
189 pref->control = create_preference_option_menu(main_tb, pref->ordinal,
190 label_string, pref->description,
191 pref->info.enum_info.enumvals,
192 pref->saved_val.enumval);
197 if (pref->saved_val.string != NULL)
198 g_free(pref->saved_val.string);
199 pref->saved_val.string = g_strdup(*pref->varp.string);
200 pref->control = create_preference_entry(main_tb, pref->ordinal,
201 label_string, pref->description,
202 pref->saved_val.string);
206 g_assert_not_reached();
209 g_free(label_string);
214 #define MAX_TREE_NODE_NAME_LEN 64
215 /* show prefs page for each registered module (protocol) */
217 module_prefs_show(module_t *module, gpointer user_data)
219 struct ct_struct *cts = user_data;
220 struct ct_struct child_cts;
221 GtkWidget *main_vb, *main_tb, *frame;
222 gchar label_str[MAX_TREE_NODE_NAME_LEN];
223 #if GTK_MAJOR_VERSION < 2
224 gchar *label_ptr = label_str;
225 GtkCTreeNode *ct_node;
232 * Is this module a subtree, with modules underneath it?
234 if (!module->is_subtree) {
237 * Does it have any preferences (other than possibly obsolete ones)?
239 if (prefs_pref_foreach(module, pref_exists, NULL) == 0) {
241 * No. Don't put the module into the preferences window.
242 * XXX - we should do the same for subtrees; if a subtree has
243 * nothing under it that will be displayed, don't put it into
251 * Add this module to the tree.
253 strcpy(label_str, module->title);
254 #if GTK_MAJOR_VERSION < 2
255 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts->tree), cts->node, NULL,
256 &label_ptr, 5, NULL, NULL, NULL, NULL, !module->is_subtree,
259 model = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(cts->tree)));
260 if (module->is_subtree)
261 gtk_tree_store_append(model, &iter, NULL);
263 gtk_tree_store_append(model, &iter, &cts->iter);
269 if (module->is_subtree) {
274 /* Note that there's no page attached to this item */
275 #if GTK_MAJOR_VERSION < 2
276 gtk_ctree_node_set_row_data(GTK_CTREE(cts->tree), ct_node,
277 GINT_TO_POINTER(-1));
279 gtk_tree_store_set(model, &iter, 0, label_str, 1, -1, -1);
283 * Walk the subtree and attach stuff to it.
286 #if GTK_MAJOR_VERSION < 2
287 child_cts.node = ct_node;
289 child_cts.iter = iter;
291 if (module == protocols_module)
292 child_cts.is_protocol = TRUE;
293 prefs_module_list_foreach(module->prefs, module_prefs_show, &child_cts);
296 * No. Create a notebook page for it.
300 frame = gtk_frame_new(module->title);
301 gtk_widget_show(frame);
303 /* Main vertical box */
304 main_vb = gtk_vbox_new(FALSE, 5);
305 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
306 gtk_container_add(GTK_CONTAINER(frame), main_vb);
309 main_tb = gtk_table_new(module->numprefs, 2, FALSE);
310 gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0);
311 gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10);
312 gtk_table_set_col_spacings(GTK_TABLE(main_tb), 15);
313 OBJECT_SET_DATA(main_tb, E_TOOLTIPS_KEY, cts->tooltips);
315 /* Add items for each of the preferences */
316 prefs_pref_foreach(module, pref_show, main_tb);
318 /* Associate this module with the page's frame. */
319 OBJECT_SET_DATA(frame, E_PAGE_MODULE_KEY, module);
321 /* Add the page to the notebook */
322 gtk_notebook_append_page(GTK_NOTEBOOK(cts->notebook), frame, NULL);
324 /* Attach the page to the tree item */
325 #if GTK_MAJOR_VERSION < 2
326 gtk_ctree_node_set_row_data(GTK_CTREE(cts->tree), ct_node,
327 GINT_TO_POINTER(cts->page));
329 gtk_tree_store_set(model, &iter, 0, label_str, 1, cts->page, -1);
334 /* Show 'em what we got */
335 gtk_widget_show_all(main_vb);
340 #if GTK_MAJOR_VERSION < 2
341 #define prefs_tree_iter GtkCTreeNode *
343 #define prefs_tree_iter GtkTreeIter
346 /* add a page to the tree */
348 prefs_tree_page_add(const gchar *title, gint page_nr,
349 gpointer store, prefs_tree_iter *parent_iter,
351 #if GTK_MAJOR_VERSION >= 2
356 #if GTK_MAJOR_VERSION < 2
357 const gchar *label_ptr = title;
359 prefs_tree_iter iter;
361 #if GTK_MAJOR_VERSION < 2
362 iter = gtk_ctree_insert_node(GTK_CTREE(store), parent_iter ? *parent_iter : NULL, NULL,
363 (gchar **) &label_ptr, 5, NULL, NULL, NULL, NULL, !has_child, TRUE);
364 gtk_ctree_node_set_row_data(GTK_CTREE(store), iter,
365 GINT_TO_POINTER(page_nr));
367 gtk_tree_store_append(store, &iter, parent_iter);
368 gtk_tree_store_set(store, &iter, 0, title, 1, page_nr, -1);
373 /* add a page to the notebook */
375 prefs_nb_page_add(GtkWidget *notebook, const gchar *title, GtkWidget *page, const char *page_key)
379 frame = gtk_frame_new(title);
380 gtk_widget_show(frame);
381 gtk_container_add(GTK_CONTAINER(frame), page);
382 OBJECT_SET_DATA(prefs_w, page_key, page);
383 gtk_notebook_append_page (GTK_NOTEBOOK(notebook), frame, NULL);
389 /* show the dialog */
391 prefs_cb(GtkWidget *w _U_, gpointer dummy _U_)
393 GtkWidget *top_hb, *bbox, *prefs_nb, *ct_sb,
394 *ok_bt, *apply_bt, *save_bt, *cancel_bt;
395 GtkWidget *gui_font_pg;
396 gchar label_str[MAX_TREE_NODE_NAME_LEN];
397 struct ct_struct cts;
398 #if GTK_MAJOR_VERSION < 2
399 gpointer store = NULL;
400 static gchar *fixedwidths[] = { "c", "m", NULL };
403 GtkTreeSelection *selection;
404 GtkCellRenderer *renderer;
405 GtkTreeViewColumn *column;
408 prefs_tree_iter gui_iter;
411 if (prefs_w != NULL) {
412 /* There's already a "Preferences" dialog box; reactivate it. */
413 reactivate_window(prefs_w);
417 /* Save the current preferences, so we can revert to those values
418 if the user presses "Cancel". */
419 copy_prefs(&saved_prefs, &prefs);
421 prefs_w = dlg_window_new("Ethereal: Preferences");
424 * Unfortunately, we can't arrange that a GtkTable widget wrap an event box
425 * around a table row, so the spacing between the preference item's label
426 * and its control widgets is inactive and the tooltip doesn't pop up when
427 * the mouse is over it.
429 cts.tooltips = gtk_tooltips_new();
431 /* Container for each row of widgets */
432 cts.main_vb = gtk_vbox_new(FALSE, 5);
433 gtk_container_border_width(GTK_CONTAINER(cts.main_vb), 5);
434 gtk_container_add(GTK_CONTAINER(prefs_w), cts.main_vb);
435 gtk_widget_show(cts.main_vb);
437 /* Top row: Preferences tree and notebook */
438 top_hb = gtk_hbox_new(FALSE, 10);
439 gtk_container_add(GTK_CONTAINER(cts.main_vb), top_hb);
440 gtk_widget_show(top_hb);
442 /* scrolled window on the left for the categories tree */
443 ct_sb = scrolled_window_new(NULL, NULL);
444 #if GTK_MAJOR_VERSION >= 2
445 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(ct_sb),
448 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ct_sb),
449 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
450 gtk_container_add(GTK_CONTAINER(top_hb), ct_sb);
451 gtk_widget_show(ct_sb);
453 /* categories tree */
454 #if GTK_MAJOR_VERSION < 2
455 cts.tree = ctree_new(1, 0);
458 gtk_clist_set_column_auto_resize(GTK_CLIST(cts.tree), 0, TRUE);
459 SIGNAL_CONNECT(cts.tree, "tree-select-row", prefs_tree_select_cb, NULL);
461 store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_INT);
462 cts.tree = tree_view_new(GTK_TREE_MODEL(store));
463 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(cts.tree), FALSE);
464 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(cts.tree));
465 gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
466 renderer = gtk_cell_renderer_text_new();
467 col_offset = gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(cts.tree),
468 -1, "Name", renderer,
470 column = gtk_tree_view_get_column(GTK_TREE_VIEW(cts.tree),
472 gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column),
473 GTK_TREE_VIEW_COLUMN_AUTOSIZE);
474 SIGNAL_CONNECT(selection, "changed", prefs_tree_select_cb, NULL);
476 gtk_container_add(GTK_CONTAINER(ct_sb), cts.tree);
477 gtk_widget_show(cts.tree);
479 /* A notebook widget without tabs is used to flip between prefs */
480 notebook = prefs_nb = gtk_notebook_new();
481 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(prefs_nb), FALSE);
482 gtk_notebook_set_show_border(GTK_NOTEBOOK(prefs_nb), FALSE);
483 gtk_container_add(GTK_CONTAINER(top_hb), prefs_nb);
484 gtk_widget_show(prefs_nb);
489 strcpy(label_str, "User Interface");
490 prefs_nb_page_add(prefs_nb, label_str, gui_prefs_show(), E_GUI_PAGE_KEY);
491 gui_iter = prefs_tree_page_add(label_str, cts.page, store, NULL, TRUE);
494 /* GUI layout prefs */
495 strcpy(label_str, "Layout");
496 prefs_nb_page_add(prefs_nb, label_str, layout_prefs_show(), E_GUI_LAYOUT_PAGE_KEY);
497 prefs_tree_page_add(label_str, cts.page, store, &gui_iter, FALSE);
500 /* GUI Column prefs */
501 strcpy(label_str, "Columns");
502 prefs_nb_page_add(prefs_nb, label_str, column_prefs_show(), E_GUI_COLUMN_PAGE_KEY);
503 prefs_tree_page_add(label_str, cts.page, store, &gui_iter, FALSE);
507 strcpy(label_str, "Font");
508 gui_font_pg = gui_font_prefs_show();
509 prefs_nb_page_add(prefs_nb, label_str, gui_font_pg, E_GUI_FONT_PAGE_KEY);
510 prefs_tree_page_add(label_str, cts.page, store, &gui_iter, FALSE);
513 gtk_container_border_width( GTK_CONTAINER(gui_font_pg), 5 );
515 /* IMPORTANT: the following gtk_font_selection_set_xy() functions will only
516 work, if the widget and it's corresponding window is already shown
517 (so don't put the following into gui_font_prefs_show()) !!! */
519 /* We set the current font and, for GTK+ 1.2[.x], the font filter
520 now, because they appear not to work when run before appending
521 the frame to the notebook. */
523 /* Set the font to the current font.
524 XXX - GTK+ 1.2.8, and probably earlier versions, have a bug
525 wherein that doesn't necessarily cause that font to be
526 selected in the dialog box. I've sent to the GTK+ folk
527 a fix; hopefully, it'll show up in 1.2.9 if, as, and when
528 they put out a 1.2.9 release. */
529 gtk_font_selection_set_font_name(
530 GTK_FONT_SELECTION(gui_font_pg), prefs.PREFS_GUI_FONT_NAME);
532 #if GTK_MAJOR_VERSION < 2
533 /* Set its filter to show only fixed_width fonts. */
534 gtk_font_selection_set_filter(
535 GTK_FONT_SELECTION(gui_font_pg),
536 GTK_FONT_FILTER_BASE, /* user can't change the filter */
537 GTK_FONT_ALL, /* bitmap or scalable are fine */
538 NULL, /* all foundries are OK */
539 NULL, /* all weights are OK (XXX - normal only?) */
540 NULL, /* all slants are OK (XXX - Roman only?) */
541 NULL, /* all setwidths are OK */
542 fixedwidths, /* ONLY fixed-width fonts */
543 NULL); /* all charsets are OK (XXX - ISO 8859/1 only?) */
546 /* GUI Colors prefs */
547 strcpy(label_str, "Colors");
548 prefs_nb_page_add(prefs_nb, label_str, stream_prefs_show(), E_GUI_COLORS_PAGE_KEY);
549 prefs_tree_page_add(label_str, cts.page, store, &gui_iter, FALSE);
552 /* select the main GUI page as the default page and expand it's children */
553 #if GTK_MAJOR_VERSION < 2
554 gtk_ctree_select(GTK_CTREE(cts.tree), gui_iter);
556 gtk_tree_selection_select_iter(selection, &gui_iter);
557 /* (expand will only take effect, when at least one child exists) */
558 gtk_tree_view_expand_all(GTK_TREE_VIEW(cts.tree));
563 /* Is WPcap loaded? */
567 strcpy(label_str, "Capture");
568 prefs_nb_page_add(prefs_nb, label_str, capture_prefs_show(), E_CAPTURE_PAGE_KEY);
569 prefs_tree_page_add(label_str, cts.page, store, NULL, FALSE);
574 #endif /* HAVE_LIBPCAP */
577 strcpy(label_str, "Printing");
578 prefs_nb_page_add(prefs_nb, label_str, printer_prefs_show(), E_PRINT_PAGE_KEY);
579 prefs_tree_page_add(label_str, cts.page, store, NULL, FALSE);
582 /* Name resolution prefs */
583 strcpy(label_str, "Name Resolution");
584 prefs_nb_page_add(prefs_nb, label_str, nameres_prefs_show(), E_NAMERES_PAGE_KEY);
585 prefs_tree_page_add(label_str, cts.page, store, NULL, FALSE);
588 /* Registered prefs */
589 cts.notebook = prefs_nb;
590 cts.is_protocol = FALSE;
591 prefs_module_list_foreach(NULL, module_prefs_show, &cts);
593 /* Button row: OK and cancel buttons */
594 bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_APPLY, GTK_STOCK_SAVE, GTK_STOCK_CANCEL, NULL);
595 gtk_box_pack_start(GTK_BOX(cts.main_vb), bbox, FALSE, FALSE, 0);
596 gtk_widget_show(bbox);
598 ok_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_OK);
599 SIGNAL_CONNECT(ok_bt, "clicked", prefs_main_ok_cb, prefs_w);
601 apply_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_APPLY);
602 SIGNAL_CONNECT(apply_bt, "clicked", prefs_main_apply_cb, prefs_w);
604 save_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_SAVE);
605 SIGNAL_CONNECT(save_bt, "clicked", prefs_main_save_cb, prefs_w);
607 cancel_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_CANCEL);
608 SIGNAL_CONNECT(cancel_bt, "clicked", prefs_main_cancel_cb, prefs_w);
609 window_set_cancel_button(prefs_w, cancel_bt, NULL);
611 gtk_widget_grab_default(ok_bt);
613 SIGNAL_CONNECT(prefs_w, "delete_event", prefs_main_delete_event_cb, prefs_w);
614 SIGNAL_CONNECT(prefs_w, "destroy", prefs_main_destroy_cb, prefs_w);
616 gtk_widget_show(prefs_w);
617 window_present(prefs_w);
619 #if GTK_MAJOR_VERSION >= 2
620 g_object_unref(G_OBJECT(store));
625 set_option_label(GtkWidget *main_tb, int table_position,
626 const gchar *label_text, const gchar *tooltip_text, GtkTooltips *tooltips)
629 GtkWidget *event_box;
631 label = gtk_label_new(label_text);
632 gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
633 gtk_widget_show(label);
635 event_box = gtk_event_box_new();
636 gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box, 0, 1,
637 table_position, table_position + 1);
638 if (tooltip_text != NULL && tooltips != NULL)
639 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
640 gtk_container_add(GTK_CONTAINER(event_box), label);
641 gtk_widget_show(event_box);
645 create_preference_check_button(GtkWidget *main_tb, int table_position,
646 const gchar *label_text, const gchar *tooltip_text, gboolean active)
648 GtkTooltips *tooltips;
649 GtkWidget *check_box;
651 tooltips = OBJECT_GET_DATA(main_tb, E_TOOLTIPS_KEY);
653 set_option_label(main_tb, table_position, label_text, tooltip_text,
656 check_box = gtk_check_button_new();
657 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_box), active);
658 gtk_table_attach_defaults(GTK_TABLE(main_tb), check_box, 1, 2,
659 table_position, table_position + 1);
660 if (tooltip_text != NULL && tooltips != NULL)
661 gtk_tooltips_set_tip(tooltips, check_box, tooltip_text, NULL);
667 create_preference_radio_buttons(GtkWidget *main_tb, int table_position,
668 const gchar *label_text, const gchar *tooltip_text,
669 const enum_val_t *enumvals, gint current_val)
671 GtkTooltips *tooltips;
672 GtkWidget *radio_button_hbox, *button = NULL;
675 const enum_val_t *enum_valp;
676 GtkWidget *event_box;
678 tooltips = OBJECT_GET_DATA(main_tb, E_TOOLTIPS_KEY);
680 set_option_label(main_tb, table_position, label_text, tooltip_text,
683 radio_button_hbox = gtk_hbox_new(FALSE, 0);
685 for (enum_valp = enumvals, index = 0; enum_valp->name != NULL;
686 enum_valp++, index++) {
687 button = gtk_radio_button_new_with_label(rb_group,
688 enum_valp->description);
689 gtk_widget_show(button);
690 rb_group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
691 gtk_box_pack_start(GTK_BOX(radio_button_hbox), button, FALSE,
693 if (enum_valp->value == current_val) {
694 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button),
698 gtk_widget_show(radio_button_hbox);
700 event_box = gtk_event_box_new();
701 gtk_container_add(GTK_CONTAINER(event_box), radio_button_hbox);
702 gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box, 1, 2,
703 table_position, table_position+1);
704 if (tooltip_text != NULL && tooltips != NULL)
705 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
706 gtk_widget_show(event_box);
709 * It doesn't matter which of the buttons we return - we fetch
710 * the value by looking at the entire radio button group to
711 * which it belongs, and we can get that from any button.
717 label_to_enum_val(GtkWidget *label, const enum_val_t *enumvals)
722 /* Get the label's text, and translate it to a value.
723 We match only the descriptions, as those are what appear in
724 the option menu items or as labels for radio buttons.
725 We fail if we don't find a match, as that "can't happen". */
726 gtk_label_get(GTK_LABEL(label), &label_string);
728 for (i = 0; enumvals[i].name != NULL; i++) {
729 if (strcasecmp(label_string, enumvals[i].description) == 0) {
730 return enumvals[i].value;
733 g_assert_not_reached();
738 fetch_preference_radio_buttons_val(GtkWidget *button,
739 const enum_val_t *enumvals)
745 * Go through the list of of radio buttons in the button's group,
746 * and find the first one that's active.
748 rb_group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
750 for (rb_entry = rb_group; rb_entry != NULL;
751 rb_entry = g_slist_next(rb_entry)) {
752 button = rb_entry->data;
753 if (GTK_TOGGLE_BUTTON(button)->active)
757 /* OK, now return the value corresponding to that button's label. */
758 return label_to_enum_val(GTK_BIN(button)->child, enumvals);
762 create_preference_option_menu(GtkWidget *main_tb, int table_position,
763 const gchar *label_text, const gchar *tooltip_text,
764 const enum_val_t *enumvals, gint current_val)
766 GtkTooltips *tooltips;
767 GtkWidget *menu_box, *menu, *menu_item, *option_menu;
768 int menu_index, index;
769 const enum_val_t *enum_valp;
770 GtkWidget *event_box;
772 tooltips = OBJECT_GET_DATA(main_tb, E_TOOLTIPS_KEY);
774 set_option_label(main_tb, table_position, label_text, tooltip_text,
777 /* Create a menu from the enumvals */
778 menu = gtk_menu_new();
779 if (tooltip_text != NULL && tooltips != NULL)
780 gtk_tooltips_set_tip(tooltips, menu, tooltip_text, NULL);
782 for (enum_valp = enumvals, index = 0; enum_valp->name != NULL;
783 enum_valp++, index++) {
784 menu_item = gtk_menu_item_new_with_label(enum_valp->description);
785 gtk_menu_append(GTK_MENU(menu), menu_item);
786 if (enum_valp->value == current_val)
788 gtk_widget_show(menu_item);
791 /* Create the option menu from the menu */
792 option_menu = gtk_option_menu_new();
793 gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), menu);
795 /* Set its current value to the variable's current value */
796 if (menu_index != -1)
797 gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu),
801 * Put the option menu in an hbox, so that it's only as wide
802 * as the widest entry, rather than being as wide as the table
805 menu_box = gtk_hbox_new(FALSE, 0);
806 gtk_box_pack_start(GTK_BOX(menu_box), option_menu, FALSE, FALSE, 0);
808 event_box = gtk_event_box_new();
809 gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box,
810 1, 2, table_position, table_position + 1);
811 if (tooltip_text != NULL && tooltips != NULL)
812 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
813 gtk_container_add(GTK_CONTAINER(event_box), menu_box);
819 fetch_preference_option_menu_val(GtkWidget *optmenu, const enum_val_t *enumvals)
822 * OK, now return the value corresponding to the label for the
823 * currently active entry in the option menu.
825 * Yes, this is how you get the label for that entry. See FAQ
826 * 6.8 in the GTK+ FAQ.
828 return label_to_enum_val(GTK_BIN(optmenu)->child, enumvals);
832 create_preference_entry(GtkWidget *main_tb, int table_position,
833 const gchar *label_text, const gchar *tooltip_text, char *value)
835 GtkTooltips *tooltips;
838 tooltips = OBJECT_GET_DATA(main_tb, E_TOOLTIPS_KEY);
840 set_option_label(main_tb, table_position, label_text, tooltip_text,
843 entry = gtk_entry_new();
845 gtk_entry_set_text(GTK_ENTRY(entry), value);
846 gtk_table_attach_defaults(GTK_TABLE(main_tb), entry, 1, 2,
847 table_position, table_position + 1);
848 if (tooltip_text != NULL && tooltips != NULL)
849 gtk_tooltips_set_tip(tooltips, entry, tooltip_text, NULL);
850 gtk_widget_show(entry);
856 pref_fetch(pref_t *pref, gpointer user_data)
863 gboolean *pref_changed_p = user_data;
865 /* Fetch the value of the preference, and set the appropriate variable
867 switch (pref->type) {
870 str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
871 uval = strtoul(str_val, &p, pref->info.base);
873 if (p == value || *p != '\0')
874 return PREFS_SET_SYNTAX_ERR; /* number was bad */
876 if (*pref->varp.uint != uval) {
877 *pref_changed_p = TRUE;
878 *pref->varp.uint = uval;
883 bval = GTK_TOGGLE_BUTTON(pref->control)->active;
884 if (*pref->varp.boolp != bval) {
885 *pref_changed_p = TRUE;
886 *pref->varp.boolp = bval;
891 if (pref->info.enum_info.radio_buttons) {
892 enumval = fetch_preference_radio_buttons_val(pref->control,
893 pref->info.enum_info.enumvals);
895 enumval = fetch_preference_option_menu_val(pref->control,
896 pref->info.enum_info.enumvals);
899 if (*pref->varp.enump != enumval) {
900 *pref_changed_p = TRUE;
901 *pref->varp.enump = enumval;
906 str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
907 if (strcmp(*pref->varp.string, str_val) != 0) {
908 *pref_changed_p = TRUE;
909 g_free(*pref->varp.string);
910 *pref->varp.string = g_strdup(str_val);
915 g_assert_not_reached();
922 module_prefs_fetch(module_t *module, gpointer user_data)
924 gboolean *must_redissect_p = user_data;
926 /* For all preferences in this module, fetch its value from this
927 module's notebook page. Find out whether any of them changed. */
928 module->prefs_changed = FALSE; /* assume none of them changed */
929 prefs_pref_foreach(module, pref_fetch, &module->prefs_changed);
931 /* If any of them changed, indicate that we must redissect and refilter
932 the current capture (if we have one), as the preference change
933 could cause packets to be dissected differently. */
934 if (module->prefs_changed)
935 *must_redissect_p = TRUE;
939 pref_clean(pref_t *pref, gpointer user_data _U_)
941 switch (pref->type) {
953 if (pref->saved_val.string != NULL) {
954 g_free(pref->saved_val.string);
955 pref->saved_val.string = NULL;
960 g_assert_not_reached();
967 module_prefs_clean(module_t *module, gpointer user_data _U_)
969 /* For all preferences in this module, clean up any cruft allocated for
970 use by the GUI code. */
971 prefs_pref_foreach(module, pref_clean, NULL);
975 /* fetch all pref values from all pages */
977 prefs_main_fetch_all(GtkWidget *dlg, gboolean *must_redissect)
979 /* Fetch the preferences (i.e., make sure all the values set in all of
980 the preferences panes have been copied to "prefs" and the registered
982 gui_prefs_fetch(OBJECT_GET_DATA(dlg, E_GUI_PAGE_KEY));
983 layout_prefs_fetch(OBJECT_GET_DATA(dlg, E_GUI_LAYOUT_PAGE_KEY));
984 column_prefs_fetch(OBJECT_GET_DATA(dlg, E_GUI_COLUMN_PAGE_KEY));
985 stream_prefs_fetch(OBJECT_GET_DATA(dlg, E_GUI_COLORS_PAGE_KEY));
989 /* Is WPcap loaded? */
992 capture_prefs_fetch(OBJECT_GET_DATA(dlg, E_CAPTURE_PAGE_KEY));
996 #endif /* HAVE_LIBPCAP */
997 printer_prefs_fetch(OBJECT_GET_DATA(dlg, E_PRINT_PAGE_KEY));
998 nameres_prefs_fetch(OBJECT_GET_DATA(dlg, E_NAMERES_PAGE_KEY));
1000 prefs_modules_foreach(module_prefs_fetch, must_redissect);
1004 /* apply all pref values to the real world */
1006 prefs_main_apply_all(GtkWidget *dlg)
1009 * Apply the protocol preferences first - "gui_prefs_apply()" could
1010 * cause redissection, and we have to make sure the protocol
1011 * preference changes have been fully applied.
1015 gui_prefs_apply(OBJECT_GET_DATA(dlg, E_GUI_PAGE_KEY));
1016 layout_prefs_apply(OBJECT_GET_DATA(dlg, E_GUI_LAYOUT_PAGE_KEY));
1017 column_prefs_apply(OBJECT_GET_DATA(dlg, E_GUI_COLUMN_PAGE_KEY));
1018 stream_prefs_apply(OBJECT_GET_DATA(dlg, E_GUI_COLORS_PAGE_KEY));
1022 /* Is WPcap loaded? */
1025 capture_prefs_apply(OBJECT_GET_DATA(dlg, E_CAPTURE_PAGE_KEY));
1029 #endif /* HAVE_LIBPCAP */
1030 printer_prefs_apply(OBJECT_GET_DATA(dlg, E_PRINT_PAGE_KEY));
1031 nameres_prefs_apply(OBJECT_GET_DATA(dlg, E_NAMERES_PAGE_KEY));
1035 /* destroy all preferences ressources from all pages */
1037 prefs_main_destroy_all(GtkWidget *dlg)
1039 gui_prefs_destroy(OBJECT_GET_DATA(dlg, E_GUI_PAGE_KEY));
1040 layout_prefs_destroy(OBJECT_GET_DATA(dlg, E_GUI_LAYOUT_PAGE_KEY));
1041 column_prefs_destroy(OBJECT_GET_DATA(dlg, E_GUI_COLUMN_PAGE_KEY));
1042 stream_prefs_destroy(OBJECT_GET_DATA(dlg, E_GUI_COLORS_PAGE_KEY));
1046 /* Is WPcap loaded? */
1049 capture_prefs_destroy(OBJECT_GET_DATA(dlg, E_CAPTURE_PAGE_KEY));
1053 #endif /* HAVE_LIBPCAP */
1054 printer_prefs_destroy(OBJECT_GET_DATA(dlg, E_PRINT_PAGE_KEY));
1055 nameres_prefs_destroy(OBJECT_GET_DATA(dlg, E_NAMERES_PAGE_KEY));
1057 /* Free up the saved preferences (both for "prefs" and for registered
1059 free_prefs(&saved_prefs);
1060 prefs_modules_foreach(module_prefs_clean, NULL);
1065 prefs_main_ok_cb(GtkWidget *ok_bt _U_, gpointer parent_w)
1067 gboolean must_redissect = FALSE;
1069 prefs_main_fetch_all(parent_w, &must_redissect);
1071 prefs_main_apply_all(parent_w);
1073 /* Now destroy the "Preferences" dialog. */
1074 window_destroy(GTK_WIDGET(parent_w));
1076 if (must_redissect) {
1077 /* Redissect all the packets, and re-evaluate the display filter. */
1078 redissect_packets(&cfile);
1083 prefs_main_apply_cb(GtkWidget *apply_bt _U_, gpointer parent_w)
1085 gboolean must_redissect = FALSE;
1087 prefs_main_fetch_all(parent_w, &must_redissect);
1089 prefs_main_apply_all(parent_w);
1091 if (must_redissect) {
1092 /* Redissect all the packets, and re-evaluate the display filter. */
1093 redissect_packets(&cfile);
1098 prefs_main_save_cb(GtkWidget *save_bt _U_, gpointer parent_w)
1100 gboolean must_redissect = FALSE;
1105 prefs_main_fetch_all(parent_w, &must_redissect);
1107 /* Create the directory that holds personal configuration files, if
1109 if (create_persconffile_dir(&pf_dir_path) == -1) {
1110 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1111 "Can't create directory\n\"%s\"\nfor preferences file: %s.", pf_dir_path,
1113 g_free(pf_dir_path);
1115 /* Write the preferencs out. */
1116 err = write_prefs(&pf_path);
1118 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1119 "Can't open preferences file\n\"%s\": %s.", pf_path,
1125 /* Now apply those preferences.
1126 XXX - should we do this? The user didn't click "OK" or "Apply".
1129 1) by saving the preferences they presumably indicate that they
1132 2) the next time they fire Ethereal up, those preferences will
1135 3) we'd have to buffer "must_redissect" so that if they do
1136 "Apply" after this, we know we have to redissect;
1138 4) we did apply the protocol preferences, at least, in the past. */
1139 prefs_main_apply_all(parent_w);
1141 if (must_redissect) {
1142 /* Redissect all the packets, and re-evaluate the display filter. */
1143 redissect_packets(&cfile);
1148 pref_revert(pref_t *pref, gpointer user_data)
1150 gboolean *pref_changed_p = user_data;
1152 /* Revert the preference to its saved value. */
1153 switch (pref->type) {
1156 if (*pref->varp.uint != pref->saved_val.uint) {
1157 *pref_changed_p = TRUE;
1158 *pref->varp.uint = pref->saved_val.uint;
1163 if (*pref->varp.boolp != pref->saved_val.boolval) {
1164 *pref_changed_p = TRUE;
1165 *pref->varp.boolp = pref->saved_val.boolval;
1170 if (*pref->varp.enump != pref->saved_val.enumval) {
1171 *pref_changed_p = TRUE;
1172 *pref->varp.enump = pref->saved_val.enumval;
1177 if (strcmp(*pref->varp.string, pref->saved_val.string) != 0) {
1178 *pref_changed_p = TRUE;
1179 g_free(*pref->varp.string);
1180 *pref->varp.string = g_strdup(pref->saved_val.string);
1185 g_assert_not_reached();
1192 module_prefs_revert(module_t *module, gpointer user_data)
1194 gboolean *must_redissect_p = user_data;
1196 /* For all preferences in this module, revert its value to the value
1197 it had when we popped up the Preferences dialog. Find out whether
1198 this changes any of them. */
1199 module->prefs_changed = FALSE; /* assume none of them changed */
1200 prefs_pref_foreach(module, pref_revert, &module->prefs_changed);
1202 /* If any of them changed, indicate that we must redissect and refilter
1203 the current capture (if we have one), as the preference change
1204 could cause packets to be dissected differently. */
1205 if (module->prefs_changed)
1206 *must_redissect_p = TRUE;
1209 /* cancel button pressed, revert prefs to saved and exit dialog */
1211 prefs_main_cancel_cb(GtkWidget *cancel_bt _U_, gpointer parent_w)
1213 gboolean must_redissect = FALSE;
1215 /* Free up the current preferences and copy the saved preferences to the
1216 current preferences. */
1218 copy_prefs(&prefs, &saved_prefs);
1220 /* Now revert the registered preferences. */
1221 prefs_modules_foreach(module_prefs_revert, &must_redissect);
1223 /* Now apply the reverted-to preferences. */
1224 prefs_main_apply_all(parent_w);
1226 window_destroy(GTK_WIDGET(parent_w));
1228 if (must_redissect) {
1229 /* Redissect all the packets, and re-evaluate the display filter. */
1230 redissect_packets(&cfile);
1234 /* Treat this as a cancel, by calling "prefs_main_cancel_cb()" */
1236 prefs_main_delete_event_cb(GtkWidget *prefs_w, GdkEvent *event _U_,
1237 gpointer parent_w _U_)
1239 prefs_main_cancel_cb(NULL, prefs_w);
1244 /* dialog *is* already destroyed, clean up memory and such */
1246 prefs_main_destroy_cb(GtkWidget *win _U_, gpointer parent_w)
1248 prefs_main_destroy_all(parent_w);
1250 /* Note that we no longer have a "Preferences" dialog box. */
1254 struct properties_data {
1260 module_search_properties(module_t *module, gpointer user_data)
1262 struct properties_data *p = (struct properties_data *)user_data;
1264 /* If this module has the specified title, remember it. */
1265 if (strcmp(module->title, p->title) == 0)
1270 properties_cb(GtkWidget *w, gpointer dummy)
1272 header_field_info *hfinfo;
1274 struct properties_data p;
1277 module_t *page_module;
1279 if (cfile.finfo_selected == NULL) {
1280 /* There is no field selected */
1284 /* Find the title for the protocol for the selected field. */
1285 hfinfo = cfile.finfo_selected->hfinfo;
1286 if (hfinfo->parent == -1)
1287 title = prefs_get_title_by_name(hfinfo->abbrev);
1289 title = prefs_get_title_by_name(proto_registrar_get_abbrev(hfinfo->parent));
1291 return; /* Couldn't find it. XXX - just crash? "Can't happen"? */
1293 /* Find the module for that protocol by searching for one with that title.
1294 XXX - should we just associate protocols with modules directly? */
1297 prefs_module_list_foreach(protocols_module->prefs, module_search_properties,
1299 if (p.module == NULL) {
1300 /* We didn't find it - that protocol probably has no preferences. */
1304 /* Create a preferences window, or pop up an existing one. */
1305 if (prefs_w != NULL) {
1306 reactivate_window(prefs_w);
1311 /* Search all the pages in that window for the one with the specified
1314 (frame = gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), page_num)) != NULL;
1316 /* Get the module for this page. */
1317 page_module = OBJECT_GET_DATA(frame, E_PAGE_MODULE_KEY);
1318 if (page_module == NULL)
1319 continue; /* It doesn't have one. */
1320 if (page_module == p.module) {
1321 /* We found it. Select that page. */
1322 gtk_notebook_set_page(GTK_NOTEBOOK(notebook), page_num);
1328 /* Prefs tree selection callback. The node data has been loaded with
1329 the proper notebook page to load. */
1330 #if GTK_MAJOR_VERSION < 2
1332 prefs_tree_select_cb(GtkCTree *ct, GtkCTreeNode *node, gint col _U_,
1336 prefs_tree_select_cb(GtkTreeSelection *sel, gpointer dummy _U_)
1340 #if GTK_MAJOR_VERSION >= 2
1341 GtkTreeModel *model;
1345 #if GTK_MAJOR_VERSION < 2
1346 page = GPOINTER_TO_INT(gtk_ctree_node_get_row_data(ct, node));
1349 gtk_notebook_set_page(GTK_NOTEBOOK(notebook), page);
1351 if (gtk_tree_selection_get_selected(sel, &model, &iter))
1353 gtk_tree_model_get(model, &iter, 1, &page, -1);
1355 gtk_notebook_set_page(GTK_NOTEBOOK(notebook), page);