2 * Routines for handling preferences
4 * $Id: prefs_dlg.c,v 1.63 2003/10/02 21:18:38 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 "capture_prefs.h"
46 #include "nameres_prefs.h"
48 #include "dlg_utils.h"
49 #include "simple_dialog.h"
50 #include "compat_macros.h"
52 #include "prefs-int.h"
56 #include "capture-wpcap.h"
58 #endif /* HAVE_LIBPCAP */
60 static void prefs_main_ok_cb(GtkWidget *, gpointer);
61 static void prefs_main_apply_cb(GtkWidget *, gpointer);
62 static void prefs_main_save_cb(GtkWidget *, gpointer);
63 static void prefs_main_cancel_cb(GtkWidget *, gpointer);
64 static gboolean prefs_main_delete_cb(GtkWidget *, gpointer);
65 static void prefs_main_destroy_cb(GtkWidget *, gpointer);
66 #if GTK_MAJOR_VERSION < 2
67 static void prefs_tree_select_cb(GtkCTree *, GtkCTreeNode *, gint,
70 static void prefs_tree_select_cb(GtkTreeSelection *, gpointer);
73 #define E_PRINT_PAGE_KEY "printer_options_page"
74 #define E_COLUMN_PAGE_KEY "column_options_page"
75 #define E_STREAM_PAGE_KEY "tcp_stream_options_page"
76 #define E_GUI_PAGE_KEY "gui_options_page"
77 #define E_CAPTURE_PAGE_KEY "capture_options_page"
78 #define E_NAMERES_PAGE_KEY "nameres_options_page"
79 #define E_TOOLTIPS_KEY "tooltips"
81 static int first_proto_prefs_page = -1;
84 * Keep a static pointer to the notebook to be able to choose the
87 static GtkWidget *notebook;
90 * Keep a static pointer to the current "Preferences" window, if any, so that
91 * if somebody tries to do "Edit:Preferences" while there's already a
92 * "Preferences" window up, we just pop up the existing one, rather than
95 static GtkWidget *prefs_w;
98 * Save the value of the preferences as of when the preferences dialog
99 * box was first popped up, so we can revert to those values if the
100 * user selects "Cancel".
102 static e_prefs saved_prefs;
108 #if GTK_MAJOR_VERSION < 2
113 GtkTooltips *tooltips;
115 gboolean is_protocol;
119 pref_exists(pref_t *pref _U_, gpointer user_data _U_)
125 pref_show(pref_t *pref, gpointer user_data)
127 GtkWidget *main_tb = user_data;
132 /* Give this preference a label which is its title, followed by a colon,
133 and left-align it. */
135 label_string = g_malloc(strlen(title) + 2);
136 strcpy(label_string, title);
137 strcat(label_string, ":");
139 /* Save the current value of the preference, so that we can revert it if
140 the user does "Apply" and then "Cancel", and create the control for
141 editing the preference. */
142 switch (pref->type) {
145 pref->saved_val.uint = *pref->varp.uint;
147 /* XXX - there are no uint spinbuttons, so we can't use a spinbutton.
148 Even more annoyingly, even if there were, GLib doesn't define
149 G_MAXUINT - but I think ANSI C may define UINT_MAX, so we could
151 switch (pref->info.base) {
154 sprintf(uint_str, "%u", pref->saved_val.uint);
158 sprintf(uint_str, "%o", pref->saved_val.uint);
162 sprintf(uint_str, "%x", pref->saved_val.uint);
165 pref->control = create_preference_entry(main_tb, pref->ordinal,
166 label_string, pref->description,
171 pref->saved_val.boolval = *pref->varp.boolp;
172 pref->control = create_preference_check_button(main_tb, pref->ordinal,
173 label_string, pref->description,
174 pref->saved_val.boolval);
178 pref->saved_val.enumval = *pref->varp.enump;
179 if (pref->info.enum_info.radio_buttons) {
180 /* Show it as radio buttons. */
181 pref->control = create_preference_radio_buttons(main_tb, pref->ordinal,
182 label_string, pref->description,
183 pref->info.enum_info.enumvals,
184 pref->saved_val.enumval);
186 /* Show it as an option menu. */
187 pref->control = create_preference_option_menu(main_tb, pref->ordinal,
188 label_string, pref->description,
189 pref->info.enum_info.enumvals,
190 pref->saved_val.enumval);
195 if (pref->saved_val.string != NULL)
196 g_free(pref->saved_val.string);
197 pref->saved_val.string = g_strdup(*pref->varp.string);
198 pref->control = create_preference_entry(main_tb, pref->ordinal,
199 label_string, pref->description,
200 pref->saved_val.string);
204 g_assert_not_reached();
207 g_free(label_string);
212 #define MAX_TREE_NODE_NAME_LEN 64
214 module_prefs_show(module_t *module, gpointer user_data)
216 struct ct_struct *cts = user_data;
217 struct ct_struct child_cts;
218 GtkWidget *main_vb, *main_tb, *frame;
219 gchar label_str[MAX_TREE_NODE_NAME_LEN];
220 #if GTK_MAJOR_VERSION < 2
221 gchar *label_ptr = label_str;
222 GtkCTreeNode *ct_node;
229 * Is this module a subtree, with modules underneath it?
231 if (!module->is_subtree) {
234 * Does it have any preferences (other than possibly obsolete ones)?
236 if (prefs_pref_foreach(module, pref_exists, NULL) == 0) {
238 * No. Don't put the module into the preferences window.
239 * XXX - we should do the same for subtrees; if a subtree has
240 * nothing under it that will be displayed, don't put it into
248 * Add this module to the tree.
250 strcpy(label_str, module->title);
251 #if GTK_MAJOR_VERSION < 2
252 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts->tree), cts->node, NULL,
253 &label_ptr, 5, NULL, NULL, NULL, NULL, !module->is_subtree,
256 model = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(cts->tree)));
257 if (module->is_subtree)
258 gtk_tree_store_append(model, &iter, NULL);
260 gtk_tree_store_append(model, &iter, &cts->iter);
266 if (module->is_subtree) {
271 /* Note that there's no page attached to this item */
272 #if GTK_MAJOR_VERSION < 2
273 gtk_ctree_node_set_row_data(GTK_CTREE(cts->tree), ct_node,
274 GINT_TO_POINTER(-1));
276 gtk_tree_store_set(model, &iter, 0, label_str, 1, -1, -1);
280 * Walk the subtree and attach stuff to it.
283 #if GTK_MAJOR_VERSION < 2
284 child_cts.node = ct_node;
286 child_cts.iter = iter;
288 if (module == protocols_module)
289 child_cts.is_protocol = TRUE;
290 prefs_module_list_foreach(module->prefs, module_prefs_show, &child_cts);
293 * No. Create a notebook page for it.
297 frame = gtk_frame_new(module->title);
298 gtk_widget_show(frame);
300 /* Main vertical box */
301 main_vb = gtk_vbox_new(FALSE, 5);
302 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
303 gtk_container_add(GTK_CONTAINER(frame), main_vb);
306 main_tb = gtk_table_new(module->numprefs, 2, FALSE);
307 gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0);
308 gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10);
309 gtk_table_set_col_spacings(GTK_TABLE(main_tb), 15);
310 OBJECT_SET_DATA(main_tb, E_TOOLTIPS_KEY, cts->tooltips);
312 /* Add items for each of the preferences */
313 prefs_pref_foreach(module, pref_show, main_tb);
315 /* Add the page to the notebook */
316 gtk_notebook_append_page(GTK_NOTEBOOK(cts->notebook), frame, NULL);
318 /* Attach the page to the tree item */
319 #if GTK_MAJOR_VERSION < 2
320 gtk_ctree_node_set_row_data(GTK_CTREE(cts->tree), ct_node,
321 GINT_TO_POINTER(cts->page));
323 gtk_tree_store_set(model, &iter, 0, label_str, 1, cts->page, -1);
326 /* If this is the first protocol page, remember its page number */
327 if (first_proto_prefs_page == -1)
328 first_proto_prefs_page = cts->page;
331 /* Show 'em what we got */
332 gtk_widget_show_all(main_vb);
337 prefs_cb(GtkWidget *w _U_, gpointer dummy _U_)
339 GtkWidget *top_hb, *bbox, *prefs_nb, *ct_sb, *frame,
340 *ok_bt, *apply_bt, *save_bt, *cancel_bt;
341 GtkWidget *print_pg, *column_pg, *stream_pg, *gui_pg;
343 GtkWidget *capture_pg;
345 GtkWidget *nameres_pg;
346 gchar label_str[MAX_TREE_NODE_NAME_LEN];
347 struct ct_struct cts;
348 #if GTK_MAJOR_VERSION < 2
349 gchar *label_ptr = label_str;
350 GtkCTreeNode *ct_node;
353 GtkTreeSelection *selection;
354 GtkCellRenderer *renderer;
355 GtkTreeViewColumn *column;
360 if (prefs_w != NULL) {
361 /* There's already a "Preferences" dialog box; reactivate it. */
362 reactivate_window(prefs_w);
366 /* Save the current preferences, so we can revert to those values
367 if the user presses "Cancel". */
368 copy_prefs(&saved_prefs, &prefs);
370 prefs_w = dlg_window_new("Ethereal: Preferences");
371 SIGNAL_CONNECT(prefs_w, "delete_event", prefs_main_delete_cb, NULL);
372 SIGNAL_CONNECT(prefs_w, "destroy", prefs_main_destroy_cb, NULL);
375 * Unfortunately, we can't arrange that a GtkTable widget wrap an event box
376 * around a table row, so the spacing between the preference item's label
377 * and its control widgets is inactive and the tooltip doesn't pop up when
378 * the mouse is over it.
380 cts.tooltips = gtk_tooltips_new();
382 /* Container for each row of widgets */
383 cts.main_vb = gtk_vbox_new(FALSE, 5);
384 gtk_container_border_width(GTK_CONTAINER(cts.main_vb), 5);
385 gtk_container_add(GTK_CONTAINER(prefs_w), cts.main_vb);
386 gtk_widget_show(cts.main_vb);
388 /* Top row: Preferences tree and notebook */
389 top_hb = gtk_hbox_new(FALSE, 10);
390 gtk_container_add(GTK_CONTAINER(cts.main_vb), top_hb);
391 gtk_widget_show(top_hb);
393 /* Place a Ctree on the left for preference categories */
394 ct_sb = scrolled_window_new(NULL, NULL);
395 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ct_sb),
396 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
397 gtk_container_add(GTK_CONTAINER(top_hb), ct_sb);
398 gtk_widget_show(ct_sb);
400 #if GTK_MAJOR_VERSION < 2
401 cts.tree = ctree_new(1, 0);
404 store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_INT);
405 cts.tree = tree_view_new(GTK_TREE_MODEL(store));
406 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(cts.tree), FALSE);
407 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(cts.tree));
408 gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
409 renderer = gtk_cell_renderer_text_new();
410 col_offset = gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(cts.tree),
411 -1, "Name", renderer,
413 column = gtk_tree_view_get_column(GTK_TREE_VIEW(cts.tree),
415 gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column),
416 GTK_TREE_VIEW_COLUMN_AUTOSIZE);
419 gtk_container_add(GTK_CONTAINER(ct_sb), cts.tree);
421 #if GTK_MAJOR_VERSION < 2
422 gtk_clist_set_column_auto_resize(GTK_CLIST(cts.tree), 0, TRUE);
423 SIGNAL_CONNECT(cts.tree, "tree-select-row", prefs_tree_select_cb, NULL);
425 SIGNAL_CONNECT(selection, "changed", prefs_tree_select_cb, NULL);
427 gtk_widget_show(cts.tree);
429 /* A notebook widget sans tabs is used to flip between prefs */
430 notebook = prefs_nb = gtk_notebook_new();
431 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(prefs_nb), FALSE);
432 gtk_notebook_set_show_border(GTK_NOTEBOOK(prefs_nb), FALSE);
433 gtk_container_add(GTK_CONTAINER(top_hb), prefs_nb);
434 gtk_widget_show(prefs_nb);
437 frame = gtk_frame_new("Printing");
438 gtk_widget_show(GTK_WIDGET(frame));
439 print_pg = printer_prefs_show();
440 gtk_container_add(GTK_CONTAINER(frame), print_pg);
441 OBJECT_SET_DATA(prefs_w, E_PRINT_PAGE_KEY, print_pg);
442 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
443 strcpy(label_str, "Printing");
444 #if GTK_MAJOR_VERSION < 2
445 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.tree), NULL, NULL,
446 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
447 gtk_ctree_node_set_row_data(GTK_CTREE(cts.tree), ct_node,
448 GINT_TO_POINTER(cts.page));
450 gtk_tree_store_append(store, &iter, NULL);
451 gtk_tree_store_set(store, &iter, 0, label_str, 1, cts.page, -1);
456 frame = gtk_frame_new("Columns");
457 gtk_widget_show(GTK_WIDGET(frame));
458 column_pg = column_prefs_show();
459 gtk_container_add(GTK_CONTAINER(frame), column_pg);
460 OBJECT_SET_DATA(prefs_w, E_COLUMN_PAGE_KEY, column_pg);
461 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
462 strcpy(label_str, "Columns");
463 #if GTK_MAJOR_VERSION < 2
464 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.tree), NULL, NULL,
465 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
466 gtk_ctree_node_set_row_data(GTK_CTREE(cts.tree), ct_node,
467 GINT_TO_POINTER(cts.page));
469 gtk_tree_store_append(store, &iter, NULL);
470 gtk_tree_store_set(store, &iter, 0, label_str, 1, cts.page, -1);
474 /* TCP Streams prefs */
475 frame = gtk_frame_new("TCP Streams");
476 gtk_widget_show(GTK_WIDGET(frame));
477 stream_pg = stream_prefs_show();
478 gtk_container_add(GTK_CONTAINER(frame), stream_pg);
479 OBJECT_SET_DATA(prefs_w, E_STREAM_PAGE_KEY, stream_pg);
480 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
481 strcpy(label_str, "TCP Streams");
482 #if GTK_MAJOR_VERSION < 2
483 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.tree), NULL, NULL,
484 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
485 gtk_ctree_node_set_row_data(GTK_CTREE(cts.tree), ct_node,
486 GINT_TO_POINTER(cts.page));
488 gtk_tree_store_append(store, &iter, NULL);
489 gtk_tree_store_set(store, &iter, 0, label_str, 1, cts.page, -1);
494 frame = gtk_frame_new("User Interface");
495 gtk_widget_show(GTK_WIDGET(frame));
496 gui_pg = gui_prefs_show();
497 gtk_container_add(GTK_CONTAINER(frame), gui_pg);
498 OBJECT_SET_DATA(prefs_w, E_GUI_PAGE_KEY, gui_pg);
499 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
500 strcpy(label_str, "User Interface");
501 #if GTK_MAJOR_VERSION < 2
502 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.tree), NULL, NULL,
503 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
504 gtk_ctree_node_set_row_data(GTK_CTREE(cts.tree), ct_node,
505 GINT_TO_POINTER(cts.page));
507 gtk_tree_store_append(store, &iter, NULL);
508 gtk_tree_store_set(store, &iter, 0, label_str, 1, cts.page, -1);
514 /* Is WPcap loaded? */
518 frame = gtk_frame_new("Capture");
519 gtk_widget_show(GTK_WIDGET(frame));
520 capture_pg = capture_prefs_show();
521 gtk_container_add(GTK_CONTAINER(frame), capture_pg);
522 OBJECT_SET_DATA(prefs_w, E_CAPTURE_PAGE_KEY, capture_pg);
523 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
524 strcpy(label_str, "Capture");
525 #if GTK_MAJOR_VERSION < 2
526 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.tree), NULL, NULL,
527 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
528 gtk_ctree_node_set_row_data(GTK_CTREE(cts.tree), ct_node,
529 GINT_TO_POINTER(cts.page));
531 gtk_tree_store_append(store, &iter, NULL);
532 gtk_tree_store_set(store, &iter, 0, label_str, 1, cts.page, -1);
538 #endif /* HAVE_LIBPCAP */
540 /* Name resolution prefs */
541 frame = gtk_frame_new("Name Resolution");
542 gtk_widget_show(GTK_WIDGET(frame));
543 nameres_pg = nameres_prefs_show();
544 gtk_container_add(GTK_CONTAINER(frame), nameres_pg);
545 OBJECT_SET_DATA(prefs_w, E_NAMERES_PAGE_KEY, nameres_pg);
546 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
547 strcpy(label_str, "Name Resolution");
548 #if GTK_MAJOR_VERSION < 2
549 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.tree), NULL, NULL,
550 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
551 gtk_ctree_node_set_row_data(GTK_CTREE(cts.tree), ct_node,
552 GINT_TO_POINTER(cts.page));
554 gtk_tree_store_append(store, &iter, NULL);
555 gtk_tree_store_set(store, &iter, 0, label_str, 1, cts.page, -1);
559 /* Registered prefs */
560 cts.notebook = prefs_nb;
561 cts.is_protocol = FALSE;
562 prefs_module_list_foreach(NULL, module_prefs_show, &cts);
564 /* Button row: OK and cancel buttons */
565 bbox = gtk_hbutton_box_new();
566 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
567 gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
568 gtk_container_add(GTK_CONTAINER(cts.main_vb), bbox);
569 gtk_widget_show(bbox);
571 #if GTK_MAJOR_VERSION < 2
572 ok_bt = gtk_button_new_with_label ("OK");
574 ok_bt = gtk_button_new_from_stock(GTK_STOCK_OK);
576 SIGNAL_CONNECT(ok_bt, "clicked", prefs_main_ok_cb, prefs_w);
577 GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT);
578 gtk_box_pack_start (GTK_BOX (bbox), ok_bt, TRUE, TRUE, 0);
579 gtk_widget_grab_default(ok_bt);
580 gtk_widget_show(ok_bt);
582 #if GTK_MAJOR_VERSION < 2
583 apply_bt = gtk_button_new_with_label ("Apply");
585 apply_bt = gtk_button_new_from_stock(GTK_STOCK_APPLY);
587 SIGNAL_CONNECT(apply_bt, "clicked", prefs_main_apply_cb, prefs_w);
588 GTK_WIDGET_SET_FLAGS(apply_bt, GTK_CAN_DEFAULT);
589 gtk_box_pack_start(GTK_BOX (bbox), apply_bt, TRUE, TRUE, 0);
590 gtk_widget_show(apply_bt);
592 #if GTK_MAJOR_VERSION < 2
593 save_bt = gtk_button_new_with_label ("Save");
595 save_bt = gtk_button_new_from_stock(GTK_STOCK_SAVE);
597 SIGNAL_CONNECT(save_bt, "clicked", prefs_main_save_cb, prefs_w);
598 GTK_WIDGET_SET_FLAGS(save_bt, GTK_CAN_DEFAULT);
599 gtk_box_pack_start (GTK_BOX (bbox), save_bt, TRUE, TRUE, 0);
600 gtk_widget_show(save_bt);
602 #if GTK_MAJOR_VERSION < 2
603 cancel_bt = gtk_button_new_with_label ("Cancel");
605 cancel_bt = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
607 SIGNAL_CONNECT(cancel_bt, "clicked", prefs_main_cancel_cb, prefs_w);
608 GTK_WIDGET_SET_FLAGS(cancel_bt, GTK_CAN_DEFAULT);
609 gtk_box_pack_start (GTK_BOX (bbox), cancel_bt, TRUE, TRUE, 0);
610 gtk_widget_show(cancel_bt);
612 /* Catch the "key_press_event" signal in the window, so that we can catch
613 the ESC key being pressed and act as if the "Cancel" button had
615 dlg_set_cancel(prefs_w, cancel_bt);
617 gtk_widget_show(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,
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 gtk_label_get(GTK_LABEL(label), &label_string);
724 enumval = find_val_for_string(label_string, enumvals, 1);
730 fetch_preference_radio_buttons_val(GtkWidget *button,
731 const enum_val_t *enumvals)
737 * Go through the list of of radio buttons in the button's group,
738 * and find the first one that's active.
740 rb_group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
742 for (rb_entry = rb_group; rb_entry != NULL;
743 rb_entry = g_slist_next(rb_entry)) {
744 button = rb_entry->data;
745 if (GTK_TOGGLE_BUTTON(button)->active)
749 /* OK, now return the value corresponding to that button's label. */
750 return label_to_enum_val(GTK_BIN(button)->child, enumvals);
754 create_preference_option_menu(GtkWidget *main_tb, int table_position,
755 const gchar *label_text, const gchar *tooltip_text,
756 const enum_val_t *enumvals, gint current_val)
758 GtkTooltips *tooltips;
759 GtkWidget *menu_box, *menu, *menu_item, *option_menu;
760 int menu_index, index;
761 const enum_val_t *enum_valp;
762 GtkWidget *event_box;
764 tooltips = OBJECT_GET_DATA(main_tb, E_TOOLTIPS_KEY);
766 set_option_label(main_tb, table_position, label_text, tooltip_text,
769 /* Create a menu from the enumvals */
770 menu = gtk_menu_new();
771 if (tooltip_text != NULL && tooltips != NULL)
772 gtk_tooltips_set_tip(tooltips, menu, tooltip_text, NULL);
774 for (enum_valp = enumvals, index = 0; enum_valp->name != NULL;
775 enum_valp++, index++) {
776 menu_item = gtk_menu_item_new_with_label(enum_valp->name);
777 gtk_menu_append(GTK_MENU(menu), menu_item);
778 if (enum_valp->value == current_val)
780 gtk_widget_show(menu_item);
783 /* Create the option menu from the menu */
784 option_menu = gtk_option_menu_new();
785 gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), menu);
787 /* Set its current value to the variable's current value */
788 if (menu_index != -1)
789 gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu),
793 * Put the option menu in an hbox, so that it's only as wide
794 * as the widest entry, rather than being as wide as the table
797 menu_box = gtk_hbox_new(FALSE, 0);
798 gtk_box_pack_start(GTK_BOX(menu_box), option_menu, FALSE, FALSE, 0);
800 event_box = gtk_event_box_new();
801 gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box,
802 1, 2, table_position, table_position + 1);
803 if (tooltip_text != NULL && tooltips != NULL)
804 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
805 gtk_container_add(GTK_CONTAINER(event_box), menu_box);
811 fetch_preference_option_menu_val(GtkWidget *optmenu, const enum_val_t *enumvals)
814 * OK, now return the value corresponding to the label for the
815 * currently active entry in the option menu.
817 * Yes, this is how you get the label for that entry. See FAQ
818 * 6.8 in the GTK+ FAQ.
820 return label_to_enum_val(GTK_BIN(optmenu)->child, enumvals);
824 create_preference_entry(GtkWidget *main_tb, int table_position,
825 const gchar *label_text, const gchar *tooltip_text, char *value)
827 GtkTooltips *tooltips;
830 tooltips = OBJECT_GET_DATA(main_tb, E_TOOLTIPS_KEY);
832 set_option_label(main_tb, table_position, label_text, tooltip_text,
835 entry = gtk_entry_new();
837 gtk_entry_set_text(GTK_ENTRY(entry), value);
838 gtk_table_attach_defaults(GTK_TABLE(main_tb), entry, 1, 2,
839 table_position, table_position + 1);
840 if (tooltip_text != NULL && tooltips != NULL)
841 gtk_tooltips_set_tip(tooltips, entry, tooltip_text, NULL);
842 gtk_widget_show(entry);
848 pref_fetch(pref_t *pref, gpointer user_data)
855 gboolean *pref_changed_p = user_data;
857 /* Fetch the value of the preference, and set the appropriate variable
859 switch (pref->type) {
862 str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
863 uval = strtoul(str_val, &p, pref->info.base);
865 if (p == value || *p != '\0')
866 return PREFS_SET_SYNTAX_ERR; /* number was bad */
868 if (*pref->varp.uint != uval) {
869 *pref_changed_p = TRUE;
870 *pref->varp.uint = uval;
875 bval = GTK_TOGGLE_BUTTON(pref->control)->active;
876 if (*pref->varp.boolp != bval) {
877 *pref_changed_p = TRUE;
878 *pref->varp.boolp = bval;
883 if (pref->info.enum_info.radio_buttons) {
884 enumval = fetch_preference_radio_buttons_val(pref->control,
885 pref->info.enum_info.enumvals);
887 enumval = fetch_preference_option_menu_val(pref->control,
888 pref->info.enum_info.enumvals);
891 if (*pref->varp.enump != enumval) {
892 *pref_changed_p = TRUE;
893 *pref->varp.enump = enumval;
898 str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
899 if (strcmp(*pref->varp.string, str_val) != 0) {
900 *pref_changed_p = TRUE;
901 g_free(*pref->varp.string);
902 *pref->varp.string = g_strdup(str_val);
907 g_assert_not_reached();
914 module_prefs_fetch(module_t *module, gpointer user_data)
916 gboolean *must_redissect_p = user_data;
918 /* For all preferences in this module, fetch its value from this
919 module's notebook page. Find out whether any of them changed. */
920 module->prefs_changed = FALSE; /* assume none of them changed */
921 prefs_pref_foreach(module, pref_fetch, &module->prefs_changed);
923 /* If any of them changed, indicate that we must redissect and refilter
924 the current capture (if we have one), as the preference change
925 could cause packets to be dissected differently. */
926 if (module->prefs_changed)
927 *must_redissect_p = TRUE;
931 pref_clean(pref_t *pref, gpointer user_data _U_)
933 switch (pref->type) {
945 if (pref->saved_val.string != NULL) {
946 g_free(pref->saved_val.string);
947 pref->saved_val.string = NULL;
952 g_assert_not_reached();
959 module_prefs_clean(module_t *module, gpointer user_data _U_)
961 /* For all preferences in this module, clean up any cruft allocated for
962 use by the GUI code. */
963 prefs_pref_foreach(module, pref_clean, NULL);
967 prefs_main_ok_cb(GtkWidget *ok_bt _U_, gpointer parent_w)
969 gboolean must_redissect = FALSE;
971 /* Fetch the preferences (i.e., make sure all the values set in all of
972 the preferences panes have been copied to "prefs" and the registered
974 printer_prefs_fetch(OBJECT_GET_DATA(parent_w, E_PRINT_PAGE_KEY));
975 column_prefs_fetch(OBJECT_GET_DATA(parent_w, E_COLUMN_PAGE_KEY));
976 stream_prefs_fetch(OBJECT_GET_DATA(parent_w, E_STREAM_PAGE_KEY));
977 gui_prefs_fetch(OBJECT_GET_DATA(parent_w, E_GUI_PAGE_KEY));
980 /* Is WPcap loaded? */
983 capture_prefs_fetch(OBJECT_GET_DATA(parent_w, E_CAPTURE_PAGE_KEY));
987 #endif /* HAVE_LIBPCAP */
988 nameres_prefs_fetch(OBJECT_GET_DATA(parent_w, E_NAMERES_PAGE_KEY));
989 prefs_modules_foreach(module_prefs_fetch, &must_redissect);
991 /* Now apply those preferences. */
992 printer_prefs_apply(OBJECT_GET_DATA(parent_w, E_PRINT_PAGE_KEY));
993 column_prefs_apply(OBJECT_GET_DATA(parent_w, E_COLUMN_PAGE_KEY));
994 stream_prefs_apply(OBJECT_GET_DATA(parent_w, E_STREAM_PAGE_KEY));
995 gui_prefs_apply(OBJECT_GET_DATA(parent_w, E_GUI_PAGE_KEY));
998 /* Is WPcap loaded? */
1001 capture_prefs_apply(OBJECT_GET_DATA(parent_w, E_CAPTURE_PAGE_KEY));
1005 #endif /* HAVE_LIBPCAP */
1006 nameres_prefs_apply(OBJECT_GET_DATA(parent_w, E_NAMERES_PAGE_KEY));
1009 /* Now destroy the "Preferences" dialog. */
1010 gtk_widget_destroy(GTK_WIDGET(parent_w));
1012 if (must_redissect) {
1013 /* Redissect all the packets, and re-evaluate the display filter. */
1014 redissect_packets(&cfile);
1019 prefs_main_apply_cb(GtkWidget *apply_bt _U_, gpointer parent_w)
1021 gboolean must_redissect = FALSE;
1023 /* Fetch the preferences (i.e., make sure all the values set in all of
1024 the preferences panes have been copied to "prefs" and the registered
1026 printer_prefs_fetch(OBJECT_GET_DATA(parent_w, E_PRINT_PAGE_KEY));
1027 column_prefs_fetch(OBJECT_GET_DATA(parent_w, E_COLUMN_PAGE_KEY));
1028 stream_prefs_fetch(OBJECT_GET_DATA(parent_w, E_STREAM_PAGE_KEY));
1029 gui_prefs_fetch(OBJECT_GET_DATA(parent_w, E_GUI_PAGE_KEY));
1032 /* Is WPcap loaded? */
1035 capture_prefs_fetch(OBJECT_GET_DATA(parent_w, E_CAPTURE_PAGE_KEY));
1039 #endif /* HAVE_LIBPCAP */
1040 nameres_prefs_fetch(OBJECT_GET_DATA(parent_w, E_NAMERES_PAGE_KEY));
1041 prefs_modules_foreach(module_prefs_fetch, &must_redissect);
1043 /* Now apply those preferences. */
1044 printer_prefs_apply(OBJECT_GET_DATA(parent_w, E_PRINT_PAGE_KEY));
1045 column_prefs_apply(OBJECT_GET_DATA(parent_w, E_COLUMN_PAGE_KEY));
1046 stream_prefs_apply(OBJECT_GET_DATA(parent_w, E_STREAM_PAGE_KEY));
1047 gui_prefs_apply(OBJECT_GET_DATA(parent_w, E_GUI_PAGE_KEY));
1050 /* Is WPcap loaded? */
1053 capture_prefs_apply(OBJECT_GET_DATA(parent_w, E_CAPTURE_PAGE_KEY));
1057 #endif /* HAVE_LIBPCAP */
1058 nameres_prefs_apply(OBJECT_GET_DATA(parent_w, E_NAMERES_PAGE_KEY));
1061 if (must_redissect) {
1062 /* Redissect all the packets, and re-evaluate the display filter. */
1063 redissect_packets(&cfile);
1068 prefs_main_save_cb(GtkWidget *save_bt _U_, gpointer parent_w)
1070 gboolean must_redissect = FALSE;
1075 /* Fetch the preferences (i.e., make sure all the values set in all of
1076 the preferences panes have been copied to "prefs" and the registered
1078 printer_prefs_fetch(OBJECT_GET_DATA(parent_w, E_PRINT_PAGE_KEY));
1079 column_prefs_fetch(OBJECT_GET_DATA(parent_w, E_COLUMN_PAGE_KEY));
1080 stream_prefs_fetch(OBJECT_GET_DATA(parent_w, E_STREAM_PAGE_KEY));
1081 gui_prefs_fetch(OBJECT_GET_DATA(parent_w, E_GUI_PAGE_KEY));
1084 /* Is WPcap loaded? */
1087 capture_prefs_fetch(OBJECT_GET_DATA(parent_w, E_CAPTURE_PAGE_KEY));
1091 #endif /* HAVE_LIBPCAP */
1092 nameres_prefs_fetch(OBJECT_GET_DATA(parent_w, E_NAMERES_PAGE_KEY));
1093 prefs_modules_foreach(module_prefs_fetch, &must_redissect);
1095 /* Create the directory that holds personal configuration files, if
1097 if (create_persconffile_dir(&pf_dir_path) == -1) {
1098 simple_dialog(ESD_TYPE_WARN, NULL,
1099 "Can't create directory\n\"%s\"\nfor preferences file: %s.", pf_dir_path,
1101 g_free(pf_dir_path);
1103 /* Write the preferencs out. */
1104 err = write_prefs(&pf_path);
1106 simple_dialog(ESD_TYPE_WARN, NULL,
1107 "Can't open preferences file\n\"%s\": %s.", pf_path,
1113 /* Now apply those preferences.
1114 XXX - should we do this? The user didn't click "OK" or "Apply".
1117 1) by saving the preferences they presumably indicate that they
1120 2) the next time they fire Ethereal up, those preferences will
1123 3) we'd have to buffer "must_redissect" so that if they do
1124 "Apply" after this, we know we have to redissect;
1126 4) we did apply the protocol preferences, at least, in the past. */
1127 printer_prefs_apply(OBJECT_GET_DATA(parent_w, E_PRINT_PAGE_KEY));
1128 column_prefs_apply(OBJECT_GET_DATA(parent_w, E_COLUMN_PAGE_KEY));
1129 stream_prefs_apply(OBJECT_GET_DATA(parent_w, E_STREAM_PAGE_KEY));
1130 gui_prefs_apply(OBJECT_GET_DATA(parent_w, E_GUI_PAGE_KEY));
1133 /* Is WPcap loaded? */
1136 capture_prefs_apply(OBJECT_GET_DATA(parent_w, E_CAPTURE_PAGE_KEY));
1140 #endif /* HAVE_LIBPCAP */
1141 nameres_prefs_apply(OBJECT_GET_DATA(parent_w, E_NAMERES_PAGE_KEY));
1144 if (must_redissect) {
1145 /* Redissect all the packets, and re-evaluate the display filter. */
1146 redissect_packets(&cfile);
1151 pref_revert(pref_t *pref, gpointer user_data)
1153 gboolean *pref_changed_p = user_data;
1155 /* Revert the preference to its saved value. */
1156 switch (pref->type) {
1159 if (*pref->varp.uint != pref->saved_val.uint) {
1160 *pref_changed_p = TRUE;
1161 *pref->varp.uint = pref->saved_val.uint;
1166 if (*pref->varp.boolp != pref->saved_val.boolval) {
1167 *pref_changed_p = TRUE;
1168 *pref->varp.boolp = pref->saved_val.boolval;
1173 if (*pref->varp.enump != pref->saved_val.enumval) {
1174 *pref_changed_p = TRUE;
1175 *pref->varp.enump = pref->saved_val.enumval;
1180 if (strcmp(*pref->varp.string, pref->saved_val.string) != 0) {
1181 *pref_changed_p = TRUE;
1182 g_free(*pref->varp.string);
1183 *pref->varp.string = g_strdup(pref->saved_val.string);
1188 g_assert_not_reached();
1195 module_prefs_revert(module_t *module, gpointer user_data)
1197 gboolean *must_redissect_p = user_data;
1199 /* For all preferences in this module, revert its value to the value
1200 it had when we popped up the Preferences dialog. Find out whether
1201 this changes any of them. */
1202 module->prefs_changed = FALSE; /* assume none of them changed */
1203 prefs_pref_foreach(module, pref_revert, &module->prefs_changed);
1205 /* If any of them changed, indicate that we must redissect and refilter
1206 the current capture (if we have one), as the preference change
1207 could cause packets to be dissected differently. */
1208 if (module->prefs_changed)
1209 *must_redissect_p = TRUE;
1213 prefs_main_cancel_cb(GtkWidget *cancel_bt _U_, gpointer parent_w)
1215 gboolean must_redissect = FALSE;
1217 /* Free up the current preferences and copy the saved preferences to the
1218 current preferences. */
1220 copy_prefs(&prefs, &saved_prefs);
1222 /* Now revert the registered preferences. */
1223 prefs_modules_foreach(module_prefs_revert, &must_redissect);
1225 /* Now apply the reverted-to preferences. */
1226 printer_prefs_apply(OBJECT_GET_DATA(parent_w, E_PRINT_PAGE_KEY));
1227 column_prefs_apply(OBJECT_GET_DATA(parent_w, E_COLUMN_PAGE_KEY));
1228 stream_prefs_apply(OBJECT_GET_DATA(parent_w, E_STREAM_PAGE_KEY));
1229 gui_prefs_apply(OBJECT_GET_DATA(parent_w, E_GUI_PAGE_KEY));
1230 nameres_prefs_apply(OBJECT_GET_DATA(parent_w, E_NAMERES_PAGE_KEY));
1233 gtk_widget_destroy(GTK_WIDGET(parent_w));
1235 if (must_redissect) {
1236 /* Redissect all the packets, and re-evaluate the display filter. */
1237 redissect_packets(&cfile);
1241 /* Treat this as a cancel, by calling "prefs_main_cancel_cb()".
1242 XXX - that'll destroy the Preferences dialog; will that upset
1243 a higher-level handler that says "OK, we've been asked to delete
1244 this, so destroy it"? */
1246 prefs_main_delete_cb(GtkWidget *prefs_w, gpointer dummy _U_)
1248 prefs_main_cancel_cb(NULL, prefs_w);
1253 prefs_main_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1255 /* Let the preference tabs clean up anything they've done. */
1256 printer_prefs_destroy(OBJECT_GET_DATA(prefs_w, E_PRINT_PAGE_KEY));
1257 column_prefs_destroy(OBJECT_GET_DATA(prefs_w, E_COLUMN_PAGE_KEY));
1258 stream_prefs_destroy(OBJECT_GET_DATA(prefs_w, E_STREAM_PAGE_KEY));
1259 gui_prefs_destroy(OBJECT_GET_DATA(prefs_w, E_GUI_PAGE_KEY));
1262 /* Is WPcap loaded? */
1265 capture_prefs_destroy(OBJECT_GET_DATA(prefs_w, E_CAPTURE_PAGE_KEY));
1269 #endif /* HAVE_LIBPCAP */
1270 nameres_prefs_destroy(OBJECT_GET_DATA(prefs_w, E_NAMERES_PAGE_KEY));
1272 /* Free up the saved preferences (both for "prefs" and for registered
1274 free_prefs(&saved_prefs);
1275 prefs_modules_foreach(module_prefs_clean, NULL);
1277 /* Note that we no longer have a "Preferences" dialog box. */
1279 first_proto_prefs_page = -1;
1282 struct properties_data {
1288 /* XXX this way of searching the correct page number is really ugly ... */
1290 module_search_properties(module_t *module, gpointer user_data)
1292 struct properties_data *p = (struct properties_data *)user_data;
1294 if (p->title == NULL) return;
1295 if (strcmp(module->title, p->title) == 0) {
1297 gtk_notebook_set_page(GTK_NOTEBOOK(p->w), p->page_num);
1305 properties_cb(GtkWidget *w, gpointer dummy)
1307 const gchar *title = NULL;
1308 struct properties_data p;
1310 if (cfile.finfo_selected) {
1311 header_field_info *hfinfo = cfile.finfo_selected->hfinfo;
1312 if (hfinfo->parent == -1) {
1313 title = prefs_get_title_by_name(hfinfo->abbrev);
1316 prefs_get_title_by_name(proto_registrar_get_abbrev(hfinfo->parent));
1324 if (prefs_w != NULL) {
1325 reactivate_window(prefs_w);
1331 p.page_num = first_proto_prefs_page;
1334 prefs_module_list_foreach(protocols_module->prefs, module_search_properties,
1338 /* Prefs tree selection callback. The node data has been loaded with
1339 the proper notebook page to load. */
1340 #if GTK_MAJOR_VERSION < 2
1342 prefs_tree_select_cb(GtkCTree *ct, GtkCTreeNode *node, gint col _U_,
1346 prefs_tree_select_cb(GtkTreeSelection *sel, gpointer dummy _U_)
1350 #if GTK_MAJOR_VERSION >= 2
1351 GtkTreeModel *model;
1355 #if GTK_MAJOR_VERSION < 2
1356 page = GPOINTER_TO_INT(gtk_ctree_node_get_row_data(ct, node));
1359 gtk_notebook_set_page(GTK_NOTEBOOK(notebook), page);
1361 if (gtk_tree_selection_get_selected(sel, &model, &iter))
1363 gtk_tree_model_get(model, &iter, 1, &page, -1);
1365 gtk_notebook_set_page(GTK_NOTEBOOK(notebook), page);