Fix build
[obnox/wireshark/wip.git] / gtk / prefs_dlg.c
index 09b659b2b384f3b4bffb607f58ef1a24925e6a4a..0d4f71e895c3864b9612b8f6e747d3c329c50802 100644 (file)
@@ -3,8 +3,8 @@
  *
  * $Id$
  *
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@ethereal.com>
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
  * Copyright 1998 Gerald Combs
  *
  * This program is free software; you can redistribute it and/or
@@ -49,6 +49,8 @@
 #include "dlg_utils.h"
 #include "simple_dialog.h"
 #include "compat_macros.h"
+#include "help_dlg.h"
+#include "keys.h"
 
 #include <epan/prefs-int.h>
 
 #ifdef _WIN32
 #include "capture-wpcap.h"
 #endif /* _WIN32 */
-#endif /* HAVE_LIBPCAP */
+#ifdef HAVE_AIRPCAP
+#include "airpcap.h"
+#include "airpcap_loader.h"
+#include "airpcap_gui_utils.h"
+#endif
+#endif
 
 static void     prefs_main_ok_cb(GtkWidget *, gpointer);
 static void     prefs_main_apply_cb(GtkWidget *, gpointer);
@@ -71,6 +78,14 @@ static void  prefs_tree_select_cb(GtkCTree *, GtkCTreeNode *, gint,
 static void    prefs_tree_select_cb(GtkTreeSelection *, gpointer);
 #endif
 
+#define E_PREFSW_SCROLLW_KEY    "prefsw_scrollw"
+#define E_PREFSW_TREE_KEY       "prefsw_tree"
+#define E_PREFSW_NOTEBOOK_KEY   "prefsw_notebook"
+#define E_PREFSW_SAVE_BT_KEY    "prefsw_save_bt"
+#define E_PAGE_ITER_KEY         "page_iter"
+#define E_PAGE_MODULE_KEY       "page_module"
+#define E_PAGESW_FRAME_KEY      "pagesw_frame"
+
 #define E_GUI_PAGE_KEY         "gui_options_page"
 #define E_GUI_LAYOUT_PAGE_KEY  "gui_layout_page"
 #define E_GUI_COLUMN_PAGE_KEY   "gui_column_options_page"
@@ -79,13 +94,6 @@ static void  prefs_tree_select_cb(GtkTreeSelection *, gpointer);
 #define E_CAPTURE_PAGE_KEY      "capture_options_page"
 #define E_PRINT_PAGE_KEY        "printer_options_page"
 #define E_NAMERES_PAGE_KEY      "nameres_options_page"
-#define E_PAGE_MODULE_KEY       "page_module"
-
-/*
- * Keep a static pointer to the notebook to be able to choose the
- * displayed page.
- */
-static GtkWidget *notebook;
 
 /*
  * Keep a static pointer to the current "Preferences" window, if any, so that
@@ -213,7 +221,6 @@ pref_show(pref_t *pref, gpointer user_data)
     pref->control = create_preference_entry(main_tb, pref->ordinal,
                                            label_string, pref->description,
                                            range_string);
-    g_free(range_string);
     break;
   }
 
@@ -233,7 +240,7 @@ module_prefs_show(module_t *module, gpointer user_data)
 {
   struct ct_struct *cts = user_data;
   struct ct_struct child_cts;
-  GtkWidget        *main_vb, *main_tb, *frame;
+  GtkWidget        *main_vb, *main_tb, *frame, *main_sw;
   gchar            label_str[MAX_TREE_NODE_NAME_LEN];
 #if GTK_MAJOR_VERSION < 2
   gchar            *label_ptr = label_str;
@@ -311,9 +318,15 @@ module_prefs_show(module_t *module, gpointer user_data)
      * No.  Create a notebook page for it.
      */
 
+    /* Scrolled window */
+    main_sw = gtk_scrolled_window_new(NULL, NULL);
+    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(main_sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+
     /* Frame */
-    frame = gtk_frame_new(module->title);
-    gtk_widget_show(frame);
+    frame = gtk_frame_new(module->description);
+    gtk_container_set_border_width(GTK_CONTAINER(frame), 5);
+    gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(main_sw), frame);
+    OBJECT_SET_DATA(main_sw, E_PAGESW_FRAME_KEY, frame);
 
     /* Main vertical box */
     main_vb = gtk_vbox_new(FALSE, 5);
@@ -334,20 +347,22 @@ module_prefs_show(module_t *module, gpointer user_data)
     OBJECT_SET_DATA(frame, E_PAGE_MODULE_KEY, module);
 
     /* Add the page to the notebook */
-    gtk_notebook_append_page(GTK_NOTEBOOK(cts->notebook), frame, NULL);
+    gtk_notebook_append_page(GTK_NOTEBOOK(cts->notebook), main_sw, NULL);
 
     /* Attach the page to the tree item */
 #if GTK_MAJOR_VERSION < 2
     gtk_ctree_node_set_row_data(GTK_CTREE(cts->tree), ct_node,
                GINT_TO_POINTER(cts->page));
+    OBJECT_SET_DATA(frame, E_PAGE_ITER_KEY, ct_node);
 #else
     gtk_tree_store_set(model, &iter, 0, label_str, 1, cts->page, -1);
+    OBJECT_SET_DATA(frame, E_PAGE_ITER_KEY, gtk_tree_iter_copy(&iter));
 #endif
 
     cts->page++;
 
     /* Show 'em what we got */
-    gtk_widget_show_all(main_vb);
+    gtk_widget_show_all(main_sw);
   }
 
   return 0;
