2 * Routines for handling preferences
4 * $Id: prefs_dlg.c,v 1.44 2002/03/05 12:03:27 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.
29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
44 #ifdef HAVE_SYS_STAT_H
48 #include <epan/filesystem.h>
51 #include <epan/packet.h>
54 #include "column_prefs.h"
56 #include "prefs_dlg.h"
57 #include "print_prefs.h"
58 #include "stream_prefs.h"
59 #include "gui_prefs.h"
60 #include "capture_prefs.h"
61 #include "nameres_prefs.h"
63 #include "dlg_utils.h"
64 #include "simple_dialog.h"
66 #include "prefs-int.h"
68 static void prefs_main_ok_cb(GtkWidget *, gpointer);
69 static void prefs_main_apply_cb(GtkWidget *, gpointer);
70 static void prefs_main_save_cb(GtkWidget *, gpointer);
71 static void prefs_main_cancel_cb(GtkWidget *, gpointer);
72 static gboolean prefs_main_delete_cb(GtkWidget *, gpointer);
73 static void prefs_main_destroy_cb(GtkWidget *, gpointer);
74 static void prefs_tree_select_cb(GtkCTree *, GtkCTreeNode *, gint, gpointer);
76 #define E_PRINT_PAGE_KEY "printer_options_page"
77 #define E_COLUMN_PAGE_KEY "column_options_page"
78 #define E_STREAM_PAGE_KEY "tcp_stream_options_page"
79 #define E_GUI_PAGE_KEY "gui_options_page"
80 #define E_CAPTURE_PAGE_KEY "capture_options_page"
81 #define E_NAMERES_PAGE_KEY "nameres_options_page"
82 #define E_TOOLTIPS_KEY "tooltips"
84 #define FIRST_PROTO_PREFS_PAGE 6
87 * Keep a static pointer to the notebook to be able to choose the
90 static GtkWidget *notebook;
93 * Keep a static pointer to the current "Preferences" window, if any, so that
94 * if somebody tries to do "Edit:Preferences" while there's already a
95 * "Preferences" window up, we just pop up the existing one, rather than
98 static GtkWidget *prefs_w;
101 * Save the value of the preferences as of when the preferences dialog
102 * box was first popped up, so we can revert to those values if the
103 * user selects "Cancel".
105 static e_prefs saved_prefs;
111 GtkTooltips *tooltips;
116 pref_show(pref_t *pref, gpointer user_data)
118 GtkWidget *main_tb = user_data;
123 /* Give this preference a label which is its title, followed by a colon,
124 and left-align it. */
126 label_string = g_malloc(strlen(title) + 2);
127 strcpy(label_string, title);
128 strcat(label_string, ":");
130 /* Save the current value of the preference, so that we can revert it if
131 the user does "Apply" and then "Cancel", and create the control for
132 editing the preference. */
133 switch (pref->type) {
136 pref->saved_val.uint = *pref->varp.uint;
138 /* XXX - there are no uint spinbuttons, so we can't use a spinbutton.
139 Even more annoyingly, even if there were, GLib doesn't define
140 G_MAXUINT - but I think ANSI C may define UINT_MAX, so we could
142 switch (pref->info.base) {
145 sprintf(uint_str, "%u", pref->saved_val.uint);
149 sprintf(uint_str, "%o", pref->saved_val.uint);
153 sprintf(uint_str, "%x", pref->saved_val.uint);
156 pref->control = create_preference_entry(main_tb, pref->ordinal,
157 label_string, pref->description,
162 pref->saved_val.bool = *pref->varp.bool;
163 pref->control = create_preference_check_button(main_tb, pref->ordinal,
164 label_string, pref->description,
165 pref->saved_val.bool);
169 pref->saved_val.enumval = *pref->varp.enump;
170 if (pref->info.enum_info.radio_buttons) {
171 /* Show it as radio buttons. */
172 pref->control = create_preference_radio_buttons(main_tb, pref->ordinal,
173 label_string, pref->description,
174 pref->info.enum_info.enumvals,
175 pref->saved_val.enumval);
177 /* Show it as an option menu. */
178 pref->control = create_preference_option_menu(main_tb, pref->ordinal,
179 label_string, pref->description,
180 pref->info.enum_info.enumvals,
181 pref->saved_val.enumval);
186 if (pref->saved_val.string != NULL)
187 g_free(pref->saved_val.string);
188 pref->saved_val.string = g_strdup(*pref->varp.string);
189 pref->control = create_preference_entry(main_tb, pref->ordinal,
190 label_string, pref->description,
191 pref->saved_val.string);
195 g_assert_not_reached();
198 g_free(label_string);
201 #define MAX_TREE_NODE_NAME_LEN 64
203 module_prefs_show(module_t *module, gpointer user_data)
205 struct ct_struct *cts = user_data;
206 GtkWidget *main_vb, *main_tb, *frame;
207 gchar label_str[MAX_TREE_NODE_NAME_LEN], *label_ptr = label_str;
208 GtkCTreeNode *ct_node;
211 frame = gtk_frame_new(module->title);
212 gtk_widget_show(frame);
214 /* Main vertical box */
215 main_vb = gtk_vbox_new(FALSE, 5);
216 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
217 gtk_container_add(GTK_CONTAINER(frame), main_vb);
220 main_tb = gtk_table_new(module->numprefs, 2, FALSE);
221 gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0);
222 gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10);
223 gtk_table_set_col_spacings(GTK_TABLE(main_tb), 15);
224 gtk_object_set_data(GTK_OBJECT(main_tb), E_TOOLTIPS_KEY, cts->tooltips);
226 /* Add items for each of the preferences */
227 prefs_pref_foreach(module, pref_show, main_tb);
229 gtk_notebook_append_page(GTK_NOTEBOOK(cts->notebook), frame, NULL);
230 strcpy(label_str, module->title);
231 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts->ctree), cts->node, NULL,
232 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
233 gtk_ctree_node_set_row_data(GTK_CTREE(cts->ctree), ct_node,
234 GINT_TO_POINTER(cts->page));
237 /* Show 'em what we got */
238 gtk_widget_show_all(main_vb);
242 prefs_cb(GtkWidget *w _U_, gpointer dummy _U_)
244 GtkWidget *main_vb, *top_hb, *bbox, *prefs_nb, *ct_sb, *frame,
245 *ok_bt, *apply_bt, *save_bt, *cancel_bt;
246 GtkWidget *print_pg, *column_pg, *stream_pg, *gui_pg, *capture_pg;
247 GtkWidget *nameres_pg;
248 gchar label_str[MAX_TREE_NODE_NAME_LEN], *label_ptr = label_str;
249 GtkCTreeNode *ct_node;
250 struct ct_struct cts;
252 if (prefs_w != NULL) {
253 /* There's already a "Preferences" dialog box; reactivate it. */
254 reactivate_window(prefs_w);
258 /* Save the current preferences, so we can revert to those values
259 if the user presses "Cancel". */
260 copy_prefs(&saved_prefs, &prefs);
262 prefs_w = dlg_window_new("Ethereal: Preferences");
263 gtk_signal_connect(GTK_OBJECT(prefs_w), "delete_event",
264 GTK_SIGNAL_FUNC(prefs_main_delete_cb), NULL);
265 gtk_signal_connect(GTK_OBJECT(prefs_w), "destroy",
266 GTK_SIGNAL_FUNC(prefs_main_destroy_cb), NULL);
269 * Unfortunately, we can't arrange that a GtkTable widget wrap an event box
270 * around a table row, so the spacing between the preference item's label
271 * and its control widgets is inactive and the tooltip doesn't pop up when
272 * the mouse is over it.
274 cts.tooltips = gtk_tooltips_new();
276 /* Container for each row of widgets */
277 main_vb = gtk_vbox_new(FALSE, 5);
278 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
279 gtk_container_add(GTK_CONTAINER(prefs_w), main_vb);
280 gtk_widget_show(main_vb);
282 /* Top row: Preferences tree and notebook */
283 top_hb = gtk_hbox_new(FALSE, 10);
284 gtk_container_add(GTK_CONTAINER(main_vb), top_hb);
285 gtk_widget_show(top_hb);
287 /* Place a Ctree on the left for preference categories */
288 ct_sb = scrolled_window_new(NULL, NULL);
289 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ct_sb),
290 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
291 gtk_container_add(GTK_CONTAINER(top_hb), ct_sb);
292 gtk_widget_show(ct_sb);
294 cts.ctree = ctree_new(1, 0);
296 gtk_container_add(GTK_CONTAINER(ct_sb), cts.ctree);
298 gtk_clist_set_column_auto_resize(GTK_CLIST(cts.ctree), 0, TRUE);
299 gtk_signal_connect(GTK_OBJECT(cts.ctree), "tree-select-row",
300 GTK_SIGNAL_FUNC(prefs_tree_select_cb), NULL);
301 gtk_widget_show(cts.ctree);
303 /* A notebook widget sans tabs is used to flip between prefs */
304 notebook = prefs_nb = gtk_notebook_new();
305 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE);
306 gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook), FALSE);
307 gtk_container_add(GTK_CONTAINER(top_hb), prefs_nb);
308 gtk_widget_show(prefs_nb);
311 frame = gtk_frame_new("Printing");
312 gtk_widget_show(GTK_WIDGET(frame));
313 print_pg = printer_prefs_show();
314 gtk_container_add(GTK_CONTAINER(frame), print_pg);
315 gtk_object_set_data(GTK_OBJECT(prefs_w), E_PRINT_PAGE_KEY, print_pg);
316 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
317 strcpy(label_str, "Printing");
318 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.ctree), NULL, NULL,
319 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
320 gtk_ctree_node_set_row_data(GTK_CTREE(cts.ctree), ct_node,
321 GINT_TO_POINTER(cts.page));
325 frame = gtk_frame_new("Columns");
326 gtk_widget_show(GTK_WIDGET(frame));
327 column_pg = column_prefs_show();
328 gtk_container_add(GTK_CONTAINER(frame), column_pg);
329 gtk_object_set_data(GTK_OBJECT(prefs_w), E_COLUMN_PAGE_KEY, column_pg);
330 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
331 strcpy(label_str, "Columns");
332 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.ctree), NULL, NULL,
333 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
334 gtk_ctree_node_set_row_data(GTK_CTREE(cts.ctree), ct_node,
335 GINT_TO_POINTER(cts.page));
338 /* TCP Streams prefs */
339 frame = gtk_frame_new("TCP Streams");
340 gtk_widget_show(GTK_WIDGET(frame));
341 stream_pg = stream_prefs_show();
342 gtk_container_add(GTK_CONTAINER(frame), stream_pg);
343 gtk_object_set_data(GTK_OBJECT(prefs_w), E_STREAM_PAGE_KEY, stream_pg);
344 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
345 strcpy(label_str, "TCP Streams");
346 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.ctree), NULL, NULL,
347 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
348 gtk_ctree_node_set_row_data(GTK_CTREE(cts.ctree), ct_node,
349 GINT_TO_POINTER(cts.page));
353 frame = gtk_frame_new("User Interface");
354 gtk_widget_show(GTK_WIDGET(frame));
355 gui_pg = gui_prefs_show();
356 gtk_container_add(GTK_CONTAINER(frame), gui_pg);
357 gtk_object_set_data(GTK_OBJECT(prefs_w), E_GUI_PAGE_KEY, gui_pg);
358 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
359 strcpy(label_str, "User Interface");
360 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.ctree), NULL, NULL,
361 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
362 gtk_ctree_node_set_row_data(GTK_CTREE(cts.ctree), ct_node,
363 GINT_TO_POINTER(cts.page));
368 frame = gtk_frame_new("Capture");
369 gtk_widget_show(GTK_WIDGET(frame));
370 capture_pg = capture_prefs_show();
371 gtk_container_add(GTK_CONTAINER(frame), capture_pg);
372 gtk_object_set_data(GTK_OBJECT(prefs_w), E_CAPTURE_PAGE_KEY, capture_pg);
373 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
374 strcpy(label_str, "Capture");
375 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.ctree), NULL, NULL,
376 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
377 gtk_ctree_node_set_row_data(GTK_CTREE(cts.ctree), ct_node,
378 GINT_TO_POINTER(cts.page));
382 /* Name resolution prefs */
383 frame = gtk_frame_new("Name resolution");
384 gtk_widget_show(GTK_WIDGET(frame));
385 nameres_pg = nameres_prefs_show();
386 gtk_container_add(GTK_CONTAINER(frame), nameres_pg);
387 gtk_object_set_data(GTK_OBJECT(prefs_w), E_NAMERES_PAGE_KEY, nameres_pg);
388 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
389 strcpy(label_str, "Name resolution");
390 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.ctree), NULL, NULL,
391 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
392 gtk_ctree_node_set_row_data(GTK_CTREE(cts.ctree), ct_node,
393 GINT_TO_POINTER(cts.page));
396 /* Registered prefs */
397 cts.notebook = prefs_nb;
398 strcpy(label_str, "Protocols");
399 cts.node = gtk_ctree_insert_node(GTK_CTREE(cts.ctree), NULL, NULL,
400 &label_ptr, 5, NULL, NULL, NULL, NULL, FALSE, FALSE);
401 gtk_ctree_node_set_row_data(GTK_CTREE(cts.ctree), cts.node,
402 GINT_TO_POINTER(-1));
403 gtk_ctree_node_set_selectable(GTK_CTREE(cts.ctree), cts.node, FALSE);
405 prefs_module_foreach(module_prefs_show, &cts);
408 /* Button row: OK and cancel buttons */
409 bbox = gtk_hbutton_box_new();
410 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
411 gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
412 gtk_container_add(GTK_CONTAINER(main_vb), bbox);
413 gtk_widget_show(bbox);
415 ok_bt = gtk_button_new_with_label ("OK");
416 gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
417 GTK_SIGNAL_FUNC(prefs_main_ok_cb), GTK_OBJECT(prefs_w));
418 GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT);
419 gtk_box_pack_start (GTK_BOX (bbox), ok_bt, TRUE, TRUE, 0);
420 gtk_widget_grab_default(ok_bt);
421 gtk_widget_show(ok_bt);
423 apply_bt = gtk_button_new_with_label ("Apply");
424 gtk_signal_connect(GTK_OBJECT(apply_bt), "clicked",
425 GTK_SIGNAL_FUNC(prefs_main_apply_cb), GTK_OBJECT(prefs_w));
426 GTK_WIDGET_SET_FLAGS(apply_bt, GTK_CAN_DEFAULT);
427 gtk_box_pack_start(GTK_BOX (bbox), apply_bt, TRUE, TRUE, 0);
428 gtk_widget_show(apply_bt);
430 save_bt = gtk_button_new_with_label ("Save");
431 gtk_signal_connect(GTK_OBJECT(save_bt), "clicked",
432 GTK_SIGNAL_FUNC(prefs_main_save_cb), GTK_OBJECT(prefs_w));
433 GTK_WIDGET_SET_FLAGS(save_bt, GTK_CAN_DEFAULT);
434 gtk_box_pack_start (GTK_BOX (bbox), save_bt, TRUE, TRUE, 0);
435 gtk_widget_show(save_bt);
437 cancel_bt = gtk_button_new_with_label ("Cancel");
438 gtk_signal_connect(GTK_OBJECT(cancel_bt), "clicked",
439 GTK_SIGNAL_FUNC(prefs_main_cancel_cb), GTK_OBJECT(prefs_w));
440 GTK_WIDGET_SET_FLAGS(cancel_bt, GTK_CAN_DEFAULT);
441 gtk_box_pack_start (GTK_BOX (bbox), cancel_bt, TRUE, TRUE, 0);
442 gtk_widget_show(cancel_bt);
444 /* Catch the "key_press_event" signal in the window, so that we can catch
445 the ESC key being pressed and act as if the "Cancel" button had
447 dlg_set_cancel(prefs_w, cancel_bt);
449 gtk_widget_show(prefs_w);
453 set_option_label(GtkWidget *main_tb, int table_position,
454 const gchar *label_text, const gchar *tooltip_text, GtkTooltips *tooltips)
457 GtkWidget *event_box;
459 label = gtk_label_new(label_text);
460 gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
461 gtk_widget_show(label);
463 event_box = gtk_event_box_new();
464 gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box, 0, 1,
465 table_position, table_position + 1);
466 if (tooltip_text != NULL && tooltips != NULL)
467 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
468 gtk_container_add(GTK_CONTAINER(event_box), label);
469 gtk_widget_show(event_box);
473 create_preference_check_button(GtkWidget *main_tb, int table_position,
474 const gchar *label_text, const gchar *tooltip_text, gboolean active)
476 GtkTooltips *tooltips;
477 GtkWidget *check_box;
479 tooltips = gtk_object_get_data(GTK_OBJECT(main_tb), E_TOOLTIPS_KEY);
481 set_option_label(main_tb, table_position, label_text, tooltip_text,
484 check_box = gtk_check_button_new();
485 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_box), active);
486 gtk_table_attach_defaults(GTK_TABLE(main_tb), check_box, 1, 2,
487 table_position, table_position + 1);
488 if (tooltip_text != NULL && tooltips != NULL)
489 gtk_tooltips_set_tip(tooltips, check_box, tooltip_text, NULL);
495 create_preference_radio_buttons(GtkWidget *main_tb, int table_position,
496 const gchar *label_text, const gchar *tooltip_text,
497 const enum_val_t *enumvals, gint current_val)
499 GtkTooltips *tooltips;
500 GtkWidget *radio_button_hbox, *button = NULL;
503 const enum_val_t *enum_valp;
504 GtkWidget *event_box;
506 tooltips = gtk_object_get_data(GTK_OBJECT(main_tb), E_TOOLTIPS_KEY);
508 set_option_label(main_tb, table_position, label_text, tooltip_text,
511 radio_button_hbox = gtk_hbox_new(FALSE, 0);
513 for (enum_valp = enumvals, index = 0; enum_valp->name != NULL;
514 enum_valp++, index++) {
515 button = gtk_radio_button_new_with_label(rb_group,
517 gtk_widget_show(button);
518 if (rb_group == NULL)
519 rb_group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
520 gtk_box_pack_start(GTK_BOX(radio_button_hbox), button, FALSE,
522 if (enum_valp->value == current_val) {
523 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button),
527 gtk_widget_show(radio_button_hbox);
529 event_box = gtk_event_box_new();
530 gtk_container_add(GTK_CONTAINER(event_box), radio_button_hbox);
531 gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box, 1, 2,
532 table_position, table_position+1);
533 if (tooltip_text != NULL && tooltips != NULL)
534 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
535 gtk_widget_show(event_box);
538 * It doesn't matter which of the buttons we return - we fetch
539 * the value by looking at the entire radio button group to
540 * which it belongs, and we can get that from any button.
546 label_to_enum_val(GtkWidget *label, const enum_val_t *enumvals)
551 /* Get the label's text, and translate it to a value. */
552 gtk_label_get(GTK_LABEL(label), &label_string);
553 enumval = find_val_for_string(label_string, enumvals, 1);
559 fetch_preference_radio_buttons_val(GtkWidget *button,
560 const enum_val_t *enumvals)
566 * Go through the list of of radio buttons in the button's group,
567 * and find the first one that's active.
569 rb_group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
571 for (rb_entry = rb_group; rb_entry != NULL;
572 rb_entry = g_slist_next(rb_entry)) {
573 button = rb_entry->data;
574 if (GTK_TOGGLE_BUTTON(button)->active)
578 /* OK, now return the value corresponding to that button's label. */
579 return label_to_enum_val(GTK_BIN(button)->child, enumvals);
583 create_preference_option_menu(GtkWidget *main_tb, int table_position,
584 const gchar *label_text, const gchar *tooltip_text,
585 const enum_val_t *enumvals, gint current_val)
587 GtkTooltips *tooltips;
588 GtkWidget *menu_box, *menu, *menu_item, *option_menu;
589 int menu_index, index;
590 const enum_val_t *enum_valp;
591 GtkWidget *event_box;
593 tooltips = gtk_object_get_data(GTK_OBJECT(main_tb), E_TOOLTIPS_KEY);
595 set_option_label(main_tb, table_position, label_text, tooltip_text,
598 /* Create a menu from the enumvals */
599 menu = gtk_menu_new();
600 if (tooltip_text != NULL && tooltips != NULL)
601 gtk_tooltips_set_tip(tooltips, menu, tooltip_text, NULL);
603 for (enum_valp = enumvals, index = 0; enum_valp->name != NULL;
604 enum_valp++, index++) {
605 menu_item = gtk_menu_item_new_with_label(enum_valp->name);
606 gtk_menu_append(GTK_MENU(menu), menu_item);
607 if (enum_valp->value == current_val)
609 gtk_widget_show(menu_item);
612 /* Create the option menu from the menu */
613 option_menu = gtk_option_menu_new();
614 gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), menu);
616 /* Set its current value to the variable's current value */
617 if (menu_index != -1)
618 gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu),
622 * Put the option menu in an hbox, so that it's only as wide
623 * as the widest entry, rather than being as wide as the table
626 menu_box = gtk_hbox_new(FALSE, 0);
627 gtk_box_pack_start(GTK_BOX(menu_box), option_menu, FALSE, FALSE, 0);
629 event_box = gtk_event_box_new();
630 gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box,
631 1, 2, table_position, table_position + 1);
632 if (tooltip_text != NULL && tooltips != NULL)
633 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
634 gtk_container_add(GTK_CONTAINER(event_box), menu_box);
640 fetch_preference_option_menu_val(GtkWidget *optmenu, const enum_val_t *enumvals)
643 * OK, now return the value corresponding to the label for the
644 * currently active entry in the option menu.
646 * Yes, this is how you get the label for that entry. See FAQ
647 * 6.8 in the GTK+ FAQ.
649 return label_to_enum_val(GTK_BIN(optmenu)->child, enumvals);
653 create_preference_entry(GtkWidget *main_tb, int table_position,
654 const gchar *label_text, const gchar *tooltip_text, char *value)
656 GtkTooltips *tooltips;
659 tooltips = gtk_object_get_data(GTK_OBJECT(main_tb), E_TOOLTIPS_KEY);
661 set_option_label(main_tb, table_position, label_text, tooltip_text,
664 entry = gtk_entry_new();
666 gtk_entry_set_text(GTK_ENTRY(entry), value);
667 gtk_table_attach_defaults(GTK_TABLE(main_tb), entry, 1, 2,
668 table_position, table_position + 1);
669 if (tooltip_text != NULL && tooltips != NULL)
670 gtk_tooltips_set_tip(tooltips, entry, tooltip_text, NULL);
671 gtk_widget_show(entry);
677 pref_fetch(pref_t *pref, gpointer user_data)
684 gboolean *pref_changed_p = user_data;
686 /* Fetch the value of the preference, and set the appropriate variable
688 switch (pref->type) {
691 str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
692 uval = strtoul(str_val, &p, pref->info.base);
694 if (p == value || *p != '\0')
695 return PREFS_SET_SYNTAX_ERR; /* number was bad */
697 if (*pref->varp.uint != uval) {
698 *pref_changed_p = TRUE;
699 *pref->varp.uint = uval;
704 bval = GTK_TOGGLE_BUTTON(pref->control)->active;
705 if (*pref->varp.bool != bval) {
706 *pref_changed_p = TRUE;
707 *pref->varp.bool = bval;
712 if (pref->info.enum_info.radio_buttons) {
713 enumval = fetch_preference_radio_buttons_val(pref->control,
714 pref->info.enum_info.enumvals);
716 enumval = fetch_preference_option_menu_val(pref->control,
717 pref->info.enum_info.enumvals);
720 if (*pref->varp.enump != enumval) {
721 *pref_changed_p = TRUE;
722 *pref->varp.enump = enumval;
727 str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
728 if (*pref->varp.string == NULL || strcmp(*pref->varp.string, str_val) != 0) {
729 *pref_changed_p = TRUE;
730 if (*pref->varp.string != NULL)
731 g_free(*pref->varp.string);
732 *pref->varp.string = g_strdup(str_val);
737 g_assert_not_reached();
743 module_prefs_fetch(module_t *module, gpointer user_data)
745 gboolean *must_redissect_p = user_data;
747 /* For all preferences in this module, fetch its value from this
748 module's notebook page. Find out whether any of them changed. */
749 module->prefs_changed = FALSE; /* assume none of them changed */
750 prefs_pref_foreach(module, pref_fetch, &module->prefs_changed);
752 /* If any of them changed, indicate that we must redissect and refilter
753 the current capture (if we have one), as the preference change
754 could cause packets to be dissected differently. */
755 if (module->prefs_changed)
756 *must_redissect_p = TRUE;
760 pref_clean(pref_t *pref, gpointer user_data _U_)
762 switch (pref->type) {
774 if (pref->saved_val.string != NULL) {
775 g_free(pref->saved_val.string);
776 pref->saved_val.string = NULL;
781 g_assert_not_reached();
787 module_prefs_clean(module_t *module, gpointer user_data _U_)
789 /* For all preferences in this module, clean up any cruft allocated for
790 use by the GUI code. */
791 prefs_pref_foreach(module, pref_clean, NULL);
795 prefs_main_ok_cb(GtkWidget *ok_bt _U_, gpointer parent_w)
797 gboolean must_redissect = FALSE;
799 /* Fetch the preferences (i.e., make sure all the values set in all of
800 the preferences panes have been copied to "prefs" and the registered
802 printer_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_PRINT_PAGE_KEY));
803 column_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
804 stream_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
805 gui_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
806 capture_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_CAPTURE_PAGE_KEY));
807 nameres_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_NAMERES_PAGE_KEY));
808 prefs_module_foreach(module_prefs_fetch, &must_redissect);
810 /* Now apply those preferences. */
811 printer_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_PRINT_PAGE_KEY));
812 column_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
813 stream_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
814 gui_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
815 capture_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_CAPTURE_PAGE_KEY));
816 nameres_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_NAMERES_PAGE_KEY));
819 /* Now destroy the "Preferences" dialog. */
820 gtk_widget_destroy(GTK_WIDGET(parent_w));
822 if (must_redissect) {
823 /* Redissect all the packets, and re-evaluate the display filter. */
824 redissect_packets(&cfile);
829 prefs_main_apply_cb(GtkWidget *apply_bt _U_, gpointer parent_w)
831 gboolean must_redissect = FALSE;
833 /* Fetch the preferences (i.e., make sure all the values set in all of
834 the preferences panes have been copied to "prefs" and the registered
836 printer_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_PRINT_PAGE_KEY));
837 column_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
838 stream_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
839 gui_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
840 capture_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_CAPTURE_PAGE_KEY));
841 nameres_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_NAMERES_PAGE_KEY));
842 prefs_module_foreach(module_prefs_fetch, &must_redissect);
844 /* Now apply those preferences. */
845 printer_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_PRINT_PAGE_KEY));
846 column_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
847 stream_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
848 gui_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
849 capture_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_CAPTURE_PAGE_KEY));
850 nameres_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_NAMERES_PAGE_KEY));
853 if (must_redissect) {
854 /* Redissect all the packets, and re-evaluate the display filter. */
855 redissect_packets(&cfile);
860 prefs_main_save_cb(GtkWidget *save_bt _U_, gpointer parent_w)
862 gboolean must_redissect = FALSE;
867 /* Fetch the preferences (i.e., make sure all the values set in all of
868 the preferences panes have been copied to "prefs" and the registered
870 printer_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_PRINT_PAGE_KEY));
871 column_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
872 stream_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
873 gui_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
874 capture_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_CAPTURE_PAGE_KEY));
875 nameres_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_NAMERES_PAGE_KEY));
876 prefs_module_foreach(module_prefs_fetch, &must_redissect);
878 /* Create the directory that holds personal configuration files, if
880 if (create_persconffile_dir(&pf_dir_path) == -1) {
881 simple_dialog(ESD_TYPE_WARN, NULL,
882 "Can't create directory\n\"%s\"\nfor preferences file: %s.", pf_dir_path,
886 /* Write the preferencs out. */
887 err = write_prefs(&pf_path);
889 simple_dialog(ESD_TYPE_WARN, NULL,
890 "Can't open preferences file\n\"%s\": %s.", pf_path,
895 /* Now apply those preferences.
896 XXX - should we do this? The user didn't click "OK" or "Apply".
899 1) by saving the preferences they presumably indicate that they
902 2) the next time they fire Ethereal up, those preferences will
905 3) we'd have to buffer "must_redissect" so that if they do
906 "Apply" after this, we know we have to redissect;
908 4) we did apply the protocol preferences, at least, in the past. */
909 printer_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_PRINT_PAGE_KEY));
910 column_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
911 stream_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
912 gui_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
913 capture_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_CAPTURE_PAGE_KEY));
914 nameres_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_NAMERES_PAGE_KEY));
917 if (must_redissect) {
918 /* Redissect all the packets, and re-evaluate the display filter. */
919 redissect_packets(&cfile);
924 pref_revert(pref_t *pref, gpointer user_data)
926 gboolean *pref_changed_p = user_data;
928 /* Revert the preference to its saved value. */
929 switch (pref->type) {
932 if (*pref->varp.uint != pref->saved_val.uint) {
933 *pref_changed_p = TRUE;
934 *pref->varp.uint = pref->saved_val.uint;
939 if (*pref->varp.bool != pref->saved_val.bool) {
940 *pref_changed_p = TRUE;
941 *pref->varp.bool = pref->saved_val.bool;
946 if (*pref->varp.enump != pref->saved_val.enumval) {
947 *pref_changed_p = TRUE;
948 *pref->varp.enump = pref->saved_val.enumval;
953 if (*pref->varp.string != pref->saved_val.string &&
954 (*pref->varp.string == NULL ||
955 pref->saved_val.string == NULL ||
956 strcmp(*pref->varp.string, pref->saved_val.string) != 0)) {
957 *pref_changed_p = TRUE;
958 if (*pref->varp.string != NULL)
959 g_free(*pref->varp.string);
960 *pref->varp.string = g_strdup(pref->saved_val.string);
965 g_assert_not_reached();
971 module_prefs_revert(module_t *module, gpointer user_data)
973 gboolean *must_redissect_p = user_data;
975 /* For all preferences in this module, revert its value to the value
976 it had when we popped up the Preferences dialog. Find out whether
977 this changes any of them. */
978 module->prefs_changed = FALSE; /* assume none of them changed */
979 prefs_pref_foreach(module, pref_revert, &module->prefs_changed);
981 /* If any of them changed, indicate that we must redissect and refilter
982 the current capture (if we have one), as the preference change
983 could cause packets to be dissected differently. */
984 if (module->prefs_changed)
985 *must_redissect_p = TRUE;
989 prefs_main_cancel_cb(GtkWidget *cancel_bt _U_, gpointer parent_w)
991 gboolean must_redissect = FALSE;
993 /* Free up the current preferences and copy the saved preferences to the
994 current preferences. */
996 copy_prefs(&prefs, &saved_prefs);
998 /* Now revert the registered preferences. */
999 prefs_module_foreach(module_prefs_revert, &must_redissect);
1001 /* Now apply the reverted-to preferences. */
1002 printer_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_PRINT_PAGE_KEY));
1003 column_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
1004 stream_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
1005 gui_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
1006 nameres_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_NAMERES_PAGE_KEY));
1009 gtk_widget_destroy(GTK_WIDGET(parent_w));
1011 if (must_redissect) {
1012 /* Redissect all the packets, and re-evaluate the display filter. */
1013 redissect_packets(&cfile);
1017 /* Treat this as a cancel, by calling "prefs_main_cancel_cb()".
1018 XXX - that'll destroy the Preferences dialog; will that upset
1019 a higher-level handler that says "OK, we've been asked to delete
1020 this, so destroy it"? */
1022 prefs_main_delete_cb(GtkWidget *prefs_w, gpointer dummy _U_)
1024 prefs_main_cancel_cb(NULL, prefs_w);
1029 prefs_main_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1031 /* Let the preference tabs clean up anything they've done. */
1032 printer_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w), E_PRINT_PAGE_KEY));
1033 column_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w), E_COLUMN_PAGE_KEY));
1034 stream_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w), E_STREAM_PAGE_KEY));
1035 gui_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w), E_GUI_PAGE_KEY));
1036 capture_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w), E_CAPTURE_PAGE_KEY));
1037 nameres_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w), E_NAMERES_PAGE_KEY));
1039 /* Free up the saved preferences (both for "prefs" and for registered
1041 free_prefs(&saved_prefs);
1042 prefs_module_foreach(module_prefs_clean, NULL);
1044 /* Note that we no longer have a "Preferences" dialog box. */
1048 struct properties_data {
1054 /* XXX this way of searching the correct page number is really ugly ... */
1056 module_search_properties(module_t *module, gpointer user_data)
1058 struct properties_data *p = (struct properties_data *)user_data;
1060 if (p->title == NULL) return;
1061 if (strcmp(module->title, p->title) == 0) {
1063 gtk_notebook_set_page(GTK_NOTEBOOK(p->w), p->page_num);
1071 properties_cb(GtkWidget *w, gpointer dummy)
1073 gchar *title = NULL;
1074 struct properties_data p;
1076 if (finfo_selected) {
1077 header_field_info *hfinfo = finfo_selected->hfinfo;
1078 if (hfinfo->parent == -1) {
1079 title = (gchar *)prefs_get_title_by_name(hfinfo->abbrev);
1082 prefs_get_title_by_name(proto_registrar_get_abbrev(hfinfo->parent));
1090 if (prefs_w != NULL) {
1091 reactivate_window(prefs_w);
1097 p.page_num = FIRST_PROTO_PREFS_PAGE;
1100 prefs_module_foreach(module_search_properties, &p);
1104 /* Prefs tree selection callback. The node data has been loaded with
1105 the proper notebook page to load. */
1107 prefs_tree_select_cb(GtkCTree *ct, GtkCTreeNode *node, gint col _U_, gpointer dummy _U_)
1109 gint page = GPOINTER_TO_INT(gtk_ctree_node_get_row_data(ct, node));
1112 gtk_notebook_set_page(GTK_NOTEBOOK(notebook), page);