2 * Routines for handling preferences
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
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>
38 #include <epan/prefs.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 "layout_prefs.h"
46 #include "capture_prefs.h"
47 #include "nameres_prefs.h"
48 #include "gui_utils.h"
49 #include "dlg_utils.h"
50 #include "simple_dialog.h"
51 #include "compat_macros.h"
54 #include <epan/prefs-int.h>
58 #include "capture-wpcap.h"
60 #endif /* HAVE_LIBPCAP */
62 static void prefs_main_ok_cb(GtkWidget *, gpointer);
63 static void prefs_main_apply_cb(GtkWidget *, gpointer);
64 static void prefs_main_save_cb(GtkWidget *, gpointer);
65 static void prefs_main_cancel_cb(GtkWidget *, gpointer);
66 static gboolean prefs_main_delete_event_cb(GtkWidget *, GdkEvent *, gpointer);
67 static void prefs_main_destroy_cb(GtkWidget *, gpointer);
68 #if GTK_MAJOR_VERSION < 2
69 static void prefs_tree_select_cb(GtkCTree *, GtkCTreeNode *, gint,
72 static void prefs_tree_select_cb(GtkTreeSelection *, gpointer);
75 #define E_PREFSW_SCROLLW_KEY "prefsw_scrollw"
76 #define E_PREFSW_TREE_KEY "prefsw_tree"
77 #define E_PREFSW_NOTEBOOK_KEY "prefsw_notebook"
78 #define E_PAGE_ITER_KEY "page_iter"
79 #define E_PAGE_MODULE_KEY "page_module"
80 #define E_PAGESW_FRAME_KEY "pagesw_frame"
82 #define E_GUI_PAGE_KEY "gui_options_page"
83 #define E_GUI_LAYOUT_PAGE_KEY "gui_layout_page"
84 #define E_GUI_COLUMN_PAGE_KEY "gui_column_options_page"
85 #define E_GUI_FONT_PAGE_KEY "gui_font_options_page"
86 #define E_GUI_COLORS_PAGE_KEY "gui_colors_options_page"
87 #define E_CAPTURE_PAGE_KEY "capture_options_page"
88 #define E_PRINT_PAGE_KEY "printer_options_page"
89 #define E_NAMERES_PAGE_KEY "nameres_options_page"
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;
110 #if GTK_MAJOR_VERSION < 2
115 GtkTooltips *tooltips;
117 gboolean is_protocol;
121 pref_exists(pref_t *pref _U_, gpointer user_data _U_)
126 /* show a single preference on the GtkTable of a preference page */
128 pref_show(pref_t *pref, gpointer user_data)
130 GtkWidget *main_tb = user_data;
135 /* Give this preference a label which is its title, followed by a colon,
136 and left-align it. */
138 label_string = g_malloc(strlen(title) + 2);
139 strcpy(label_string, title);
140 strcat(label_string, ":");
142 /* Save the current value of the preference, so that we can revert it if
143 the user does "Apply" and then "Cancel", and create the control for
144 editing the preference. */
145 switch (pref->type) {
148 pref->saved_val.uint = *pref->varp.uint;
150 /* XXX - there are no uint spinbuttons, so we can't use a spinbutton.
151 Even more annoyingly, even if there were, GLib doesn't define
152 G_MAXUINT - but I think ANSI C may define UINT_MAX, so we could
154 switch (pref->info.base) {
157 g_snprintf(uint_str, 10+1, "%u", pref->saved_val.uint);
161 g_snprintf(uint_str, 10+1, "%o", pref->saved_val.uint);
165 g_snprintf(uint_str, 10+1, "%x", pref->saved_val.uint);
168 pref->control = create_preference_entry(main_tb, pref->ordinal,
169 label_string, pref->description,
174 pref->saved_val.boolval = *pref->varp.boolp;
175 pref->control = create_preference_check_button(main_tb, pref->ordinal,
176 label_string, pref->description,
177 pref->saved_val.boolval);
181 pref->saved_val.enumval = *pref->varp.enump;
182 if (pref->info.enum_info.radio_buttons) {
183 /* Show it as radio buttons. */
184 pref->control = create_preference_radio_buttons(main_tb, pref->ordinal,
185 label_string, pref->description,
186 pref->info.enum_info.enumvals,
187 pref->saved_val.enumval);
189 /* Show it as an option menu. */
190 pref->control = create_preference_option_menu(main_tb, pref->ordinal,
191 label_string, pref->description,
192 pref->info.enum_info.enumvals,
193 pref->saved_val.enumval);
198 if (pref->saved_val.string != NULL)
199 g_free(pref->saved_val.string);
200 pref->saved_val.string = g_strdup(*pref->varp.string);
201 pref->control = create_preference_entry(main_tb, pref->ordinal,
202 label_string, pref->description,
203 pref->saved_val.string);
210 if (pref->saved_val.range != NULL)
211 g_free(pref->saved_val.range);
212 pref->saved_val.range = range_copy(*pref->varp.range);
213 range_string = range_convert_range(*pref->varp.range);
214 pref->control = create_preference_entry(main_tb, pref->ordinal,
215 label_string, pref->description,
221 g_assert_not_reached();
224 g_free(label_string);
229 #define MAX_TREE_NODE_NAME_LEN 64
230 /* show prefs page for each registered module (protocol) */
232 module_prefs_show(module_t *module, gpointer user_data)
234 struct ct_struct *cts = user_data;
235 struct ct_struct child_cts;
236 GtkWidget *main_vb, *main_tb, *frame, *main_sw;
237 gchar label_str[MAX_TREE_NODE_NAME_LEN];
238 #if GTK_MAJOR_VERSION < 2
239 gchar *label_ptr = label_str;
240 GtkCTreeNode *ct_node;
247 * Is this module a subtree, with modules underneath it?
249 if (!module->is_subtree) {
252 * Does it have any preferences (other than possibly obsolete ones)?
254 if (prefs_pref_foreach(module, pref_exists, NULL) == 0) {
256 * No. Don't put the module into the preferences window.
257 * XXX - we should do the same for subtrees; if a subtree has
258 * nothing under it that will be displayed, don't put it into
266 * Add this module to the tree.
268 strcpy(label_str, module->title);
269 #if GTK_MAJOR_VERSION < 2
270 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts->tree), cts->node, NULL,
271 &label_ptr, 5, NULL, NULL, NULL, NULL, !module->is_subtree,
274 model = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(cts->tree)));
275 if (module->is_subtree)
276 gtk_tree_store_append(model, &iter, NULL);
278 gtk_tree_store_append(model, &iter, &cts->iter);
284 if (module->is_subtree) {
289 /* Note that there's no page attached to this item */
290 #if GTK_MAJOR_VERSION < 2
291 gtk_ctree_node_set_row_data(GTK_CTREE(cts->tree), ct_node,
292 GINT_TO_POINTER(-1));
294 gtk_tree_store_set(model, &iter, 0, label_str, 1, -1, -1);
298 * Walk the subtree and attach stuff to it.
301 #if GTK_MAJOR_VERSION < 2
302 child_cts.node = ct_node;
304 child_cts.iter = iter;
306 if (module == protocols_module)
307 child_cts.is_protocol = TRUE;
308 prefs_module_list_foreach(module->prefs, module_prefs_show, &child_cts);
311 * No. Create a notebook page for it.
314 /* Scrolled window */
315 main_sw = gtk_scrolled_window_new(NULL, NULL);
316 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(main_sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
319 frame = gtk_frame_new(module->description);
320 gtk_container_set_border_width(GTK_CONTAINER(frame), 5);
321 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(main_sw), frame);
322 OBJECT_SET_DATA(main_sw, E_PAGESW_FRAME_KEY, frame);
324 /* Main vertical box */
325 main_vb = gtk_vbox_new(FALSE, 5);
326 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
327 gtk_container_add(GTK_CONTAINER(frame), main_vb);
330 main_tb = gtk_table_new(module->numprefs, 2, FALSE);
331 gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0);
332 gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10);
333 gtk_table_set_col_spacings(GTK_TABLE(main_tb), 15);
334 OBJECT_SET_DATA(main_tb, E_TOOLTIPS_KEY, cts->tooltips);
336 /* Add items for each of the preferences */
337 prefs_pref_foreach(module, pref_show, main_tb);
339 /* Associate this module with the page's frame. */
340 OBJECT_SET_DATA(frame, E_PAGE_MODULE_KEY, module);
342 /* Add the page to the notebook */
343 gtk_notebook_append_page(GTK_NOTEBOOK(cts->notebook), main_sw, NULL);
345 /* Attach the page to the tree item */
346 #if GTK_MAJOR_VERSION < 2
347 gtk_ctree_node_set_row_data(GTK_CTREE(cts->tree), ct_node,
348 GINT_TO_POINTER(cts->page));
349 OBJECT_SET_DATA(frame, E_PAGE_ITER_KEY, ct_node);
351 gtk_tree_store_set(model, &iter, 0, label_str, 1, cts->page, -1);
352 OBJECT_SET_DATA(frame, E_PAGE_ITER_KEY, gtk_tree_iter_copy(&iter));
357 /* Show 'em what we got */
358 gtk_widget_show_all(main_sw);
365 #if GTK_MAJOR_VERSION < 2
366 #define prefs_tree_iter GtkCTreeNode *
368 #define prefs_tree_iter GtkTreeIter
371 /* add a page to the tree */
372 static prefs_tree_iter
373 prefs_tree_page_add(const gchar *title, gint page_nr,
374 gpointer store, prefs_tree_iter *parent_iter,
376 #if GTK_MAJOR_VERSION >= 2
381 #if GTK_MAJOR_VERSION < 2
382 const gchar *label_ptr = title;
384 prefs_tree_iter iter;
386 #if GTK_MAJOR_VERSION < 2
387 iter = gtk_ctree_insert_node(GTK_CTREE(store), parent_iter ? *parent_iter : NULL, NULL,
388 (gchar **) &label_ptr, 5, NULL, NULL, NULL, NULL, !has_child, TRUE);
389 gtk_ctree_node_set_row_data(GTK_CTREE(store), iter,
390 GINT_TO_POINTER(page_nr));
392 gtk_tree_store_append(store, &iter, parent_iter);
393 gtk_tree_store_set(store, &iter, 0, title, 1, page_nr, -1);
398 /* add a page to the notebook */
400 prefs_nb_page_add(GtkWidget *notebook, const gchar *title, GtkWidget *page, const char *page_key)
404 frame = gtk_frame_new(title);
405 gtk_widget_show(frame);
406 gtk_container_add(GTK_CONTAINER(frame), page);
407 OBJECT_SET_DATA(prefs_w, page_key, page);
408 gtk_notebook_append_page (GTK_NOTEBOOK(notebook), frame, NULL);
414 /* show the dialog */
416 prefs_cb(GtkWidget *w _U_, gpointer dummy _U_)
418 GtkWidget *top_hb, *bbox, *prefs_nb, *ct_sb,
419 *ok_bt, *apply_bt, *save_bt, *cancel_bt, *help_bt;
420 GtkWidget *gui_font_pg;
421 gchar label_str[MAX_TREE_NODE_NAME_LEN];
422 struct ct_struct cts;
423 #if GTK_MAJOR_VERSION < 2
424 gpointer store = NULL;
425 static gchar *fixedwidths[] = { "c", "m", NULL };
428 GtkTreeSelection *selection;
429 GtkCellRenderer *renderer;
430 GtkTreeViewColumn *column;
433 prefs_tree_iter gui_iter;
436 if (prefs_w != NULL) {
437 /* There's already a "Preferences" dialog box; reactivate it. */
438 reactivate_window(prefs_w);
442 /* Save the current preferences, so we can revert to those values
443 if the user presses "Cancel". */
444 copy_prefs(&saved_prefs, &prefs);
446 prefs_w = dlg_window_new("Wireshark: Preferences");
449 * Unfortunately, we can't arrange that a GtkTable widget wrap an event box
450 * around a table row, so the spacing between the preference item's label
451 * and its control widgets is inactive and the tooltip doesn't pop up when
452 * the mouse is over it.
454 cts.tooltips = gtk_tooltips_new();
456 /* Container for each row of widgets */
457 cts.main_vb = gtk_vbox_new(FALSE, 5);
458 gtk_container_border_width(GTK_CONTAINER(cts.main_vb), 5);
459 gtk_container_add(GTK_CONTAINER(prefs_w), cts.main_vb);
460 gtk_widget_show(cts.main_vb);
462 /* Top row: Preferences tree and notebook */
463 top_hb = gtk_hbox_new(FALSE, 10);
464 gtk_container_add(GTK_CONTAINER(cts.main_vb), top_hb);
465 gtk_widget_show(top_hb);
467 /* scrolled window on the left for the categories tree */
468 ct_sb = scrolled_window_new(NULL, NULL);
469 #if GTK_MAJOR_VERSION >= 2
470 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(ct_sb),
473 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ct_sb),
474 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
475 gtk_container_add(GTK_CONTAINER(top_hb), ct_sb);
476 gtk_widget_show(ct_sb);
477 OBJECT_SET_DATA(prefs_w, E_PREFSW_SCROLLW_KEY, ct_sb);
479 /* categories tree */
480 #if GTK_MAJOR_VERSION < 2
481 cts.tree = ctree_new(1, 0);
484 gtk_clist_set_column_auto_resize(GTK_CLIST(cts.tree), 0, TRUE);
485 SIGNAL_CONNECT(cts.tree, "tree-select-row", prefs_tree_select_cb, NULL);
486 OBJECT_SET_DATA(prefs_w, E_PREFSW_TREE_KEY, cts.tree);
488 store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_INT);
489 cts.tree = tree_view_new(GTK_TREE_MODEL(store));
490 OBJECT_SET_DATA(prefs_w, E_PREFSW_TREE_KEY, cts.tree);
491 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(cts.tree), FALSE);
492 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(cts.tree));
493 gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
494 renderer = gtk_cell_renderer_text_new();
495 col_offset = gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(cts.tree),
496 -1, "Name", renderer,
498 column = gtk_tree_view_get_column(GTK_TREE_VIEW(cts.tree),
500 gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column),
501 GTK_TREE_VIEW_COLUMN_AUTOSIZE);
502 SIGNAL_CONNECT(selection, "changed", prefs_tree_select_cb, NULL);
504 gtk_container_add(GTK_CONTAINER(ct_sb), cts.tree);
505 gtk_widget_show(cts.tree);
507 /* A notebook widget without tabs is used to flip between prefs */
508 prefs_nb = gtk_notebook_new();
509 OBJECT_SET_DATA(prefs_w, E_PREFSW_NOTEBOOK_KEY, prefs_nb);
510 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(prefs_nb), FALSE);
511 gtk_notebook_set_show_border(GTK_NOTEBOOK(prefs_nb), FALSE);
512 gtk_container_add(GTK_CONTAINER(top_hb), prefs_nb);
513 gtk_widget_show(prefs_nb);
518 strcpy(label_str, "User Interface");
519 prefs_nb_page_add(prefs_nb, label_str, gui_prefs_show(), E_GUI_PAGE_KEY);
520 gui_iter = prefs_tree_page_add(label_str, cts.page, store, NULL, TRUE);
523 /* GUI layout prefs */
524 strcpy(label_str, "Layout");
525 prefs_nb_page_add(prefs_nb, label_str, layout_prefs_show(), E_GUI_LAYOUT_PAGE_KEY);
526 prefs_tree_page_add(label_str, cts.page, store, &gui_iter, FALSE);
529 /* GUI Column prefs */
530 strcpy(label_str, "Columns");
531 prefs_nb_page_add(prefs_nb, label_str, column_prefs_show(), E_GUI_COLUMN_PAGE_KEY);
532 prefs_tree_page_add(label_str, cts.page, store, &gui_iter, FALSE);
536 strcpy(label_str, "Font");
537 gui_font_pg = gui_font_prefs_show();
538 prefs_nb_page_add(prefs_nb, label_str, gui_font_pg, E_GUI_FONT_PAGE_KEY);
539 prefs_tree_page_add(label_str, cts.page, store, &gui_iter, FALSE);
542 gtk_container_border_width( GTK_CONTAINER(gui_font_pg), 5 );
544 /* IMPORTANT: the following gtk_font_selection_set_xy() functions will only
545 work, if the widget and it's corresponding window is already shown
546 (so don't put the following into gui_font_prefs_show()) !!! */
548 /* We set the current font and, for GTK+ 1.2[.x], the font filter
549 now, because they appear not to work when run before appending
550 the frame to the notebook. */
552 /* Set the font to the current font.
553 XXX - GTK+ 1.2.8, and probably earlier versions, have a bug
554 wherein that doesn't necessarily cause that font to be
555 selected in the dialog box. I've sent to the GTK+ folk
556 a fix; hopefully, it'll show up in 1.2.9 if, as, and when
557 they put out a 1.2.9 release. */
558 gtk_font_selection_set_font_name(
559 GTK_FONT_SELECTION(gui_font_pg), prefs.PREFS_GUI_FONT_NAME);
561 #if GTK_MAJOR_VERSION < 2
562 /* Set its filter to show only fixed_width fonts. */
563 gtk_font_selection_set_filter(
564 GTK_FONT_SELECTION(gui_font_pg),
565 GTK_FONT_FILTER_BASE, /* user can't change the filter */
566 GTK_FONT_ALL, /* bitmap or scalable are fine */
567 NULL, /* all foundries are OK */
568 NULL, /* all weights are OK (XXX - normal only?) */
569 NULL, /* all slants are OK (XXX - Roman only?) */
570 NULL, /* all setwidths are OK */
571 fixedwidths, /* ONLY fixed-width fonts */
572 NULL); /* all charsets are OK (XXX - ISO 8859/1 only?) */
575 /* GUI Colors prefs */
576 strcpy(label_str, "Colors");
577 prefs_nb_page_add(prefs_nb, label_str, stream_prefs_show(), E_GUI_COLORS_PAGE_KEY);
578 prefs_tree_page_add(label_str, cts.page, store, &gui_iter, FALSE);
581 /* select the main GUI page as the default page and expand it's children */
582 #if GTK_MAJOR_VERSION < 2
583 gtk_ctree_select(GTK_CTREE(cts.tree), gui_iter);
585 gtk_tree_selection_select_iter(selection, &gui_iter);
586 /* (expand will only take effect, when at least one child exists) */
587 gtk_tree_view_expand_all(GTK_TREE_VIEW(cts.tree));
592 /* Is WPcap loaded? */
596 strcpy(label_str, "Capture");
597 prefs_nb_page_add(prefs_nb, label_str, capture_prefs_show(), E_CAPTURE_PAGE_KEY);
598 prefs_tree_page_add(label_str, cts.page, store, NULL, FALSE);
603 #endif /* HAVE_LIBPCAP */
606 strcpy(label_str, "Printing");
607 prefs_nb_page_add(prefs_nb, label_str, printer_prefs_show(), E_PRINT_PAGE_KEY);
608 prefs_tree_page_add(label_str, cts.page, store, NULL, FALSE);
611 /* Name resolution prefs */
612 strcpy(label_str, "Name Resolution");
613 prefs_nb_page_add(prefs_nb, label_str, nameres_prefs_show(), E_NAMERES_PAGE_KEY);
614 prefs_tree_page_add(label_str, cts.page, store, NULL, FALSE);
617 /* Registered prefs */
618 cts.notebook = prefs_nb;
619 cts.is_protocol = FALSE;
620 prefs_module_list_foreach(NULL, module_prefs_show, &cts);
622 /* Button row: OK and cancel buttons */
624 if(topic_available(HELP_PREFERENCES_DIALOG)) {
625 bbox = dlg_button_row_new(GTK_STOCK_HELP, GTK_STOCK_OK, GTK_STOCK_APPLY, GTK_STOCK_SAVE, GTK_STOCK_CANCEL, NULL);
627 bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_APPLY, GTK_STOCK_SAVE, GTK_STOCK_CANCEL, NULL);
629 gtk_box_pack_start(GTK_BOX(cts.main_vb), bbox, FALSE, FALSE, 0);
630 gtk_widget_show(bbox);
632 ok_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_OK);
633 SIGNAL_CONNECT(ok_bt, "clicked", prefs_main_ok_cb, prefs_w);
635 apply_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_APPLY);
636 SIGNAL_CONNECT(apply_bt, "clicked", prefs_main_apply_cb, prefs_w);
638 save_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_SAVE);
639 SIGNAL_CONNECT(save_bt, "clicked", prefs_main_save_cb, prefs_w);
641 cancel_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_CANCEL);
642 SIGNAL_CONNECT(cancel_bt, "clicked", prefs_main_cancel_cb, prefs_w);
643 window_set_cancel_button(prefs_w, cancel_bt, NULL);
645 gtk_widget_grab_default(ok_bt);
647 if(topic_available(HELP_PREFERENCES_DIALOG)) {
648 help_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_HELP);
649 SIGNAL_CONNECT(help_bt, "clicked", topic_cb, HELP_PREFERENCES_DIALOG);
652 SIGNAL_CONNECT(prefs_w, "delete_event", prefs_main_delete_event_cb, prefs_w);
653 SIGNAL_CONNECT(prefs_w, "destroy", prefs_main_destroy_cb, prefs_w);
655 gtk_widget_show(prefs_w);
656 window_present(prefs_w);
658 #if GTK_MAJOR_VERSION >= 2
659 g_object_unref(G_OBJECT(store));
664 set_option_label(GtkWidget *main_tb, int table_position,
665 const gchar *label_text, const gchar *tooltip_text, GtkTooltips *tooltips)
668 GtkWidget *event_box;
670 label = gtk_label_new(label_text);
671 gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
672 gtk_widget_show(label);
674 event_box = gtk_event_box_new();
675 gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box, 0, 1,
676 table_position, table_position + 1);
677 if (tooltip_text != NULL && tooltips != NULL)
678 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
679 gtk_container_add(GTK_CONTAINER(event_box), label);
680 gtk_widget_show(event_box);
684 create_preference_check_button(GtkWidget *main_tb, int table_position,
685 const gchar *label_text, const gchar *tooltip_text, gboolean active)
687 GtkTooltips *tooltips;
688 GtkWidget *check_box;
690 tooltips = OBJECT_GET_DATA(main_tb, E_TOOLTIPS_KEY);
692 set_option_label(main_tb, table_position, label_text, tooltip_text,
695 check_box = gtk_check_button_new();
696 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_box), active);
697 gtk_table_attach_defaults(GTK_TABLE(main_tb), check_box, 1, 2,
698 table_position, table_position + 1);
699 if (tooltip_text != NULL && tooltips != NULL)
700 gtk_tooltips_set_tip(tooltips, check_box, tooltip_text, NULL);
706 create_preference_radio_buttons(GtkWidget *main_tb, int table_position,
707 const gchar *label_text, const gchar *tooltip_text,
708 const enum_val_t *enumvals, gint current_val)
710 GtkTooltips *tooltips;
711 GtkWidget *radio_button_hbox, *button = NULL;
714 const enum_val_t *enum_valp;
715 GtkWidget *event_box;
717 tooltips = OBJECT_GET_DATA(main_tb, E_TOOLTIPS_KEY);
719 set_option_label(main_tb, table_position, label_text, tooltip_text,
722 radio_button_hbox = gtk_hbox_new(FALSE, 0);
724 for (enum_valp = enumvals, index = 0; enum_valp->name != NULL;
725 enum_valp++, index++) {
726 button = gtk_radio_button_new_with_label(rb_group,
727 enum_valp->description);
728 gtk_widget_show(button);
729 rb_group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
730 gtk_box_pack_start(GTK_BOX(radio_button_hbox), button, FALSE,
732 if (enum_valp->value == current_val) {
733 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button),
737 gtk_widget_show(radio_button_hbox);
739 event_box = gtk_event_box_new();
740 gtk_container_add(GTK_CONTAINER(event_box), radio_button_hbox);
741 gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box, 1, 2,
742 table_position, table_position+1);
743 if (tooltip_text != NULL && tooltips != NULL)
744 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
745 gtk_widget_show(event_box);
748 * It doesn't matter which of the buttons we return - we fetch
749 * the value by looking at the entire radio button group to
750 * which it belongs, and we can get that from any button.
756 label_to_enum_val(GtkWidget *label, const enum_val_t *enumvals)
761 /* Get the label's text, and translate it to a value.
762 We match only the descriptions, as those are what appear in
763 the option menu items or as labels for radio buttons.
764 We fail if we don't find a match, as that "can't happen". */
765 gtk_label_get(GTK_LABEL(label), &label_string);
767 for (i = 0; enumvals[i].name != NULL; i++) {
768 if (strcasecmp(label_string, enumvals[i].description) == 0) {
769 return enumvals[i].value;
772 g_assert_not_reached();
777 fetch_preference_radio_buttons_val(GtkWidget *button,
778 const enum_val_t *enumvals)
784 * Go through the list of of radio buttons in the button's group,
785 * and find the first one that's active.
787 rb_group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
789 for (rb_entry = rb_group; rb_entry != NULL;
790 rb_entry = g_slist_next(rb_entry)) {
791 button = rb_entry->data;
792 if (GTK_TOGGLE_BUTTON(button)->active)
796 /* OK, now return the value corresponding to that button's label. */
797 return label_to_enum_val(GTK_BIN(button)->child, enumvals);
801 create_preference_option_menu(GtkWidget *main_tb, int table_position,
802 const gchar *label_text, const gchar *tooltip_text,
803 const enum_val_t *enumvals, gint current_val)
805 GtkTooltips *tooltips;
806 GtkWidget *menu_box, *menu, *menu_item, *option_menu;
807 int menu_index, index;
808 const enum_val_t *enum_valp;
809 GtkWidget *event_box;
811 tooltips = OBJECT_GET_DATA(main_tb, E_TOOLTIPS_KEY);
813 set_option_label(main_tb, table_position, label_text, tooltip_text,
816 /* Create a menu from the enumvals */
817 menu = gtk_menu_new();
818 if (tooltip_text != NULL && tooltips != NULL)
819 gtk_tooltips_set_tip(tooltips, menu, tooltip_text, NULL);
821 for (enum_valp = enumvals, index = 0; enum_valp->name != NULL;
822 enum_valp++, index++) {
823 menu_item = gtk_menu_item_new_with_label(enum_valp->description);
824 gtk_menu_append(GTK_MENU(menu), menu_item);
825 if (enum_valp->value == current_val)
827 gtk_widget_show(menu_item);
830 /* Create the option menu from the menu */
831 option_menu = gtk_option_menu_new();
832 gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), menu);
834 /* Set its current value to the variable's current value */
835 if (menu_index != -1)
836 gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu),
840 * Put the option menu in an hbox, so that it's only as wide
841 * as the widest entry, rather than being as wide as the table
844 menu_box = gtk_hbox_new(FALSE, 0);
845 gtk_box_pack_start(GTK_BOX(menu_box), option_menu, FALSE, FALSE, 0);
847 event_box = gtk_event_box_new();
848 gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box,
849 1, 2, table_position, table_position + 1);
850 if (tooltip_text != NULL && tooltips != NULL)
851 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
852 gtk_container_add(GTK_CONTAINER(event_box), menu_box);
858 fetch_preference_option_menu_val(GtkWidget *optmenu, const enum_val_t *enumvals)
861 * OK, now return the value corresponding to the label for the
862 * currently active entry in the option menu.
864 * Yes, this is how you get the label for that entry. See FAQ
865 * 6.8 in the GTK+ FAQ.
867 return label_to_enum_val(GTK_BIN(optmenu)->child, enumvals);
871 create_preference_entry(GtkWidget *main_tb, int table_position,
872 const gchar *label_text, const gchar *tooltip_text, char *value)
874 GtkTooltips *tooltips;
877 tooltips = OBJECT_GET_DATA(main_tb, E_TOOLTIPS_KEY);
879 set_option_label(main_tb, table_position, label_text, tooltip_text,
882 entry = gtk_entry_new();
884 gtk_entry_set_text(GTK_ENTRY(entry), value);
885 gtk_table_attach_defaults(GTK_TABLE(main_tb), entry, 1, 2,
886 table_position, table_position + 1);
887 if (tooltip_text != NULL && tooltips != NULL)
888 gtk_tooltips_set_tip(tooltips, entry, tooltip_text, NULL);
889 gtk_widget_show(entry);
895 pref_check(pref_t *pref, gpointer user_data)
900 pref_t **badpref = user_data;
902 /* Fetch the value of the preference, and check whether it's valid. */
903 switch (pref->type) {
906 str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
907 uval = strtoul(str_val, &p, pref->info.base);
908 if (p == str_val || *p != '\0') {
910 return PREFS_SET_SYNTAX_ERR; /* number was bad */
915 /* Value can't be bad. */
919 /* Value can't be bad. */
923 /* Value can't be bad. */
927 str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
929 if (strlen(str_val) != 0) {
932 if (range_convert_str(&newrange, str_val, pref->info.max_value) !=
935 return PREFS_SET_SYNTAX_ERR; /* range was bad */
942 g_assert_not_reached();
949 module_prefs_check(module_t *module, gpointer user_data)
951 /* For all preferences in this module, fetch its value from this
952 module's notebook page and check whether it's valid. */
953 return prefs_pref_foreach(module, pref_check, user_data);
957 pref_fetch(pref_t *pref, gpointer user_data)
964 gboolean *pref_changed_p = user_data;
966 /* Fetch the value of the preference, and set the appropriate variable
968 switch (pref->type) {
971 str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
972 uval = strtoul(str_val, &p, pref->info.base);
974 if (p == value || *p != '\0')
975 return PREFS_SET_SYNTAX_ERR; /* number was bad */
977 if (*pref->varp.uint != uval) {
978 *pref_changed_p = TRUE;
979 *pref->varp.uint = uval;
984 bval = GTK_TOGGLE_BUTTON(pref->control)->active;
985 if (*pref->varp.boolp != bval) {
986 *pref_changed_p = TRUE;
987 *pref->varp.boolp = bval;
992 if (pref->info.enum_info.radio_buttons) {
993 enumval = fetch_preference_radio_buttons_val(pref->control,
994 pref->info.enum_info.enumvals);
996 enumval = fetch_preference_option_menu_val(pref->control,
997 pref->info.enum_info.enumvals);
1000 if (*pref->varp.enump != enumval) {
1001 *pref_changed_p = TRUE;
1002 *pref->varp.enump = enumval;
1007 str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
1008 if (strcmp(*pref->varp.string, str_val) != 0) {
1009 *pref_changed_p = TRUE;
1010 g_free((void *)*pref->varp.string);
1011 *pref->varp.string = g_strdup(str_val);
1020 str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
1021 ret = range_convert_str(&newrange, str_val, pref->info.max_value);
1022 if (ret != CVT_NO_ERROR)
1024 return PREFS_SET_SYNTAX_ERR; /* range was bad */
1026 return 0; /* XXX - should fail */
1029 if (!ranges_are_equal(*pref->varp.range, newrange)) {
1030 *pref_changed_p = TRUE;
1031 g_free(*pref->varp.range);
1032 *pref->varp.range = newrange;
1040 g_assert_not_reached();
1047 module_prefs_fetch(module_t *module, gpointer user_data)
1049 gboolean *must_redissect_p = user_data;
1051 /* For all preferences in this module, fetch its value from this
1052 module's notebook page. Find out whether any of them changed. */
1053 module->prefs_changed = FALSE; /* assume none of them changed */
1054 prefs_pref_foreach(module, pref_fetch, &module->prefs_changed);
1056 /* If any of them changed, indicate that we must redissect and refilter
1057 the current capture (if we have one), as the preference change
1058 could cause packets to be dissected differently. */
1059 if (module->prefs_changed)
1060 *must_redissect_p = TRUE;
1062 return 0; /* keep fetching module preferences */
1066 pref_clean(pref_t *pref, gpointer user_data _U_)
1068 switch (pref->type) {
1080 if (pref->saved_val.string != NULL) {
1081 g_free(pref->saved_val.string);
1082 pref->saved_val.string = NULL;
1087 if (pref->saved_val.range != NULL) {
1088 g_free(pref->saved_val.range);
1089 pref->saved_val.range = NULL;
1094 g_assert_not_reached();
1101 module_prefs_clean(module_t *module, gpointer user_data _U_)
1103 /* For all preferences in this module, clean up any cruft allocated for
1104 use by the GUI code. */
1105 prefs_pref_foreach(module, pref_clean, NULL);
1106 return 0; /* keep cleaning modules */
1109 /* fetch all pref values from all pages */
1111 prefs_main_fetch_all(GtkWidget *dlg, gboolean *must_redissect)
1115 /* First, check that the values are all valid. */
1116 /* XXX - check the non-registered preferences too */
1117 switch (prefs_modules_foreach(module_prefs_check, (gpointer)&badpref)) {
1119 case PREFS_SET_SYNTAX_ERR:
1120 switch (badpref->type) {
1123 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1124 "The value for \"%s\" isn't a valid number.",
1129 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1130 "The value for \"%s\" isn't a valid range.",
1135 g_assert_not_reached();
1140 /* Fetch the preferences (i.e., make sure all the values set in all of
1141 the preferences panes have been copied to "prefs" and the registered
1143 gui_prefs_fetch(OBJECT_GET_DATA(dlg, E_GUI_PAGE_KEY));
1144 layout_prefs_fetch(OBJECT_GET_DATA(dlg, E_GUI_LAYOUT_PAGE_KEY));
1145 column_prefs_fetch(OBJECT_GET_DATA(dlg, E_GUI_COLUMN_PAGE_KEY));
1146 stream_prefs_fetch(OBJECT_GET_DATA(dlg, E_GUI_COLORS_PAGE_KEY));
1150 /* Is WPcap loaded? */
1153 capture_prefs_fetch(OBJECT_GET_DATA(dlg, E_CAPTURE_PAGE_KEY));
1157 #endif /* HAVE_LIBPCAP */
1158 printer_prefs_fetch(OBJECT_GET_DATA(dlg, E_PRINT_PAGE_KEY));
1159 nameres_prefs_fetch(OBJECT_GET_DATA(dlg, E_NAMERES_PAGE_KEY));
1161 prefs_modules_foreach(module_prefs_fetch, must_redissect);
1166 /* apply all pref values to the real world */
1168 prefs_main_apply_all(GtkWidget *dlg)
1171 * Apply the protocol preferences first - "gui_prefs_apply()" could
1172 * cause redissection, and we have to make sure the protocol
1173 * preference changes have been fully applied.
1177 gui_prefs_apply(OBJECT_GET_DATA(dlg, E_GUI_PAGE_KEY));
1178 layout_prefs_apply(OBJECT_GET_DATA(dlg, E_GUI_LAYOUT_PAGE_KEY));
1179 column_prefs_apply(OBJECT_GET_DATA(dlg, E_GUI_COLUMN_PAGE_KEY));
1180 stream_prefs_apply(OBJECT_GET_DATA(dlg, E_GUI_COLORS_PAGE_KEY));
1184 /* Is WPcap loaded? */
1187 capture_prefs_apply(OBJECT_GET_DATA(dlg, E_CAPTURE_PAGE_KEY));
1191 #endif /* HAVE_LIBPCAP */
1192 printer_prefs_apply(OBJECT_GET_DATA(dlg, E_PRINT_PAGE_KEY));
1193 nameres_prefs_apply(OBJECT_GET_DATA(dlg, E_NAMERES_PAGE_KEY));
1197 /* destroy all preferences ressources from all pages */
1199 prefs_main_destroy_all(GtkWidget *dlg)
1201 #if GTK_MAJOR_VERSION >= 2
1206 (frame = gtk_notebook_get_nth_page(OBJECT_GET_DATA(prefs_w, E_PREFSW_NOTEBOOK_KEY), page_num)) != NULL;
1208 if(OBJECT_GET_DATA(frame, E_PAGE_ITER_KEY))
1209 gtk_tree_iter_free(OBJECT_GET_DATA(frame, E_PAGE_ITER_KEY));
1213 gui_prefs_destroy(OBJECT_GET_DATA(dlg, E_GUI_PAGE_KEY));
1214 layout_prefs_destroy(OBJECT_GET_DATA(dlg, E_GUI_LAYOUT_PAGE_KEY));
1215 column_prefs_destroy(OBJECT_GET_DATA(dlg, E_GUI_COLUMN_PAGE_KEY));
1216 stream_prefs_destroy(OBJECT_GET_DATA(dlg, E_GUI_COLORS_PAGE_KEY));
1220 /* Is WPcap loaded? */
1223 capture_prefs_destroy(OBJECT_GET_DATA(dlg, E_CAPTURE_PAGE_KEY));
1227 #endif /* HAVE_LIBPCAP */
1228 printer_prefs_destroy(OBJECT_GET_DATA(dlg, E_PRINT_PAGE_KEY));
1229 nameres_prefs_destroy(OBJECT_GET_DATA(dlg, E_NAMERES_PAGE_KEY));
1231 /* Free up the saved preferences (both for "prefs" and for registered
1233 free_prefs(&saved_prefs);
1234 prefs_modules_foreach(module_prefs_clean, NULL);
1239 prefs_main_ok_cb(GtkWidget *ok_bt _U_, gpointer parent_w)
1241 gboolean must_redissect = FALSE;
1243 if (!prefs_main_fetch_all(parent_w, &must_redissect))
1244 return; /* Errors in some preference setting */
1246 prefs_main_apply_all(parent_w);
1248 /* Now destroy the "Preferences" dialog. */
1249 window_destroy(GTK_WIDGET(parent_w));
1251 if (must_redissect) {
1252 /* Redissect all the packets, and re-evaluate the display filter. */
1253 cf_redissect_packets(&cfile);
1258 prefs_main_apply_cb(GtkWidget *apply_bt _U_, gpointer parent_w)
1260 gboolean must_redissect = FALSE;
1262 if (!prefs_main_fetch_all(parent_w, &must_redissect))
1263 return; /* Errors in some preference setting */
1265 prefs_main_apply_all(parent_w);
1267 if (must_redissect) {
1268 /* Redissect all the packets, and re-evaluate the display filter. */
1269 cf_redissect_packets(&cfile);
1274 prefs_main_save_cb(GtkWidget *save_bt _U_, gpointer parent_w)
1276 gboolean must_redissect = FALSE;
1281 if (!prefs_main_fetch_all(parent_w, &must_redissect))
1282 return; /* Errors in some preference setting */
1284 /* Create the directory that holds personal configuration files, if
1286 if (create_persconffile_dir(&pf_dir_path) == -1) {
1287 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1288 "Can't create directory\n\"%s\"\nfor preferences file: %s.", pf_dir_path,
1290 g_free(pf_dir_path);
1292 /* Write the preferencs out. */
1293 err = write_prefs(&pf_path);
1295 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1296 "Can't open preferences file\n\"%s\": %s.", pf_path,
1302 /* Now apply those preferences.
1303 XXX - should we do this? The user didn't click "OK" or "Apply".
1306 1) by saving the preferences they presumably indicate that they
1309 2) the next time they fire Wireshark up, those preferences will
1312 3) we'd have to buffer "must_redissect" so that if they do
1313 "Apply" after this, we know we have to redissect;
1315 4) we did apply the protocol preferences, at least, in the past. */
1316 prefs_main_apply_all(parent_w);
1318 if (must_redissect) {
1319 /* Redissect all the packets, and re-evaluate the display filter. */
1320 cf_redissect_packets(&cfile);
1325 pref_revert(pref_t *pref, gpointer user_data)
1327 gboolean *pref_changed_p = user_data;
1329 /* Revert the preference to its saved value. */
1330 switch (pref->type) {
1333 if (*pref->varp.uint != pref->saved_val.uint) {
1334 *pref_changed_p = TRUE;
1335 *pref->varp.uint = pref->saved_val.uint;
1340 if (*pref->varp.boolp != pref->saved_val.boolval) {
1341 *pref_changed_p = TRUE;
1342 *pref->varp.boolp = pref->saved_val.boolval;
1347 if (*pref->varp.enump != pref->saved_val.enumval) {
1348 *pref_changed_p = TRUE;
1349 *pref->varp.enump = pref->saved_val.enumval;
1354 if (strcmp(*pref->varp.string, pref->saved_val.string) != 0) {
1355 *pref_changed_p = TRUE;
1356 g_free((void *)*pref->varp.string);
1357 *pref->varp.string = g_strdup(pref->saved_val.string);
1362 if (!ranges_are_equal(*pref->varp.range, pref->saved_val.range)) {
1363 *pref_changed_p = TRUE;
1364 g_free(*pref->varp.range);
1365 *pref->varp.range = range_copy(pref->saved_val.range);
1370 g_assert_not_reached();
1377 module_prefs_revert(module_t *module, gpointer user_data)
1379 gboolean *must_redissect_p = user_data;
1381 /* For all preferences in this module, revert its value to the value
1382 it had when we popped up the Preferences dialog. Find out whether
1383 this changes any of them. */
1384 module->prefs_changed = FALSE; /* assume none of them changed */
1385 prefs_pref_foreach(module, pref_revert, &module->prefs_changed);
1387 /* If any of them changed, indicate that we must redissect and refilter
1388 the current capture (if we have one), as the preference change
1389 could cause packets to be dissected differently. */
1390 if (module->prefs_changed)
1391 *must_redissect_p = TRUE;
1392 return 0; /* keep processing modules */
1395 /* cancel button pressed, revert prefs to saved and exit dialog */
1397 prefs_main_cancel_cb(GtkWidget *cancel_bt _U_, gpointer parent_w)
1399 gboolean must_redissect = FALSE;
1401 /* Free up the current preferences and copy the saved preferences to the
1402 current preferences. */
1404 copy_prefs(&prefs, &saved_prefs);
1406 /* Now revert the registered preferences. */
1407 prefs_modules_foreach(module_prefs_revert, &must_redissect);
1409 /* Now apply the reverted-to preferences. */
1410 prefs_main_apply_all(parent_w);
1412 window_destroy(GTK_WIDGET(parent_w));
1414 if (must_redissect) {
1415 /* Redissect all the packets, and re-evaluate the display filter. */
1416 cf_redissect_packets(&cfile);
1420 /* Treat this as a cancel, by calling "prefs_main_cancel_cb()" */
1422 prefs_main_delete_event_cb(GtkWidget *prefs_w, GdkEvent *event _U_,
1423 gpointer parent_w _U_)
1425 prefs_main_cancel_cb(NULL, prefs_w);
1430 /* dialog *is* already destroyed, clean up memory and such */
1432 prefs_main_destroy_cb(GtkWidget *win _U_, gpointer parent_w)
1434 prefs_main_destroy_all(parent_w);
1436 /* Note that we no longer have a "Preferences" dialog box. */
1440 struct properties_data {
1446 module_search_properties(module_t *module, gpointer user_data)
1448 struct properties_data *p = (struct properties_data *)user_data;
1450 /* If this module has the specified title, remember it. */
1451 if (strcmp(module->title, p->title) == 0) {
1453 return 1; /* stops the search */
1459 /* select a node in the tree view */
1460 /* XXX - this is almost 100% copied from byte_view_select() in proto_draw.c,
1461 * find a way to combine both to have a generic function for this */
1463 tree_select_node(GtkWidget *tree, prefs_tree_iter *iter)
1465 #if GTK_MAJOR_VERSION < 2
1466 GtkCTree *ctree = GTK_CTREE(tree);
1467 GtkCTreeNode *node = (GtkCTreeNode *) iter;
1468 GtkCTreeNode *parent;
1470 GtkTreeIter local_iter = *iter;
1471 GtkTreeView *tree_view = GTK_TREE_VIEW(tree);
1472 GtkTreeModel *model;
1473 GtkTreePath *first_path, *path;
1477 #if GTK_MAJOR_VERSION < 2
1478 /* Expand and select our field's row */
1479 gtk_ctree_expand(ctree, node);
1480 gtk_ctree_select(ctree, node);
1481 /*expand_tree(ctree, node, NULL);*/
1483 /* ... and its parents */
1484 parent = GTK_CTREE_ROW(node)->parent;
1486 gtk_ctree_expand(ctree, parent);
1487 /*expand_tree(ctree, parent, NULL);*/
1488 parent = GTK_CTREE_ROW(parent)->parent;
1491 /* And position the window so the selection is visible.
1492 * Position the selection in the middle of the viewable
1494 gtk_ctree_node_moveto(ctree, node, 0, .5, 0);
1496 model = gtk_tree_view_get_model(tree_view);
1498 /* Expand our field's row */
1499 first_path = gtk_tree_model_get_path(model, &local_iter);
1500 gtk_tree_view_expand_row(tree_view, first_path, FALSE);
1501 /*expand_tree(tree_view, &iter, NULL, NULL);*/
1503 /* ... and its parents */
1504 while (gtk_tree_model_iter_parent(model, &parent, &local_iter)) {
1505 path = gtk_tree_model_get_path(model, &parent);
1506 gtk_tree_view_expand_row(tree_view, path, FALSE);
1507 /*expand_tree(tree_view, &parent, NULL, NULL);*/
1508 local_iter = parent;
1509 gtk_tree_path_free(path);
1512 /* select our field's row */
1513 gtk_tree_selection_select_path(gtk_tree_view_get_selection(tree_view),
1516 /* And position the window so the selection is visible.
1517 * Position the selection in the middle of the viewable
1519 gtk_tree_view_scroll_to_cell(tree_view, first_path, NULL, TRUE, 0.5, 0.0);
1521 gtk_tree_path_free(first_path);
1526 /* search the corresponding protocol page of the currently selected field */
1528 properties_cb(GtkWidget *w, gpointer dummy)
1530 header_field_info *hfinfo;
1532 struct properties_data p;
1536 module_t *page_module;
1538 if (cfile.finfo_selected == NULL) {
1539 /* There is no field selected */
1543 /* Find the title for the protocol for the selected field. */
1544 hfinfo = cfile.finfo_selected->hfinfo;
1545 if (hfinfo->parent == -1)
1546 title = prefs_get_title_by_name(hfinfo->abbrev);
1548 title = prefs_get_title_by_name(proto_registrar_get_abbrev(hfinfo->parent));
1550 return; /* Couldn't find it. XXX - just crash? "Can't happen"? */
1552 /* Find the module for that protocol by searching for one with that title.
1553 XXX - should we just associate protocols with modules directly? */
1556 prefs_module_list_foreach(protocols_module->prefs, module_search_properties,
1558 if (p.module == NULL) {
1559 /* We didn't find it - that protocol probably has no preferences. */
1563 /* Create a preferences window, or pop up an existing one. */
1564 if (prefs_w != NULL) {
1565 reactivate_window(prefs_w);
1570 /* Search all the pages in that window for the one with the specified
1573 (sw = gtk_notebook_get_nth_page(OBJECT_GET_DATA(prefs_w, E_PREFSW_NOTEBOOK_KEY), page_num)) != NULL;
1575 /* Get the frame from the scrollable window */
1576 frame = OBJECT_GET_DATA(sw, E_PAGESW_FRAME_KEY);
1577 /* Get the module for this page. */
1578 page_module = OBJECT_GET_DATA(frame, E_PAGE_MODULE_KEY);
1579 if (page_module == NULL)
1580 continue; /* It doesn't have one. */
1581 if (page_module == p.module) {
1583 OBJECT_GET_DATA(prefs_w, E_PREFSW_TREE_KEY),
1584 OBJECT_GET_DATA(frame, E_PAGE_ITER_KEY));
1590 /* Prefs tree selection callback. The node data has been loaded with
1591 the proper notebook page to load. */
1592 #if GTK_MAJOR_VERSION < 2
1594 prefs_tree_select_cb(GtkCTree *ct, GtkCTreeNode *node, gint col _U_,
1598 prefs_tree_select_cb(GtkTreeSelection *sel, gpointer dummy _U_)
1602 #if GTK_MAJOR_VERSION >= 2
1603 GtkTreeModel *model;
1607 #if GTK_MAJOR_VERSION < 2
1608 page = GPOINTER_TO_INT(gtk_ctree_node_get_row_data(ct, node));
1611 gtk_notebook_set_page(OBJECT_GET_DATA(prefs_w, E_PREFSW_NOTEBOOK_KEY), page);
1613 if (gtk_tree_selection_get_selected(sel, &model, &iter))
1615 gtk_tree_model_get(model, &iter, 1, &page, -1);
1617 gtk_notebook_set_page(OBJECT_GET_DATA(prefs_w, E_PREFSW_NOTEBOOK_KEY), page);