@@ -362,7 +377,7 @@ module_prefs_show(module_t *module, gpointer user_data)
 
 /* add a page to the tree */
 static prefs_tree_iter
-prefs_tree_page_add(const gchar *title, gint page_nr, 
+prefs_tree_page_add(const gchar *title, gint page_nr,
                     gpointer store, prefs_tree_iter *parent_iter,
                     gboolean has_child
 #if GTK_MAJOR_VERSION >= 2
@@ -408,7 +423,7 @@ void
 prefs_cb(GtkWidget *w _U_, gpointer dummy _U_)
 {
   GtkWidget         *top_hb, *bbox, *prefs_nb, *ct_sb,
-                    *ok_bt, *apply_bt, *save_bt, *cancel_bt;
+                    *ok_bt, *apply_bt, *save_bt, *cancel_bt, *help_bt;
   GtkWidget         *gui_font_pg;
   gchar             label_str[MAX_TREE_NODE_NAME_LEN];
   struct ct_struct  cts;
@@ -435,7 +450,7 @@ prefs_cb(GtkWidget *w _U_, gpointer dummy _U_)
      if the user presses "Cancel". */
   copy_prefs(&saved_prefs, &prefs);
 
-  prefs_w = dlg_window_new("Ethereal: Preferences");
+  prefs_w = dlg_window_new("Wireshark: Preferences");
 
   /*
    * Unfortunately, we can't arrange that a GtkTable widget wrap an event box
@@ -459,13 +474,14 @@ prefs_cb(GtkWidget *w _U_, gpointer dummy _U_)
   /* scrolled window on the left for the categories tree */
   ct_sb = scrolled_window_new(NULL, NULL);
 #if GTK_MAJOR_VERSION >= 2
-  gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(ct_sb), 
+  gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(ct_sb),
                                    GTK_SHADOW_IN);
 #endif
   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ct_sb),
        GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
   gtk_container_add(GTK_CONTAINER(top_hb), ct_sb);
   gtk_widget_show(ct_sb);
+  OBJECT_SET_DATA(prefs_w, E_PREFSW_SCROLLW_KEY, ct_sb);
 
   /* categories tree */
 #if GTK_MAJOR_VERSION < 2
@@ -474,9 +490,11 @@ prefs_cb(GtkWidget *w _U_, gpointer dummy _U_)
   cts.node = NULL;
   gtk_clist_set_column_auto_resize(GTK_CLIST(cts.tree), 0, TRUE);
   SIGNAL_CONNECT(cts.tree, "tree-select-row", prefs_tree_select_cb, NULL);
+  OBJECT_SET_DATA(prefs_w, E_PREFSW_TREE_KEY, cts.tree);
 #else
   store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_INT);
   cts.tree = tree_view_new(GTK_TREE_MODEL(store));
