2 * Routines for handling preferences
4 * $Id: prefs_dlg.c,v 1.61 2003/09/24 00:47:37 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_show(pref_t *pref, gpointer user_data)
121 GtkWidget *main_tb = user_data;
126 /* Give this preference a label which is its title, followed by a colon,
127 and left-align it. */
129 label_string = g_malloc(strlen(title) + 2);
130 strcpy(label_string, title);
131 strcat(label_string, ":");
133 /* Save the current value of the preference, so that we can revert it if
134 the user does "Apply" and then "Cancel", and create the control for
135 editing the preference. */
136 switch (pref->type) {
139 pref->saved_val.uint = *pref->varp.uint;
141 /* XXX - there are no uint spinbuttons, so we can't use a spinbutton.
142 Even more annoyingly, even if there were, GLib doesn't define
143 G_MAXUINT - but I think ANSI C may define UINT_MAX, so we could
145 switch (pref->info.base) {
148 sprintf(uint_str, "%u", pref->saved_val.uint);
152 sprintf(uint_str, "%o", pref->saved_val.uint);
156 sprintf(uint_str, "%x", pref->saved_val.uint);
159 pref->control = create_preference_entry(main_tb, pref->ordinal,
160 label_string, pref->description,
165 pref->saved_val.boolval = *pref->varp.boolp;
166 pref->control = create_preference_check_button(main_tb, pref->ordinal,
167 label_string, pref->description,
168 pref->saved_val.boolval);
172 pref->saved_val.enumval = *pref->varp.enump;
173 if (pref->info.enum_info.radio_buttons) {
174 /* Show it as radio buttons. */
175 pref->control = create_preference_radio_buttons(main_tb, pref->ordinal,
176 label_string, pref->description,
177 pref->info.enum_info.enumvals,
178 pref->saved_val.enumval);
180 /* Show it as an option menu. */
181 pref->control = create_preference_option_menu(main_tb, pref->ordinal,
182 label_string, pref->description,
183 pref->info.enum_info.enumvals,
184 pref->saved_val.enumval);
189 if (pref->saved_val.string != NULL)
190 g_free(pref->saved_val.string);
191 pref->saved_val.string = g_strdup(*pref->varp.string);
192 pref->control = create_preference_entry(main_tb, pref->ordinal,
193 label_string, pref->description,
194 pref->saved_val.string);
198 g_assert_not_reached();
201 g_free(label_string);
204 #define MAX_TREE_NODE_NAME_LEN 64
206 module_prefs_show(module_t *module, gpointer user_data)
208 struct ct_struct *cts = user_data;
209 struct ct_struct child_cts;
210 GtkWidget *main_vb, *main_tb, *frame;
211 gchar label_str[MAX_TREE_NODE_NAME_LEN];
212 #if GTK_MAJOR_VERSION < 2
213 gchar *label_ptr = label_str;
214 GtkCTreeNode *ct_node;
221 * Add this module to the tree.
223 strcpy(label_str, module->title);
224 #if GTK_MAJOR_VERSION < 2
225 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts->tree), cts->node, NULL,
226 &label_ptr, 5, NULL, NULL, NULL, NULL, !module->is_subtree,
229 model = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(cts->tree)));
230 if (module->is_subtree)
231 gtk_tree_store_append(model, &iter, NULL);
233 gtk_tree_store_append(model, &iter, &cts->iter);
239 if (module->is_subtree) {
244 /* Note that there's no page attached to this item */
245 #if GTK_MAJOR_VERSION < 2
246 gtk_ctree_node_set_row_data(GTK_CTREE(cts->tree), ct_node,
247 GINT_TO_POINTER(-1));
249 gtk_tree_store_set(model, &iter, 0, label_str, 1, -1, -1);
253 * Walk the subtree and attach stuff to it.
256 #if GTK_MAJOR_VERSION < 2
257 child_cts.node = ct_node;
259 child_cts.iter = iter;
261 if (module == protocols_module)
262 child_cts.is_protocol = TRUE;
263 prefs_module_list_foreach(module->prefs, module_prefs_show, &child_cts);
267 * Create a notebook page for it.
271 frame = gtk_frame_new(module->title);
272 gtk_widget_show(frame);
274 /* Main vertical box */
275 main_vb = gtk_vbox_new(FALSE, 5);
276 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
277 gtk_container_add(GTK_CONTAINER(frame), main_vb);
280 main_tb = gtk_table_new(module->numprefs, 2, FALSE);
281 gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0);
282 gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10);
283 gtk_table_set_col_spacings(GTK_TABLE(main_tb), 15);
284 OBJECT_SET_DATA(main_tb, E_TOOLTIPS_KEY, cts->tooltips);
286 /* Add items for each of the preferences */
287 prefs_pref_foreach(module, pref_show, main_tb);
289 /* Add the page to the notebook */
290 gtk_notebook_append_page(GTK_NOTEBOOK(cts->notebook), frame, NULL);
292 /* Attach the page to the tree item */
293 #if GTK_MAJOR_VERSION < 2
294 gtk_ctree_node_set_row_data(GTK_CTREE(cts->tree), ct_node,
295 GINT_TO_POINTER(cts->page));
297 gtk_tree_store_set(model, &iter, 0, label_str, 1, cts->page, -1);
300 /* If this is the first protocol page, remember its page number */
301 if (first_proto_prefs_page == -1)
302 first_proto_prefs_page = cts->page;
305 /* Show 'em what we got */
306 gtk_widget_show_all(main_vb);
311 prefs_cb(GtkWidget *w _U_, gpointer dummy _U_)
313 GtkWidget *top_hb, *bbox, *prefs_nb, *ct_sb, *frame,
314 *ok_bt, *apply_bt, *save_bt, *cancel_bt;
315 GtkWidget *print_pg, *column_pg, *stream_pg, *gui_pg;
317 GtkWidget *capture_pg;
319 GtkWidget *nameres_pg;
320 gchar label_str[MAX_TREE_NODE_NAME_LEN];
321 struct ct_struct cts;
322 #if GTK_MAJOR_VERSION < 2
323 gchar *label_ptr = label_str;
324 GtkCTreeNode *ct_node;
327 GtkTreeSelection *selection;
328 GtkCellRenderer *renderer;
329 GtkTreeViewColumn *column;
334 if (prefs_w != NULL) {
335 /* There's already a "Preferences" dialog box; reactivate it. */
336 reactivate_window(prefs_w);
340 /* Save the current preferences, so we can revert to those values
341 if the user presses "Cancel". */
342 copy_prefs(&saved_prefs, &prefs);
344 prefs_w = dlg_window_new("Ethereal: Preferences");
345 SIGNAL_CONNECT(prefs_w, "delete_event", prefs_main_delete_cb, NULL);
346 SIGNAL_CONNECT(prefs_w, "destroy", prefs_main_destroy_cb, NULL);
349 * Unfortunately, we can't arrange that a GtkTable widget wrap an event box
350 * around a table row, so the spacing between the preference item's label
351 * and its control widgets is inactive and the tooltip doesn't pop up when
352 * the mouse is over it.
354 cts.tooltips = gtk_tooltips_new();
356 /* Container for each row of widgets */
357 cts.main_vb = gtk_vbox_new(FALSE, 5);
358 gtk_container_border_width(GTK_CONTAINER(cts.main_vb), 5);
359 gtk_container_add(GTK_CONTAINER(prefs_w), cts.main_vb);
360 gtk_widget_show(cts.main_vb);
362 /* Top row: Preferences tree and notebook */
363 top_hb = gtk_hbox_new(FALSE, 10);
364 gtk_container_add(GTK_CONTAINER(cts.main_vb), top_hb);
365 gtk_widget_show(top_hb);
367 /* Place a Ctree on the left for preference categories */
368 ct_sb = scrolled_window_new(NULL, NULL);
369 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ct_sb),
370 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
371 gtk_container_add(GTK_CONTAINER(top_hb), ct_sb);
372 gtk_widget_show(ct_sb);
374 #if GTK_MAJOR_VERSION < 2
375 cts.tree = ctree_new(1, 0);
378 store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_INT);
379 cts.tree = tree_view_new(GTK_TREE_MODEL(store));
380 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(cts.tree), FALSE);
381 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(cts.tree));
382 gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
383 renderer = gtk_cell_renderer_text_new();
384 col_offset = gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(cts.tree),
385 -1, "Name", renderer,
387 column = gtk_tree_view_get_column(GTK_TREE_VIEW(cts.tree),
389 gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column),
390 GTK_TREE_VIEW_COLUMN_AUTOSIZE);
393 gtk_container_add(GTK_CONTAINER(ct_sb), cts.tree);
395 #if GTK_MAJOR_VERSION < 2
396 gtk_clist_set_column_auto_resize(GTK_CLIST(cts.tree), 0, TRUE);
397 SIGNAL_CONNECT(cts.tree, "tree-select-row", prefs_tree_select_cb, NULL);
399 SIGNAL_CONNECT(selection, "changed", prefs_tree_select_cb, NULL);
401 gtk_widget_show(cts.tree);
403 /* A notebook widget sans tabs is used to flip between prefs */
404 notebook = prefs_nb = gtk_notebook_new();
405 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(prefs_nb), FALSE);
406 gtk_notebook_set_show_border(GTK_NOTEBOOK(prefs_nb), FALSE);
407 gtk_container_add(GTK_CONTAINER(top_hb), prefs_nb);
408 gtk_widget_show(prefs_nb);
411 frame = gtk_frame_new("Printing");
412 gtk_widget_show(GTK_WIDGET(frame));
413 print_pg = printer_prefs_show();
414 gtk_container_add(GTK_CONTAINER(frame), print_pg);
415 OBJECT_SET_DATA(prefs_w, E_PRINT_PAGE_KEY, print_pg);
416 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
417 strcpy(label_str, "Printing");
418 #if GTK_MAJOR_VERSION < 2
419 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.tree), NULL, NULL,
420 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
421 gtk_ctree_node_set_row_data(GTK_CTREE(cts.tree), ct_node,
422 GINT_TO_POINTER(cts.page));
424 gtk_tree_store_append(store, &iter, NULL);
425 gtk_tree_store_set(store, &iter, 0, label_str, 1, cts.page, -1);
430 frame = gtk_frame_new("Columns");
431 gtk_widget_show(GTK_WIDGET(frame));
432 column_pg = column_prefs_show();
433 gtk_container_add(GTK_CONTAINER(frame), column_pg);
434 OBJECT_SET_DATA(prefs_w, E_COLUMN_PAGE_KEY, column_pg);
435 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
436 strcpy(label_str, "Columns");
437 #if GTK_MAJOR_VERSION < 2
438 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.tree), NULL, NULL,
439 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
440 gtk_ctree_node_set_row_data(GTK_CTREE(cts.tree), ct_node,
441 GINT_TO_POINTER(cts.page));
443 gtk_tree_store_append(store, &iter, NULL);
444 gtk_tree_store_set(store, &iter, 0, label_str, 1, cts.page, -1);
448 /* TCP Streams prefs */
449 frame = gtk_frame_new("TCP Streams");
450 gtk_widget_show(GTK_WIDGET(frame));
451 stream_pg = stream_prefs_show();
452 gtk_container_add(GTK_CONTAINER(frame), stream_pg);
453 OBJECT_SET_DATA(prefs_w, E_STREAM_PAGE_KEY, stream_pg);
454 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
455 strcpy(label_str, "TCP Streams");
456 #if GTK_MAJOR_VERSION < 2
457 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.tree), NULL, NULL,
458 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
459 gtk_ctree_node_set_row_data(GTK_CTREE(cts.tree), ct_node,
460 GINT_TO_POINTER(cts.page));
462 gtk_tree_store_append(store, &iter, NULL);
463 gtk_tree_store_set(store, &iter, 0, label_str, 1, cts.page, -1);
468 frame = gtk_frame_new("User Interface");
469 gtk_widget_show(GTK_WIDGET(frame));
470 gui_pg = gui_prefs_show();
471 gtk_container_add(GTK_CONTAINER(frame), gui_pg);
472 OBJECT_SET_DATA(prefs_w, E_GUI_PAGE_KEY, gui_pg);
473 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
474 strcpy(label_str, "User Interface");
475 #if GTK_MAJOR_VERSION < 2
476 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.tree), NULL, NULL,
477 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
478 gtk_ctree_node_set_row_data(GTK_CTREE(cts.tree), ct_node,
479 GINT_TO_POINTER(cts.page));
481 gtk_tree_store_append(store, &iter, NULL);
482 gtk_tree_store_set(store, &iter, 0, label_str, 1, cts.page, -1);
488 /* Is WPcap loaded? */
492 frame = gtk_frame_new("Capture");
493 gtk_widget_show(GTK_WIDGET(frame));
494 capture_pg = capture_prefs_show();
495 gtk_container_add(GTK_CONTAINER(frame), capture_pg);
496 OBJECT_SET_DATA(prefs_w, E_CAPTURE_PAGE_KEY, capture_pg);
497 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
498 strcpy(label_str, "Capture");
499 #if GTK_MAJOR_VERSION < 2
500 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.tree), NULL, NULL,
501 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
502 gtk_ctree_node_set_row_data(GTK_CTREE(cts.tree), ct_node,
503 GINT_TO_POINTER(cts.page));
505 gtk_tree_store_append(store, &iter, NULL);
506 gtk_tree_store_set(store, &iter, 0, label_str, 1, cts.page, -1);
512 #endif /* HAVE_LIBPCAP */
514 /* Name resolution prefs */
515 frame = gtk_frame_new("Name Resolution");
516 gtk_widget_show(GTK_WIDGET(frame));
517 nameres_pg = nameres_prefs_show();
518 gtk_container_add(GTK_CONTAINER(frame), nameres_pg);
519 OBJECT_SET_DATA(prefs_w, E_NAMERES_PAGE_KEY, nameres_pg);
520 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
521 strcpy(label_str, "Name Resolution");
522 #if GTK_MAJOR_VERSION < 2
523 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.tree), NULL, NULL,
524 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
525 gtk_ctree_node_set_row_data(GTK_CTREE(cts.tree), ct_node,
526 GINT_TO_POINTER(cts.page));
528 gtk_tree_store_append(store, &iter, NULL);
529 gtk_tree_store_set(store, &iter, 0, label_str, 1, cts.page, -1);
533 /* Registered prefs */
534 cts.notebook = prefs_nb;
535 cts.is_protocol = FALSE;
536 prefs_module_list_foreach(NULL, module_prefs_show, &cts);
538 /* Button row: OK and cancel buttons */
539 bbox = gtk_hbutton_box_new();
540 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
541 gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
542 gtk_container_add(GTK_CONTAINER(cts.main_vb), bbox);
543 gtk_widget_show(bbox);
545 #if GTK_MAJOR_VERSION < 2
546 ok_bt = gtk_button_new_with_label ("OK");
548 ok_bt = gtk_button_new_from_stock(GTK_STOCK_OK);
550 SIGNAL_CONNECT(ok_bt, "clicked", prefs_main_ok_cb, prefs_w);
551 GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT);
552 gtk_box_pack_start (GTK_BOX (bbox), ok_bt, TRUE, TRUE, 0);
553 gtk_widget_grab_default(ok_bt);
554 gtk_widget_show(ok_bt);
556 #if GTK_MAJOR_VERSION < 2
557 apply_bt = gtk_button_new_with_label ("Apply");
559 apply_bt = gtk_button_new_from_stock(GTK_STOCK_APPLY);
561 SIGNAL_CONNECT(apply_bt, "clicked", prefs_main_apply_cb, prefs_w);
562 GTK_WIDGET_SET_FLAGS(apply_bt, GTK_CAN_DEFAULT);
563 gtk_box_pack_start(GTK_BOX (bbox), apply_bt, TRUE, TRUE, 0);
564 gtk_widget_show(apply_bt);
566 #if GTK_MAJOR_VERSION < 2
567 save_bt = gtk_button_new_with_label ("Save");
569 save_bt = gtk_button_new_from_stock(GTK_STOCK_SAVE);
571 SIGNAL_CONNECT(save_bt, "clicked", prefs_main_save_cb, prefs_w);
572 GTK_WIDGET_SET_FLAGS(save_bt, GTK_CAN_DEFAULT);
573 gtk_box_pack_start (GTK_BOX (bbox), save_bt, TRUE, TRUE, 0);
574 gtk_widget_show(save_bt);
576 #if GTK_MAJOR_VERSION < 2
577 cancel_bt = gtk_button_new_with_label ("Cancel");
579 cancel_bt = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
581 SIGNAL_CONNECT(cancel_bt, "clicked", prefs_main_cancel_cb, prefs_w);
582 GTK_WIDGET_SET_FLAGS(cancel_bt, GTK_CAN_DEFAULT);
583 gtk_box_pack_start (GTK_BOX (bbox), cancel_bt, TRUE, TRUE, 0);
584 gtk_widget_show(cancel_bt);
586 /* Catch the "key_press_event" signal in the window, so that we can catch
587 the ESC key being pressed and act as if the "Cancel" button had
589 dlg_set_cancel(prefs_w, cancel_bt);
591 gtk_widget_show(prefs_w);
593 #if GTK_MAJOR_VERSION >= 2
594 g_object_unref(G_OBJECT(store));
599 set_option_label(GtkWidget *main_tb, int table_position,
600 const gchar *label_text, const gchar *tooltip_text, GtkTooltips *tooltips)
603 GtkWidget *event_box;
605 label = gtk_label_new(label_text);
606 gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
607 gtk_widget_show(label);
609 event_box = gtk_event_box_new();
610 gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box, 0, 1,
611 table_position, table_position + 1);
612 if (tooltip_text != NULL && tooltips != NULL)
613 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
614 gtk_container_add(GTK_CONTAINER(event_box), label);
615 gtk_widget_show(event_box);
619 create_preference_check_button(GtkWidget *main_tb, int table_position,
620 const gchar *label_text, const gchar *tooltip_text, gboolean active)
622 GtkTooltips *tooltips;
623 GtkWidget *check_box;
625 tooltips = OBJECT_GET_DATA(main_tb, E_TOOLTIPS_KEY);
627 set_option_label(main_tb, table_position, label_text, tooltip_text,
630 check_box = gtk_check_button_new();
631 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_box), active);
632 gtk_table_attach_defaults(GTK_TABLE(main_tb), check_box, 1, 2,
633 table_position, table_position + 1);
634 if (tooltip_text != NULL && tooltips != NULL)
635 gtk_tooltips_set_tip(tooltips, check_box, tooltip_text, NULL);
641 create_preference_radio_buttons(GtkWidget *main_tb, int table_position,
642 const gchar *label_text, const gchar *tooltip_text,
643 const enum_val_t *enumvals, gint current_val)
645 GtkTooltips *tooltips;
646 GtkWidget *radio_button_hbox, *button = NULL;
649 const enum_val_t *enum_valp;
650 GtkWidget *event_box;
652 tooltips = OBJECT_GET_DATA(main_tb, E_TOOLTIPS_KEY);
654 set_option_label(main_tb, table_position, label_text, tooltip_text,
657 radio_button_hbox = gtk_hbox_new(FALSE, 0);
659 for (enum_valp = enumvals, index = 0; enum_valp->name != NULL;
660 enum_valp++, index++) {
661 button = gtk_radio_button_new_with_label(rb_group,
663 gtk_widget_show(button);
664 if (rb_group == NULL)
665 rb_group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
666 gtk_box_pack_start(GTK_BOX(radio_button_hbox), button, FALSE,
668 if (enum_valp->value == current_val) {
669 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button),
673 gtk_widget_show(radio_button_hbox);
675 event_box = gtk_event_box_new();
676 gtk_container_add(GTK_CONTAINER(event_box), radio_button_hbox);
677 gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box, 1, 2,
678 table_position, table_position+1);
679 if (tooltip_text != NULL && tooltips != NULL)
680 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
681 gtk_widget_show(event_box);
684 * It doesn't matter which of the buttons we return - we fetch
685 * the value by looking at the entire radio button group to
686 * which it belongs, and we can get that from any button.
692 label_to_enum_val(GtkWidget *label, const enum_val_t *enumvals)
697 /* Get the label's text, and translate it to a value. */
698 gtk_label_get(GTK_LABEL(label), &label_string);
699 enumval = find_val_for_string(label_string, enumvals, 1);
705 fetch_preference_radio_buttons_val(GtkWidget *button,
706 const enum_val_t *enumvals)
712 * Go through the list of of radio buttons in the button's group,
713 * and find the first one that's active.
715 rb_group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
717 for (rb_entry = rb_group; rb_entry != NULL;
718 rb_entry = g_slist_next(rb_entry)) {
719 button = rb_entry->data;
720 if (GTK_TOGGLE_BUTTON(button)->active)
724 /* OK, now return the value corresponding to that button's label. */
725 return label_to_enum_val(GTK_BIN(button)->child, enumvals);
729 create_preference_option_menu(GtkWidget *main_tb, int table_position,
730 const gchar *label_text, const gchar *tooltip_text,
731 const enum_val_t *enumvals, gint current_val)
733 GtkTooltips *tooltips;
734 GtkWidget *menu_box, *menu, *menu_item, *option_menu;
735 int menu_index, index;
736 const enum_val_t *enum_valp;
737 GtkWidget *event_box;
739 tooltips = OBJECT_GET_DATA(main_tb, E_TOOLTIPS_KEY);
741 set_option_label(main_tb, table_position, label_text, tooltip_text,
744 /* Create a menu from the enumvals */
745 menu = gtk_menu_new();
746 if (tooltip_text != NULL && tooltips != NULL)
747 gtk_tooltips_set_tip(tooltips, menu, tooltip_text, NULL);
749 for (enum_valp = enumvals, index = 0; enum_valp->name != NULL;
750 enum_valp++, index++) {
751 menu_item = gtk_menu_item_new_with_label(enum_valp->name);
752 gtk_menu_append(GTK_MENU(menu), menu_item);
753 if (enum_valp->value == current_val)
755 gtk_widget_show(menu_item);
758 /* Create the option menu from the menu */
759 option_menu = gtk_option_menu_new();
760 gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), menu);
762 /* Set its current value to the variable's current value */
763 if (menu_index != -1)
764 gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu),
768 * Put the option menu in an hbox, so that it's only as wide
769 * as the widest entry, rather than being as wide as the table
772 menu_box = gtk_hbox_new(FALSE, 0);
773 gtk_box_pack_start(GTK_BOX(menu_box), option_menu, FALSE, FALSE, 0);
775 event_box = gtk_event_box_new();
776 gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box,
777 1, 2, table_position, table_position + 1);
778 if (tooltip_text != NULL && tooltips != NULL)
779 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
780 gtk_container_add(GTK_CONTAINER(event_box), menu_box);
786 fetch_preference_option_menu_val(GtkWidget *optmenu, const enum_val_t *enumvals)
789 * OK, now return the value corresponding to the label for the
790 * currently active entry in the option menu.
792 * Yes, this is how you get the label for that entry. See FAQ
793 * 6.8 in the GTK+ FAQ.
795 return label_to_enum_val(GTK_BIN(optmenu)->child, enumvals);
799 create_preference_entry(GtkWidget *main_tb, int table_position,
800 const gchar *label_text, const gchar *tooltip_text, char *value)
802 GtkTooltips *tooltips;
805 tooltips = OBJECT_GET_DATA(main_tb, E_TOOLTIPS_KEY);
807 set_option_label(main_tb, table_position, label_text, tooltip_text,
810 entry = gtk_entry_new();
812 gtk_entry_set_text(GTK_ENTRY(entry), value);
813 gtk_table_attach_defaults(GTK_TABLE(main_tb), entry, 1, 2,
814 table_position, table_position + 1);
815 if (tooltip_text != NULL && tooltips != NULL)
816 gtk_tooltips_set_tip(tooltips, entry, tooltip_text, NULL);
817 gtk_widget_show(entry);
823 pref_fetch(pref_t *pref, gpointer user_data)
830 gboolean *pref_changed_p = user_data;
832 /* Fetch the value of the preference, and set the appropriate variable
834 switch (pref->type) {
837 str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
838 uval = strtoul(str_val, &p, pref->info.base);
840 if (p == value || *p != '\0')
841 return PREFS_SET_SYNTAX_ERR; /* number was bad */
843 if (*pref->varp.uint != uval) {
844 *pref_changed_p = TRUE;
845 *pref->varp.uint = uval;
850 bval = GTK_TOGGLE_BUTTON(pref->control)->active;
851 if (*pref->varp.boolp != bval) {
852 *pref_changed_p = TRUE;
853 *pref->varp.boolp = bval;
858 if (pref->info.enum_info.radio_buttons) {
859 enumval = fetch_preference_radio_buttons_val(pref->control,
860 pref->info.enum_info.enumvals);
862 enumval = fetch_preference_option_menu_val(pref->control,
863 pref->info.enum_info.enumvals);
866 if (*pref->varp.enump != enumval) {
867 *pref_changed_p = TRUE;
868 *pref->varp.enump = enumval;
873 str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
874 if (strcmp(*pref->varp.string, str_val) != 0) {
875 *pref_changed_p = TRUE;
876 g_free(*pref->varp.string);
877 *pref->varp.string = g_strdup(str_val);
882 g_assert_not_reached();
888 module_prefs_fetch(module_t *module, gpointer user_data)
890 gboolean *must_redissect_p = user_data;
892 /* For all preferences in this module, fetch its value from this
893 module's notebook page. Find out whether any of them changed. */
894 module->prefs_changed = FALSE; /* assume none of them changed */
895 prefs_pref_foreach(module, pref_fetch, &module->prefs_changed);
897 /* If any of them changed, indicate that we must redissect and refilter
898 the current capture (if we have one), as the preference change
899 could cause packets to be dissected differently. */
900 if (module->prefs_changed)
901 *must_redissect_p = TRUE;
905 pref_clean(pref_t *pref, gpointer user_data _U_)
907 switch (pref->type) {
919 if (pref->saved_val.string != NULL) {
920 g_free(pref->saved_val.string);
921 pref->saved_val.string = NULL;
926 g_assert_not_reached();
932 module_prefs_clean(module_t *module, gpointer user_data _U_)
934 /* For all preferences in this module, clean up any cruft allocated for
935 use by the GUI code. */
936 prefs_pref_foreach(module, pref_clean, NULL);
940 prefs_main_ok_cb(GtkWidget *ok_bt _U_, gpointer parent_w)
942 gboolean must_redissect = FALSE;
944 /* Fetch the preferences (i.e., make sure all the values set in all of
945 the preferences panes have been copied to "prefs" and the registered
947 printer_prefs_fetch(OBJECT_GET_DATA(parent_w, E_PRINT_PAGE_KEY));
948 column_prefs_fetch(OBJECT_GET_DATA(parent_w, E_COLUMN_PAGE_KEY));
949 stream_prefs_fetch(OBJECT_GET_DATA(parent_w, E_STREAM_PAGE_KEY));
950 gui_prefs_fetch(OBJECT_GET_DATA(parent_w, E_GUI_PAGE_KEY));
953 /* Is WPcap loaded? */
956 capture_prefs_fetch(OBJECT_GET_DATA(parent_w, E_CAPTURE_PAGE_KEY));
960 #endif /* HAVE_LIBPCAP */
961 nameres_prefs_fetch(OBJECT_GET_DATA(parent_w, E_NAMERES_PAGE_KEY));
962 prefs_modules_foreach(module_prefs_fetch, &must_redissect);
964 /* Now apply those preferences. */
965 printer_prefs_apply(OBJECT_GET_DATA(parent_w, E_PRINT_PAGE_KEY));
966 column_prefs_apply(OBJECT_GET_DATA(parent_w, E_COLUMN_PAGE_KEY));
967 stream_prefs_apply(OBJECT_GET_DATA(parent_w, E_STREAM_PAGE_KEY));
968 gui_prefs_apply(OBJECT_GET_DATA(parent_w, E_GUI_PAGE_KEY));
971 /* Is WPcap loaded? */
974 capture_prefs_apply(OBJECT_GET_DATA(parent_w, E_CAPTURE_PAGE_KEY));
978 #endif /* HAVE_LIBPCAP */
979 nameres_prefs_apply(OBJECT_GET_DATA(parent_w, E_NAMERES_PAGE_KEY));
982 /* Now destroy the "Preferences" dialog. */
983 gtk_widget_destroy(GTK_WIDGET(parent_w));
985 if (must_redissect) {
986 /* Redissect all the packets, and re-evaluate the display filter. */
987 redissect_packets(&cfile);
992 prefs_main_apply_cb(GtkWidget *apply_bt _U_, gpointer parent_w)
994 gboolean must_redissect = FALSE;
996 /* Fetch the preferences (i.e., make sure all the values set in all of
997 the preferences panes have been copied to "prefs" and the registered
999 printer_prefs_fetch(OBJECT_GET_DATA(parent_w, E_PRINT_PAGE_KEY));
1000 column_prefs_fetch(OBJECT_GET_DATA(parent_w, E_COLUMN_PAGE_KEY));
1001 stream_prefs_fetch(OBJECT_GET_DATA(parent_w, E_STREAM_PAGE_KEY));
1002 gui_prefs_fetch(OBJECT_GET_DATA(parent_w, E_GUI_PAGE_KEY));
1005 /* Is WPcap loaded? */
1008 capture_prefs_fetch(OBJECT_GET_DATA(parent_w, E_CAPTURE_PAGE_KEY));
1012 #endif /* HAVE_LIBPCAP */
1013 nameres_prefs_fetch(OBJECT_GET_DATA(parent_w, E_NAMERES_PAGE_KEY));
1014 prefs_modules_foreach(module_prefs_fetch, &must_redissect);
1016 /* Now apply those preferences. */
1017 printer_prefs_apply(OBJECT_GET_DATA(parent_w, E_PRINT_PAGE_KEY));
1018 column_prefs_apply(OBJECT_GET_DATA(parent_w, E_COLUMN_PAGE_KEY));
1019 stream_prefs_apply(OBJECT_GET_DATA(parent_w, E_STREAM_PAGE_KEY));
1020 gui_prefs_apply(OBJECT_GET_DATA(parent_w, E_GUI_PAGE_KEY));
1023 /* Is WPcap loaded? */
1026 capture_prefs_apply(OBJECT_GET_DATA(parent_w, E_CAPTURE_PAGE_KEY));
1030 #endif /* HAVE_LIBPCAP */
1031 nameres_prefs_apply(OBJECT_GET_DATA(parent_w, E_NAMERES_PAGE_KEY));
1034 if (must_redissect) {
1035 /* Redissect all the packets, and re-evaluate the display filter. */
1036 redissect_packets(&cfile);
1041 prefs_main_save_cb(GtkWidget *save_bt _U_, gpointer parent_w)
1043 gboolean must_redissect = FALSE;
1048 /* Fetch the preferences (i.e., make sure all the values set in all of
1049 the preferences panes have been copied to "prefs" and the registered
1051 printer_prefs_fetch(OBJECT_GET_DATA(parent_w, E_PRINT_PAGE_KEY));
1052 column_prefs_fetch(OBJECT_GET_DATA(parent_w, E_COLUMN_PAGE_KEY));
1053 stream_prefs_fetch(OBJECT_GET_DATA(parent_w, E_STREAM_PAGE_KEY));
1054 gui_prefs_fetch(OBJECT_GET_DATA(parent_w, E_GUI_PAGE_KEY));
1057 /* Is WPcap loaded? */
1060 capture_prefs_fetch(OBJECT_GET_DATA(parent_w, E_CAPTURE_PAGE_KEY));
1064 #endif /* HAVE_LIBPCAP */
1065 nameres_prefs_fetch(OBJECT_GET_DATA(parent_w, E_NAMERES_PAGE_KEY));
1066 prefs_modules_foreach(module_prefs_fetch, &must_redissect);
1068 /* Create the directory that holds personal configuration files, if
1070 if (create_persconffile_dir(&pf_dir_path) == -1) {
1071 simple_dialog(ESD_TYPE_WARN, NULL,
1072 "Can't create directory\n\"%s\"\nfor preferences file: %s.", pf_dir_path,
1074 g_free(pf_dir_path);
1076 /* Write the preferencs out. */
1077 err = write_prefs(&pf_path);
1079 simple_dialog(ESD_TYPE_WARN, NULL,
1080 "Can't open preferences file\n\"%s\": %s.", pf_path,
1086 /* Now apply those preferences.
1087 XXX - should we do this? The user didn't click "OK" or "Apply".
1090 1) by saving the preferences they presumably indicate that they
1093 2) the next time they fire Ethereal up, those preferences will
1096 3) we'd have to buffer "must_redissect" so that if they do
1097 "Apply" after this, we know we have to redissect;
1099 4) we did apply the protocol preferences, at least, in the past. */
1100 printer_prefs_apply(OBJECT_GET_DATA(parent_w, E_PRINT_PAGE_KEY));
1101 column_prefs_apply(OBJECT_GET_DATA(parent_w, E_COLUMN_PAGE_KEY));
1102 stream_prefs_apply(OBJECT_GET_DATA(parent_w, E_STREAM_PAGE_KEY));
1103 gui_prefs_apply(OBJECT_GET_DATA(parent_w, E_GUI_PAGE_KEY));
1106 /* Is WPcap loaded? */
1109 capture_prefs_apply(OBJECT_GET_DATA(parent_w, E_CAPTURE_PAGE_KEY));
1113 #endif /* HAVE_LIBPCAP */
1114 nameres_prefs_apply(OBJECT_GET_DATA(parent_w, E_NAMERES_PAGE_KEY));
1117 if (must_redissect) {
1118 /* Redissect all the packets, and re-evaluate the display filter. */
1119 redissect_packets(&cfile);
1124 pref_revert(pref_t *pref, gpointer user_data)
1126 gboolean *pref_changed_p = user_data;
1128 /* Revert the preference to its saved value. */
1129 switch (pref->type) {
1132 if (*pref->varp.uint != pref->saved_val.uint) {
1133 *pref_changed_p = TRUE;
1134 *pref->varp.uint = pref->saved_val.uint;
1139 if (*pref->varp.boolp != pref->saved_val.boolval) {
1140 *pref_changed_p = TRUE;
1141 *pref->varp.boolp = pref->saved_val.boolval;
1146 if (*pref->varp.enump != pref->saved_val.enumval) {
1147 *pref_changed_p = TRUE;
1148 *pref->varp.enump = pref->saved_val.enumval;
1153 if (strcmp(*pref->varp.string, pref->saved_val.string) != 0) {
1154 *pref_changed_p = TRUE;
1155 g_free(*pref->varp.string);
1156 *pref->varp.string = g_strdup(pref->saved_val.string);
1161 g_assert_not_reached();
1167 module_prefs_revert(module_t *module, gpointer user_data)
1169 gboolean *must_redissect_p = user_data;
1171 /* For all preferences in this module, revert its value to the value
1172 it had when we popped up the Preferences dialog. Find out whether
1173 this changes any of them. */
1174 module->prefs_changed = FALSE; /* assume none of them changed */
1175 prefs_pref_foreach(module, pref_revert, &module->prefs_changed);
1177 /* If any of them changed, indicate that we must redissect and refilter
1178 the current capture (if we have one), as the preference change
1179 could cause packets to be dissected differently. */
1180 if (module->prefs_changed)
1181 *must_redissect_p = TRUE;
1185 prefs_main_cancel_cb(GtkWidget *cancel_bt _U_, gpointer parent_w)
1187 gboolean must_redissect = FALSE;
1189 /* Free up the current preferences and copy the saved preferences to the
1190 current preferences. */
1192 copy_prefs(&prefs, &saved_prefs);
1194 /* Now revert the registered preferences. */
1195 prefs_modules_foreach(module_prefs_revert, &must_redissect);
1197 /* Now apply the reverted-to preferences. */
1198 printer_prefs_apply(OBJECT_GET_DATA(parent_w, E_PRINT_PAGE_KEY));
1199 column_prefs_apply(OBJECT_GET_DATA(parent_w, E_COLUMN_PAGE_KEY));
1200 stream_prefs_apply(OBJECT_GET_DATA(parent_w, E_STREAM_PAGE_KEY));
1201 gui_prefs_apply(OBJECT_GET_DATA(parent_w, E_GUI_PAGE_KEY));
1202 nameres_prefs_apply(OBJECT_GET_DATA(parent_w, E_NAMERES_PAGE_KEY));
1205 gtk_widget_destroy(GTK_WIDGET(parent_w));
1207 if (must_redissect) {
1208 /* Redissect all the packets, and re-evaluate the display filter. */
1209 redissect_packets(&cfile);
1213 /* Treat this as a cancel, by calling "prefs_main_cancel_cb()".
1214 XXX - that'll destroy the Preferences dialog; will that upset
1215 a higher-level handler that says "OK, we've been asked to delete
1216 this, so destroy it"? */
1218 prefs_main_delete_cb(GtkWidget *prefs_w, gpointer dummy _U_)
1220 prefs_main_cancel_cb(NULL, prefs_w);
1225 prefs_main_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1227 /* Let the preference tabs clean up anything they've done. */
1228 printer_prefs_destroy(OBJECT_GET_DATA(prefs_w, E_PRINT_PAGE_KEY));
1229 column_prefs_destroy(OBJECT_GET_DATA(prefs_w, E_COLUMN_PAGE_KEY));
1230 stream_prefs_destroy(OBJECT_GET_DATA(prefs_w, E_STREAM_PAGE_KEY));
1231 gui_prefs_destroy(OBJECT_GET_DATA(prefs_w, E_GUI_PAGE_KEY));
1234 /* Is WPcap loaded? */
1237 capture_prefs_destroy(OBJECT_GET_DATA(prefs_w, E_CAPTURE_PAGE_KEY));
1241 #endif /* HAVE_LIBPCAP */
1242 nameres_prefs_destroy(OBJECT_GET_DATA(prefs_w, E_NAMERES_PAGE_KEY));
1244 /* Free up the saved preferences (both for "prefs" and for registered
1246 free_prefs(&saved_prefs);
1247 prefs_modules_foreach(module_prefs_clean, NULL);
1249 /* Note that we no longer have a "Preferences" dialog box. */
1251 first_proto_prefs_page = -1;
1254 struct properties_data {
1260 /* XXX this way of searching the correct page number is really ugly ... */
1262 module_search_properties(module_t *module, gpointer user_data)
1264 struct properties_data *p = (struct properties_data *)user_data;
1266 if (p->title == NULL) return;
1267 if (strcmp(module->title, p->title) == 0) {
1269 gtk_notebook_set_page(GTK_NOTEBOOK(p->w), p->page_num);
1277 properties_cb(GtkWidget *w, gpointer dummy)
1279 const gchar *title = NULL;
1280 struct properties_data p;
1282 if (cfile.finfo_selected) {
1283 header_field_info *hfinfo = cfile.finfo_selected->hfinfo;
1284 if (hfinfo->parent == -1) {
1285 title = prefs_get_title_by_name(hfinfo->abbrev);
1288 prefs_get_title_by_name(proto_registrar_get_abbrev(hfinfo->parent));
1296 if (prefs_w != NULL) {
1297 reactivate_window(prefs_w);
1303 p.page_num = first_proto_prefs_page;
1306 prefs_module_list_foreach(protocols_module->prefs, module_search_properties,
1310 /* Prefs tree selection callback. The node data has been loaded with
1311 the proper notebook page to load. */
1312 #if GTK_MAJOR_VERSION < 2
1314 prefs_tree_select_cb(GtkCTree *ct, GtkCTreeNode *node, gint col _U_,
1318 prefs_tree_select_cb(GtkTreeSelection *sel, gpointer dummy _U_)
1322 #if GTK_MAJOR_VERSION >= 2
1323 GtkTreeModel *model;
1327 #if GTK_MAJOR_VERSION < 2
1328 page = GPOINTER_TO_INT(gtk_ctree_node_get_row_data(ct, node));
1331 gtk_notebook_set_page(GTK_NOTEBOOK(notebook), page);
1333 if (gtk_tree_selection_get_selected(sel, &model, &iter))
1335 gtk_tree_model_get(model, &iter, 1, &page, -1);
1337 gtk_notebook_set_page(GTK_NOTEBOOK(notebook), page);