2 * Routines for handling preferences
4 * $Id: prefs_dlg.c,v 1.4 2002/09/14 10:07:39 oabad 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"
51 #include "prefs-int.h"
55 #include "capture-wpcap.h"
57 #endif /* HAVE_LIBPCAP */
59 static void prefs_main_ok_cb(GtkWidget *, gpointer);
60 static void prefs_main_apply_cb(GtkWidget *, gpointer);
61 static void prefs_main_save_cb(GtkWidget *, gpointer);
62 static void prefs_main_cancel_cb(GtkWidget *, gpointer);
63 static gboolean prefs_main_delete_cb(GtkWidget *, gpointer);
64 static void prefs_main_destroy_cb(GtkWidget *, gpointer);
65 static void prefs_tree_select_cb(GtkTreeSelection *, gpointer);
67 #define E_PRINT_PAGE_KEY "printer_options_page"
68 #define E_COLUMN_PAGE_KEY "column_options_page"
69 #define E_STREAM_PAGE_KEY "tcp_stream_options_page"
70 #define E_GUI_PAGE_KEY "gui_options_page"
71 #define E_CAPTURE_PAGE_KEY "capture_options_page"
72 #define E_NAMERES_PAGE_KEY "nameres_options_page"
73 #define E_TOOLTIPS_KEY "tooltips"
75 #define FIRST_PROTO_PREFS_PAGE 6
78 * Keep a static pointer to the notebook to be able to choose the
81 static GtkWidget *notebook;
84 * Keep a static pointer to the current "Preferences" window, if any, so that
85 * if somebody tries to do "Edit:Preferences" while there's already a
86 * "Preferences" window up, we just pop up the existing one, rather than
89 static GtkWidget *prefs_w;
92 * Save the value of the preferences as of when the preferences dialog
93 * box was first popped up, so we can revert to those values if the
94 * user selects "Cancel".
96 static e_prefs saved_prefs;
101 GtkTreeIter proto_iter;
103 GtkTooltips *tooltips;
108 pref_show(pref_t *pref, gpointer user_data)
110 GtkWidget *main_tb = user_data;
115 /* Give this preference a label which is its title, followed by a colon,
116 and left-align it. */
118 label_string = g_malloc(strlen(title) + 2);
119 strcpy(label_string, title);
120 strcat(label_string, ":");
122 /* Save the current value of the preference, so that we can revert it if
123 the user does "Apply" and then "Cancel", and create the control for
124 editing the preference. */
125 switch (pref->type) {
128 pref->saved_val.uint = *pref->varp.uint;
130 /* XXX - there are no uint spinbuttons, so we can't use a spinbutton.
131 Even more annoyingly, even if there were, GLib doesn't define
132 G_MAXUINT - but I think ANSI C may define UINT_MAX, so we could
134 switch (pref->info.base) {
137 sprintf(uint_str, "%u", pref->saved_val.uint);
141 sprintf(uint_str, "%o", pref->saved_val.uint);
145 sprintf(uint_str, "%x", pref->saved_val.uint);
148 pref->control = create_preference_entry(main_tb, pref->ordinal,
149 label_string, pref->description,
154 pref->saved_val.boolval = *pref->varp.boolp;
155 pref->control = create_preference_check_button(main_tb, pref->ordinal,
156 label_string, pref->description,
157 pref->saved_val.boolval);
161 pref->saved_val.enumval = *pref->varp.enump;
162 if (pref->info.enum_info.radio_buttons) {
163 /* Show it as radio buttons. */
164 pref->control = create_preference_radio_buttons(main_tb, pref->ordinal,
165 label_string, pref->description,
166 pref->info.enum_info.enumvals,
167 pref->saved_val.enumval);
169 /* Show it as an option menu. */
170 pref->control = create_preference_option_menu(main_tb, pref->ordinal,
171 label_string, pref->description,
172 pref->info.enum_info.enumvals,
173 pref->saved_val.enumval);
178 if (pref->saved_val.string != NULL)
179 g_free(pref->saved_val.string);
180 pref->saved_val.string = g_strdup(*pref->varp.string);
181 pref->control = create_preference_entry(main_tb, pref->ordinal,
182 label_string, pref->description,
183 pref->saved_val.string);
187 g_assert_not_reached();
190 g_free(label_string);
193 #define MAX_TREE_NODE_NAME_LEN 64
195 module_prefs_show(module_t *module, gpointer user_data)
197 struct ct_struct *cts = user_data;
198 GtkWidget *main_vb, *main_tb, *frame;
199 gchar label_str[MAX_TREE_NODE_NAME_LEN];
204 frame = gtk_frame_new(module->title);
205 gtk_widget_show(frame);
207 /* Main vertical box */
208 main_vb = gtk_vbox_new(FALSE, 5);
209 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
210 gtk_container_add(GTK_CONTAINER(frame), main_vb);
213 main_tb = gtk_table_new(module->numprefs, 2, FALSE);
214 gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0);
215 gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10);
216 gtk_table_set_col_spacings(GTK_TABLE(main_tb), 15);
217 gtk_object_set_data(GTK_OBJECT(main_tb), E_TOOLTIPS_KEY, cts->tooltips);
219 /* Add items for each of the preferences */
220 prefs_pref_foreach(module, pref_show, main_tb);
222 gtk_notebook_append_page(GTK_NOTEBOOK(cts->notebook), frame, NULL);
223 strcpy(label_str, module->title);
224 model = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(cts->treeview)));
225 gtk_tree_store_append(model, &iter, &cts->proto_iter);
226 gtk_tree_store_set(model, &iter, 0, label_str, 1, cts->page, -1);
229 /* Show 'em what we got */
230 gtk_widget_show_all(main_vb);
234 prefs_cb(GtkWidget *w _U_, gpointer dummy _U_)
236 GtkWidget *main_vb, *top_hb, *bbox, *prefs_nb, *ct_sb, *frame,
237 *ok_bt, *apply_bt, *save_bt, *cancel_bt;
238 GtkWidget *print_pg, *column_pg, *stream_pg, *gui_pg;
240 GtkWidget *capture_pg;
242 GtkWidget *nameres_pg;
243 gchar label_str[MAX_TREE_NODE_NAME_LEN];
244 struct ct_struct cts;
246 GtkTreeSelection *selection;
247 GtkCellRenderer *renderer;
248 GtkTreeViewColumn *column;
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 g_signal_connect(G_OBJECT(prefs_w), "delete_event",
264 G_CALLBACK(prefs_main_delete_cb), NULL);
265 g_signal_connect(G_OBJECT(prefs_w), "destroy",
266 G_CALLBACK(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 store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_INT);
295 cts.treeview = tree_view_new(GTK_TREE_MODEL(store));
296 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(cts.treeview), FALSE);
297 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(cts.treeview));
298 gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
299 renderer = gtk_cell_renderer_text_new();
300 col_offset = gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(cts.treeview),
301 -1, "Name", renderer,
303 column = gtk_tree_view_get_column(GTK_TREE_VIEW(cts.treeview),
305 gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column),
306 GTK_TREE_VIEW_COLUMN_AUTOSIZE);
308 gtk_container_add(GTK_CONTAINER(ct_sb), cts.treeview);
310 g_signal_connect(G_OBJECT(selection), "changed",
311 G_CALLBACK(prefs_tree_select_cb), NULL);
312 gtk_widget_show(cts.treeview);
314 /* A notebook widget sans tabs is used to flip between prefs */
315 notebook = prefs_nb = gtk_notebook_new();
316 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE);
317 gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook), FALSE);
318 gtk_container_add(GTK_CONTAINER(top_hb), prefs_nb);
319 gtk_widget_show(prefs_nb);
322 frame = gtk_frame_new("Printing");
323 gtk_widget_show(GTK_WIDGET(frame));
324 print_pg = printer_prefs_show();
325 gtk_container_add(GTK_CONTAINER(frame), print_pg);
326 gtk_object_set_data(GTK_OBJECT(prefs_w), E_PRINT_PAGE_KEY, print_pg);
327 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
328 strcpy(label_str, "Printing");
329 gtk_tree_store_append(store, &iter, NULL);
330 gtk_tree_store_set(store, &iter, 0, label_str, 1, cts.page, -1);
334 frame = gtk_frame_new("Columns");
335 gtk_widget_show(GTK_WIDGET(frame));
336 column_pg = column_prefs_show();
337 gtk_container_add(GTK_CONTAINER(frame), column_pg);
338 gtk_object_set_data(GTK_OBJECT(prefs_w), E_COLUMN_PAGE_KEY, column_pg);
339 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
340 strcpy(label_str, "Columns");
341 gtk_tree_store_append(store, &iter, NULL);
342 gtk_tree_store_set(store, &iter, 0, label_str, 1, cts.page, -1);
345 /* TCP Streams prefs */
346 frame = gtk_frame_new("TCP Streams");
347 gtk_widget_show(GTK_WIDGET(frame));
348 stream_pg = stream_prefs_show();
349 gtk_container_add(GTK_CONTAINER(frame), stream_pg);
350 gtk_object_set_data(GTK_OBJECT(prefs_w), E_STREAM_PAGE_KEY, stream_pg);
351 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
352 strcpy(label_str, "TCP Streams");
353 gtk_tree_store_append(store, &iter, NULL);
354 gtk_tree_store_set(store, &iter, 0, label_str, 1, cts.page, -1);
358 frame = gtk_frame_new("User Interface");
359 gtk_widget_show(GTK_WIDGET(frame));
360 gui_pg = gui_prefs_show();
361 gtk_container_add(GTK_CONTAINER(frame), gui_pg);
362 gtk_object_set_data(GTK_OBJECT(prefs_w), E_GUI_PAGE_KEY, gui_pg);
363 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
364 strcpy(label_str, "User Interface");
365 gtk_tree_store_append(store, &iter, NULL);
366 gtk_tree_store_set(store, &iter, 0, label_str, 1, cts.page, -1);
371 /* Is WPcap loaded? */
375 frame = gtk_frame_new("Capture");
376 gtk_widget_show(GTK_WIDGET(frame));
377 capture_pg = capture_prefs_show();
378 gtk_container_add(GTK_CONTAINER(frame), capture_pg);
379 gtk_object_set_data(GTK_OBJECT(prefs_w), E_CAPTURE_PAGE_KEY, capture_pg);
380 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
381 strcpy(label_str, "Capture");
382 gtk_tree_store_append(store, &iter, NULL);
383 gtk_tree_store_set(store, &iter, 0, label_str, 1, cts.page, -1);
388 #endif /* HAVE_LIBPCAP */
390 /* Name resolution prefs */
391 frame = gtk_frame_new("Name resolution");
392 gtk_widget_show(GTK_WIDGET(frame));
393 nameres_pg = nameres_prefs_show();
394 gtk_container_add(GTK_CONTAINER(frame), nameres_pg);
395 gtk_object_set_data(GTK_OBJECT(prefs_w), E_NAMERES_PAGE_KEY, nameres_pg);
396 gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
397 strcpy(label_str, "Name resolution");
398 gtk_tree_store_append(store, &iter, NULL);
399 gtk_tree_store_set(store, &iter, 0, label_str, 1, cts.page, -1);
402 /* Registered prefs */
403 cts.notebook = prefs_nb;
404 strcpy(label_str, "Protocols");
405 gtk_tree_store_append(store, &cts.proto_iter, NULL);
406 gtk_tree_store_set(store, &cts.proto_iter, 0, label_str, 1, -1, -1);
407 /* gtk_ctree_node_set_selectable(GTK_CTREE(cts.ctree), cts.node, FALSE); */
409 prefs_module_foreach(module_prefs_show, &cts);
412 /* Button row: OK and cancel buttons */
413 bbox = gtk_hbutton_box_new();
414 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
415 gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
416 gtk_container_add(GTK_CONTAINER(main_vb), bbox);
417 gtk_widget_show(bbox);
419 ok_bt = gtk_button_new_from_stock(GTK_STOCK_OK);
420 g_signal_connect(G_OBJECT(ok_bt), "clicked",
421 G_CALLBACK(prefs_main_ok_cb), GTK_OBJECT(prefs_w));
422 GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT);
423 gtk_box_pack_start (GTK_BOX (bbox), ok_bt, TRUE, TRUE, 0);
424 gtk_widget_grab_default(ok_bt);
425 gtk_widget_show(ok_bt);
427 apply_bt = gtk_button_new_from_stock(GTK_STOCK_APPLY);
428 g_signal_connect(G_OBJECT(apply_bt), "clicked",
429 G_CALLBACK(prefs_main_apply_cb), GTK_OBJECT(prefs_w));
430 GTK_WIDGET_SET_FLAGS(apply_bt, GTK_CAN_DEFAULT);
431 gtk_box_pack_start(GTK_BOX (bbox), apply_bt, TRUE, TRUE, 0);
432 gtk_widget_show(apply_bt);
434 save_bt = gtk_button_new_from_stock(GTK_STOCK_SAVE);
435 g_signal_connect(G_OBJECT(save_bt), "clicked",
436 G_CALLBACK(prefs_main_save_cb), GTK_OBJECT(prefs_w));
437 GTK_WIDGET_SET_FLAGS(save_bt, GTK_CAN_DEFAULT);
438 gtk_box_pack_start (GTK_BOX (bbox), save_bt, TRUE, TRUE, 0);
439 gtk_widget_show(save_bt);
441 cancel_bt = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
442 g_signal_connect(G_OBJECT(cancel_bt), "clicked",
443 G_CALLBACK(prefs_main_cancel_cb), GTK_OBJECT(prefs_w));
444 GTK_WIDGET_SET_FLAGS(cancel_bt, GTK_CAN_DEFAULT);
445 gtk_box_pack_start (GTK_BOX (bbox), cancel_bt, TRUE, TRUE, 0);
446 gtk_widget_show(cancel_bt);
448 /* Catch the "key_press_event" signal in the window, so that we can catch
449 the ESC key being pressed and act as if the "Cancel" button had
451 dlg_set_cancel(prefs_w, cancel_bt);
453 gtk_widget_show(prefs_w);
455 g_object_unref(G_OBJECT(store));
459 set_option_label(GtkWidget *main_tb, int table_position,
460 const gchar *label_text, const gchar *tooltip_text, GtkTooltips *tooltips)
463 GtkWidget *event_box;
465 label = gtk_label_new(label_text);
466 gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
467 gtk_widget_show(label);
469 event_box = gtk_event_box_new();
470 gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box, 0, 1,
471 table_position, table_position + 1);
472 if (tooltip_text != NULL && tooltips != NULL)
473 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
474 gtk_container_add(GTK_CONTAINER(event_box), label);
475 gtk_widget_show(event_box);
479 create_preference_check_button(GtkWidget *main_tb, int table_position,
480 const gchar *label_text, const gchar *tooltip_text, gboolean active)
482 GtkTooltips *tooltips;
483 GtkWidget *check_box;
485 tooltips = gtk_object_get_data(GTK_OBJECT(main_tb), E_TOOLTIPS_KEY);
487 set_option_label(main_tb, table_position, label_text, tooltip_text,
490 check_box = gtk_check_button_new();
491 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_box), active);
492 gtk_table_attach_defaults(GTK_TABLE(main_tb), check_box, 1, 2,
493 table_position, table_position + 1);
494 if (tooltip_text != NULL && tooltips != NULL)
495 gtk_tooltips_set_tip(tooltips, check_box, tooltip_text, NULL);
501 create_preference_radio_buttons(GtkWidget *main_tb, int table_position,
502 const gchar *label_text, const gchar *tooltip_text,
503 const enum_val_t *enumvals, gint current_val)
505 GtkTooltips *tooltips;
506 GtkWidget *radio_button_hbox, *button = NULL;
509 const enum_val_t *enum_valp;
510 GtkWidget *event_box;
512 tooltips = gtk_object_get_data(GTK_OBJECT(main_tb), E_TOOLTIPS_KEY);
514 set_option_label(main_tb, table_position, label_text, tooltip_text,
517 radio_button_hbox = gtk_hbox_new(FALSE, 0);
519 for (enum_valp = enumvals, index = 0; enum_valp->name != NULL;
520 enum_valp++, index++) {
521 button = gtk_radio_button_new_with_label(rb_group,
523 gtk_widget_show(button);
524 if (rb_group == NULL)
525 rb_group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
526 gtk_box_pack_start(GTK_BOX(radio_button_hbox), button, FALSE,
528 if (enum_valp->value == current_val) {
529 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button),
533 gtk_widget_show(radio_button_hbox);
535 event_box = gtk_event_box_new();
536 gtk_container_add(GTK_CONTAINER(event_box), radio_button_hbox);
537 gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box, 1, 2,
538 table_position, table_position+1);
539 if (tooltip_text != NULL && tooltips != NULL)
540 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
541 gtk_widget_show(event_box);
544 * It doesn't matter which of the buttons we return - we fetch
545 * the value by looking at the entire radio button group to
546 * which it belongs, and we can get that from any button.
552 label_to_enum_val(GtkWidget *label, const enum_val_t *enumvals)
557 /* Get the label's text, and translate it to a value. */
558 gtk_label_get(GTK_LABEL(label), &label_string);
559 enumval = find_val_for_string(label_string, enumvals, 1);
565 fetch_preference_radio_buttons_val(GtkWidget *button,
566 const enum_val_t *enumvals)
572 * Go through the list of of radio buttons in the button's group,
573 * and find the first one that's active.
575 rb_group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
577 for (rb_entry = rb_group; rb_entry != NULL;
578 rb_entry = g_slist_next(rb_entry)) {
579 button = rb_entry->data;
580 if (GTK_TOGGLE_BUTTON(button)->active)
584 /* OK, now return the value corresponding to that button's label. */
585 return label_to_enum_val(GTK_BIN(button)->child, enumvals);
589 create_preference_option_menu(GtkWidget *main_tb, int table_position,
590 const gchar *label_text, const gchar *tooltip_text,
591 const enum_val_t *enumvals, gint current_val)
593 GtkTooltips *tooltips;
594 GtkWidget *menu_box, *menu, *menu_item, *option_menu;
595 int menu_index, index;
596 const enum_val_t *enum_valp;
597 GtkWidget *event_box;
599 tooltips = gtk_object_get_data(GTK_OBJECT(main_tb), E_TOOLTIPS_KEY);
601 set_option_label(main_tb, table_position, label_text, tooltip_text,
604 /* Create a menu from the enumvals */
605 menu = gtk_menu_new();
606 if (tooltip_text != NULL && tooltips != NULL)
607 gtk_tooltips_set_tip(tooltips, menu, tooltip_text, NULL);
609 for (enum_valp = enumvals, index = 0; enum_valp->name != NULL;
610 enum_valp++, index++) {
611 menu_item = gtk_menu_item_new_with_label(enum_valp->name);
612 gtk_menu_append(GTK_MENU(menu), menu_item);
613 if (enum_valp->value == current_val)
615 gtk_widget_show(menu_item);
618 /* Create the option menu from the menu */
619 option_menu = gtk_option_menu_new();
620 gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), menu);
622 /* Set its current value to the variable's current value */
623 if (menu_index != -1)
624 gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu),
628 * Put the option menu in an hbox, so that it's only as wide
629 * as the widest entry, rather than being as wide as the table
632 menu_box = gtk_hbox_new(FALSE, 0);
633 gtk_box_pack_start(GTK_BOX(menu_box), option_menu, FALSE, FALSE, 0);
635 event_box = gtk_event_box_new();
636 gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box,
637 1, 2, table_position, table_position + 1);
638 if (tooltip_text != NULL && tooltips != NULL)
639 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
640 gtk_container_add(GTK_CONTAINER(event_box), menu_box);
646 fetch_preference_option_menu_val(GtkWidget *optmenu, const enum_val_t *enumvals)
649 * OK, now return the value corresponding to the label for the
650 * currently active entry in the option menu.
652 * Yes, this is how you get the label for that entry. See FAQ
653 * 6.8 in the GTK+ FAQ.
655 return label_to_enum_val(GTK_BIN(optmenu)->child, enumvals);
659 create_preference_entry(GtkWidget *main_tb, int table_position,
660 const gchar *label_text, const gchar *tooltip_text, char *value)
662 GtkTooltips *tooltips;
665 tooltips = gtk_object_get_data(GTK_OBJECT(main_tb), E_TOOLTIPS_KEY);
667 set_option_label(main_tb, table_position, label_text, tooltip_text,
670 entry = gtk_entry_new();
672 gtk_entry_set_text(GTK_ENTRY(entry), value);
673 gtk_table_attach_defaults(GTK_TABLE(main_tb), entry, 1, 2,
674 table_position, table_position + 1);
675 if (tooltip_text != NULL && tooltips != NULL)
676 gtk_tooltips_set_tip(tooltips, entry, tooltip_text, NULL);
677 gtk_widget_show(entry);
683 pref_fetch(pref_t *pref, gpointer user_data)
690 gboolean *pref_changed_p = user_data;
692 /* Fetch the value of the preference, and set the appropriate variable
694 switch (pref->type) {
697 str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
698 uval = strtoul(str_val, &p, pref->info.base);
700 if (p == value || *p != '\0')
701 return PREFS_SET_SYNTAX_ERR; /* number was bad */
703 if (*pref->varp.uint != uval) {
704 *pref_changed_p = TRUE;
705 *pref->varp.uint = uval;
710 bval = GTK_TOGGLE_BUTTON(pref->control)->active;
711 if (*pref->varp.boolp != bval) {
712 *pref_changed_p = TRUE;
713 *pref->varp.boolp = bval;
718 if (pref->info.enum_info.radio_buttons) {
719 enumval = fetch_preference_radio_buttons_val(pref->control,
720 pref->info.enum_info.enumvals);
722 enumval = fetch_preference_option_menu_val(pref->control,
723 pref->info.enum_info.enumvals);
726 if (*pref->varp.enump != enumval) {
727 *pref_changed_p = TRUE;
728 *pref->varp.enump = enumval;
733 str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
734 if (*pref->varp.string == NULL || strcmp(*pref->varp.string, str_val) != 0) {
735 *pref_changed_p = TRUE;
736 if (*pref->varp.string != NULL)
737 g_free(*pref->varp.string);
738 *pref->varp.string = g_strdup(str_val);
743 g_assert_not_reached();
749 module_prefs_fetch(module_t *module, gpointer user_data)
751 gboolean *must_redissect_p = user_data;
753 /* For all preferences in this module, fetch its value from this
754 module's notebook page. Find out whether any of them changed. */
755 module->prefs_changed = FALSE; /* assume none of them changed */
756 prefs_pref_foreach(module, pref_fetch, &module->prefs_changed);
758 /* If any of them changed, indicate that we must redissect and refilter
759 the current capture (if we have one), as the preference change
760 could cause packets to be dissected differently. */
761 if (module->prefs_changed)
762 *must_redissect_p = TRUE;
766 pref_clean(pref_t *pref, gpointer user_data _U_)
768 switch (pref->type) {
780 if (pref->saved_val.string != NULL) {
781 g_free(pref->saved_val.string);
782 pref->saved_val.string = NULL;
787 g_assert_not_reached();
793 module_prefs_clean(module_t *module, gpointer user_data _U_)
795 /* For all preferences in this module, clean up any cruft allocated for
796 use by the GUI code. */
797 prefs_pref_foreach(module, pref_clean, NULL);
801 prefs_main_ok_cb(GtkWidget *ok_bt _U_, gpointer parent_w)
803 gboolean must_redissect = FALSE;
805 /* Fetch the preferences (i.e., make sure all the values set in all of
806 the preferences panes have been copied to "prefs" and the registered
808 printer_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
810 column_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
812 stream_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
814 gui_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
818 /* Is WPcap loaded? */
821 capture_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
822 E_CAPTURE_PAGE_KEY));
826 #endif /* HAVE_LIBPCAP */
827 nameres_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
828 E_NAMERES_PAGE_KEY));
829 prefs_module_foreach(module_prefs_fetch, &must_redissect);
831 /* Now apply those preferences. */
832 printer_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
834 column_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
836 stream_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
838 gui_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
842 /* Is WPcap loaded? */
845 capture_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
846 E_CAPTURE_PAGE_KEY));
850 #endif /* HAVE_LIBPCAP */
851 nameres_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
852 E_NAMERES_PAGE_KEY));
855 /* Now destroy the "Preferences" dialog. */
856 gtk_widget_destroy(GTK_WIDGET(parent_w));
858 if (must_redissect) {
859 /* Redissect all the packets, and re-evaluate the display filter. */
860 redissect_packets(&cfile);
865 prefs_main_apply_cb(GtkWidget *apply_bt _U_, gpointer parent_w)
867 gboolean must_redissect = FALSE;
869 /* Fetch the preferences (i.e., make sure all the values set in all of
870 the preferences panes have been copied to "prefs" and the registered
872 printer_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
874 column_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
876 stream_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
878 gui_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
881 /* Is WPcap loaded? */
884 capture_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
885 E_CAPTURE_PAGE_KEY));
889 #endif /* HAVE_LIBPCAP */
890 nameres_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
891 E_NAMERES_PAGE_KEY));
892 prefs_module_foreach(module_prefs_fetch, &must_redissect);
894 /* Now apply those preferences. */
895 printer_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
897 column_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
899 stream_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
901 gui_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
904 /* Is WPcap loaded? */
907 capture_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
908 E_CAPTURE_PAGE_KEY));
912 #endif /* HAVE_LIBPCAP */
913 nameres_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
914 E_NAMERES_PAGE_KEY));
917 if (must_redissect) {
918 /* Redissect all the packets, and re-evaluate the display filter. */
919 redissect_packets(&cfile);
924 prefs_main_save_cb(GtkWidget *save_bt _U_, gpointer parent_w)
926 gboolean must_redissect = FALSE;
931 /* Fetch the preferences (i.e., make sure all the values set in all of
932 the preferences panes have been copied to "prefs" and the registered
934 printer_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
936 column_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
938 stream_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
940 gui_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
943 /* Is WPcap loaded? */
946 capture_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
947 E_CAPTURE_PAGE_KEY));
951 #endif /* HAVE_LIBPCAP */
952 nameres_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
953 E_NAMERES_PAGE_KEY));
954 prefs_module_foreach(module_prefs_fetch, &must_redissect);
956 /* Create the directory that holds personal configuration files, if
958 if (create_persconffile_dir(&pf_dir_path) == -1) {
959 simple_dialog(ESD_TYPE_WARN, NULL,
960 "Can't create directory\n\"%s\"\nfor preferences file: %s.", pf_dir_path,
964 /* Write the preferencs out. */
965 err = write_prefs(&pf_path);
967 simple_dialog(ESD_TYPE_WARN, NULL,
968 "Can't open preferences file\n\"%s\": %s.", pf_path,
974 /* Now apply those preferences.
975 XXX - should we do this? The user didn't click "OK" or "Apply".
978 1) by saving the preferences they presumably indicate that they
981 2) the next time they fire Ethereal up, those preferences will
984 3) we'd have to buffer "must_redissect" so that if they do
985 "Apply" after this, we know we have to redissect;
987 4) we did apply the protocol preferences, at least, in the past. */
988 printer_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
990 column_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
992 stream_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
994 gui_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
997 /* Is WPcap loaded? */
1000 capture_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
1001 E_CAPTURE_PAGE_KEY));
1005 #endif /* HAVE_LIBPCAP */
1006 nameres_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
1007 E_NAMERES_PAGE_KEY));
1010 if (must_redissect) {
1011 /* Redissect all the packets, and re-evaluate the display filter. */
1012 redissect_packets(&cfile);
1017 pref_revert(pref_t *pref, gpointer user_data)
1019 gboolean *pref_changed_p = user_data;
1021 /* Revert the preference to its saved value. */
1022 switch (pref->type) {
1025 if (*pref->varp.uint != pref->saved_val.uint) {
1026 *pref_changed_p = TRUE;
1027 *pref->varp.uint = pref->saved_val.uint;
1032 if (*pref->varp.boolp != pref->saved_val.boolval) {
1033 *pref_changed_p = TRUE;
1034 *pref->varp.boolp = pref->saved_val.boolval;
1039 if (*pref->varp.enump != pref->saved_val.enumval) {
1040 *pref_changed_p = TRUE;
1041 *pref->varp.enump = pref->saved_val.enumval;
1046 if (*pref->varp.string != pref->saved_val.string &&
1047 (*pref->varp.string == NULL ||
1048 pref->saved_val.string == NULL ||
1049 strcmp(*pref->varp.string, pref->saved_val.string) != 0)) {
1050 *pref_changed_p = TRUE;
1051 if (*pref->varp.string != NULL)
1052 g_free(*pref->varp.string);
1053 *pref->varp.string = g_strdup(pref->saved_val.string);
1058 g_assert_not_reached();
1064 module_prefs_revert(module_t *module, gpointer user_data)
1066 gboolean *must_redissect_p = user_data;
1068 /* For all preferences in this module, revert its value to the value
1069 it had when we popped up the Preferences dialog. Find out whether
1070 this changes any of them. */
1071 module->prefs_changed = FALSE; /* assume none of them changed */
1072 prefs_pref_foreach(module, pref_revert, &module->prefs_changed);
1074 /* If any of them changed, indicate that we must redissect and refilter
1075 the current capture (if we have one), as the preference change
1076 could cause packets to be dissected differently. */
1077 if (module->prefs_changed)
1078 *must_redissect_p = TRUE;
1082 prefs_main_cancel_cb(GtkWidget *cancel_bt _U_, gpointer parent_w)
1084 gboolean must_redissect = FALSE;
1086 /* Free up the current preferences and copy the saved preferences to the
1087 current preferences. */
1089 copy_prefs(&prefs, &saved_prefs);
1091 /* Now revert the registered preferences. */
1092 prefs_module_foreach(module_prefs_revert, &must_redissect);
1094 /* Now apply the reverted-to preferences. */
1095 printer_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
1097 column_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
1098 E_COLUMN_PAGE_KEY));
1099 stream_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
1100 E_STREAM_PAGE_KEY));
1101 gui_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
1102 nameres_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
1103 E_NAMERES_PAGE_KEY));
1106 gtk_widget_destroy(GTK_WIDGET(parent_w));
1108 if (must_redissect) {
1109 /* Redissect all the packets, and re-evaluate the display filter. */
1110 redissect_packets(&cfile);
1114 /* Treat this as a cancel, by calling "prefs_main_cancel_cb()".
1115 XXX - that'll destroy the Preferences dialog; will that upset
1116 a higher-level handler that says "OK, we've been asked to delete
1117 this, so destroy it"? */
1119 prefs_main_delete_cb(GtkWidget *prefs_w, gpointer dummy _U_)
1121 prefs_main_cancel_cb(NULL, prefs_w);
1126 prefs_main_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1128 /* Let the preference tabs clean up anything they've done. */
1129 printer_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w),
1131 column_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w),
1132 E_COLUMN_PAGE_KEY));
1133 stream_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w),
1134 E_STREAM_PAGE_KEY));
1135 gui_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w), E_GUI_PAGE_KEY));
1138 /* Is WPcap loaded? */
1141 capture_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w),
1142 E_CAPTURE_PAGE_KEY));
1146 #endif /* HAVE_LIBPCAP */
1147 nameres_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w),
1148 E_NAMERES_PAGE_KEY));
1150 /* Free up the saved preferences (both for "prefs" and for registered
1152 free_prefs(&saved_prefs);
1153 prefs_module_foreach(module_prefs_clean, NULL);
1155 /* Note that we no longer have a "Preferences" dialog box. */
1159 struct properties_data {
1165 /* XXX this way of searching the correct page number is really ugly ... */
1167 module_search_properties(module_t *module, gpointer user_data)
1169 struct properties_data *p = (struct properties_data *)user_data;
1171 if (p->title == NULL) return;
1172 if (strcmp(module->title, p->title) == 0) {
1174 gtk_notebook_set_page(GTK_NOTEBOOK(p->w), p->page_num);
1182 properties_cb(GtkWidget *w, gpointer dummy)
1184 gchar *title = NULL;
1185 struct properties_data p;
1187 if (finfo_selected) {
1188 header_field_info *hfinfo = finfo_selected->hfinfo;
1189 if (hfinfo->parent == -1) {
1190 title = (gchar *)prefs_get_title_by_name(hfinfo->abbrev);
1193 prefs_get_title_by_name(proto_registrar_get_abbrev(hfinfo->parent));
1201 if (prefs_w != NULL) {
1202 reactivate_window(prefs_w);
1208 p.page_num = FIRST_PROTO_PREFS_PAGE;
1211 prefs_module_foreach(module_search_properties, &p);
1215 /* Prefs tree selection callback. The node data has been loaded with
1216 the proper notebook page to load. */
1218 prefs_tree_select_cb(GtkTreeSelection *sel, gpointer dummy _U_)
1221 GtkTreeModel *model;
1224 if (gtk_tree_selection_get_selected(sel, &model, &iter))
1226 gtk_tree_model_get(model, &iter, 1, &page, -1);
1228 gtk_notebook_set_page(GTK_NOTEBOOK(notebook), page);