+  OBJECT_SET_DATA(prefs_w, E_PREFSW_TREE_KEY, cts.tree);
   gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(cts.tree), FALSE);
   selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(cts.tree));
   gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
@@ -494,7 +512,8 @@ prefs_cb(GtkWidget *w _U_, gpointer dummy _U_)
   gtk_widget_show(cts.tree);
 
   /* A notebook widget without tabs is used to flip between prefs */
-  notebook = prefs_nb = gtk_notebook_new();
+  prefs_nb = gtk_notebook_new();
+  OBJECT_SET_DATA(prefs_w, E_PREFSW_NOTEBOOK_KEY, prefs_nb);
   gtk_notebook_set_show_tabs(GTK_NOTEBOOK(prefs_nb), FALSE);
   gtk_notebook_set_show_border(GTK_NOTEBOOK(prefs_nb), FALSE);
   gtk_container_add(GTK_CONTAINER(top_hb), prefs_nb);
@@ -529,8 +548,8 @@ prefs_cb(GtkWidget *w _U_, gpointer dummy _U_)
 
   gtk_container_border_width( GTK_CONTAINER(gui_font_pg), 5 );
 
-  /* IMPORTANT: the following gtk_font_selection_set_xy() functions will only 
-     work, if the widget and it's corresponding window is already shown 
+  /* IMPORTANT: the following gtk_font_selection_set_xy() functions will only
+     work, if the widget and it's corresponding window is already shown
      (so don't put the following into gui_font_prefs_show()) !!! */
 
   /* We set the current font and, for GTK+ 1.2[.x], the font filter
@@ -558,8 +577,8 @@ prefs_cb(GtkWidget *w _U_, gpointer dummy _U_)
            NULL,                 /* all setwidths are OK */
            fixedwidths,          /* ONLY fixed-width fonts */
            NULL);      /* all charsets are OK (XXX - ISO 8859/1 only?) */
-#endif  
-  
+#endif
+
   /* GUI Colors prefs */
   strcpy(label_str, "Colors");
   prefs_nb_page_add(prefs_nb, label_str, stream_prefs_show(), E_GUI_COLORS_PAGE_KEY);
@@ -607,8 +626,13 @@ prefs_cb(GtkWidget *w _U_, gpointer dummy _U_)
   cts.is_protocol = FALSE;
   prefs_module_list_foreach(NULL, module_prefs_show, &cts);
 
-  /* Button row: OK and cancel buttons */
-  bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_APPLY, GTK_STOCK_SAVE, GTK_STOCK_CANCEL, NULL);
+  /* Button row: OK and alike buttons */
+
+  if(topic_available(HELP_PREFERENCES_DIALOG)) {
+    bbox = dlg_button_row_new(GTK_STOCK_HELP, GTK_STOCK_OK, GTK_STOCK_APPLY, GTK_STOCK_SAVE, GTK_STOCK_CANCEL, NULL);
+  } else {
+    bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_APPLY, GTK_STOCK_SAVE, GTK_STOCK_CANCEL, NULL);
+  }
   gtk_box_pack_start(GTK_BOX(cts.main_vb), bbox, FALSE, FALSE, 0);
   gtk_widget_show(bbox);
 
@@ -620,6 +644,7 @@ prefs_cb(GtkWidget *w _U_, gpointer dummy _U_)
 
   save_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_SAVE);
   SIGNAL_CONNECT(save_bt, "clicked", prefs_main_save_cb, prefs_w);
+  OBJECT_SET_DATA(prefs_w, E_PREFSW_SAVE_BT_KEY, save_bt);
 
   cancel_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_CANCEL);
   SIGNAL_CONNECT(cancel_bt, "clicked", prefs_main_cancel_cb, prefs_w);
@@ -627,10 +652,21 @@ prefs_cb(GtkWidget *w _U_, gpointer dummy _U_)
 
   gtk_widget_grab_default(ok_bt);
 
+  if(topic_available(HELP_PREFERENCES_DIALOG)) {
+    help_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_HELP);
+    SIGNAL_CONNECT(help_bt, "clicked", topic_cb, HELP_PREFERENCES_DIALOG);
+  }
+
   SIGNAL_CONNECT(prefs_w, "delete_event", prefs_main_delete_event_cb, prefs_w);
   SIGNAL_CONNECT(prefs_w, "destroy", prefs_main_destroy_cb, prefs_w);
 
   gtk_widget_show(prefs_w);
