2 * Routines for handling preferences
4 * $Id: prefs_dlg.c,v 1.85 2004/05/27 18:12:58 guy Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
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_cb(GtkWidget *, 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, gboolean has_child)
351 #if GTK_MAJOR_VERSION < 2
352 const gchar *label_ptr = title;
354 prefs_tree_iter iter;
356 #if GTK_MAJOR_VERSION < 2
357 iter = gtk_ctree_insert_node(GTK_CTREE(store), parent_iter ? *parent_iter : NULL, NULL,
358 (gchar **) &label_ptr, 5, NULL, NULL, NULL, NULL, !has_child, TRUE);
359 gtk_ctree_node_set_row_data(GTK_CTREE(store), iter,
360 GINT_TO_POINTER(page_nr));
362 gtk_tree_store_append(store, &iter, parent_iter);
363 gtk_tree_store_set(store, &iter, 0, title, 1, page_nr, -1);
368 /* add a page to the notebook */
370 prefs_nb_page_add(GtkWidget *notebook, const gchar *title, GtkWidget *page, const char *page_key)
374 frame = gtk_frame_new(title);
375 gtk_widget_show(frame);
376 gtk_container_add(GTK_CONTAINER(frame), page);
377 OBJECT_SET_DATA(prefs_w, page_key, page);
378 gtk_notebook_append_page (GTK_NOTEBOOK(notebook), frame, NULL);
384 /* show the dialog */
386 prefs_cb(GtkWidget *w _U_, gpointer dummy _U_)
388 GtkWidget *top_hb, *bbox, *prefs_nb, *ct_sb,
389 *ok_bt, *apply_bt, *save_bt, *cancel_bt;
390 GtkWidget *gui_font_pg;
391 gchar label_str[MAX_TREE_NODE_NAME_LEN];
392 struct ct_struct cts;
393 #if GTK_MAJOR_VERSION < 2
394 gpointer store = NULL;
395 static gchar *fixedwidths[] = { "c", "m", NULL };
398 GtkTreeSelection *selection;
399 GtkCellRenderer *renderer;
400 GtkTreeViewColumn *column;
403 prefs_tree_iter gui_iter;
406 if (prefs_w != NULL) {
407 /* There's already a "Preferences" dialog box; reactivate it. */
408 reactivate_window(prefs_w);
412 /* Save the current preferences, so we can revert to those values
413 if the user presses "Cancel". */
414 copy_prefs(&saved_prefs, &prefs);
416 prefs_w = dlg_window_new("Ethereal: Preferences");
419 * Unfortunately, we can't arrange that a GtkTable widget wrap an event box
420 * around a table row, so the spacing between the preference item's label
421 * and its control widgets is inactive and the tooltip doesn't pop up when
422 * the mouse is over it.
424 cts.tooltips = gtk_tooltips_new();
426 /* Container for each row of widgets */
427 cts.main_vb = gtk_vbox_new(FALSE, 5);
428 gtk_container_border_width(GTK_CONTAINER(cts.main_vb), 5);
429 gtk_container_add(GTK_CONTAINER(prefs_w), cts.main_vb);
430 gtk_widget_show(cts.main_vb);
432 /* Top row: Preferences tree and notebook */
433 top_hb = gtk_hbox_new(FALSE, 10);
434 gtk_container_add(GTK_CONTAINER(cts.main_vb), top_hb);
435 gtk_widget_show(top_hb);
437 /* scrolled window on the left for the categories tree */
438 ct_sb = scrolled_window_new(NULL, NULL);
439 #if GTK_MAJOR_VERSION >= 2
440 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(ct_sb),
443 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ct_sb),
444 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
445 gtk_container_add(GTK_CONTAINER(top_hb), ct_sb);
446 gtk_widget_show(ct_sb);
448 /* categories tree */
449 #if GTK_MAJOR_VERSION < 2
450 cts.tree = ctree_new(1, 0);
453 gtk_clist_set_column_auto_resize(GTK_CLIST(cts.tree), 0, TRUE);
454 SIGNAL_CONNECT(cts.tree, "tree-select-row", prefs_tree_select_cb, NULL);
456 store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_INT);
457 cts.tree = tree_view_new(GTK_TREE_MODEL(store));
458 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(cts.tree), FALSE);
459 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(cts.tree));
460 gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
461 renderer = gtk_cell_renderer_text_new();
462 col_offset = gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(cts.tree),
463 -1, "Name", renderer,
465 column = gtk_tree_view_get_column(GTK_TREE_VIEW(cts.tree),
467 gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column),
468 GTK_TREE_VIEW_COLUMN_AUTOSIZE);
469 SIGNAL_CONNECT(selection, "changed", prefs_tree_select_cb, NULL);
471 gtk_container_add(GTK_CONTAINER(ct_sb), cts.tree);
472 gtk_widget_show(cts.tree);
474 /* A notebook widget without tabs is used to flip between prefs */
475 notebook = prefs_nb = gtk_notebook_new();
476 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(prefs_nb), FALSE);
477 gtk_notebook_set_show_border(GTK_NOTEBOOK(prefs_nb), FALSE);
478 gtk_container_add(GTK_CONTAINER(top_hb), prefs_nb);
479 gtk_widget_show(prefs_nb);
484 strcpy(label_str, "User Interface");
485 prefs_nb_page_add(prefs_nb, label_str, gui_prefs_show(), E_GUI_PAGE_KEY);
486 gui_iter = prefs_tree_page_add(label_str, cts.page, store, NULL, TRUE);
489 /* GUI layout prefs */
490 strcpy(label_str, "Layout");
491 prefs_nb_page_add(prefs_nb, label_str, layout_prefs_show(), E_GUI_LAYOUT_PAGE_KEY);
492 prefs_tree_page_add(label_str, cts.page, store, &gui_iter, FALSE);
495 /* GUI Column prefs */
496 strcpy(label_str, "Columns");
497 prefs_nb_page_add(prefs_nb, label_str, column_prefs_show(), E_GUI_COLUMN_PAGE_KEY);
498 prefs_tree_page_add(label_str, cts.page, store, &gui_iter, FALSE);
502 strcpy(label_str, "Font");
503 gui_font_pg = gui_font_prefs_show();
504 prefs_nb_page_add(prefs_nb, label_str, gui_font_pg, E_GUI_FONT_PAGE_KEY);
505 prefs_tree_page_add(label_str, cts.page, store, &gui_iter, FALSE);
508 gtk_container_border_width( GTK_CONTAINER(gui_font_pg), 5 );
510 /* IMPORTANT: the following gtk_font_selection_set_xy() functions will only
511 work, if the widget and it's corresponding window is already shown
512 (so don't put the following into gui_font_prefs_show()) !!! */
514 /* We set the current font and, for GTK+ 1.2[.x], the font filter
515 now, because they appear not to work when run before appending
516 the frame to the notebook. */
518 /* Set the font to the current font.
519 XXX - GTK+ 1.2.8, and probably earlier versions, have a bug
520 wherein that doesn't necessarily cause that font to be
521 selected in the dialog box. I've sent to the GTK+ folk
522 a fix; hopefully, it'll show up in 1.2.9 if, as, and when
523 they put out a 1.2.9 release. */
524 gtk_font_selection_set_font_name(
525 GTK_FONT_SELECTION(gui_font_pg), prefs.PREFS_GUI_FONT_NAME);
527 #if GTK_MAJOR_VERSION < 2
528 /* Set its filter to show only fixed_width fonts. */
529 gtk_font_selection_set_filter(
530 GTK_FONT_SELECTION(gui_font_pg),
531 GTK_FONT_FILTER_BASE, /* user can't change the filter */
532 GTK_FONT_ALL, /* bitmap or scalable are fine */
533 NULL, /* all foundries are OK */
534 NULL, /* all weights are OK (XXX - normal only?) */
535 NULL, /* all slants are OK (XXX - Roman only?) */
536 NULL, /* all setwidths are OK */
537 fixedwidths, /* ONLY fixed-width fonts */
538 NULL); /* all charsets are OK (XXX - ISO 8859/1 only?) */
541 /* GUI Colors prefs */
542 strcpy(label_str, "Colors");
543 prefs_nb_page_add(prefs_nb, label_str, stream_prefs_show(), E_GUI_COLORS_PAGE_KEY);
544 prefs_tree_page_add(label_str, cts.page, store, &gui_iter, FALSE);
547 /* select the main GUI page as the default page and expand it's children */
548 #if GTK_MAJOR_VERSION < 2
549 gtk_ctree_select(GTK_CTREE(cts.tree), gui_iter);
551 gtk_tree_selection_select_iter(selection, &gui_iter);
552 /* (expand will only take effect, when at least one child exists) */
553 gtk_tree_view_expand_all(GTK_TREE_VIEW(cts.tree));
558 /* Is WPcap loaded? */
562 strcpy(label_str, "Capture");
563 prefs_nb_page_add(prefs_nb, label_str, capture_prefs_show(), E_CAPTURE_PAGE_KEY);
564 prefs_tree_page_add(label_str, cts.page, store, NULL, FALSE);
569 #endif /* HAVE_LIBPCAP */
572 strcpy(label_str, "Printing");
573 prefs_nb_page_add(prefs_nb, label_str, printer_prefs_show(), E_PRINT_PAGE_KEY);
574 prefs_tree_page_add(label_str, cts.page, store, NULL, FALSE);
577 /* Name resolution prefs */
578 strcpy(label_str, "Name Resolution");
579 prefs_nb_page_add(prefs_nb, label_str, nameres_prefs_show(), E_NAMERES_PAGE_KEY);
580 prefs_tree_page_add(label_str, cts.page, store, NULL, FALSE);
583 /* Registered prefs */
584 cts.notebook = prefs_nb;
585 cts.is_protocol = FALSE;
586 prefs_module_list_foreach(NULL, module_prefs_show, &cts);
588 /* Button row: OK and cancel buttons */
589 bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_APPLY, GTK_STOCK_SAVE, GTK_STOCK_CANCEL, NULL);
590 gtk_box_pack_start(GTK_BOX(cts.main_vb), bbox, FALSE, FALSE, 0);
591 gtk_widget_show(bbox);
593 ok_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_OK);
594 SIGNAL_CONNECT(ok_bt, "clicked", prefs_main_ok_cb, prefs_w);
596 apply_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_APPLY);
597 SIGNAL_CONNECT(apply_bt, "clicked", prefs_main_apply_cb, prefs_w);
599 save_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_SAVE);
600 SIGNAL_CONNECT(save_bt, "clicked", prefs_main_save_cb, prefs_w);
602 cancel_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_CANCEL);
603 SIGNAL_CONNECT(cancel_bt, "clicked", prefs_main_cancel_cb, prefs_w);
604 window_set_cancel_button(prefs_w, cancel_bt, NULL);
606 gtk_widget_grab_default(ok_bt);
608 SIGNAL_CONNECT(prefs_w, "delete_event", prefs_main_delete_cb, prefs_w);
609 SIGNAL_CONNECT(prefs_w, "destroy", prefs_main_destroy_cb, prefs_w);
611 gtk_widget_show(prefs_w);
612 window_present(prefs_w);
614 #if GTK_MAJOR_VERSION >= 2
615 g_object_unref(G_OBJECT(store));
620 set_option_label(GtkWidget *main_tb, int table_position,
621 const gchar *label_text, const gchar *tooltip_text, GtkTooltips *tooltips)
624 GtkWidget *event_box;
626 label = gtk_label_new(label_text);
627 gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
628 gtk_widget_show(label);
630 event_box = gtk_event_box_new();
631 gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box, 0, 1,
632 table_position, table_position + 1);
633 if (tooltip_text != NULL && tooltips != NULL)
634 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
635 gtk_container_add(GTK_CONTAINER(event_box), label);
636 gtk_widget_show(event_box);
640 create_preference_check_button(GtkWidget *main_tb, int table_position,
641 const gchar *label_text, const gchar *tooltip_text, gboolean active)
643 GtkTooltips *tooltips;
644 GtkWidget *check_box;
646 tooltips = OBJECT_GET_DATA(main_tb, E_TOOLTIPS_KEY);
648 set_option_label(main_tb, table_position, label_text, tooltip_text,
651 check_box = gtk_check_button_new();
652 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_box), active);
653 gtk_table_attach_defaults(GTK_TABLE(main_tb), check_box, 1, 2,
654 table_position, table_position + 1);
655 if (tooltip_text != NULL && tooltips != NULL)
656 gtk_tooltips_set_tip(tooltips, check_box, tooltip_text, NULL);
662 create_preference_radio_buttons(GtkWidget *main_tb, int table_position,
663 const gchar *label_text, const gchar *tooltip_text,
664 const enum_val_t *enumvals, gint current_val)
666 GtkTooltips *tooltips;
667 GtkWidget *radio_button_hbox, *button = NULL;
670 const enum_val_t *enum_valp;
671 GtkWidget *event_box;
673 tooltips = OBJECT_GET_DATA(main_tb, E_TOOLTIPS_KEY);
675 set_option_label(main_tb, table_position, label_text, tooltip_text,
678 radio_button_hbox = gtk_hbox_new(FALSE, 0);
680 for (enum_valp = enumvals, index = 0; enum_valp->name != NULL;
681 enum_valp++, index++) {
682 button = gtk_radio_button_new_with_label(rb_group,
683 enum_valp->description);
684 gtk_widget_show(button);
685 rb_group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
686 gtk_box_pack_start(GTK_BOX(radio_button_hbox), button, FALSE,
688 if (enum_valp->value == current_val) {
689 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button),
693 gtk_widget_show(radio_button_hbox);
695 event_box = gtk_event_box_new();
696 gtk_container_add(GTK_CONTAINER(event_box), radio_button_hbox);
697 gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box, 1, 2,
698 table_position, table_position+1);
699 if (tooltip_text != NULL && tooltips != NULL)
700 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
701 gtk_widget_show(event_box);
704 * It doesn't matter which of the buttons we return - we fetch
705 * the value by looking at the entire radio button group to
706 * which it belongs, and we can get that from any button.
712 label_to_enum_val(GtkWidget *label, const enum_val_t *enumvals)
717 /* Get the label's text, and translate it to a value.
718 We match only the descriptions, as those are what appear in
719 the option menu items or as labels for radio buttons.
720 We fail if we don't find a match, as that "can't happen". */
721 gtk_label_get(GTK_LABEL(label), &label_string);
723 for (i = 0; enumvals[i].name != NULL; i++) {
724 if (strcasecmp(label_string, enumvals[i].description) == 0) {
725 return enumvals[i].value;
728 g_assert_not_reached();
733 fetch_preference_radio_buttons_val(GtkWidget *button,
734 const enum_val_t *enumvals)
740 * Go through the list of of radio buttons in the button's group,
741 * and find the first one that's active.
743 rb_group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
745 for (rb_entry = rb_group; rb_entry != NULL;
746 rb_entry = g_slist_next(rb_entry)) {
747 button = rb_entry->data;
748 if (GTK_TOGGLE_BUTTON(button)->active)
752 /* OK, now return the value corresponding to that button's label. */
753 return label_to_enum_val(GTK_BIN(button)->child, enumvals);
757 create_preference_option_menu(GtkWidget *main_tb, int table_position,
758 const gchar *label_text, const gchar *tooltip_text,
759 const enum_val_t *enumvals, gint current_val)
761 GtkTooltips *tooltips;
762 GtkWidget *menu_box, *menu, *menu_item, *option_menu;
763 int menu_index, index;
764 const enum_val_t *enum_valp;
765 GtkWidget *event_box;
767 tooltips = OBJECT_GET_DATA(main_tb, E_TOOLTIPS_KEY);
769 set_option_label(main_tb, table_position, label_text, tooltip_text,
772 /* Create a menu from the enumvals */
773 menu = gtk_menu_new();
774 if (tooltip_text != NULL && tooltips != NULL)
775 gtk_tooltips_set_tip(tooltips, menu, tooltip_text, NULL);
777 for (enum_valp = enumvals, index = 0; enum_valp->name != NULL;
778 enum_valp++, index++) {
779 menu_item = gtk_menu_item_new_with_label(enum_valp->description);
780 gtk_menu_append(GTK_MENU(menu), menu_item);
781 if (enum_valp->value == current_val)
783 gtk_widget_show(menu_item);
786 /* Create the option menu from the menu */
787 option_menu = gtk_option_menu_new();
788 gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), menu);
790 /* Set its current value to the variable's current value */
791 if (menu_index != -1)
792 gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu),
796 * Put the option menu in an hbox, so that it's only as wide
797 * as the widest entry, rather than being as wide as the table
800 menu_box = gtk_hbox_new(FALSE, 0);
801 gtk_box_pack_start(GTK_BOX(menu_box), option_menu, FALSE, FALSE, 0);
803 event_box = gtk_event_box_new();
804 gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box,
805 1, 2, table_position, table_position + 1);
806 if (tooltip_text != NULL && tooltips != NULL)
807 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
808 gtk_container_add(GTK_CONTAINER(event_box), menu_box);
814 fetch_preference_option_menu_val(GtkWidget *optmenu, const enum_val_t *enumvals)
817 * OK, now return the value corresponding to the label for the
818 * currently active entry in the option menu.
820 * Yes, this is how you get the label for that entry. See FAQ
821 * 6.8 in the GTK+ FAQ.
823 return label_to_enum_val(GTK_BIN(optmenu)->child, enumvals);
827 create_preference_entry(GtkWidget *main_tb, int table_position,
828 const gchar *label_text, const gchar *tooltip_text, char *value)
830 GtkTooltips *tooltips;
833 tooltips = OBJECT_GET_DATA(main_tb, E_TOOLTIPS_KEY);
835 set_option_label(main_tb, table_position, label_text, tooltip_text,
838 entry = gtk_entry_new();
840 gtk_entry_set_text(GTK_ENTRY(entry), value);
841 gtk_table_attach_defaults(GTK_TABLE(main_tb), entry, 1, 2,
842 table_position, table_position + 1);
843 if (tooltip_text != NULL && tooltips != NULL)
844 gtk_tooltips_set_tip(tooltips, entry, tooltip_text, NULL);
845 gtk_widget_show(entry);
851 pref_fetch(pref_t *pref, gpointer user_data)
858 gboolean *pref_changed_p = user_data;
860 /* Fetch the value of the preference, and set the appropriate variable
862 switch (pref->type) {
865 str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
866 uval = strtoul(str_val, &p, pref->info.base);
868 if (p == value || *p != '\0')
869 return PREFS_SET_SYNTAX_ERR; /* number was bad */
871 if (*pref->varp.uint != uval) {
872 *pref_changed_p = TRUE;
873 *pref->varp.uint = uval;
878 bval = GTK_TOGGLE_BUTTON(pref->control)->active;
879 if (*pref->varp.boolp != bval) {
880 *pref_changed_p = TRUE;
881 *pref->varp.boolp = bval;
886 if (pref->info.enum_info.radio_buttons) {
887 enumval = fetch_preference_radio_buttons_val(pref->control,
888 pref->info.enum_info.enumvals);
890 enumval = fetch_preference_option_menu_val(pref->control,
891 pref->info.enum_info.enumvals);
894 if (*pref->varp.enump != enumval) {
895 *pref_changed_p = TRUE;
896 *pref->varp.enump = enumval;
901 str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
902 if (strcmp(*pref->varp.string, str_val) != 0) {
903 *pref_changed_p = TRUE;
904 g_free(*pref->varp.string);
905 *pref->varp.string = g_strdup(str_val);
910 g_assert_not_reached();
917 module_prefs_fetch(module_t *module, gpointer user_data)
919 gboolean *must_redissect_p = user_data;
921 /* For all preferences in this module, fetch its value from this
922 module's notebook page. Find out whether any of them changed. */
923 module->prefs_changed = FALSE; /* assume none of them changed */
924 prefs_pref_foreach(module, pref_fetch, &module->prefs_changed);
926 /* If any of them changed, indicate that we must redissect and refilter
927 the current capture (if we have one), as the preference change
928 could cause packets to be dissected differently. */
929 if (module->prefs_changed)
930 *must_redissect_p = TRUE;
934 pref_clean(pref_t *pref, gpointer user_data _U_)
936 switch (pref->type) {
948 if (pref->saved_val.string != NULL) {
949 g_free(pref->saved_val.string);
950 pref->saved_val.string = NULL;
955 g_assert_not_reached();
962 module_prefs_clean(module_t *module, gpointer user_data _U_)
964 /* For all preferences in this module, clean up any cruft allocated for
965 use by the GUI code. */
966 prefs_pref_foreach(module, pref_clean, NULL);
970 /* fetch all pref values from all pages */
972 prefs_main_fetch_all(GtkWidget *dlg, gboolean *must_redissect)
974 /* Fetch the preferences (i.e., make sure all the values set in all of
975 the preferences panes have been copied to "prefs" and the registered
977 gui_prefs_fetch(OBJECT_GET_DATA(dlg, E_GUI_PAGE_KEY));
978 layout_prefs_fetch(OBJECT_GET_DATA(dlg, E_GUI_LAYOUT_PAGE_KEY));
979 column_prefs_fetch(OBJECT_GET_DATA(dlg, E_GUI_COLUMN_PAGE_KEY));
980 stream_prefs_fetch(OBJECT_GET_DATA(dlg, E_GUI_COLORS_PAGE_KEY));
984 /* Is WPcap loaded? */
987 capture_prefs_fetch(OBJECT_GET_DATA(dlg, E_CAPTURE_PAGE_KEY));
991 #endif /* HAVE_LIBPCAP */
992 printer_prefs_fetch(OBJECT_GET_DATA(dlg, E_PRINT_PAGE_KEY));
993 nameres_prefs_fetch(OBJECT_GET_DATA(dlg, E_NAMERES_PAGE_KEY));
995 prefs_modules_foreach(module_prefs_fetch, must_redissect);
999 /* apply all pref values to the real world */
1001 prefs_main_apply_all(GtkWidget *dlg)
1003 /* Now apply those preferences. */
1004 gui_prefs_apply(OBJECT_GET_DATA(dlg, E_GUI_PAGE_KEY));
1005 layout_prefs_apply(OBJECT_GET_DATA(dlg, E_GUI_LAYOUT_PAGE_KEY));
1006 column_prefs_apply(OBJECT_GET_DATA(dlg, E_GUI_COLUMN_PAGE_KEY));
1007 stream_prefs_apply(OBJECT_GET_DATA(dlg, E_GUI_COLORS_PAGE_KEY));
1011 /* Is WPcap loaded? */
1014 capture_prefs_apply(OBJECT_GET_DATA(dlg, E_CAPTURE_PAGE_KEY));
1018 #endif /* HAVE_LIBPCAP */
1019 printer_prefs_apply(OBJECT_GET_DATA(dlg, E_PRINT_PAGE_KEY));
1020 nameres_prefs_apply(OBJECT_GET_DATA(dlg, E_NAMERES_PAGE_KEY));
1026 /* destroy all preferences ressources from all pages */
1028 prefs_main_destroy_all(GtkWidget *dlg)
1030 gui_prefs_destroy(OBJECT_GET_DATA(dlg, E_GUI_PAGE_KEY));
1031 layout_prefs_destroy(OBJECT_GET_DATA(dlg, E_GUI_LAYOUT_PAGE_KEY));
1032 column_prefs_destroy(OBJECT_GET_DATA(dlg, E_GUI_COLUMN_PAGE_KEY));
1033 stream_prefs_destroy(OBJECT_GET_DATA(dlg, E_GUI_COLORS_PAGE_KEY));
1037 /* Is WPcap loaded? */
1040 capture_prefs_destroy(OBJECT_GET_DATA(dlg, E_CAPTURE_PAGE_KEY));
1044 #endif /* HAVE_LIBPCAP */
1045 printer_prefs_destroy(OBJECT_GET_DATA(dlg, E_PRINT_PAGE_KEY));
1046 nameres_prefs_destroy(OBJECT_GET_DATA(dlg, E_NAMERES_PAGE_KEY));
1048 /* Free up the saved preferences (both for "prefs" and for registered
1050 free_prefs(&saved_prefs);
1051 prefs_modules_foreach(module_prefs_clean, NULL);
1056 prefs_main_ok_cb(GtkWidget *ok_bt _U_, gpointer parent_w)
1058 gboolean must_redissect = FALSE;
1060 prefs_main_fetch_all(parent_w, &must_redissect);
1062 prefs_main_apply_all(parent_w);
1064 /* Now destroy the "Preferences" dialog. */
1065 window_destroy(GTK_WIDGET(parent_w));
1067 if (must_redissect) {
1068 /* Redissect all the packets, and re-evaluate the display filter. */
1069 redissect_packets(&cfile);
1074 prefs_main_apply_cb(GtkWidget *apply_bt _U_, gpointer parent_w)
1076 gboolean must_redissect = FALSE;
1078 prefs_main_fetch_all(parent_w, &must_redissect);
1080 prefs_main_apply_all(parent_w);
1082 if (must_redissect) {
1083 /* Redissect all the packets, and re-evaluate the display filter. */
1084 redissect_packets(&cfile);
1089 prefs_main_save_cb(GtkWidget *save_bt _U_, gpointer parent_w)
1091 gboolean must_redissect = FALSE;
1096 prefs_main_fetch_all(parent_w, &must_redissect);
1098 /* Create the directory that holds personal configuration files, if
1100 if (create_persconffile_dir(&pf_dir_path) == -1) {
1101 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1102 "Can't create directory\n\"%s\"\nfor preferences file: %s.", pf_dir_path,
1104 g_free(pf_dir_path);
1106 /* Write the preferencs out. */
1107 err = write_prefs(&pf_path);
1109 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1110 "Can't open preferences file\n\"%s\": %s.", pf_path,
1116 /* Now apply those preferences.
1117 XXX - should we do this? The user didn't click "OK" or "Apply".
1120 1) by saving the preferences they presumably indicate that they
1123 2) the next time they fire Ethereal up, those preferences will
1126 3) we'd have to buffer "must_redissect" so that if they do
1127 "Apply" after this, we know we have to redissect;
1129 4) we did apply the protocol preferences, at least, in the past. */
1130 prefs_main_apply_all(parent_w);
1132 if (must_redissect) {
1133 /* Redissect all the packets, and re-evaluate the display filter. */
1134 redissect_packets(&cfile);
1139 pref_revert(pref_t *pref, gpointer user_data)
1141 gboolean *pref_changed_p = user_data;
1143 /* Revert the preference to its saved value. */
1144 switch (pref->type) {
1147 if (*pref->varp.uint != pref->saved_val.uint) {
1148 *pref_changed_p = TRUE;
1149 *pref->varp.uint = pref->saved_val.uint;
1154 if (*pref->varp.boolp != pref->saved_val.boolval) {
1155 *pref_changed_p = TRUE;
1156 *pref->varp.boolp = pref->saved_val.boolval;
1161 if (*pref->varp.enump != pref->saved_val.enumval) {
1162 *pref_changed_p = TRUE;
1163 *pref->varp.enump = pref->saved_val.enumval;
1168 if (strcmp(*pref->varp.string, pref->saved_val.string) != 0) {
1169 *pref_changed_p = TRUE;
1170 g_free(*pref->varp.string);
1171 *pref->varp.string = g_strdup(pref->saved_val.string);
1176 g_assert_not_reached();
1183 module_prefs_revert(module_t *module, gpointer user_data)
1185 gboolean *must_redissect_p = user_data;
1187 /* For all preferences in this module, revert its value to the value
1188 it had when we popped up the Preferences dialog. Find out whether
1189 this changes any of them. */
1190 module->prefs_changed = FALSE; /* assume none of them changed */
1191 prefs_pref_foreach(module, pref_revert, &module->prefs_changed);
1193 /* If any of them changed, indicate that we must redissect and refilter
1194 the current capture (if we have one), as the preference change
1195 could cause packets to be dissected differently. */
1196 if (module->prefs_changed)
1197 *must_redissect_p = TRUE;
1200 /* cancel button pressed, revert prefs to saved and exit dialog */
1202 prefs_main_cancel_cb(GtkWidget *cancel_bt _U_, gpointer parent_w)
1204 gboolean must_redissect = FALSE;
1206 /* Free up the current preferences and copy the saved preferences to the
1207 current preferences. */
1209 copy_prefs(&prefs, &saved_prefs);
1211 /* Now revert the registered preferences. */
1212 prefs_modules_foreach(module_prefs_revert, &must_redissect);
1214 /* Now apply the reverted-to preferences. */
1215 prefs_main_apply_all(parent_w);
1217 window_destroy(GTK_WIDGET(parent_w));
1219 if (must_redissect) {
1220 /* Redissect all the packets, and re-evaluate the display filter. */
1221 redissect_packets(&cfile);
1225 /* Treat this as a cancel, by calling "prefs_main_cancel_cb()" */
1227 prefs_main_delete_cb(GtkWidget *prefs_w _U_, gpointer parent_w)
1229 prefs_main_cancel_cb(NULL, parent_w);
1234 /* dialog *is* already destroyed, clean up memory and such */
1236 prefs_main_destroy_cb(GtkWidget *win _U_, gpointer parent_w)
1238 prefs_main_destroy_all(parent_w);
1240 /* Note that we no longer have a "Preferences" dialog box. */
1244 struct properties_data {
1250 module_search_properties(module_t *module, gpointer user_data)
1252 struct properties_data *p = (struct properties_data *)user_data;
1254 /* If this module has the specified title, remember it. */
1255 if (strcmp(module->title, p->title) == 0)
1260 properties_cb(GtkWidget *w, gpointer dummy)
1262 header_field_info *hfinfo;
1264 struct properties_data p;
1267 module_t *page_module;
1269 if (cfile.finfo_selected == NULL) {
1270 /* There is no field selected */
1274 /* Find the title for the protocol for the selected field. */
1275 hfinfo = cfile.finfo_selected->hfinfo;
1276 if (hfinfo->parent == -1)
1277 title = prefs_get_title_by_name(hfinfo->abbrev);
1279 title = prefs_get_title_by_name(proto_registrar_get_abbrev(hfinfo->parent));
1281 return; /* Couldn't find it. XXX - just crash? "Can't happen"? */
1283 /* Find the module for that protocol by searching for one with that title.
1284 XXX - should we just associate protocols with modules directly? */
1287 prefs_module_list_foreach(protocols_module->prefs, module_search_properties,
1289 if (p.module == NULL) {
1290 /* We didn't find it - that protocol probably has no preferences. */
1294 /* Create a preferences window, or pop up an existing one. */
1295 if (prefs_w != NULL) {
1296 reactivate_window(prefs_w);
1301 /* Search all the pages in that window for the one with the specified
1304 (frame = gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), page_num)) != NULL;
1306 /* Get the module for this page. */
1307 page_module = OBJECT_GET_DATA(frame, E_PAGE_MODULE_KEY);
1308 if (page_module == NULL)
1309 continue; /* It doesn't have one. */
1310 if (page_module == p.module) {
1311 /* We found it. Select that page. */
1312 gtk_notebook_set_page(GTK_NOTEBOOK(notebook), page_num);
1318 /* Prefs tree selection callback. The node data has been loaded with
1319 the proper notebook page to load. */
1320 #if GTK_MAJOR_VERSION < 2
1322 prefs_tree_select_cb(GtkCTree *ct, GtkCTreeNode *node, gint col _U_,
1326 prefs_tree_select_cb(GtkTreeSelection *sel, gpointer dummy _U_)
1330 #if GTK_MAJOR_VERSION >= 2
1331 GtkTreeModel *model;
1335 #if GTK_MAJOR_VERSION < 2
1336 page = GPOINTER_TO_INT(gtk_ctree_node_get_row_data(ct, node));
1339 gtk_notebook_set_page(GTK_NOTEBOOK(notebook), page);
1341 if (gtk_tree_selection_get_selected(sel, &model, &iter))
1343 gtk_tree_model_get(model, &iter, 1, &page, -1);
1345 gtk_notebook_set_page(GTK_NOTEBOOK(notebook), page);