2 * Routines for handling preferences
4 * $Id: prefs_dlg.c,v 1.38 2002/01/13 20:35:12 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>
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"
83 #define FIRST_PROTO_PREFS_PAGE 4
86 * Keep a static pointer to the notebook to be able to choose the
89 static GtkWidget *notebook;
92 * Keep a static pointer to the current "Preferences" window, if any, so that
93 * if somebody tries to do "Edit:Preferences" while there's already a
94 * "Preferences" window up, we just pop up the existing one, rather than
97 static GtkWidget *prefs_w;
100 * Save the value of the preferences as of when the preferences dialog
101 * box was first popped up, so we can revert to those values if the
102 * user selects "Cancel".
104 static e_prefs saved_prefs;
114 pref_show(pref_t *pref, gpointer user_data)
116 GtkWidget *main_tb = user_data;
121 /* Give this preference a label which is its title, followed by a colon,
122 and left-align it. */
124 label_string = g_malloc(strlen(title) + 2);
125 strcpy(label_string, title);
126 strcat(label_string, ":");
128 /* Save the current value of the preference, so that we can revert it if
129 the user does "Apply" and then "Cancel", and create the control for
130 editing the preference. */
131 switch (pref->type) {
134 pref->saved_val.uint = *pref->varp.uint;
136 /* XXX - there are no uint spinbuttons, so we can't use a spinbutton.
137 Even more annoyingly, even if there were, GLib doesn't define
138 G_MAXUINT - but I think ANSI C may define UINT_MAX, so we could
140 switch (pref->info.base) {
143 sprintf(uint_str, "%u", pref->saved_val.uint);
147 sprintf(uint_str, "%o", pref->saved_val.uint);
151 sprintf(uint_str, "%x", pref->saved_val.uint);
154 pref->control = create_preference_entry(main_tb, pref->ordinal,
155 label_string, uint_str);
159 pref->control = create_preference_check_button(main_tb, pref->ordinal,
161 pref->saved_val.bool);
165 pref->saved_val.enumval = *pref->varp.enump;
166 if (pref->info.enum_info.radio_buttons) {
167 /* Show it as radio buttons. */
168 pref->control = create_preference_radio_buttons(main_tb, pref->ordinal,
170 pref->info.enum_info.enumvals,
171 pref->saved_val.enumval);
173 /* Show it as an option menu. */
174 pref->control = create_preference_option_menu(main_tb, pref->ordinal,
176 pref->info.enum_info.enumvals,
177 pref->saved_val.enumval);
182 if (pref->saved_val.string != NULL)
183 g_free(pref->saved_val.string);
184 pref->saved_val.string = g_strdup(*pref->varp.string);
185 pref->control = create_preference_entry(main_tb, pref->ordinal,
187 pref->saved_val.string);
191 g_assert_not_reached();
194 g_free(label_string);
197 #define MAX_TREE_NODE_NAME_LEN 64
199 module_prefs_show(module_t *module, gpointer user_data)
201 struct ct_struct *cts = user_data;
202 GtkWidget *main_vb, *main_tb, *frame;
203 gchar label_str[MAX_TREE_NODE_NAME_LEN], *label_ptr = label_str;
204 GtkCTreeNode *ct_node;
207 frame = gtk_frame_new(module->title);
208 gtk_widget_show(frame);
210 /* Main vertical box */
211 main_vb = gtk_vbox_new(FALSE, 5);
212 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
213 gtk_container_add(GTK_CONTAINER(frame), main_vb);
216 main_tb = gtk_table_new(module->numprefs, 2, FALSE);
217 gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0);
218 gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10);
219 gtk_table_set_col_spacings(GTK_TABLE(main_tb), 15);
221 /* Add items for each of the preferences */
222 prefs_pref_foreach(module, pref_show, main_tb);
224 gtk_notebook_append_page(GTK_NOTEBOOK(cts->notebook), frame, NULL);
225 strcpy(label_str, module->title);
226 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts->ctree), cts->node, NULL,
227 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
228 gtk_ctree_node_set_row_data(GTK_CTREE(cts->ctree), ct_node,
229 GINT_TO_POINTER(cts->page));
232 /* Show 'em what we got */
233 gtk_widget_show_all(main_vb);
237 prefs_cb(GtkWidget *w, gpointer dummy) {
238 GtkWidget *main_vb, *top_hb, *bbox, *prefs_nb, *ct_sb, *frame,
239 *ok_bt, *apply_bt, *save_bt, *cancel_bt;
240 GtkWidget *print_pg, *column_pg, *stream_pg, *gui_pg, *capture_pg;
241 GtkWidget *nameres_pg;
242 gchar label_str[MAX_TREE_NODE_NAME_LEN], *label_ptr = label_str;
243 GtkCTreeNode *ct_node;
244 struct ct_struct cts;
247 if (prefs_w != NULL) {
248 /* There's already a "Preferences" dialog box; reactivate it. */
249 reactivate_window(prefs_w);
253 /* Save the current preferences, so we can revert to those values
254 if the user presses "Cancel". */
255 copy_prefs(&saved_prefs, &prefs);
257 prefs_w = dlg_window_new("Ethereal: Preferences");
258 gtk_signal_connect(GTK_OBJECT(prefs_w), "delete_event",
259 GTK_SIGNAL_FUNC(prefs_main_delete_cb), NULL);
260 gtk_signal_connect(GTK_OBJECT(prefs_w), "destroy",
261 GTK_SIGNAL_FUNC(prefs_main_destroy_cb), NULL);
263 /* Container for each row of widgets */
264 main_vb = gtk_vbox_new(FALSE, 5);
265 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
266 gtk_container_add(GTK_CONTAINER(prefs_w), main_vb);
267 gtk_widget_show(main_vb);
269 /* Top row: Preferences tree and notebook */
270 top_hb = gtk_hbox_new(FALSE, 10);
271 gtk_container_add(GTK_CONTAINER(main_vb), top_hb);
272 gtk_widget_show(top_hb);
274 /* Place a Ctree on the left for preference categories */
275 ct_sb = scrolled_window_new(NULL, NULL);
276 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ct_sb),
277 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
278 gtk_container_add(GTK_CONTAINER(top_hb), ct_sb);
279 gtk_widget_show(ct_sb);
281 cts.ctree = ctree_new(1, 0);
283 gtk_container_add(GTK_CONTAINER(ct_sb), cts.ctree);
285 gtk_clist_set_column_auto_resize(GTK_CLIST(cts.ctree), 0, TRUE);
286 gtk_signal_connect(GTK_OBJECT(cts.ctree), "tree-select-row",
287 GTK_SIGNAL_FUNC(prefs_tree_select_cb), NULL);
288 gtk_widget_show(cts.ctree);
290 /* A notebook widget sans tabs is used to flip between prefs */
291 notebook = prefs_nb = gtk_notebook_new();
292 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE);
293 gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook), FALSE);
294 gtk_container_add(GTK_CONTAINER(top_hb), prefs_nb);
295 gtk_widget_show(prefs_nb);
298 frame = gtk_frame_new("Printing");
299 gtk_widget_show(GTK_WIDGET(frame));
300 print_pg = printer_prefs_show();
301 gtk_container_add(GTK_CONTAINER(frame), print_pg);
302 gtk_object_set_data(GTK_OBJECT(prefs_w), E_PRINT_PAGE_KEY, print_pg);
303 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
304 strcpy(label_str, "Printing");
305 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.ctree), NULL, NULL,
306 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
307 gtk_ctree_node_set_row_data(GTK_CTREE(cts.ctree), ct_node,
308 GINT_TO_POINTER(cts.page));
312 frame = gtk_frame_new("Columns");
313 gtk_widget_show(GTK_WIDGET(frame));
314 column_pg = column_prefs_show();
315 gtk_container_add(GTK_CONTAINER(frame), column_pg);
316 gtk_object_set_data(GTK_OBJECT(prefs_w), E_COLUMN_PAGE_KEY, column_pg);
317 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
318 strcpy(label_str, "Columns");
319 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.ctree), NULL, NULL,
320 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
321 gtk_ctree_node_set_row_data(GTK_CTREE(cts.ctree), ct_node,
322 GINT_TO_POINTER(cts.page));
325 /* TCP Streams prefs */
326 frame = gtk_frame_new("TCP Streams");
327 gtk_widget_show(GTK_WIDGET(frame));
328 stream_pg = stream_prefs_show();
329 gtk_container_add(GTK_CONTAINER(frame), stream_pg);
330 gtk_object_set_data(GTK_OBJECT(prefs_w), E_STREAM_PAGE_KEY, stream_pg);
331 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
332 strcpy(label_str, "TCP Streams");
333 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.ctree), NULL, NULL,
334 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
335 gtk_ctree_node_set_row_data(GTK_CTREE(cts.ctree), ct_node,
336 GINT_TO_POINTER(cts.page));
340 frame = gtk_frame_new("User Interface");
341 gtk_widget_show(GTK_WIDGET(frame));
342 gui_pg = gui_prefs_show();
343 gtk_container_add(GTK_CONTAINER(frame), gui_pg);
344 gtk_object_set_data(GTK_OBJECT(prefs_w), E_GUI_PAGE_KEY, gui_pg);
345 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
346 strcpy(label_str, "User Interface");
347 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.ctree), NULL, NULL,
348 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
349 gtk_ctree_node_set_row_data(GTK_CTREE(cts.ctree), ct_node,
350 GINT_TO_POINTER(cts.page));
355 frame = gtk_frame_new("Capture");
356 gtk_widget_show(GTK_WIDGET(frame));
357 capture_pg = capture_prefs_show();
358 gtk_container_add(GTK_CONTAINER(frame), capture_pg);
359 gtk_object_set_data(GTK_OBJECT(prefs_w), E_CAPTURE_PAGE_KEY, capture_pg);
360 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
361 strcpy(label_str, "Capture");
362 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.ctree), NULL, NULL,
363 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
364 gtk_ctree_node_set_row_data(GTK_CTREE(cts.ctree), ct_node,
365 GINT_TO_POINTER(cts.page));
369 /* Name resolution prefs */
370 frame = gtk_frame_new("Name resolution");
371 gtk_widget_show(GTK_WIDGET(frame));
372 nameres_pg = nameres_prefs_show();
373 gtk_container_add(GTK_CONTAINER(frame), nameres_pg);
374 gtk_object_set_data(GTK_OBJECT(prefs_w), E_NAMERES_PAGE_KEY, nameres_pg);
375 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
376 strcpy(label_str, "Name resolution");
377 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts.ctree), NULL, NULL,
378 &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE);
379 gtk_ctree_node_set_row_data(GTK_CTREE(cts.ctree), ct_node,
380 GINT_TO_POINTER(cts.page));
383 /* Registered prefs */
384 cts.notebook = prefs_nb;
385 strcpy(label_str, "Protocols");
386 cts.node = gtk_ctree_insert_node(GTK_CTREE(cts.ctree), NULL, NULL,
387 &label_ptr, 5, NULL, NULL, NULL, NULL, FALSE, FALSE);
388 gtk_ctree_node_set_row_data(GTK_CTREE(cts.ctree), cts.node,
389 GINT_TO_POINTER(-1));
390 gtk_ctree_node_set_selectable(GTK_CTREE(cts.ctree), cts.node, FALSE);
392 prefs_module_foreach(module_prefs_show, &cts);
395 /* Button row: OK and cancel buttons */
396 bbox = gtk_hbutton_box_new();
397 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
398 gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
399 gtk_container_add(GTK_CONTAINER(main_vb), bbox);
400 gtk_widget_show(bbox);
402 ok_bt = gtk_button_new_with_label ("OK");
403 gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
404 GTK_SIGNAL_FUNC(prefs_main_ok_cb), GTK_OBJECT(prefs_w));
405 GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT);
406 gtk_box_pack_start (GTK_BOX (bbox), ok_bt, TRUE, TRUE, 0);
407 gtk_widget_grab_default(ok_bt);
408 gtk_widget_show(ok_bt);
410 apply_bt = gtk_button_new_with_label ("Apply");
411 gtk_signal_connect(GTK_OBJECT(apply_bt), "clicked",
412 GTK_SIGNAL_FUNC(prefs_main_apply_cb), GTK_OBJECT(prefs_w));
413 GTK_WIDGET_SET_FLAGS(apply_bt, GTK_CAN_DEFAULT);
414 gtk_box_pack_start(GTK_BOX (bbox), apply_bt, TRUE, TRUE, 0);
415 gtk_widget_show(apply_bt);
417 save_bt = gtk_button_new_with_label ("Save");
418 gtk_signal_connect(GTK_OBJECT(save_bt), "clicked",
419 GTK_SIGNAL_FUNC(prefs_main_save_cb), GTK_OBJECT(prefs_w));
420 GTK_WIDGET_SET_FLAGS(save_bt, GTK_CAN_DEFAULT);
421 gtk_box_pack_start (GTK_BOX (bbox), save_bt, TRUE, TRUE, 0);
422 gtk_widget_show(save_bt);
424 cancel_bt = gtk_button_new_with_label ("Cancel");
425 gtk_signal_connect(GTK_OBJECT(cancel_bt), "clicked",
426 GTK_SIGNAL_FUNC(prefs_main_cancel_cb), GTK_OBJECT(prefs_w));
427 GTK_WIDGET_SET_FLAGS(cancel_bt, GTK_CAN_DEFAULT);
428 gtk_box_pack_start (GTK_BOX (bbox), cancel_bt, TRUE, TRUE, 0);
429 gtk_widget_show(cancel_bt);
431 /* Catch the "key_press_event" signal in the window, so that we can catch
432 the ESC key being pressed and act as if the "Cancel" button had
434 dlg_set_cancel(prefs_w, cancel_bt);
436 gtk_widget_show(prefs_w);
440 set_option_label(GtkWidget *main_tb, int table_position,
441 const gchar *label_text)
445 label = gtk_label_new(label_text);
446 gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
447 gtk_table_attach_defaults(GTK_TABLE(main_tb), label, 0, 1,
448 table_position, table_position + 1);
449 gtk_widget_show(label);
453 create_preference_check_button(GtkWidget *main_tb, int table_position,
454 const gchar *label_text, gboolean active)
456 GtkWidget *check_box;
458 set_option_label(main_tb, table_position, label_text);
460 check_box = gtk_check_button_new();
461 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_box), active);
462 gtk_table_attach_defaults(GTK_TABLE(main_tb), check_box, 1, 2,
463 table_position, table_position + 1);
469 create_preference_radio_buttons(GtkWidget *main_tb, int table_position,
470 const gchar *label_text, const enum_val_t *enumvals, gint current_val)
472 GtkWidget *radio_button_hbox, *button = NULL;
475 const enum_val_t *enum_valp;
477 set_option_label(main_tb, table_position, label_text);
479 radio_button_hbox = gtk_hbox_new(FALSE, 0);
481 for (enum_valp = enumvals, index = 0; enum_valp->name != NULL;
482 enum_valp++, index++) {
483 button = gtk_radio_button_new_with_label(rb_group,
485 gtk_widget_show(button);
486 if (rb_group == NULL)
487 rb_group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
488 gtk_box_pack_start(GTK_BOX(radio_button_hbox), button, FALSE,
490 if (enum_valp->value == current_val) {
491 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button),
495 gtk_widget_show(radio_button_hbox);
496 gtk_table_attach_defaults(GTK_TABLE(main_tb), radio_button_hbox, 1, 2,
497 table_position, table_position+1);
500 * It doesn't matter which of the buttons we return - we fetch
501 * the value by looking at the entire radio button group to
502 * which it belongs, and we can get that from any button.
508 label_to_enum_val(GtkWidget *label, const enum_val_t *enumvals)
513 /* Get the label's text, and translate it to a value. */
514 gtk_label_get(GTK_LABEL(label), &label_string);
515 enumval = find_val_for_string(label_string, enumvals, 1);
521 fetch_preference_radio_buttons_val(GtkWidget *button,
522 const enum_val_t *enumvals)
528 * Go through the list of of radio buttons in the button's group,
529 * and find the first one that's active.
531 rb_group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
533 for (rb_entry = rb_group; rb_entry != NULL;
534 rb_entry = g_slist_next(rb_entry)) {
535 button = rb_entry->data;
536 if (GTK_TOGGLE_BUTTON(button)->active)
540 /* OK, now return the value corresponding to that button's label. */
541 return label_to_enum_val(GTK_BIN(button)->child, enumvals);
545 create_preference_option_menu(GtkWidget *main_tb, int table_position,
546 const gchar *label_text, const enum_val_t *enumvals, gint current_val)
548 GtkWidget *label, *menu_box, *menu, *menu_item, *option_menu;
549 int menu_index, index;
550 const enum_val_t *enum_valp;
552 set_option_label(main_tb, table_position, label_text);
554 /* Create a menu from the enumvals */
555 menu = gtk_menu_new();
557 for (enum_valp = enumvals, index = 0; enum_valp->name != NULL;
558 enum_valp++, index++) {
559 menu_item = gtk_menu_item_new_with_label(enum_valp->name);
560 gtk_menu_append(GTK_MENU(menu), menu_item);
561 if (enum_valp->value == current_val)
563 gtk_widget_show(menu_item);
566 /* Create the option menu from the menu */
567 option_menu = gtk_option_menu_new();
568 gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), menu);
570 /* Set its current value to the variable's current value */
571 if (menu_index != -1)
572 gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu),
576 * Put the option menu in an hbox, so that it's only as wide
577 * as the widest entry, rather than being as wide as the table
580 menu_box = gtk_hbox_new(FALSE, 0);
581 gtk_table_attach_defaults(GTK_TABLE(main_tb), menu_box,
582 1, 2, table_position, table_position + 1);
583 gtk_box_pack_start(GTK_BOX(menu_box), option_menu, FALSE, FALSE, 0);
588 fetch_preference_option_menu_val(GtkWidget *optmenu, const enum_val_t *enumvals)
591 * OK, now return the value corresponding to the label for the
592 * currently active entry in the option menu.
594 * Yes, this is how you get the label for that entry. See FAQ
595 * 6.8 in the GTK+ FAQ.
597 return label_to_enum_val(GTK_BIN(optmenu)->child, enumvals);
601 create_preference_entry(GtkWidget *main_tb, int table_position,
602 const gchar *label_text, char *value)
606 set_option_label(main_tb, table_position, label_text);
608 entry = gtk_entry_new();
610 gtk_entry_set_text(GTK_ENTRY(entry), value);
611 gtk_table_attach_defaults(GTK_TABLE(main_tb), entry, 1, 2,
612 table_position, table_position + 1);
613 gtk_widget_show(entry);
619 pref_fetch(pref_t *pref, gpointer user_data)
630 gboolean *pref_changed_p = user_data;
632 /* Fetch the value of the preference, and set the appropriate variable
634 switch (pref->type) {
637 str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
638 uval = strtoul(str_val, &p, pref->info.base);
640 if (p == value || *p != '\0')
641 return PREFS_SET_SYNTAX_ERR; /* number was bad */
643 if (*pref->varp.uint != uval) {
644 *pref_changed_p = TRUE;
645 *pref->varp.uint = uval;
650 bval = GTK_TOGGLE_BUTTON(pref->control)->active;
651 if (*pref->varp.bool != bval) {
652 *pref_changed_p = TRUE;
653 *pref->varp.bool = bval;
658 if (pref->info.enum_info.radio_buttons) {
659 enumval = fetch_preference_radio_buttons_val(pref->control,
660 pref->info.enum_info.enumvals);
662 enumval = fetch_preference_option_menu_val(pref->control,
663 pref->info.enum_info.enumvals);
666 if (*pref->varp.enump != enumval) {
667 *pref_changed_p = TRUE;
668 *pref->varp.enump = enumval;
673 str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
674 if (*pref->varp.string == NULL || strcmp(*pref->varp.string, str_val) != 0) {
675 *pref_changed_p = TRUE;
676 if (*pref->varp.string != NULL)
677 g_free(*pref->varp.string);
678 *pref->varp.string = g_strdup(str_val);
683 g_assert_not_reached();
689 module_prefs_fetch(module_t *module, gpointer user_data)
691 gboolean *must_redissect_p = user_data;
693 /* For all preferences in this module, fetch its value from this
694 module's notebook page. Find out whether any of them changed. */
695 module->prefs_changed = FALSE; /* assume none of them changed */
696 prefs_pref_foreach(module, pref_fetch, &module->prefs_changed);
698 /* If any of them changed, indicate that we must redissect and refilter
699 the current capture (if we have one), as the preference change
700 could cause packets to be dissected differently. */
701 if (module->prefs_changed)
702 *must_redissect_p = TRUE;
706 pref_clean(pref_t *pref, gpointer user_data)
708 switch (pref->type) {
720 if (pref->saved_val.string != NULL) {
721 g_free(pref->saved_val.string);
722 pref->saved_val.string = NULL;
727 g_assert_not_reached();
733 module_prefs_clean(module_t *module, gpointer user_data)
735 /* For all preferences in this module, clean up any cruft allocated for
736 use by the GUI code. */
737 prefs_pref_foreach(module, pref_clean, NULL);
741 prefs_main_ok_cb(GtkWidget *ok_bt, gpointer parent_w)
743 gboolean must_redissect = FALSE;
745 /* Fetch the preferences (i.e., make sure all the values set in all of
746 the preferences panes have been copied to "prefs" and the registered
748 printer_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_PRINT_PAGE_KEY));
749 column_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
750 stream_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
751 gui_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
752 capture_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_CAPTURE_PAGE_KEY));
753 nameres_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_NAMERES_PAGE_KEY));
754 prefs_module_foreach(module_prefs_fetch, &must_redissect);
756 /* Now apply those preferences. */
757 printer_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_PRINT_PAGE_KEY));
758 column_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
759 stream_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
760 gui_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
761 capture_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_CAPTURE_PAGE_KEY));
762 nameres_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_NAMERES_PAGE_KEY));
765 /* Now destroy the "Preferences" dialog. */
766 gtk_widget_destroy(GTK_WIDGET(parent_w));
768 if (must_redissect) {
769 /* Redissect all the packets, and re-evaluate the display filter. */
770 redissect_packets(&cfile);
775 prefs_main_apply_cb(GtkWidget *apply_bt, gpointer parent_w)
777 gboolean must_redissect = FALSE;
779 /* Fetch the preferences (i.e., make sure all the values set in all of
780 the preferences panes have been copied to "prefs" and the registered
782 printer_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_PRINT_PAGE_KEY));
783 column_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
784 stream_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
785 gui_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
786 capture_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_CAPTURE_PAGE_KEY));
787 nameres_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_NAMERES_PAGE_KEY));
788 prefs_module_foreach(module_prefs_fetch, &must_redissect);
790 /* Now apply those preferences. */
791 printer_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_PRINT_PAGE_KEY));
792 column_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
793 stream_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
794 gui_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
795 capture_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_CAPTURE_PAGE_KEY));
796 nameres_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_NAMERES_PAGE_KEY));
799 if (must_redissect) {
800 /* Redissect all the packets, and re-evaluate the display filter. */
801 redissect_packets(&cfile);
806 prefs_main_save_cb(GtkWidget *save_bt, gpointer parent_w)
808 gboolean must_redissect = FALSE;
813 /* Fetch the preferences (i.e., make sure all the values set in all of
814 the preferences panes have been copied to "prefs" and the registered
816 printer_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_PRINT_PAGE_KEY));
817 column_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
818 stream_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
819 gui_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
820 capture_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_CAPTURE_PAGE_KEY));
821 nameres_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_NAMERES_PAGE_KEY));
822 prefs_module_foreach(module_prefs_fetch, &must_redissect);
824 /* Create the directory that holds personal configuration files, if
826 if (create_persconffile_dir(&pf_dir_path) == -1) {
827 simple_dialog(ESD_TYPE_WARN, NULL,
828 "Can't create directory\n\"%s\"\nfor preferences file: %s.", pf_dir_path,
832 /* Write the preferencs out. */
833 err = write_prefs(&pf_path);
835 simple_dialog(ESD_TYPE_WARN, NULL,
836 "Can't open preferences file\n\"%s\": %s.", pf_path,
841 /* Now apply those preferences.
842 XXX - should we do this? The user didn't click "OK" or "Apply".
845 1) by saving the preferences they presumably indicate that they
848 2) the next time they fire Ethereal up, those preferences will
851 3) we'd have to buffer "must_redissect" so that if they do
852 "Apply" after this, we know we have to redissect;
854 4) we did apply the protocol preferences, at least, in the past. */
855 printer_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_PRINT_PAGE_KEY));
856 column_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
857 stream_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
858 gui_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
859 capture_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_CAPTURE_PAGE_KEY));
860 nameres_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_NAMERES_PAGE_KEY));
863 if (must_redissect) {
864 /* Redissect all the packets, and re-evaluate the display filter. */
865 redissect_packets(&cfile);
870 pref_revert(pref_t *pref, gpointer user_data)
872 gboolean *pref_changed_p = user_data;
874 /* Revert the preference to its saved value. */
875 switch (pref->type) {
878 if (*pref->varp.uint != pref->saved_val.uint) {
879 *pref_changed_p = TRUE;
880 *pref->varp.uint = pref->saved_val.uint;
885 if (*pref->varp.bool != pref->saved_val.bool) {
886 *pref_changed_p = TRUE;
887 *pref->varp.bool = pref->saved_val.bool;
892 if (*pref->varp.enump != pref->saved_val.enumval) {
893 *pref_changed_p = TRUE;
894 *pref->varp.enump = pref->saved_val.enumval;
899 if (*pref->varp.string != pref->saved_val.string &&
900 (*pref->varp.string == NULL ||
901 pref->saved_val.string == NULL ||
902 strcmp(*pref->varp.string, pref->saved_val.string) != 0)) {
903 *pref_changed_p = TRUE;
904 if (*pref->varp.string != NULL)
905 g_free(*pref->varp.string);
906 *pref->varp.string = g_strdup(pref->saved_val.string);
911 g_assert_not_reached();
917 module_prefs_revert(module_t *module, gpointer user_data)
919 gboolean *must_redissect_p = user_data;
921 /* For all preferences in this module, revert its value to the value
922 it had when we popped up the Preferences dialog. Find out whether
923 this changes any of them. */
924 module->prefs_changed = FALSE; /* assume none of them changed */
925 prefs_pref_foreach(module, pref_revert, &module->prefs_changed);
927 /* If any of them changed, indicate that we must redissect and refilter
928 the current capture (if we have one), as the preference change
929 could cause packets to be dissected differently. */
930 if (module->prefs_changed)
931 *must_redissect_p = TRUE;
935 prefs_main_cancel_cb(GtkWidget *cancel_bt, gpointer parent_w)
937 gboolean must_redissect = FALSE;
939 /* Free up the current preferences and copy the saved preferences to the
940 current preferences. */
942 copy_prefs(&prefs, &saved_prefs);
944 /* Now revert the registered preferences. */
945 prefs_module_foreach(module_prefs_revert, &must_redissect);
947 /* Now apply the reverted-to preferences. */
948 printer_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_PRINT_PAGE_KEY));
949 column_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_COLUMN_PAGE_KEY));
950 stream_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_STREAM_PAGE_KEY));
951 gui_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
952 nameres_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_NAMERES_PAGE_KEY));
955 gtk_widget_destroy(GTK_WIDGET(parent_w));
957 if (must_redissect) {
958 /* Redissect all the packets, and re-evaluate the display filter. */
959 redissect_packets(&cfile);
963 /* Treat this as a cancel, by calling "prefs_main_cancel_cb()".
964 XXX - that'll destroy the Preferences dialog; will that upset
965 a higher-level handler that says "OK, we've been asked to delete
966 this, so destroy it"? */
968 prefs_main_delete_cb(GtkWidget *prefs_w, gpointer dummy)
970 prefs_main_cancel_cb(NULL, prefs_w);
975 prefs_main_destroy_cb(GtkWidget *win, gpointer user_data)
977 /* Let the preference tabs clean up anything they've done. */
978 printer_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w), E_PRINT_PAGE_KEY));
979 column_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w), E_COLUMN_PAGE_KEY));
980 stream_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w), E_STREAM_PAGE_KEY));
981 gui_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w), E_GUI_PAGE_KEY));
982 capture_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w), E_CAPTURE_PAGE_KEY));
983 nameres_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w), E_NAMERES_PAGE_KEY));
985 /* Free up the saved preferences (both for "prefs" and for registered
987 free_prefs(&saved_prefs);
988 prefs_module_foreach(module_prefs_clean, NULL);
990 /* Note that we no longer have a "Preferences" dialog box. */
994 struct properties_data {
1000 /* XXX this way of searching the correct page number is really ugly ... */
1002 module_search_properties(module_t *module, gpointer user_data)
1004 struct properties_data *p = (struct properties_data *)user_data;
1006 if (p->title == NULL) return;
1007 if (strcmp(module->title, p->title) == 0) {
1009 gtk_notebook_set_page(GTK_NOTEBOOK(p->w), p->page_num);
1017 properties_cb(GtkWidget *w, gpointer dummy)
1019 gchar *title = NULL;
1020 struct properties_data p;
1022 if (finfo_selected) {
1023 header_field_info *hfinfo = finfo_selected->hfinfo;
1024 if (hfinfo->parent == -1) {
1025 title = (gchar *)prefs_get_title_by_name(hfinfo->abbrev);
1028 prefs_get_title_by_name(proto_registrar_get_abbrev(hfinfo->parent));
1036 if (prefs_w != NULL) {
1037 reactivate_window(prefs_w);
1043 p.page_num = FIRST_PROTO_PREFS_PAGE;
1046 prefs_module_foreach(module_search_properties, &p);
1050 /* Prefs tree selection callback. The node data has been loaded with
1051 the proper notebook page to load. */
1053 prefs_tree_select_cb(GtkCTree *ct, GtkCTreeNode *node, gint col, gpointer dummy)
1055 gint page = GPOINTER_TO_INT(gtk_ctree_node_get_row_data(ct, node));
1058 gtk_notebook_set_page(GTK_NOTEBOOK(notebook), page);