+
+  /* hide the Save button if the user uses implicit save */
+  if(!prefs.gui_use_pref_save) {
+    gtk_widget_hide(save_bt);
+  }
+
   window_present(prefs_w);
 
 #if GTK_MAJOR_VERSION >= 2
@@ -1040,6 +1076,67 @@ module_prefs_fetch(module_t *module, gpointer user_data)
   return 0;    /* keep fetching module preferences */
 }
 
+#ifdef HAVE_AIRPCAP
+/*
+ * This function is used to apply changes and update the Wireless Toolbar
+ * whenever we apply some changes to the WEP preferences
+ */
+static void
+prefs_airpcap_update()
+{
+GtkWidget *decryption_cm;
+GtkWidget *decryption_en;
+gboolean wireshark_decryption_was_enabled;
+gboolean airpcap_decryption_was_enabled;
+gboolean wireshark_decryption_is_now_enabled;
+
+decryption_cm = GTK_WIDGET(OBJECT_GET_DATA(airpcap_tb,AIRPCAP_TOOLBAR_DECRYPTION_KEY));
+decryption_en = GTK_WIDGET(GTK_ENTRY(GTK_COMBO(decryption_cm)->entry));
+
+if( g_strcasecmp(gtk_entry_get_text(GTK_ENTRY(decryption_en)),AIRPCAP_DECRYPTION_TYPE_STRING_WIRESHARK) == 0 )
+{
+wireshark_decryption_was_enabled = TRUE;
+airpcap_decryption_was_enabled = FALSE;
+}
+else if( g_strcasecmp(gtk_entry_get_text(GTK_ENTRY(decryption_en)),AIRPCAP_DECRYPTION_TYPE_STRING_AIRPCAP) == 0 )
+{
+wireshark_decryption_was_enabled = FALSE;
+airpcap_decryption_was_enabled = TRUE;
+}
+else if( g_strcasecmp(gtk_entry_get_text(GTK_ENTRY(decryption_en)),AIRPCAP_DECRYPTION_TYPE_STRING_NONE) == 0 )
+{
+wireshark_decryption_was_enabled = FALSE;
+airpcap_decryption_was_enabled = FALSE;
+}
+
+wireshark_decryption_is_now_enabled = wireshark_decryption_on();
+
+if(wireshark_decryption_is_now_enabled && airpcap_decryption_was_enabled)
+       {
+       set_airpcap_decryption(FALSE);
+       gtk_entry_set_text(GTK_ENTRY(decryption_en),AIRPCAP_DECRYPTION_TYPE_STRING_WIRESHARK);
+       }
+if(wireshark_decryption_is_now_enabled && !airpcap_decryption_was_enabled)
+       {
+       set_airpcap_decryption(FALSE);
+       gtk_entry_set_text(GTK_ENTRY(decryption_en),AIRPCAP_DECRYPTION_TYPE_STRING_WIRESHARK);
+       }
+else if(!wireshark_decryption_is_now_enabled && wireshark_decryption_was_enabled)
+       {
+       if(airpcap_decryption_was_enabled)
+               {
+               set_airpcap_decryption(TRUE);
+               gtk_entry_set_text(GTK_ENTRY(decryption_en),AIRPCAP_DECRYPTION_TYPE_STRING_AIRPCAP);
+               }
+       else
+               {
+               set_airpcap_decryption(FALSE);
+               gtk_entry_set_text(GTK_ENTRY(decryption_en),AIRPCAP_DECRYPTION_TYPE_STRING_NONE);
+               }
+       }
+}
+#endif
+
 static guint
 pref_clean(pref_t *pref, gpointer user_data _U_)
 {
@@ -1145,6 +1242,8 @@ prefs_main_fetch_all(GtkWidget *dlg, gboolean *must_redissect)
 static void
 prefs_main_apply_all(GtkWidget *dlg)
 {
+  GtkWidget *save_bt;
+
   /*
    * Apply the protocol preferences first - "gui_prefs_apply()" could
    * cause redissection, and we have to make sure the protocol
@@ -1169,6 +1268,14 @@ prefs_main_apply_all(GtkWidget *dlg)
 #endif /* HAVE_LIBPCAP */
   printer_prefs_apply(OBJECT_GET_DATA(dlg, E_PRINT_PAGE_KEY));
   nameres_prefs_apply(OBJECT_GET_DATA(dlg, E_NAMERES_PAGE_KEY));
+
+  /* show/hide the Save button - depending on setting */
+  save_bt = OBJECT_GET_DATA(prefs_w, E_PREFSW_SAVE_BT_KEY);
+  if(prefs.gui_use_pref_save) {
+    gtk_widget_show(save_bt);
+  } else {
+    gtk_widget_hide(save_bt);
+  }
 }
 
 
@@ -1176,6 +1283,18 @@ prefs_main_apply_all(GtkWidget *dlg)
 static void
 prefs_main_destroy_all(GtkWidget *dlg)
 {
+#if GTK_MAJOR_VERSION >= 2
+  int page_num;
+  GtkWidget *frame;
+
+  for (page_num = 0;
+       (frame = gtk_notebook_get_nth_page(OBJECT_GET_DATA(prefs_w, E_PREFSW_NOTEBOOK_KEY), page_num)) != NULL;
+       page_num++) {
+                  if(OBJECT_GET_DATA(frame, E_PAGE_ITER_KEY))
+               gtk_tree_iter_free(OBJECT_GET_DATA(frame, E_PAGE_ITER_KEY));
+          }
+#endif
+
   gui_prefs_destroy(OBJECT_GET_DATA(dlg, E_GUI_PAGE_KEY));
   layout_prefs_destroy(OBJECT_GET_DATA(dlg, E_GUI_LAYOUT_PAGE_KEY));
   column_prefs_destroy(OBJECT_GET_DATA(dlg, E_GUI_COLUMN_PAGE_KEY));
@@ -1201,16 +1320,63 @@ prefs_main_destroy_all(GtkWidget *dlg)
 }
 
 
+static void
+prefs_main_write(void)
+{
+  int err;
+  char *pf_dir_path;
+  char *pf_path;
+
+  /* Create the directory that holds personal configuration files, if
+     necessary.  */
+  if (create_persconffile_dir(&pf_dir_path) == -1) {
+     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+      "Can't create directory\n\"%s\"\nfor preferences file: %s.", pf_dir_path,
+      strerror(errno));
+     g_free(pf_dir_path);
+  } else {
+    /* Write the preferencs out. */
+    err = write_prefs(&pf_path);
+    if (err != 0) {
+       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+        "Can't open preferences file\n\"%s\": %s.", pf_path,
+        strerror(err));
+       g_free(pf_path);
+    }
+  }
+
+#ifdef HAVE_AIRPCAP
+/* 
+ * Load the Wireshark decryption keys (just set) and save 
+ * the changes to the adapters' registry 
+ */ 
+airpcap_load_decryption_keys(airpcap_if_list);
+#endif
+}
+
+
 static void
 prefs_main_ok_cb(GtkWidget *ok_bt _U_, gpointer parent_w)
 {
   gboolean must_redissect = FALSE;
 
   if (!prefs_main_fetch_all(parent_w, &must_redissect))
-    return; /* Errors in some preference setting */
+    return; /* Errors in some preference setting - already reported */
+
+  /* if we don't have a Save button, just save the settings now */
+  if (!prefs.gui_use_pref_save) {
+      prefs_main_write();
+  }
 
   prefs_main_apply_all(parent_w);
 
+  /* Fill in capture options with values from the preferences */
+  prefs_to_capture_opts();
+
+       #ifdef HAVE_AIRPCAP
+       prefs_airpcap_update();
+       #endif
+
   /* Now destroy the "Preferences" dialog. */
   window_destroy(GTK_WIDGET(parent_w));
 
@@ -1218,6 +1384,7 @@ prefs_main_ok_cb(GtkWidget *ok_bt _U_, gpointer parent_w)
     /* Redissect all the packets, and re-evaluate the display filter. */
     cf_redissect_packets(&cfile);
   }
