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>
38 #include <epan/prefs.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 <epan/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);
209 if (pref->saved_val.range != NULL)
210 g_free(pref->saved_val.range);
211 pref->saved_val.range = range_copy(*pref->varp.range);
212 range_string = range_convert_range(*pref->varp.range);
213 pref->control = create_preference_entry(main_tb, pref->ordinal,
214 label_string, pref->description,
216 g_free(range_string);
221 g_assert_not_reached();
224 g_free(label_string);
229 #define MAX_TREE_NODE_NAME_LEN 64
230 /* show prefs page for each registered module (protocol) */
232 module_prefs_show(module_t *module, gpointer user_data)
234 struct ct_struct *cts = user_data;
235 struct ct_struct child_cts;
236 GtkWidget *main_vb, *main_tb, *frame;
237 gchar label_str[MAX_TREE_NODE_NAME_LEN];
238 #if GTK_MAJOR_VERSION < 2
239 gchar *label_ptr = label_str;
240 GtkCTreeNode *ct_node;
247 * Is this module a subtree, with modules underneath it?
249 if (!module->is_subtree) {
252 * Does it have any preferences (other than possibly obsolete ones)?
254 if (prefs_pref_foreach(module, pref_exists, NULL) == 0) {
256 * No. Don't put the module into the preferences window.
257 * XXX - we should do the same for subtrees; if a subtree has
258 * nothing under it that will be displayed, don't put it into
266 * Add this module to the tree.
268 strcpy(label_str, module->title);
269 #if GTK_MAJOR_VERSION < 2
270 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts->tree), cts->node, NULL,
271 &label_ptr, 5, NULL, NULL, NULL, NULL, !module->is_subtree,
274 model = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(cts->tree)));
275 if (module->is_subtree)
276 gtk_tree_store_append(model, &iter, NULL);
278 gtk_tree_store_append(model, &iter, &cts->iter);
284 if (module->is_subtree) {
289 /* Note that there's no page attached to this item */
290 #if GTK_MAJOR_VERSION < 2
291 gtk_ctree_node_set_row_data(GTK_CTREE(cts->tree), ct_node,
292 GINT_TO_POINTER(-1));
294 gtk_tree_store_set(model, &iter, 0, label_str, 1, -1, -1);
298 * Walk the subtree and attach stuff to it.
301 #if GTK_MAJOR_VERSION < 2
302 child_cts.node = ct_node;
304 child_cts.iter = iter;
306 if (module == protocols_module)
307 child_cts.is_protocol = TRUE;
308 prefs_module_list_foreach(module->prefs, module_prefs_show, &child_cts);
311 * No. Create a notebook page for it.
315 frame = gtk_frame_new(module->title);
316 gtk_widget_show(frame);
318 /* Main vertical box */
319 main_vb = gtk_vbox_new(FALSE, 5);
320 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
321 gtk_container_add(GTK_CONTAINER(frame), main_vb);
324 main_tb = gtk_table_new(module->numprefs, 2, FALSE);
325 gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0);
326 gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10);
327 gtk_table_set_col_spacings(GTK_TABLE(main_tb), 15);
328 OBJECT_SET_DATA(main_tb, E_TOOLTIPS_KEY, cts->tooltips);
330 /* Add items for each of the preferences */
331 prefs_pref_foreach(module, pref_show, main_tb);
333 /* Associate this module with the page's frame. */
334 OBJECT_SET_DATA(frame, E_PAGE_MODULE_KEY, module);
336 /* Add the page to the notebook */
337 gtk_notebook_append_page(GTK_NOTEBOOK(cts->notebook), frame, NULL);
339 /* Attach the page to the tree item */
340 #if GTK_MAJOR_VERSION < 2
341 gtk_ctree_node_set_row_data(GTK_CTREE(cts->tree), ct_node,
342 GINT_TO_POINTER(cts->page));
344 gtk_tree_store_set(model, &iter, 0, label_str, 1, cts->page, -1);
349 /* Show 'em what we got */
350 gtk_widget_show_all(main_vb);
357 #if GTK_MAJOR_VERSION < 2
358 #define prefs_tree_iter GtkCTreeNode *
360 #define prefs_tree_iter GtkTreeIter
363 /* add a page to the tree */
365 prefs_tree_page_add(const gchar *title, gint page_nr,
366 gpointer store, prefs_tree_iter *parent_iter,
368 #if GTK_MAJOR_VERSION >= 2
373 #if GTK_MAJOR_VERSION < 2
374 const gchar *label_ptr = title;
376 prefs_tree_iter iter;
378 #if GTK_MAJOR_VERSION < 2
379 iter = gtk_ctree_insert_node(GTK_CTREE(store), parent_iter ? *parent_iter : NULL, NULL,
380 (gchar **) &label_ptr, 5, NULL, NULL, NULL, NULL, !has_child, TRUE);
381 gtk_ctree_node_set_row_data(GTK_CTREE(store), iter,
382 GINT_TO_POINTER(page_nr));
384 gtk_tree_store_append(store, &iter, parent_iter);
385 gtk_tree_store_set(store, &iter, 0, title, 1, page_nr, -1);
390 /* add a page to the notebook */
392 prefs_nb_page_add(GtkWidget *notebook, const gchar *title, GtkWidget *page, const char *page_key)
396 frame = gtk_frame_new(title);
397 gtk_widget_show(frame);
398 gtk_container_add(GTK_CONTAINER(frame), page);
399 OBJECT_SET_DATA(prefs_w, page_key, page);
400 gtk_notebook_append_page (GTK_NOTEBOOK(notebook), frame, NULL);
406 /* show the dialog */
408 prefs_cb(GtkWidget *w _U_, gpointer dummy _U_)
410 GtkWidget *top_hb, *bbox, *prefs_nb, *ct_sb,
411 *ok_bt, *apply_bt, *save_bt, *cancel_bt;
412 GtkWidget *gui_font_pg;
413 gchar label_str[MAX_TREE_NODE_NAME_LEN];
414 struct ct_struct cts;
415 #if GTK_MAJOR_VERSION < 2
416 gpointer store = NULL;
417 static gchar *fixedwidths[] = { "c", "m", NULL };
420 GtkTreeSelection *selection;
421 GtkCellRenderer *renderer;
422 GtkTreeViewColumn *column;
425 prefs_tree_iter gui_iter;
428 if (prefs_w != NULL) {
429 /* There's already a "Preferences" dialog box; reactivate it. */
430 reactivate_window(prefs_w);
434 /* Save the current preferences, so we can revert to those values
435 if the user presses "Cancel". */
436 copy_prefs(&saved_prefs, &prefs);
438 prefs_w = dlg_window_new("Ethereal: Preferences");
441 * Unfortunately, we can't arrange that a GtkTable widget wrap an event box
442 * around a table row, so the spacing between the preference item's label
443 * and its control widgets is inactive and the tooltip doesn't pop up when
444 * the mouse is over it.
446 cts.tooltips = gtk_tooltips_new();
448 /* Container for each row of widgets */
449 cts.main_vb = gtk_vbox_new(FALSE, 5);
450 gtk_container_border_width(GTK_CONTAINER(cts.main_vb), 5);
451 gtk_container_add(GTK_CONTAINER(prefs_w), cts.main_vb);
452 gtk_widget_show(cts.main_vb);
454 /* Top row: Preferences tree and notebook */
455 top_hb = gtk_hbox_new(FALSE, 10);
456 gtk_container_add(GTK_CONTAINER(cts.main_vb), top_hb);
457 gtk_widget_show(top_hb);
459 /* scrolled window on the left for the categories tree */
460 ct_sb = scrolled_window_new(NULL, NULL);
461 #if GTK_MAJOR_VERSION >= 2
462 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(ct_sb),
465 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ct_sb),
466 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
467 gtk_container_add(GTK_CONTAINER(top_hb), ct_sb);
468 gtk_widget_show(ct_sb);
470 /* categories tree */
471 #if GTK_MAJOR_VERSION < 2
472 cts.tree = ctree_new(1, 0);
475 gtk_clist_set_column_auto_resize(GTK_CLIST(cts.tree), 0, TRUE);
476 SIGNAL_CONNECT(cts.tree, "tree-select-row", prefs_tree_select_cb, NULL);
478 store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_INT);
479 cts.tree = tree_view_new(GTK_TREE_MODEL(store));
480 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(cts.tree), FALSE);
481 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(cts.tree));
482 gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
483 renderer = gtk_cell_renderer_text_new();
484 col_offset = gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(cts.tree),
485 -1, "Name", renderer,
487 column = gtk_tree_view_get_column(GTK_TREE_VIEW(cts.tree),
489 gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column),
490 GTK_TREE_VIEW_COLUMN_AUTOSIZE);
491 SIGNAL_CONNECT(selection, "changed", prefs_tree_select_cb, NULL);
493 gtk_container_add(GTK_CONTAINER(ct_sb), cts.tree);
494 gtk_widget_show(cts.tree);
496 /* A notebook widget without tabs is used to flip between prefs */
497 notebook = prefs_nb = gtk_notebook_new();
498 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(prefs_nb), FALSE);
499 gtk_notebook_set_show_border(GTK_NOTEBOOK(prefs_nb), FALSE);
500 gtk_container_add(GTK_CONTAINER(top_hb), prefs_nb);
501 gtk_widget_show(prefs_nb);
506 strcpy(label_str, "User Interface");
507 prefs_nb_page_add(prefs_nb, label_str, gui_prefs_show(), E_GUI_PAGE_KEY);
508 gui_iter = prefs_tree_page_add(label_str, cts.page, store, NULL, TRUE);
511 /* GUI layout prefs */
512 strcpy(label_str, "Layout");
513 prefs_nb_page_add(prefs_nb, label_str, layout_prefs_show(), E_GUI_LAYOUT_PAGE_KEY);
514 prefs_tree_page_add(label_str, cts.page, store, &gui_iter, FALSE);
517 /* GUI Column prefs */
518 strcpy(label_str, "Columns");
519 prefs_nb_page_add(prefs_nb, label_str, column_prefs_show(), E_GUI_COLUMN_PAGE_KEY);
520 prefs_tree_page_add(label_str, cts.page, store, &gui_iter, FALSE);
524 strcpy(label_str, "Font");
525 gui_font_pg = gui_font_prefs_show();
526 prefs_nb_page_add(prefs_nb, label_str, gui_font_pg, E_GUI_FONT_PAGE_KEY);
527 prefs_tree_page_add(label_str, cts.page, store, &gui_iter, FALSE);
530 gtk_container_border_width( GTK_CONTAINER(gui_font_pg), 5 );
532 /* IMPORTANT: the following gtk_font_selection_set_xy() functions will only
533 work, if the widget and it's corresponding window is already shown
534 (so don't put the following into gui_font_prefs_show()) !!! */
536 /* We set the current font and, for GTK+ 1.2[.x], the font filter
537 now, because they appear not to work when run before appending
538 the frame to the notebook. */
540 /* Set the font to the current font.
541 XXX - GTK+ 1.2.8, and probably earlier versions, have a bug
542 wherein that doesn't necessarily cause that font to be
543 selected in the dialog box. I've sent to the GTK+ folk
544 a fix; hopefully, it'll show up in 1.2.9 if, as, and when
545 they put out a 1.2.9 release. */
546 gtk_font_selection_set_font_name(
547 GTK_FONT_SELECTION(gui_font_pg), prefs.PREFS_GUI_FONT_NAME);
549 #if GTK_MAJOR_VERSION < 2
550 /* Set its filter to show only fixed_width fonts. */
551 gtk_font_selection_set_filter(
552 GTK_FONT_SELECTION(gui_font_pg),
553 GTK_FONT_FILTER_BASE, /* user can't change the filter */
554 GTK_FONT_ALL, /* bitmap or scalable are fine */
555 NULL, /* all foundries are OK */
556 NULL, /* all weights are OK (XXX - normal only?) */
557 NULL, /* all slants are OK (XXX - Roman only?) */
558 NULL, /* all setwidths are OK */
559 fixedwidths, /* ONLY fixed-width fonts */
560 NULL); /* all charsets are OK (XXX - ISO 8859/1 only?) */
563 /* GUI Colors prefs */
564 strcpy(label_str, "Colors");
565 prefs_nb_page_add(prefs_nb, label_str, stream_prefs_show(), E_GUI_COLORS_PAGE_KEY);
566 prefs_tree_page_add(label_str, cts.page, store, &gui_iter, FALSE);
569 /* select the main GUI page as the default page and expand it's children */
570 #if GTK_MAJOR_VERSION < 2
571 gtk_ctree_select(GTK_CTREE(cts.tree), gui_iter);
573 gtk_tree_selection_select_iter(selection, &gui_iter);
574 /* (expand will only take effect, when at least one child exists) */
575 gtk_tree_view_expand_all(GTK_TREE_VIEW(cts.tree));
580 /* Is WPcap loaded? */
584 strcpy(label_str, "Capture");
585 prefs_nb_page_add(prefs_nb, label_str, capture_prefs_show(), E_CAPTURE_PAGE_KEY);
586 prefs_tree_page_add(label_str, cts.page, store, NULL, FALSE);
591 #endif /* HAVE_LIBPCAP */
594 strcpy(label_str, "Printing");
595 prefs_nb_page_add(prefs_nb, label_str, printer_prefs_show(), E_PRINT_PAGE_KEY);
596 prefs_tree_page_add(label_str, cts.page, store, NULL, FALSE);
599 /* Name resolution prefs */
600 strcpy(label_str, "Name Resolution");
601 prefs_nb_page_add(prefs_nb, label_str, nameres_prefs_show(), E_NAMERES_PAGE_KEY);
602 prefs_tree_page_add(label_str, cts.page, store, NULL, FALSE);
605 /* Registered prefs */
606 cts.notebook = prefs_nb;
607 cts.is_protocol = FALSE;
608 prefs_module_list_foreach(NULL, module_prefs_show, &cts);
610 /* Button row: OK and cancel buttons */
611 bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_APPLY, GTK_STOCK_SAVE, GTK_STOCK_CANCEL, NULL);
612 gtk_box_pack_start(GTK_BOX(cts.main_vb), bbox, FALSE, FALSE, 0);
613 gtk_widget_show(bbox);
615 ok_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_OK);
616 SIGNAL_CONNECT(ok_bt, "clicked", prefs_main_ok_cb, prefs_w);
618 apply_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_APPLY);
619 SIGNAL_CONNECT(apply_bt, "clicked", prefs_main_apply_cb, prefs_w);
621 save_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_SAVE);
622 SIGNAL_CONNECT(save_bt, "clicked", prefs_main_save_cb, prefs_w);
624 cancel_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_CANCEL);
625 SIGNAL_CONNECT(cancel_bt, "clicked", prefs_main_cancel_cb, prefs_w);
626 window_set_cancel_button(prefs_w, cancel_bt, NULL);
628 gtk_widget_grab_default(ok_bt);
630 SIGNAL_CONNECT(prefs_w, "delete_event", prefs_main_delete_event_cb, prefs_w);
631 SIGNAL_CONNECT(prefs_w, "destroy", prefs_main_destroy_cb, prefs_w);
633 gtk_widget_show(prefs_w);
634 window_present(prefs_w);
636 #if GTK_MAJOR_VERSION >= 2
637 g_object_unref(G_OBJECT(store));
642 set_option_label(GtkWidget *main_tb, int table_position,
643 const gchar *label_text, const gchar *tooltip_text, GtkTooltips *tooltips)
646 GtkWidget *event_box;
648 label = gtk_label_new(label_text);
649 gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
650 gtk_widget_show(label);
652 event_box = gtk_event_box_new();
653 gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box, 0, 1,
654 table_position, table_position + 1);
655 if (tooltip_text != NULL && tooltips != NULL)
656 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
657 gtk_container_add(GTK_CONTAINER(event_box), label);
658 gtk_widget_show(event_box);
662 create_preference_check_button(GtkWidget *main_tb, int table_position,
663 const gchar *label_text, const gchar *tooltip_text, gboolean active)
665 GtkTooltips *tooltips;
666 GtkWidget *check_box;
668 tooltips = OBJECT_GET_DATA(main_tb, E_TOOLTIPS_KEY);
670 set_option_label(main_tb, table_position, label_text, tooltip_text,
673 check_box = gtk_check_button_new();
674 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_box), active);
675 gtk_table_attach_defaults(GTK_TABLE(main_tb), check_box, 1, 2,
676 table_position, table_position + 1);
677 if (tooltip_text != NULL && tooltips != NULL)
678 gtk_tooltips_set_tip(tooltips, check_box, tooltip_text, NULL);
684 create_preference_radio_buttons(GtkWidget *main_tb, int table_position,
685 const gchar *label_text, const gchar *tooltip_text,
686 const enum_val_t *enumvals, gint current_val)
688 GtkTooltips *tooltips;
689 GtkWidget *radio_button_hbox, *button = NULL;
692 const enum_val_t *enum_valp;
693 GtkWidget *event_box;
695 tooltips = OBJECT_GET_DATA(main_tb, E_TOOLTIPS_KEY);
697 set_option_label(main_tb, table_position, label_text, tooltip_text,
700 radio_button_hbox = gtk_hbox_new(FALSE, 0);
702 for (enum_valp = enumvals, index = 0; enum_valp->name != NULL;
703 enum_valp++, index++) {
704 button = gtk_radio_button_new_with_label(rb_group,
705 enum_valp->description);
706 gtk_widget_show(button);
707 rb_group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
708 gtk_box_pack_start(GTK_BOX(radio_button_hbox), button, FALSE,
710 if (enum_valp->value == current_val) {
711 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button),
715 gtk_widget_show(radio_button_hbox);
717 event_box = gtk_event_box_new();
718 gtk_container_add(GTK_CONTAINER(event_box), radio_button_hbox);
719 gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box, 1, 2,
720 table_position, table_position+1);
721 if (tooltip_text != NULL && tooltips != NULL)
722 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
723 gtk_widget_show(event_box);
726 * It doesn't matter which of the buttons we return - we fetch
727 * the value by looking at the entire radio button group to
728 * which it belongs, and we can get that from any button.
734 label_to_enum_val(GtkWidget *label, const enum_val_t *enumvals)
739 /* Get the label's text, and translate it to a value.
740 We match only the descriptions, as those are what appear in
741 the option menu items or as labels for radio buttons.
742 We fail if we don't find a match, as that "can't happen". */
743 gtk_label_get(GTK_LABEL(label), &label_string);
745 for (i = 0; enumvals[i].name != NULL; i++) {
746 if (strcasecmp(label_string, enumvals[i].description) == 0) {
747 return enumvals[i].value;
750 g_assert_not_reached();
755 fetch_preference_radio_buttons_val(GtkWidget *button,
756 const enum_val_t *enumvals)
762 * Go through the list of of radio buttons in the button's group,
763 * and find the first one that's active.
765 rb_group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
767 for (rb_entry = rb_group; rb_entry != NULL;
768 rb_entry = g_slist_next(rb_entry)) {
769 button = rb_entry->data;
770 if (GTK_TOGGLE_BUTTON(button)->active)
774 /* OK, now return the value corresponding to that button's label. */
775 return label_to_enum_val(GTK_BIN(button)->child, enumvals);
779 create_preference_option_menu(GtkWidget *main_tb, int table_position,
780 const gchar *label_text, const gchar *tooltip_text,
781 const enum_val_t *enumvals, gint current_val)
783 GtkTooltips *tooltips;
784 GtkWidget *menu_box, *menu, *menu_item, *option_menu;
785 int menu_index, index;
786 const enum_val_t *enum_valp;
787 GtkWidget *event_box;
789 tooltips = OBJECT_GET_DATA(main_tb, E_TOOLTIPS_KEY);
791 set_option_label(main_tb, table_position, label_text, tooltip_text,
794 /* Create a menu from the enumvals */
795 menu = gtk_menu_new();
796 if (tooltip_text != NULL && tooltips != NULL)
797 gtk_tooltips_set_tip(tooltips, menu, tooltip_text, NULL);
799 for (enum_valp = enumvals, index = 0; enum_valp->name != NULL;
800 enum_valp++, index++) {
801 menu_item = gtk_menu_item_new_with_label(enum_valp->description);
802 gtk_menu_append(GTK_MENU(menu), menu_item);
803 if (enum_valp->value == current_val)
805 gtk_widget_show(menu_item);
808 /* Create the option menu from the menu */
809 option_menu = gtk_option_menu_new();
810 gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), menu);
812 /* Set its current value to the variable's current value */
813 if (menu_index != -1)
814 gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu),
818 * Put the option menu in an hbox, so that it's only as wide
819 * as the widest entry, rather than being as wide as the table
822 menu_box = gtk_hbox_new(FALSE, 0);
823 gtk_box_pack_start(GTK_BOX(menu_box), option_menu, FALSE, FALSE, 0);
825 event_box = gtk_event_box_new();
826 gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box,
827 1, 2, table_position, table_position + 1);
828 if (tooltip_text != NULL && tooltips != NULL)
829 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
830 gtk_container_add(GTK_CONTAINER(event_box), menu_box);
836 fetch_preference_option_menu_val(GtkWidget *optmenu, const enum_val_t *enumvals)
839 * OK, now return the value corresponding to the label for the
840 * currently active entry in the option menu.
842 * Yes, this is how you get the label for that entry. See FAQ
843 * 6.8 in the GTK+ FAQ.
845 return label_to_enum_val(GTK_BIN(optmenu)->child, enumvals);
849 create_preference_entry(GtkWidget *main_tb, int table_position,
850 const gchar *label_text, const gchar *tooltip_text, char *value)
852 GtkTooltips *tooltips;
855 tooltips = OBJECT_GET_DATA(main_tb, E_TOOLTIPS_KEY);
857 set_option_label(main_tb, table_position, label_text, tooltip_text,
860 entry = gtk_entry_new();
862 gtk_entry_set_text(GTK_ENTRY(entry), value);
863 gtk_table_attach_defaults(GTK_TABLE(main_tb), entry, 1, 2,
864 table_position, table_position + 1);
865 if (tooltip_text != NULL && tooltips != NULL)
866 gtk_tooltips_set_tip(tooltips, entry, tooltip_text, NULL);
867 gtk_widget_show(entry);
873 pref_check(pref_t *pref, gpointer user_data)
878 pref_t **badpref = user_data;
880 /* Fetch the value of the preference, and check whether it's valid. */
881 switch (pref->type) {
884 str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
885 uval = strtoul(str_val, &p, pref->info.base);
886 if (p == str_val || *p != '\0') {
888 return PREFS_SET_SYNTAX_ERR; /* number was bad */
893 /* Value can't be bad. */
897 /* Value can't be bad. */
901 /* Value can't be bad. */
905 str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
907 if (strlen(str_val) != 0) {
910 if (range_convert_str(&newrange, str_val, pref->info.max_value) !=
913 return PREFS_SET_SYNTAX_ERR; /* range was bad */
920 g_assert_not_reached();
927 module_prefs_check(module_t *module, gpointer user_data)
929 /* For all preferences in this module, fetch its value from this
930 module's notebook page and check whether it's valid. */
931 return prefs_pref_foreach(module, pref_check, user_data);
935 pref_fetch(pref_t *pref, gpointer user_data)
942 gboolean *pref_changed_p = user_data;
944 /* Fetch the value of the preference, and set the appropriate variable
946 switch (pref->type) {
949 str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
950 uval = strtoul(str_val, &p, pref->info.base);
952 if (p == value || *p != '\0')
953 return PREFS_SET_SYNTAX_ERR; /* number was bad */
955 if (*pref->varp.uint != uval) {
956 *pref_changed_p = TRUE;
957 *pref->varp.uint = uval;
962 bval = GTK_TOGGLE_BUTTON(pref->control)->active;
963 if (*pref->varp.boolp != bval) {
964 *pref_changed_p = TRUE;
965 *pref->varp.boolp = bval;
970 if (pref->info.enum_info.radio_buttons) {
971 enumval = fetch_preference_radio_buttons_val(pref->control,
972 pref->info.enum_info.enumvals);
974 enumval = fetch_preference_option_menu_val(pref->control,
975 pref->info.enum_info.enumvals);
978 if (*pref->varp.enump != enumval) {
979 *pref_changed_p = TRUE;
980 *pref->varp.enump = enumval;
985 str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
986 if (strcmp(*pref->varp.string, str_val) != 0) {
987 *pref_changed_p = TRUE;
988 g_free(*pref->varp.string);
989 *pref->varp.string = g_strdup(str_val);
998 str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
999 ret = range_convert_str(&newrange, str_val, pref->info.max_value);
1000 if (ret != CVT_NO_ERROR)
1002 return PREFS_SET_SYNTAX_ERR; /* range was bad */
1004 return 0; /* XXX - should fail */
1007 if (!ranges_are_equal(*pref->varp.range, newrange)) {
1008 *pref_changed_p = TRUE;
1009 g_free(*pref->varp.range);
1010 *pref->varp.range = newrange;
1018 g_assert_not_reached();
1025 module_prefs_fetch(module_t *module, gpointer user_data)
1027 gboolean *must_redissect_p = user_data;
1029 /* For all preferences in this module, fetch its value from this
1030 module's notebook page. Find out whether any of them changed. */
1031 module->prefs_changed = FALSE; /* assume none of them changed */
1032 prefs_pref_foreach(module, pref_fetch, &module->prefs_changed);
1034 /* If any of them changed, indicate that we must redissect and refilter
1035 the current capture (if we have one), as the preference change
1036 could cause packets to be dissected differently. */
1037 if (module->prefs_changed)
1038 *must_redissect_p = TRUE;
1040 return 0; /* keep fetching module preferences */
1044 pref_clean(pref_t *pref, gpointer user_data _U_)
1046 switch (pref->type) {
1058 if (pref->saved_val.string != NULL) {
1059 g_free(pref->saved_val.string);
1060 pref->saved_val.string = NULL;
1065 if (pref->saved_val.range != NULL) {
1066 g_free(pref->saved_val.range);
1067 pref->saved_val.range = NULL;
1072 g_assert_not_reached();
1079 module_prefs_clean(module_t *module, gpointer user_data _U_)
1081 /* For all preferences in this module, clean up any cruft allocated for
1082 use by the GUI code. */
1083 prefs_pref_foreach(module, pref_clean, NULL);
1084 return 0; /* keep cleaning modules */
1087 /* fetch all pref values from all pages */
1089 prefs_main_fetch_all(GtkWidget *dlg, gboolean *must_redissect)
1093 /* First, check that the values are all valid. */
1094 /* XXX - check the non-registered preferences too */
1095 switch (prefs_modules_foreach(module_prefs_check, (gpointer)&badpref)) {
1097 case PREFS_SET_SYNTAX_ERR:
1098 switch (badpref->type) {
1101 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1102 "The value for \"%s\" isn't a valid number.",
1107 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1108 "The value for \"%s\" isn't a valid range.",
1113 g_assert_not_reached();
1118 /* Fetch the preferences (i.e., make sure all the values set in all of
1119 the preferences panes have been copied to "prefs" and the registered
1121 gui_prefs_fetch(OBJECT_GET_DATA(dlg, E_GUI_PAGE_KEY));
1122 layout_prefs_fetch(OBJECT_GET_DATA(dlg, E_GUI_LAYOUT_PAGE_KEY));
1123 column_prefs_fetch(OBJECT_GET_DATA(dlg, E_GUI_COLUMN_PAGE_KEY));
1124 stream_prefs_fetch(OBJECT_GET_DATA(dlg, E_GUI_COLORS_PAGE_KEY));
1128 /* Is WPcap loaded? */
1131 capture_prefs_fetch(OBJECT_GET_DATA(dlg, E_CAPTURE_PAGE_KEY));
1135 #endif /* HAVE_LIBPCAP */
1136 printer_prefs_fetch(OBJECT_GET_DATA(dlg, E_PRINT_PAGE_KEY));
1137 nameres_prefs_fetch(OBJECT_GET_DATA(dlg, E_NAMERES_PAGE_KEY));
1139 prefs_modules_foreach(module_prefs_fetch, must_redissect);
1144 /* apply all pref values to the real world */
1146 prefs_main_apply_all(GtkWidget *dlg)
1149 * Apply the protocol preferences first - "gui_prefs_apply()" could
1150 * cause redissection, and we have to make sure the protocol
1151 * preference changes have been fully applied.
1155 gui_prefs_apply(OBJECT_GET_DATA(dlg, E_GUI_PAGE_KEY));
1156 layout_prefs_apply(OBJECT_GET_DATA(dlg, E_GUI_LAYOUT_PAGE_KEY));
1157 column_prefs_apply(OBJECT_GET_DATA(dlg, E_GUI_COLUMN_PAGE_KEY));
1158 stream_prefs_apply(OBJECT_GET_DATA(dlg, E_GUI_COLORS_PAGE_KEY));
1162 /* Is WPcap loaded? */
1165 capture_prefs_apply(OBJECT_GET_DATA(dlg, E_CAPTURE_PAGE_KEY));
1169 #endif /* HAVE_LIBPCAP */
1170 printer_prefs_apply(OBJECT_GET_DATA(dlg, E_PRINT_PAGE_KEY));
1171 nameres_prefs_apply(OBJECT_GET_DATA(dlg, E_NAMERES_PAGE_KEY));
1175 /* destroy all preferences ressources from all pages */
1177 prefs_main_destroy_all(GtkWidget *dlg)
1179 gui_prefs_destroy(OBJECT_GET_DATA(dlg, E_GUI_PAGE_KEY));
1180 layout_prefs_destroy(OBJECT_GET_DATA(dlg, E_GUI_LAYOUT_PAGE_KEY));
1181 column_prefs_destroy(OBJECT_GET_DATA(dlg, E_GUI_COLUMN_PAGE_KEY));
1182 stream_prefs_destroy(OBJECT_GET_DATA(dlg, E_GUI_COLORS_PAGE_KEY));
1186 /* Is WPcap loaded? */
1189 capture_prefs_destroy(OBJECT_GET_DATA(dlg, E_CAPTURE_PAGE_KEY));
1193 #endif /* HAVE_LIBPCAP */
1194 printer_prefs_destroy(OBJECT_GET_DATA(dlg, E_PRINT_PAGE_KEY));
1195 nameres_prefs_destroy(OBJECT_GET_DATA(dlg, E_NAMERES_PAGE_KEY));
1197 /* Free up the saved preferences (both for "prefs" and for registered
1199 free_prefs(&saved_prefs);
1200 prefs_modules_foreach(module_prefs_clean, NULL);
1205 prefs_main_ok_cb(GtkWidget *ok_bt _U_, gpointer parent_w)
1207 gboolean must_redissect = FALSE;
1209 if (!prefs_main_fetch_all(parent_w, &must_redissect))
1210 return; /* Errors in some preference setting */
1212 prefs_main_apply_all(parent_w);
1214 /* Now destroy the "Preferences" dialog. */
1215 window_destroy(GTK_WIDGET(parent_w));
1217 if (must_redissect) {
1218 /* Redissect all the packets, and re-evaluate the display filter. */
1219 redissect_packets(&cfile);
1224 prefs_main_apply_cb(GtkWidget *apply_bt _U_, gpointer parent_w)
1226 gboolean must_redissect = FALSE;
1228 if (!prefs_main_fetch_all(parent_w, &must_redissect))
1229 return; /* Errors in some preference setting */
1231 prefs_main_apply_all(parent_w);
1233 if (must_redissect) {
1234 /* Redissect all the packets, and re-evaluate the display filter. */
1235 redissect_packets(&cfile);
1240 prefs_main_save_cb(GtkWidget *save_bt _U_, gpointer parent_w)
1242 gboolean must_redissect = FALSE;
1247 if (!prefs_main_fetch_all(parent_w, &must_redissect))
1248 return; /* Errors in some preference setting */
1250 /* Create the directory that holds personal configuration files, if
1252 if (create_persconffile_dir(&pf_dir_path) == -1) {
1253 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1254 "Can't create directory\n\"%s\"\nfor preferences file: %s.", pf_dir_path,
1256 g_free(pf_dir_path);
1258 /* Write the preferencs out. */
1259 err = write_prefs(&pf_path);
1261 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1262 "Can't open preferences file\n\"%s\": %s.", pf_path,
1268 /* Now apply those preferences.
1269 XXX - should we do this? The user didn't click "OK" or "Apply".
1272 1) by saving the preferences they presumably indicate that they
1275 2) the next time they fire Ethereal up, those preferences will
1278 3) we'd have to buffer "must_redissect" so that if they do
1279 "Apply" after this, we know we have to redissect;
1281 4) we did apply the protocol preferences, at least, in the past. */
1282 prefs_main_apply_all(parent_w);
1284 if (must_redissect) {
1285 /* Redissect all the packets, and re-evaluate the display filter. */
1286 redissect_packets(&cfile);
1291 pref_revert(pref_t *pref, gpointer user_data)
1293 gboolean *pref_changed_p = user_data;
1295 /* Revert the preference to its saved value. */
1296 switch (pref->type) {
1299 if (*pref->varp.uint != pref->saved_val.uint) {
1300 *pref_changed_p = TRUE;
1301 *pref->varp.uint = pref->saved_val.uint;
1306 if (*pref->varp.boolp != pref->saved_val.boolval) {
1307 *pref_changed_p = TRUE;
1308 *pref->varp.boolp = pref->saved_val.boolval;
1313 if (*pref->varp.enump != pref->saved_val.enumval) {
1314 *pref_changed_p = TRUE;
1315 *pref->varp.enump = pref->saved_val.enumval;
1320 if (strcmp(*pref->varp.string, pref->saved_val.string) != 0) {
1321 *pref_changed_p = TRUE;
1322 g_free(*pref->varp.string);
1323 *pref->varp.string = g_strdup(pref->saved_val.string);
1328 if (!ranges_are_equal(*pref->varp.range, pref->saved_val.range)) {
1329 *pref_changed_p = TRUE;
1330 g_free(*pref->varp.range);
1331 *pref->varp.range = range_copy(pref->saved_val.range);
1336 g_assert_not_reached();
1343 module_prefs_revert(module_t *module, gpointer user_data)
1345 gboolean *must_redissect_p = user_data;
1347 /* For all preferences in this module, revert its value to the value
1348 it had when we popped up the Preferences dialog. Find out whether
1349 this changes any of them. */
1350 module->prefs_changed = FALSE; /* assume none of them changed */
1351 prefs_pref_foreach(module, pref_revert, &module->prefs_changed);
1353 /* If any of them changed, indicate that we must redissect and refilter
1354 the current capture (if we have one), as the preference change
1355 could cause packets to be dissected differently. */
1356 if (module->prefs_changed)
1357 *must_redissect_p = TRUE;
1358 return 0; /* keep processing modules */
1361 /* cancel button pressed, revert prefs to saved and exit dialog */
1363 prefs_main_cancel_cb(GtkWidget *cancel_bt _U_, gpointer parent_w)
1365 gboolean must_redissect = FALSE;
1367 /* Free up the current preferences and copy the saved preferences to the
1368 current preferences. */
1370 copy_prefs(&prefs, &saved_prefs);
1372 /* Now revert the registered preferences. */
1373 prefs_modules_foreach(module_prefs_revert, &must_redissect);
1375 /* Now apply the reverted-to preferences. */
1376 prefs_main_apply_all(parent_w);
1378 window_destroy(GTK_WIDGET(parent_w));
1380 if (must_redissect) {
1381 /* Redissect all the packets, and re-evaluate the display filter. */
1382 redissect_packets(&cfile);
1386 /* Treat this as a cancel, by calling "prefs_main_cancel_cb()" */
1388 prefs_main_delete_event_cb(GtkWidget *prefs_w, GdkEvent *event _U_,
1389 gpointer parent_w _U_)
1391 prefs_main_cancel_cb(NULL, prefs_w);
1396 /* dialog *is* already destroyed, clean up memory and such */
1398 prefs_main_destroy_cb(GtkWidget *win _U_, gpointer parent_w)
1400 prefs_main_destroy_all(parent_w);
1402 /* Note that we no longer have a "Preferences" dialog box. */
1406 struct properties_data {
1412 module_search_properties(module_t *module, gpointer user_data)
1414 struct properties_data *p = (struct properties_data *)user_data;
1416 /* If this module has the specified title, remember it. */
1417 if (strcmp(module->title, p->title) == 0) {
1419 return 1; /* stops the search */
1425 properties_cb(GtkWidget *w, gpointer dummy)
1427 header_field_info *hfinfo;
1429 struct properties_data p;
1432 module_t *page_module;
1434 if (cfile.finfo_selected == NULL) {
1435 /* There is no field selected */
1439 /* Find the title for the protocol for the selected field. */
1440 hfinfo = cfile.finfo_selected->hfinfo;
1441 if (hfinfo->parent == -1)
1442 title = prefs_get_title_by_name(hfinfo->abbrev);
1444 title = prefs_get_title_by_name(proto_registrar_get_abbrev(hfinfo->parent));
1446 return; /* Couldn't find it. XXX - just crash? "Can't happen"? */
1448 /* Find the module for that protocol by searching for one with that title.
1449 XXX - should we just associate protocols with modules directly? */
1452 prefs_module_list_foreach(protocols_module->prefs, module_search_properties,
1454 if (p.module == NULL) {
1455 /* We didn't find it - that protocol probably has no preferences. */
1459 /* Create a preferences window, or pop up an existing one. */
1460 if (prefs_w != NULL) {
1461 reactivate_window(prefs_w);
1466 /* Search all the pages in that window for the one with the specified
1469 (frame = gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), page_num)) != NULL;
1471 /* Get the module for this page. */
1472 page_module = OBJECT_GET_DATA(frame, E_PAGE_MODULE_KEY);
1473 if (page_module == NULL)
1474 continue; /* It doesn't have one. */
1475 if (page_module == p.module) {
1476 /* We found it. Select that page. */
1477 gtk_notebook_set_page(GTK_NOTEBOOK(notebook), page_num);
1483 /* Prefs tree selection callback. The node data has been loaded with
1484 the proper notebook page to load. */
1485 #if GTK_MAJOR_VERSION < 2
1487 prefs_tree_select_cb(GtkCTree *ct, GtkCTreeNode *node, gint col _U_,
1491 prefs_tree_select_cb(GtkTreeSelection *sel, gpointer dummy _U_)
1495 #if GTK_MAJOR_VERSION >= 2
1496 GtkTreeModel *model;
1500 #if GTK_MAJOR_VERSION < 2
1501 page = GPOINTER_TO_INT(gtk_ctree_node_get_row_data(ct, node));
1504 gtk_notebook_set_page(GTK_NOTEBOOK(notebook), page);
1506 if (gtk_tree_selection_get_selected(sel, &model, &iter))
1508 gtk_tree_model_get(model, &iter, 1, &page, -1);
1510 gtk_notebook_set_page(GTK_NOTEBOOK(notebook), page);