+
 }
 
 static void
@@ -1226,10 +1393,22 @@ prefs_main_apply_cb(GtkWidget *apply_bt _U_, gpointer parent_w)
   gboolean must_redissect = FALSE;
 
   if (!prefs_main_fetch_all(parent_w, &must_redissect))
-    return; /* Errors in some preference setting */
+    return; /* Errors in some preference setting - already reported */
+
+  /* if we don't have a Save button, just save the settings now */
+  if (!prefs.gui_use_pref_save) {
+      prefs_main_write();
+  }
 
   prefs_main_apply_all(parent_w);
 
+  /* Fill in capture options with values from the preferences */
+  prefs_to_capture_opts();
+
+       #ifdef HAVE_AIRPCAP
+       prefs_airpcap_update();
+       #endif
+
   if (must_redissect) {
     /* Redissect all the packets, and re-evaluate the display filter. */
     cf_redissect_packets(&cfile);
@@ -1240,30 +1419,11 @@ static void
 prefs_main_save_cb(GtkWidget *save_bt _U_, gpointer parent_w)
 {
   gboolean must_redissect = FALSE;
-  int err;
-  char *pf_dir_path;
-  char *pf_path;
 
   if (!prefs_main_fetch_all(parent_w, &must_redissect))
-    return; /* Errors in some preference setting */
+    return; /* Errors in some preference setting - already reported */
 
-  /* Create the directory that holds personal configuration files, if
-     necessary.  */
-  if (create_persconffile_dir(&pf_dir_path) == -1) {
-     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
-      "Can't create directory\n\"%s\"\nfor preferences file: %s.", pf_dir_path,
-      strerror(errno));
-     g_free(pf_dir_path);
-  } else {
-    /* Write the preferencs out. */
-    err = write_prefs(&pf_path);
-    if (err != 0) {
-       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
-        "Can't open preferences file\n\"%s\": %s.", pf_path,
-        strerror(err));
-       g_free(pf_path);
-    }
-  }
+  prefs_main_write();
 
   /* Now apply those preferences.
      XXX - should we do this?  The user didn't click "OK" or "Apply".
@@ -1272,7 +1432,7 @@ prefs_main_save_cb(GtkWidget *save_bt _U_, gpointer parent_w)
        1) by saving the preferences they presumably indicate that they
           like them;
 
-       2) the next time they fire Ethereal up, those preferences will
+       2) the next time they fire Wireshark up, those preferences will
           apply;
 
        3) we'd have to buffer "must_redissect" so that if they do
@@ -1281,6 +1441,9 @@ prefs_main_save_cb(GtkWidget *save_bt _U_, gpointer parent_w)
        4) we did apply the protocol preferences, at least, in the past. */
   prefs_main_apply_all(parent_w);
 
+  /* Fill in capture options with values from the preferences */
+  prefs_to_capture_opts();
+
   if (must_redissect) {
     /* Redissect all the packets, and re-evaluate the display filter. */
     cf_redissect_packets(&cfile);
@@ -1421,6 +1584,75 @@ module_search_properties(module_t *module, gpointer user_data)
   return 0;
 }
 
+
+/* select a node in the tree view */
+/* XXX - this is almost 100% copied from byte_view_select() in proto_draw.c,
+ *       find a way to combine both to have a generic function for this */
+void
+tree_select_node(GtkWidget *tree, prefs_tree_iter *iter)
+{
+#if GTK_MAJOR_VERSION < 2
+    GtkCTree     *ctree = GTK_CTREE(tree);
+    GtkCTreeNode *node = (GtkCTreeNode *) iter;
+       GtkCTreeNode *parent;
+#else
+       GtkTreeIter  local_iter = *iter;
+    GtkTreeView  *tree_view = GTK_TREE_VIEW(tree);
+    GtkTreeModel *model;
+    GtkTreePath  *first_path, *path;
+    GtkTreeIter   parent;
+#endif
+
+#if GTK_MAJOR_VERSION < 2
+    /* Expand and select our field's row */
+    gtk_ctree_expand(ctree, node);
+    gtk_ctree_select(ctree, node);
+    /*expand_tree(ctree, node, NULL);*/
+
+    /* ... and its parents */
+    parent = GTK_CTREE_ROW(node)->parent;
+    while (parent) {
+        gtk_ctree_expand(ctree, parent);
+        /*expand_tree(ctree, parent, NULL);*/
+        parent = GTK_CTREE_ROW(parent)->parent;
+    }
+
+    /* And position the window so the selection is visible.
+     * Position the selection in the middle of the viewable
+     * pane. */
+    gtk_ctree_node_moveto(ctree, node, 0, .5, 0);
+#else
+    model = gtk_tree_view_get_model(tree_view);
+
+    /* Expand our field's row */
+    first_path = gtk_tree_model_get_path(model, &local_iter);
+    gtk_tree_view_expand_row(tree_view, first_path, FALSE);
+    /*expand_tree(tree_view, &iter, NULL, NULL);*/
+
+    /* ... and its parents */
+    while (gtk_tree_model_iter_parent(model, &parent, &local_iter)) {
+        path = gtk_tree_model_get_path(model, &parent);
+        gtk_tree_view_expand_row(tree_view, path, FALSE);
+        /*expand_tree(tree_view, &parent, NULL, NULL);*/
+        local_iter = parent;
+        gtk_tree_path_free(path);
+    }
+
+    /* select our field's row */
+    gtk_tree_selection_select_path(gtk_tree_view_get_selection(tree_view),
+                                   first_path);
+
+    /* And position the window so the selection is visible.
+     * Position the selection in the middle of the viewable
+     * pane. */
+    gtk_tree_view_scroll_to_cell(tree_view, first_path, NULL, TRUE, 0.5, 0.0);
+
+    gtk_tree_path_free(first_path);
+#endif
+}
+
+
+/* search the corresponding protocol page of the currently selected field */
 void
 properties_cb(GtkWidget *w, gpointer dummy)
 {
@@ -1428,6 +1660,7 @@ properties_cb(GtkWidget *w, gpointer dummy)
   const gchar *title;
   struct properties_data p;
   int page_num;
+  GtkWidget *sw;
   GtkWidget *frame;
   module_t *page_module;
 
@@ -1466,17 +1699,20 @@ properties_cb(GtkWidget *w, gpointer dummy)
   /* Search all the pages in that window for the one with the specified
      module. */
   for (page_num = 0;
-       (frame = gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), page_num)) != NULL;
+       (sw = gtk_notebook_get_nth_page(OBJECT_GET_DATA(prefs_w, E_PREFSW_NOTEBOOK_KEY), page_num)) != NULL;
        page_num++) {
+    /* Get the frame from the scrollable window */
+    frame = OBJECT_GET_DATA(sw, E_PAGESW_FRAME_KEY);
     /* Get the module for this page. */
     page_module = OBJECT_GET_DATA(frame, E_PAGE_MODULE_KEY);
     if (page_module == NULL)
       continue;        /* It doesn't have one. */
     if (page_module == p.module) {
-      /* We found it.  Select that page. */
-      gtk_notebook_set_page(GTK_NOTEBOOK(notebook), page_num);
-      break;
-    }
+         tree_select_node(
+                 OBJECT_GET_DATA(prefs_w, E_PREFSW_TREE_KEY),
+                 OBJECT_GET_DATA(frame, E_PAGE_ITER_KEY));
+         return;
+       }
   }
 }
 
@@ -1501,13 +1737,13 @@ prefs_tree_select_cb(GtkTreeSelection *sel, gpointer dummy _U_)
   page = GPOINTER_TO_INT(gtk_ctree_node_get_row_data(ct, node));
 
   if (page >= 0)
-    gtk_notebook_set_page(GTK_NOTEBOOK(notebook), page);
+    gtk_notebook_set_page(OBJECT_GET_DATA(prefs_w, E_PREFSW_NOTEBOOK_KEY), page);
 #else
   if (gtk_tree_selection_get_selected(sel, &model, &iter))
   {
     gtk_tree_model_get(model, &iter, 1, &page, -1);
     if (page >= 0)
-      gtk_notebook_set_page(GTK_NOTEBOOK(notebook), page);
+      gtk_notebook_set_page(OBJECT_GET_DATA(prefs_w, E_PREFSW_NOTEBOOK_KEY), page);
   }
 #endif
 }