Fix build
[obnox/wireshark/wip.git] / gtk / prefs_dlg.c
1 /* prefs_dlg.c
2  * Routines for handling preferences
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
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.
14  *
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.
19  *
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.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <gtk/gtk.h>
30
31 #include <string.h>
32
33 #include <epan/filesystem.h>
34
35 #include "main.h"
36 #include <epan/packet.h>
37 #include "file.h"
38 #include <epan/prefs.h>
39 #include "column_prefs.h"
40 #include "print.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"
52 #include "help_dlg.h"
53 #include "keys.h"
54
55 #include <epan/prefs-int.h>
56
57 #ifdef HAVE_LIBPCAP
58 #ifdef _WIN32
59 #include "capture-wpcap.h"
60 #endif /* _WIN32 */
61 #ifdef HAVE_AIRPCAP
62 #include "airpcap.h"
63 #include "airpcap_loader.h"
64 #include "airpcap_gui_utils.h"
65 #endif
66 #endif
67
68 static void     prefs_main_ok_cb(GtkWidget *, gpointer);
69 static void     prefs_main_apply_cb(GtkWidget *, gpointer);
70 static void     prefs_main_save_cb(GtkWidget *, gpointer);
71 static void     prefs_main_cancel_cb(GtkWidget *, gpointer);
72 static gboolean prefs_main_delete_event_cb(GtkWidget *, GdkEvent *, gpointer);
73 static void     prefs_main_destroy_cb(GtkWidget *, gpointer);
74 #if GTK_MAJOR_VERSION < 2
75 static void     prefs_tree_select_cb(GtkCTree *, GtkCTreeNode *, gint,
76                                      gpointer);
77 #else
78 static void     prefs_tree_select_cb(GtkTreeSelection *, gpointer);
79 #endif
80
81 #define E_PREFSW_SCROLLW_KEY    "prefsw_scrollw"
82 #define E_PREFSW_TREE_KEY       "prefsw_tree"
83 #define E_PREFSW_NOTEBOOK_KEY   "prefsw_notebook"
84 #define E_PREFSW_SAVE_BT_KEY    "prefsw_save_bt"
85 #define E_PAGE_ITER_KEY         "page_iter"
86 #define E_PAGE_MODULE_KEY       "page_module"
87 #define E_PAGESW_FRAME_KEY      "pagesw_frame"
88
89 #define E_GUI_PAGE_KEY          "gui_options_page"
90 #define E_GUI_LAYOUT_PAGE_KEY   "gui_layout_page"
91 #define E_GUI_COLUMN_PAGE_KEY   "gui_column_options_page"
92 #define E_GUI_FONT_PAGE_KEY     "gui_font_options_page"
93 #define E_GUI_COLORS_PAGE_KEY   "gui_colors_options_page"
94 #define E_CAPTURE_PAGE_KEY      "capture_options_page"
95 #define E_PRINT_PAGE_KEY        "printer_options_page"
96 #define E_NAMERES_PAGE_KEY      "nameres_options_page"
97
98 /*
99  * Keep a static pointer to the current "Preferences" window, if any, so that
100  * if somebody tries to do "Edit:Preferences" while there's already a
101  * "Preferences" window up, we just pop up the existing one, rather than
102  * creating a new one.
103  */
104 static GtkWidget *prefs_w;
105
106 /*
107  * Save the value of the preferences as of when the preferences dialog
108  * box was first popped up, so we can revert to those values if the
109  * user selects "Cancel".
110  */
111 static e_prefs saved_prefs;
112
113 struct ct_struct {
114   GtkWidget    *main_vb;
115   GtkWidget    *notebook;
116   GtkWidget    *tree;
117 #if GTK_MAJOR_VERSION < 2
118   GtkCTreeNode *node;
119 #else
120   GtkTreeIter  iter;
121 #endif
122   GtkTooltips  *tooltips;
123   gint         page;
124   gboolean     is_protocol;
125 };
126
127 static guint
128 pref_exists(pref_t *pref _U_, gpointer user_data _U_)
129 {
130   return 1;
131 }
132
133 /* show a single preference on the GtkTable of a preference page */
134 static guint
135 pref_show(pref_t *pref, gpointer user_data)
136 {
137   GtkWidget *main_tb = user_data;
138   const char *title;
139   char *label_string;
140   char uint_str[10+1];
141
142   /* Give this preference a label which is its title, followed by a colon,
143      and left-align it. */
144   title = pref->title;
145   label_string = g_malloc(strlen(title) + 2);
146   strcpy(label_string, title);
147   strcat(label_string, ":");
148
149   /* Save the current value of the preference, so that we can revert it if
150      the user does "Apply" and then "Cancel", and create the control for
151      editing the preference. */
152   switch (pref->type) {
153
154   case PREF_UINT:
155     pref->saved_val.uint = *pref->varp.uint;
156
157     /* XXX - there are no uint spinbuttons, so we can't use a spinbutton.
158        Even more annoyingly, even if there were, GLib doesn't define
159        G_MAXUINT - but I think ANSI C may define UINT_MAX, so we could
160        use that. */
161     switch (pref->info.base) {
162
163     case 10:
164       g_snprintf(uint_str, 10+1, "%u", pref->saved_val.uint);
165       break;
166
167     case 8:
168       g_snprintf(uint_str, 10+1, "%o", pref->saved_val.uint);
169       break;
170
171     case 16:
172       g_snprintf(uint_str, 10+1, "%x", pref->saved_val.uint);
173       break;
174     }
175     pref->control = create_preference_entry(main_tb, pref->ordinal,
176                                             label_string, pref->description,
177                                             uint_str);
178     break;
179
180   case PREF_BOOL:
181     pref->saved_val.boolval = *pref->varp.boolp;
182     pref->control = create_preference_check_button(main_tb, pref->ordinal,
183                                                label_string, pref->description,
184                                                pref->saved_val.boolval);
185     break;
186
187   case PREF_ENUM:
188     pref->saved_val.enumval = *pref->varp.enump;
189     if (pref->info.enum_info.radio_buttons) {
190       /* Show it as radio buttons. */
191       pref->control = create_preference_radio_buttons(main_tb, pref->ordinal,
192                                                   label_string, pref->description,
193                                                   pref->info.enum_info.enumvals,
194                                                   pref->saved_val.enumval);
195     } else {
196       /* Show it as an option menu. */
197       pref->control = create_preference_option_menu(main_tb, pref->ordinal,
198                                          label_string, pref->description,
199                                          pref->info.enum_info.enumvals,
200                                          pref->saved_val.enumval);
201     }
202     break;
203
204   case PREF_STRING:
205     if (pref->saved_val.string != NULL)
206       g_free(pref->saved_val.string);
207     pref->saved_val.string = g_strdup(*pref->varp.string);
208     pref->control = create_preference_entry(main_tb, pref->ordinal,
209                                             label_string, pref->description,
210                                             pref->saved_val.string);
211     break;
212
213   case PREF_RANGE:
214   {
215     char *range_string;
216
217     if (pref->saved_val.range != NULL)
218       g_free(pref->saved_val.range);
219     pref->saved_val.range = range_copy(*pref->varp.range);
220     range_string = range_convert_range(*pref->varp.range);
221     pref->control = create_preference_entry(main_tb, pref->ordinal,
222                                             label_string, pref->description,
223                                             range_string);
224     break;
225   }
226
227   case PREF_OBSOLETE:
228     g_assert_not_reached();
229     break;
230   }
231   g_free(label_string);
232
233   return 0;
234 }
235
236 #define MAX_TREE_NODE_NAME_LEN 64
237 /* show prefs page for each registered module (protocol) */
238 static guint
239 module_prefs_show(module_t *module, gpointer user_data)
240 {
241   struct ct_struct *cts = user_data;
242   struct ct_struct child_cts;
243   GtkWidget        *main_vb, *main_tb, *frame, *main_sw;
244   gchar            label_str[MAX_TREE_NODE_NAME_LEN];
245 #if GTK_MAJOR_VERSION < 2
246   gchar            *label_ptr = label_str;
247   GtkCTreeNode     *ct_node;
248 #else
249   GtkTreeStore     *model;
250   GtkTreeIter      iter;
251 #endif
252
253   /*
254    * Is this module a subtree, with modules underneath it?
255    */
256   if (!module->is_subtree) {
257     /*
258      * No.
259      * Does it have any preferences (other than possibly obsolete ones)?
260      */
261     if (prefs_pref_foreach(module, pref_exists, NULL) == 0) {
262       /*
263        * No.  Don't put the module into the preferences window.
264        * XXX - we should do the same for subtrees; if a subtree has
265        * nothing under it that will be displayed, don't put it into
266        * the window.
267        */
268       return 0;
269     }
270   }
271
272   /*
273    * Add this module to the tree.
274    */
275   strcpy(label_str, module->title);
276 #if GTK_MAJOR_VERSION < 2
277   ct_node = gtk_ctree_insert_node(GTK_CTREE(cts->tree), cts->node, NULL,
278                 &label_ptr, 5, NULL, NULL, NULL, NULL, !module->is_subtree,
279                 FALSE);
280 #else
281   model = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(cts->tree)));
282   if (module->is_subtree)
283       gtk_tree_store_append(model, &iter, NULL);
284   else
285       gtk_tree_store_append(model, &iter, &cts->iter);
286 #endif
287
288   /*
289    * Is this a subtree?
290    */
291   if (module->is_subtree) {
292     /*
293      * Yes.
294      */
295
296     /* Note that there's no page attached to this item */
297 #if GTK_MAJOR_VERSION < 2
298     gtk_ctree_node_set_row_data(GTK_CTREE(cts->tree), ct_node,
299                 GINT_TO_POINTER(-1));
300 #else
301     gtk_tree_store_set(model, &iter, 0, label_str, 1, -1, -1);
302 #endif
303
304     /*
305      * Walk the subtree and attach stuff to it.
306      */
307     child_cts = *cts;
308 #if GTK_MAJOR_VERSION < 2
309     child_cts.node = ct_node;
310 #else
311     child_cts.iter = iter;
312 #endif
313     if (module == protocols_module)
314       child_cts.is_protocol = TRUE;
315     prefs_module_list_foreach(module->prefs, module_prefs_show, &child_cts);
316   } else {
317     /*
318      * No.  Create a notebook page for it.
319      */
320
321     /* Scrolled window */
322     main_sw = gtk_scrolled_window_new(NULL, NULL);
323     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(main_sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
324
325     /* Frame */
326     frame = gtk_frame_new(module->description);
327     gtk_container_set_border_width(GTK_CONTAINER(frame), 5);
328     gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(main_sw), frame);
329     OBJECT_SET_DATA(main_sw, E_PAGESW_FRAME_KEY, frame);
330
331     /* Main vertical box */
332     main_vb = gtk_vbox_new(FALSE, 5);
333     gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
334     gtk_container_add(GTK_CONTAINER(frame), main_vb);
335
336     /* Main table */
337     main_tb = gtk_table_new(module->numprefs, 2, FALSE);
338     gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0);
339     gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10);
340     gtk_table_set_col_spacings(GTK_TABLE(main_tb), 15);
341     OBJECT_SET_DATA(main_tb, E_TOOLTIPS_KEY, cts->tooltips);
342
343     /* Add items for each of the preferences */
344     prefs_pref_foreach(module, pref_show, main_tb);
345
346     /* Associate this module with the page's frame. */
347     OBJECT_SET_DATA(frame, E_PAGE_MODULE_KEY, module);
348
349     /* Add the page to the notebook */
350     gtk_notebook_append_page(GTK_NOTEBOOK(cts->notebook), main_sw, NULL);
351
352     /* Attach the page to the tree item */
353 #if GTK_MAJOR_VERSION < 2
354     gtk_ctree_node_set_row_data(GTK_CTREE(cts->tree), ct_node,
355                 GINT_TO_POINTER(cts->page));
356     OBJECT_SET_DATA(frame, E_PAGE_ITER_KEY, ct_node);
357 #else
358     gtk_tree_store_set(model, &iter, 0, label_str, 1, cts->page, -1);
359     OBJECT_SET_DATA(frame, E_PAGE_ITER_KEY, gtk_tree_iter_copy(&iter));
360 #endif
361
362     cts->page++;
363
364     /* Show 'em what we got */
365     gtk_widget_show_all(main_sw);
366   }
367
368   return 0;
369 }
370
371
372 #if GTK_MAJOR_VERSION < 2
373 #define prefs_tree_iter GtkCTreeNode *
374 #else
375 #define prefs_tree_iter GtkTreeIter
376 #endif
377
378 /* add a page to the tree */
379 static prefs_tree_iter
380 prefs_tree_page_add(const gchar *title, gint page_nr,
381                     gpointer store, prefs_tree_iter *parent_iter,
382                     gboolean has_child
383 #if GTK_MAJOR_VERSION >= 2
384                     _U_
385 #endif
386                     )
387 {
388 #if GTK_MAJOR_VERSION < 2
389   const gchar       *label_ptr = title;
390 #endif
391   prefs_tree_iter   iter;
392
393 #if GTK_MAJOR_VERSION < 2
394   iter = gtk_ctree_insert_node(GTK_CTREE(store), parent_iter ? *parent_iter : NULL, NULL,
395                 (gchar **) &label_ptr, 5, NULL, NULL, NULL, NULL, !has_child, TRUE);
396   gtk_ctree_node_set_row_data(GTK_CTREE(store), iter,
397                 GINT_TO_POINTER(page_nr));
398 #else
399   gtk_tree_store_append(store, &iter, parent_iter);
400   gtk_tree_store_set(store, &iter, 0, title, 1, page_nr, -1);
401 #endif
402   return iter;
403 }
404
405 /* add a page to the notebook */
406 static GtkWidget *
407 prefs_nb_page_add(GtkWidget *notebook, const gchar *title, GtkWidget *page, const char *page_key)
408 {
409   GtkWidget         *frame;
410
411   frame = gtk_frame_new(title);
412   gtk_widget_show(frame);
413   gtk_container_add(GTK_CONTAINER(frame), page);
414   OBJECT_SET_DATA(prefs_w, page_key, page);
415   gtk_notebook_append_page (GTK_NOTEBOOK(notebook), frame, NULL);
416
417   return frame;
418 }
419
420
421 /* show the dialog */
422 void
423 prefs_cb(GtkWidget *w _U_, gpointer dummy _U_)
424 {
425   GtkWidget         *top_hb, *bbox, *prefs_nb, *ct_sb,
426                     *ok_bt, *apply_bt, *save_bt, *cancel_bt, *help_bt;
427   GtkWidget         *gui_font_pg;
428   gchar             label_str[MAX_TREE_NODE_NAME_LEN];
429   struct ct_struct  cts;
430 #if GTK_MAJOR_VERSION < 2
431   gpointer          store = NULL;
432   static gchar *fixedwidths[] = { "c", "m", NULL };
433 #else
434   GtkTreeStore      *store;
435   GtkTreeSelection  *selection;
436   GtkCellRenderer   *renderer;
437   GtkTreeViewColumn *column;
438   gint              col_offset;
439 #endif
440   prefs_tree_iter   gui_iter;
441
442
443   if (prefs_w != NULL) {
444     /* There's already a "Preferences" dialog box; reactivate it. */
445     reactivate_window(prefs_w);
446     return;
447   }
448
449   /* Save the current preferences, so we can revert to those values
450      if the user presses "Cancel". */
451   copy_prefs(&saved_prefs, &prefs);
452
453   prefs_w = dlg_window_new("Wireshark: Preferences");
454
455   /*
456    * Unfortunately, we can't arrange that a GtkTable widget wrap an event box
457    * around a table row, so the spacing between the preference item's label
458    * and its control widgets is inactive and the tooltip doesn't pop up when
459    * the mouse is over it.
460    */
461   cts.tooltips = gtk_tooltips_new();
462
463   /* Container for each row of widgets */
464   cts.main_vb = gtk_vbox_new(FALSE, 5);
465   gtk_container_border_width(GTK_CONTAINER(cts.main_vb), 5);
466   gtk_container_add(GTK_CONTAINER(prefs_w), cts.main_vb);
467   gtk_widget_show(cts.main_vb);
468
469   /* Top row: Preferences tree and notebook */
470   top_hb = gtk_hbox_new(FALSE, 10);
471   gtk_container_add(GTK_CONTAINER(cts.main_vb), top_hb);
472   gtk_widget_show(top_hb);
473
474   /* scrolled window on the left for the categories tree */
475   ct_sb = scrolled_window_new(NULL, NULL);
476 #if GTK_MAJOR_VERSION >= 2
477   gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(ct_sb),
478                                    GTK_SHADOW_IN);
479 #endif
480   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ct_sb),
481         GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
482   gtk_container_add(GTK_CONTAINER(top_hb), ct_sb);
483   gtk_widget_show(ct_sb);
484   OBJECT_SET_DATA(prefs_w, E_PREFSW_SCROLLW_KEY, ct_sb);
485
486   /* categories tree */
487 #if GTK_MAJOR_VERSION < 2
488   cts.tree = ctree_new(1, 0);
489   store = cts.tree;
490   cts.node = NULL;
491   gtk_clist_set_column_auto_resize(GTK_CLIST(cts.tree), 0, TRUE);
492   SIGNAL_CONNECT(cts.tree, "tree-select-row", prefs_tree_select_cb, NULL);
493   OBJECT_SET_DATA(prefs_w, E_PREFSW_TREE_KEY, cts.tree);
494 #else
495   store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_INT);
496   cts.tree = tree_view_new(GTK_TREE_MODEL(store));
497   OBJECT_SET_DATA(prefs_w, E_PREFSW_TREE_KEY, cts.tree);
498   gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(cts.tree), FALSE);
499   selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(cts.tree));
500   gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
501   renderer = gtk_cell_renderer_text_new();
502   col_offset = gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(cts.tree),
503                                                            -1, "Name", renderer,
504                                                            "text", 0, NULL);
505   column = gtk_tree_view_get_column(GTK_TREE_VIEW(cts.tree),
506                                     col_offset - 1);
507   gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column),
508                                   GTK_TREE_VIEW_COLUMN_AUTOSIZE);
509   SIGNAL_CONNECT(selection, "changed", prefs_tree_select_cb, NULL);
510 #endif
511   gtk_container_add(GTK_CONTAINER(ct_sb), cts.tree);
512   gtk_widget_show(cts.tree);
513
514   /* A notebook widget without tabs is used to flip between prefs */
515   prefs_nb = gtk_notebook_new();
516   OBJECT_SET_DATA(prefs_w, E_PREFSW_NOTEBOOK_KEY, prefs_nb);
517   gtk_notebook_set_show_tabs(GTK_NOTEBOOK(prefs_nb), FALSE);
518   gtk_notebook_set_show_border(GTK_NOTEBOOK(prefs_nb), FALSE);
519   gtk_container_add(GTK_CONTAINER(top_hb), prefs_nb);
520   gtk_widget_show(prefs_nb);
521
522   cts.page = 0;
523
524   /* GUI prefs */
525   strcpy(label_str, "User Interface");
526   prefs_nb_page_add(prefs_nb, label_str, gui_prefs_show(), E_GUI_PAGE_KEY);
527   gui_iter = prefs_tree_page_add(label_str, cts.page, store, NULL, TRUE);
528   cts.page++;
529
530   /* GUI layout prefs */
531   strcpy(label_str, "Layout");
532   prefs_nb_page_add(prefs_nb, label_str, layout_prefs_show(), E_GUI_LAYOUT_PAGE_KEY);
533   prefs_tree_page_add(label_str, cts.page, store, &gui_iter, FALSE);
534   cts.page++;
535
536   /* GUI Column prefs */
537   strcpy(label_str, "Columns");
538   prefs_nb_page_add(prefs_nb, label_str, column_prefs_show(), E_GUI_COLUMN_PAGE_KEY);
539   prefs_tree_page_add(label_str, cts.page, store, &gui_iter, FALSE);
540   cts.page++;
541
542   /* GUI Font prefs */
543   strcpy(label_str, "Font");
544   gui_font_pg = gui_font_prefs_show();
545   prefs_nb_page_add(prefs_nb, label_str, gui_font_pg, E_GUI_FONT_PAGE_KEY);
546   prefs_tree_page_add(label_str, cts.page, store, &gui_iter, FALSE);
547   cts.page++;
548
549   gtk_container_border_width( GTK_CONTAINER(gui_font_pg), 5 );
550
551   /* IMPORTANT: the following gtk_font_selection_set_xy() functions will only
552      work, if the widget and it's corresponding window is already shown
553      (so don't put the following into gui_font_prefs_show()) !!! */
554
555   /* We set the current font and, for GTK+ 1.2[.x], the font filter
556      now, because they appear not to work when run before appending
557      the frame to the notebook. */
558
559   /* Set the font to the current font.
560      XXX - GTK+ 1.2.8, and probably earlier versions, have a bug
561      wherein that doesn't necessarily cause that font to be
562      selected in the dialog box.  I've sent to the GTK+ folk
563      a fix; hopefully, it'll show up in 1.2.9 if, as, and when
564      they put out a 1.2.9 release. */
565   gtk_font_selection_set_font_name(
566             GTK_FONT_SELECTION(gui_font_pg), prefs.PREFS_GUI_FONT_NAME);
567
568 #if GTK_MAJOR_VERSION < 2
569   /* Set its filter to show only fixed_width fonts. */
570   gtk_font_selection_set_filter(
571             GTK_FONT_SELECTION(gui_font_pg),
572             GTK_FONT_FILTER_BASE, /* user can't change the filter */
573             GTK_FONT_ALL,         /* bitmap or scalable are fine */
574             NULL,                 /* all foundries are OK */
575             NULL,                 /* all weights are OK (XXX - normal only?) */
576             NULL,                 /* all slants are OK (XXX - Roman only?) */
577             NULL,                 /* all setwidths are OK */
578             fixedwidths,          /* ONLY fixed-width fonts */
579             NULL);      /* all charsets are OK (XXX - ISO 8859/1 only?) */
580 #endif
581
582   /* GUI Colors prefs */
583   strcpy(label_str, "Colors");
584   prefs_nb_page_add(prefs_nb, label_str, stream_prefs_show(), E_GUI_COLORS_PAGE_KEY);
585   prefs_tree_page_add(label_str, cts.page, store, &gui_iter, FALSE);
586   cts.page++;
587
588   /* select the main GUI page as the default page and expand it's children */
589 #if GTK_MAJOR_VERSION < 2
590   gtk_ctree_select(GTK_CTREE(cts.tree), gui_iter);
591 #else
592   gtk_tree_selection_select_iter(selection, &gui_iter);
593   /* (expand will only take effect, when at least one child exists) */
594   gtk_tree_view_expand_all(GTK_TREE_VIEW(cts.tree));
595 #endif
596
597 #ifdef HAVE_LIBPCAP
598 #ifdef _WIN32
599   /* Is WPcap loaded? */
600   if (has_wpcap) {
601 #endif /* _WIN32 */
602   /* capture prefs */
603   strcpy(label_str, "Capture");
604   prefs_nb_page_add(prefs_nb, label_str, capture_prefs_show(), E_CAPTURE_PAGE_KEY);
605   prefs_tree_page_add(label_str, cts.page, store, NULL, FALSE);
606   cts.page++;
607 #ifdef _WIN32
608   }
609 #endif /* _WIN32 */
610 #endif /* HAVE_LIBPCAP */
611
612   /* Printing prefs */
613   strcpy(label_str, "Printing");
614   prefs_nb_page_add(prefs_nb, label_str, printer_prefs_show(), E_PRINT_PAGE_KEY);
615   prefs_tree_page_add(label_str, cts.page, store, NULL, FALSE);
616   cts.page++;
617
618   /* Name resolution prefs */
619   strcpy(label_str, "Name Resolution");
620   prefs_nb_page_add(prefs_nb, label_str, nameres_prefs_show(), E_NAMERES_PAGE_KEY);
621   prefs_tree_page_add(label_str, cts.page, store, NULL, FALSE);
622   cts.page++;
623
624   /* Registered prefs */
625   cts.notebook = prefs_nb;
626   cts.is_protocol = FALSE;
627   prefs_module_list_foreach(NULL, module_prefs_show, &cts);
628
629   /* Button row: OK and alike buttons */
630
631   if(topic_available(HELP_PREFERENCES_DIALOG)) {
632     bbox = dlg_button_row_new(GTK_STOCK_HELP, GTK_STOCK_OK, GTK_STOCK_APPLY, GTK_STOCK_SAVE, GTK_STOCK_CANCEL, NULL);
633   } else {
634     bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_APPLY, GTK_STOCK_SAVE, GTK_STOCK_CANCEL, NULL);
635   }
636   gtk_box_pack_start(GTK_BOX(cts.main_vb), bbox, FALSE, FALSE, 0);
637   gtk_widget_show(bbox);
638
639   ok_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_OK);
640   SIGNAL_CONNECT(ok_bt, "clicked", prefs_main_ok_cb, prefs_w);
641
642   apply_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_APPLY);
643   SIGNAL_CONNECT(apply_bt, "clicked", prefs_main_apply_cb, prefs_w);
644
645   save_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_SAVE);
646   SIGNAL_CONNECT(save_bt, "clicked", prefs_main_save_cb, prefs_w);
647   OBJECT_SET_DATA(prefs_w, E_PREFSW_SAVE_BT_KEY, save_bt);
648
649   cancel_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_CANCEL);
650   SIGNAL_CONNECT(cancel_bt, "clicked", prefs_main_cancel_cb, prefs_w);
651   window_set_cancel_button(prefs_w, cancel_bt, NULL);
652
653   gtk_widget_grab_default(ok_bt);
654
655   if(topic_available(HELP_PREFERENCES_DIALOG)) {
656     help_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_HELP);
657     SIGNAL_CONNECT(help_bt, "clicked", topic_cb, HELP_PREFERENCES_DIALOG);
658   }
659
660   SIGNAL_CONNECT(prefs_w, "delete_event", prefs_main_delete_event_cb, prefs_w);
661   SIGNAL_CONNECT(prefs_w, "destroy", prefs_main_destroy_cb, prefs_w);
662
663   gtk_widget_show(prefs_w);
664
665   /* hide the Save button if the user uses implicit save */
666   if(!prefs.gui_use_pref_save) {
667     gtk_widget_hide(save_bt);
668   }
669
670   window_present(prefs_w);
671
672 #if GTK_MAJOR_VERSION >= 2
673   g_object_unref(G_OBJECT(store));
674 #endif
675 }
676
677 static void
678 set_option_label(GtkWidget *main_tb, int table_position,
679     const gchar *label_text, const gchar *tooltip_text, GtkTooltips *tooltips)
680 {
681         GtkWidget *label;
682         GtkWidget *event_box;
683
684         label = gtk_label_new(label_text);
685         gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
686         gtk_widget_show(label);
687
688         event_box = gtk_event_box_new();
689         gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box, 0, 1,
690             table_position, table_position + 1);
691         if (tooltip_text != NULL && tooltips != NULL)
692                 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
693         gtk_container_add(GTK_CONTAINER(event_box), label);
694         gtk_widget_show(event_box);
695 }
696
697 GtkWidget *
698 create_preference_check_button(GtkWidget *main_tb, int table_position,
699     const gchar *label_text, const gchar *tooltip_text, gboolean active)
700 {
701         GtkTooltips *tooltips;
702         GtkWidget *check_box;
703
704         tooltips = OBJECT_GET_DATA(main_tb, E_TOOLTIPS_KEY);
705
706         set_option_label(main_tb, table_position, label_text, tooltip_text,
707             tooltips);
708
709         check_box = gtk_check_button_new();
710         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_box), active);
711         gtk_table_attach_defaults(GTK_TABLE(main_tb), check_box, 1, 2,
712             table_position, table_position + 1);
713         if (tooltip_text != NULL && tooltips != NULL)
714                 gtk_tooltips_set_tip(tooltips, check_box, tooltip_text, NULL);
715
716         return check_box;
717 }
718
719 GtkWidget *
720 create_preference_radio_buttons(GtkWidget *main_tb, int table_position,
721     const gchar *label_text, const gchar *tooltip_text,
722     const enum_val_t *enumvals, gint current_val)
723 {
724         GtkTooltips *tooltips;
725         GtkWidget *radio_button_hbox, *button = NULL;
726         GSList *rb_group;
727         int index;
728         const enum_val_t *enum_valp;
729         GtkWidget *event_box;
730
731         tooltips = OBJECT_GET_DATA(main_tb, E_TOOLTIPS_KEY);
732
733         set_option_label(main_tb, table_position, label_text, tooltip_text,
734             tooltips);
735
736         radio_button_hbox = gtk_hbox_new(FALSE, 0);
737         rb_group = NULL;
738         for (enum_valp = enumvals, index = 0; enum_valp->name != NULL;
739             enum_valp++, index++) {
740                 button = gtk_radio_button_new_with_label(rb_group,
741                     enum_valp->description);
742                 gtk_widget_show(button);
743                 rb_group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
744                 gtk_box_pack_start(GTK_BOX(radio_button_hbox), button, FALSE,
745                     FALSE, 10);
746                 if (enum_valp->value == current_val) {
747                         gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button),
748                             TRUE);
749                 }
750         }
751         gtk_widget_show(radio_button_hbox);
752
753         event_box = gtk_event_box_new();
754         gtk_container_add(GTK_CONTAINER(event_box), radio_button_hbox);
755         gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box, 1, 2,
756             table_position, table_position+1);
757         if (tooltip_text != NULL && tooltips != NULL)
758                 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
759         gtk_widget_show(event_box);
760
761         /*
762          * It doesn't matter which of the buttons we return - we fetch
763          * the value by looking at the entire radio button group to
764          * which it belongs, and we can get that from any button.
765          */
766         return button;
767 }
768
769 static gint
770 label_to_enum_val(GtkWidget *label, const enum_val_t *enumvals)
771 {
772         char *label_string;
773         int i;
774
775         /* Get the label's text, and translate it to a value.
776            We match only the descriptions, as those are what appear in
777            the option menu items or as labels for radio buttons.
778            We fail if we don't find a match, as that "can't happen". */
779         gtk_label_get(GTK_LABEL(label), &label_string);
780
781         for (i = 0; enumvals[i].name != NULL; i++) {
782                 if (strcasecmp(label_string, enumvals[i].description) == 0) {
783                         return enumvals[i].value;
784                 }
785         }
786         g_assert_not_reached();
787         return -1;
788 }
789
790 gint
791 fetch_preference_radio_buttons_val(GtkWidget *button,
792     const enum_val_t *enumvals)
793 {
794         GSList *rb_group;
795         GSList *rb_entry;
796
797         /*
798          * Go through the list of of radio buttons in the button's group,
799          * and find the first one that's active.
800          */
801         rb_group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
802         button = NULL;
803         for (rb_entry = rb_group; rb_entry != NULL;
804             rb_entry = g_slist_next(rb_entry)) {
805                 button = rb_entry->data;
806                 if (GTK_TOGGLE_BUTTON(button)->active)
807                         break;
808         }
809
810         /* OK, now return the value corresponding to that button's label. */
811         return label_to_enum_val(GTK_BIN(button)->child, enumvals);
812 }
813
814 GtkWidget *
815 create_preference_option_menu(GtkWidget *main_tb, int table_position,
816     const gchar *label_text, const gchar *tooltip_text,
817     const enum_val_t *enumvals, gint current_val)
818 {
819         GtkTooltips *tooltips;
820         GtkWidget *menu_box, *menu, *menu_item, *option_menu;
821         int menu_index, index;
822         const enum_val_t *enum_valp;
823         GtkWidget *event_box;
824
825         tooltips = OBJECT_GET_DATA(main_tb, E_TOOLTIPS_KEY);
826
827         set_option_label(main_tb, table_position, label_text, tooltip_text,
828             tooltips);
829
830         /* Create a menu from the enumvals */
831         menu = gtk_menu_new();
832         if (tooltip_text != NULL && tooltips != NULL)
833                 gtk_tooltips_set_tip(tooltips, menu, tooltip_text, NULL);
834         menu_index = -1;
835         for (enum_valp = enumvals, index = 0; enum_valp->name != NULL;
836             enum_valp++, index++) {
837                 menu_item = gtk_menu_item_new_with_label(enum_valp->description);
838                 gtk_menu_append(GTK_MENU(menu), menu_item);
839                 if (enum_valp->value == current_val)
840                         menu_index = index;
841                 gtk_widget_show(menu_item);
842         }
843
844         /* Create the option menu from the menu */
845         option_menu = gtk_option_menu_new();
846         gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), menu);
847
848         /* Set its current value to the variable's current value */
849         if (menu_index != -1)
850                 gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu),
851                     menu_index);
852
853         /*
854          * Put the option menu in an hbox, so that it's only as wide
855          * as the widest entry, rather than being as wide as the table
856          * space.
857          */
858         menu_box = gtk_hbox_new(FALSE, 0);
859         gtk_box_pack_start(GTK_BOX(menu_box), option_menu, FALSE, FALSE, 0);
860
861         event_box = gtk_event_box_new();
862         gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box,
863             1, 2, table_position, table_position + 1);
864         if (tooltip_text != NULL && tooltips != NULL)
865                 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
866         gtk_container_add(GTK_CONTAINER(event_box), menu_box);
867
868         return option_menu;
869 }
870
871 gint
872 fetch_preference_option_menu_val(GtkWidget *optmenu, const enum_val_t *enumvals)
873 {
874         /*
875          * OK, now return the value corresponding to the label for the
876          * currently active entry in the option menu.
877          *
878          * Yes, this is how you get the label for that entry.  See FAQ
879          * 6.8 in the GTK+ FAQ.
880          */
881         return label_to_enum_val(GTK_BIN(optmenu)->child, enumvals);
882 }
883
884 GtkWidget *
885 create_preference_entry(GtkWidget *main_tb, int table_position,
886     const gchar *label_text, const gchar *tooltip_text, char *value)
887 {
888         GtkTooltips *tooltips;
889         GtkWidget *entry;
890
891         tooltips = OBJECT_GET_DATA(main_tb, E_TOOLTIPS_KEY);
892
893         set_option_label(main_tb, table_position, label_text, tooltip_text,
894             tooltips);
895
896         entry = gtk_entry_new();
897         if (value != NULL)
898                 gtk_entry_set_text(GTK_ENTRY(entry), value);
899         gtk_table_attach_defaults(GTK_TABLE(main_tb), entry, 1, 2,
900             table_position, table_position + 1);
901         if (tooltip_text != NULL && tooltips != NULL)
902                 gtk_tooltips_set_tip(tooltips, entry, tooltip_text, NULL);
903         gtk_widget_show(entry);
904
905         return entry;
906 }
907
908 static guint
909 pref_check(pref_t *pref, gpointer user_data)
910 {
911   const char *str_val;
912   char *p;
913   guint uval;
914   pref_t **badpref = user_data;
915
916   /* Fetch the value of the preference, and check whether it's valid. */
917   switch (pref->type) {
918
919   case PREF_UINT:
920     str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
921     uval = strtoul(str_val, &p, pref->info.base);
922     if (p == str_val || *p != '\0') {
923       *badpref = pref;
924       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
925     }
926     break;
927
928   case PREF_BOOL:
929     /* Value can't be bad. */
930     break;
931
932   case PREF_ENUM:
933     /* Value can't be bad. */
934     break;
935
936   case PREF_STRING:
937     /* Value can't be bad. */
938     break;
939
940   case PREF_RANGE:
941     str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
942
943     if (strlen(str_val) != 0) {
944         range_t *newrange;
945
946         if (range_convert_str(&newrange, str_val, pref->info.max_value) !=
947             CVT_NO_ERROR) {
948             *badpref = pref;
949             return PREFS_SET_SYNTAX_ERR;        /* range was bad */
950         }
951         g_free(newrange);
952     }
953     break;
954
955   case PREF_OBSOLETE:
956     g_assert_not_reached();
957     break;
958   }
959   return 0;
960 }
961
962 static guint
963 module_prefs_check(module_t *module, gpointer user_data)
964 {
965   /* For all preferences in this module, fetch its value from this
966      module's notebook page and check whether it's valid. */
967   return prefs_pref_foreach(module, pref_check, user_data);
968 }
969
970 static guint
971 pref_fetch(pref_t *pref, gpointer user_data)
972 {
973   const char *str_val;
974   char *p;
975   guint uval;
976   gboolean bval;
977   gint enumval;
978   gboolean *pref_changed_p = user_data;
979
980   /* Fetch the value of the preference, and set the appropriate variable
981      to it. */
982   switch (pref->type) {
983
984   case PREF_UINT:
985     str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
986     uval = strtoul(str_val, &p, pref->info.base);
987 #if 0
988     if (p == value || *p != '\0')
989       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
990 #endif
991     if (*pref->varp.uint != uval) {
992       *pref_changed_p = TRUE;
993       *pref->varp.uint = uval;
994     }
995     break;
996
997   case PREF_BOOL:
998     bval = GTK_TOGGLE_BUTTON(pref->control)->active;
999     if (*pref->varp.boolp != bval) {
1000       *pref_changed_p = TRUE;
1001       *pref->varp.boolp = bval;
1002     }
1003     break;
1004
1005   case PREF_ENUM:
1006     if (pref->info.enum_info.radio_buttons) {
1007       enumval = fetch_preference_radio_buttons_val(pref->control,
1008           pref->info.enum_info.enumvals);
1009     } else {
1010       enumval = fetch_preference_option_menu_val(pref->control,
1011           pref->info.enum_info.enumvals);
1012     }
1013
1014     if (*pref->varp.enump != enumval) {
1015       *pref_changed_p = TRUE;
1016       *pref->varp.enump = enumval;
1017     }
1018     break;
1019
1020   case PREF_STRING:
1021     str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
1022     if (strcmp(*pref->varp.string, str_val) != 0) {
1023       *pref_changed_p = TRUE;
1024       g_free((void *)*pref->varp.string);
1025       *pref->varp.string = g_strdup(str_val);
1026     }
1027     break;
1028
1029   case PREF_RANGE:
1030   {
1031     range_t *newrange;
1032     convert_ret_t ret;
1033
1034     str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
1035     ret = range_convert_str(&newrange, str_val, pref->info.max_value);
1036     if (ret != CVT_NO_ERROR)
1037 #if 0
1038       return PREFS_SET_SYNTAX_ERR;      /* range was bad */
1039 #else
1040       return 0; /* XXX - should fail */
1041 #endif
1042
1043     if (!ranges_are_equal(*pref->varp.range, newrange)) {
1044       *pref_changed_p = TRUE;
1045       g_free(*pref->varp.range);
1046       *pref->varp.range = newrange;
1047     } else
1048       g_free(newrange);
1049
1050     break;
1051   }
1052
1053   case PREF_OBSOLETE:
1054     g_assert_not_reached();
1055     break;
1056   }
1057   return 0;
1058 }
1059
1060 static guint
1061 module_prefs_fetch(module_t *module, gpointer user_data)
1062 {
1063   gboolean *must_redissect_p = user_data;
1064
1065   /* For all preferences in this module, fetch its value from this
1066      module's notebook page.  Find out whether any of them changed. */
1067   module->prefs_changed = FALSE;        /* assume none of them changed */
1068   prefs_pref_foreach(module, pref_fetch, &module->prefs_changed);
1069
1070   /* If any of them changed, indicate that we must redissect and refilter
1071      the current capture (if we have one), as the preference change
1072      could cause packets to be dissected differently. */
1073   if (module->prefs_changed)
1074     *must_redissect_p = TRUE;
1075
1076   return 0;     /* keep fetching module preferences */
1077 }
1078
1079 #ifdef HAVE_AIRPCAP
1080 /*
1081  * This function is used to apply changes and update the Wireless Toolbar
1082  * whenever we apply some changes to the WEP preferences
1083  */
1084 static void
1085 prefs_airpcap_update()
1086 {
1087 GtkWidget *decryption_cm;
1088 GtkWidget *decryption_en;
1089 gboolean wireshark_decryption_was_enabled;
1090 gboolean airpcap_decryption_was_enabled;
1091 gboolean wireshark_decryption_is_now_enabled;
1092
1093 decryption_cm = GTK_WIDGET(OBJECT_GET_DATA(airpcap_tb,AIRPCAP_TOOLBAR_DECRYPTION_KEY));
1094 decryption_en = GTK_WIDGET(GTK_ENTRY(GTK_COMBO(decryption_cm)->entry));
1095
1096 if( g_strcasecmp(gtk_entry_get_text(GTK_ENTRY(decryption_en)),AIRPCAP_DECRYPTION_TYPE_STRING_WIRESHARK) == 0 )
1097 {
1098 wireshark_decryption_was_enabled = TRUE;
1099 airpcap_decryption_was_enabled = FALSE;
1100 }
1101 else if( g_strcasecmp(gtk_entry_get_text(GTK_ENTRY(decryption_en)),AIRPCAP_DECRYPTION_TYPE_STRING_AIRPCAP) == 0 )
1102 {
1103 wireshark_decryption_was_enabled = FALSE;
1104 airpcap_decryption_was_enabled = TRUE;
1105 }
1106 else if( g_strcasecmp(gtk_entry_get_text(GTK_ENTRY(decryption_en)),AIRPCAP_DECRYPTION_TYPE_STRING_NONE) == 0 )
1107 {
1108 wireshark_decryption_was_enabled = FALSE;
1109 airpcap_decryption_was_enabled = FALSE;
1110 }
1111
1112 wireshark_decryption_is_now_enabled = wireshark_decryption_on();
1113
1114 if(wireshark_decryption_is_now_enabled && airpcap_decryption_was_enabled)
1115         {
1116         set_airpcap_decryption(FALSE);
1117         gtk_entry_set_text(GTK_ENTRY(decryption_en),AIRPCAP_DECRYPTION_TYPE_STRING_WIRESHARK);
1118         }
1119 if(wireshark_decryption_is_now_enabled && !airpcap_decryption_was_enabled)
1120         {
1121         set_airpcap_decryption(FALSE);
1122         gtk_entry_set_text(GTK_ENTRY(decryption_en),AIRPCAP_DECRYPTION_TYPE_STRING_WIRESHARK);
1123         }
1124 else if(!wireshark_decryption_is_now_enabled && wireshark_decryption_was_enabled)
1125         {
1126         if(airpcap_decryption_was_enabled)
1127                 {
1128                 set_airpcap_decryption(TRUE);
1129                 gtk_entry_set_text(GTK_ENTRY(decryption_en),AIRPCAP_DECRYPTION_TYPE_STRING_AIRPCAP);
1130                 }
1131         else
1132                 {
1133                 set_airpcap_decryption(FALSE);
1134                 gtk_entry_set_text(GTK_ENTRY(decryption_en),AIRPCAP_DECRYPTION_TYPE_STRING_NONE);
1135                 }
1136         }
1137 }
1138 #endif
1139
1140 static guint
1141 pref_clean(pref_t *pref, gpointer user_data _U_)
1142 {
1143   switch (pref->type) {
1144
1145   case PREF_UINT:
1146     break;
1147
1148   case PREF_BOOL:
1149     break;
1150
1151   case PREF_ENUM:
1152     break;
1153
1154   case PREF_STRING:
1155     if (pref->saved_val.string != NULL) {
1156       g_free(pref->saved_val.string);
1157       pref->saved_val.string = NULL;
1158     }
1159     break;
1160
1161   case PREF_RANGE:
1162     if (pref->saved_val.range != NULL) {
1163       g_free(pref->saved_val.range);
1164       pref->saved_val.range = NULL;
1165     }
1166     break;
1167
1168   case PREF_OBSOLETE:
1169     g_assert_not_reached();
1170     break;
1171   }
1172   return 0;
1173 }
1174
1175 static guint
1176 module_prefs_clean(module_t *module, gpointer user_data _U_)
1177 {
1178   /* For all preferences in this module, clean up any cruft allocated for
1179      use by the GUI code. */
1180   prefs_pref_foreach(module, pref_clean, NULL);
1181   return 0;     /* keep cleaning modules */
1182 }
1183
1184 /* fetch all pref values from all pages */
1185 static gboolean
1186 prefs_main_fetch_all(GtkWidget *dlg, gboolean *must_redissect)
1187 {
1188   pref_t *badpref;
1189
1190   /* First, check that the values are all valid. */
1191   /* XXX - check the non-registered preferences too */
1192   switch (prefs_modules_foreach(module_prefs_check, (gpointer)&badpref)) {
1193
1194   case PREFS_SET_SYNTAX_ERR:
1195     switch (badpref->type) {
1196
1197     case PREF_UINT:
1198       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1199                     "The value for \"%s\" isn't a valid number.",
1200                     badpref->title);
1201       return FALSE;
1202
1203     case PREF_RANGE:
1204       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1205                     "The value for \"%s\" isn't a valid range.",
1206                     badpref->title);
1207       return FALSE;
1208
1209     default:
1210       g_assert_not_reached();
1211       break;
1212     }
1213   }
1214
1215   /* Fetch the preferences (i.e., make sure all the values set in all of
1216      the preferences panes have been copied to "prefs" and the registered
1217      preferences). */
1218   gui_prefs_fetch(OBJECT_GET_DATA(dlg, E_GUI_PAGE_KEY));
1219   layout_prefs_fetch(OBJECT_GET_DATA(dlg, E_GUI_LAYOUT_PAGE_KEY));
1220   column_prefs_fetch(OBJECT_GET_DATA(dlg, E_GUI_COLUMN_PAGE_KEY));
1221   stream_prefs_fetch(OBJECT_GET_DATA(dlg, E_GUI_COLORS_PAGE_KEY));
1222
1223 #ifdef HAVE_LIBPCAP
1224 #ifdef _WIN32
1225   /* Is WPcap loaded? */
1226   if (has_wpcap) {
1227 #endif /* _WIN32 */
1228   capture_prefs_fetch(OBJECT_GET_DATA(dlg, E_CAPTURE_PAGE_KEY));
1229 #ifdef _WIN32
1230   }
1231 #endif /* _WIN32 */
1232 #endif /* HAVE_LIBPCAP */
1233   printer_prefs_fetch(OBJECT_GET_DATA(dlg, E_PRINT_PAGE_KEY));
1234   nameres_prefs_fetch(OBJECT_GET_DATA(dlg, E_NAMERES_PAGE_KEY));
1235
1236   prefs_modules_foreach(module_prefs_fetch, must_redissect);
1237
1238   return TRUE;
1239 }
1240
1241 /* apply all pref values to the real world */
1242 static void
1243 prefs_main_apply_all(GtkWidget *dlg)
1244 {
1245   GtkWidget *save_bt;
1246
1247   /*
1248    * Apply the protocol preferences first - "gui_prefs_apply()" could
1249    * cause redissection, and we have to make sure the protocol
1250    * preference changes have been fully applied.
1251    */
1252   prefs_apply_all();
1253
1254   gui_prefs_apply(OBJECT_GET_DATA(dlg, E_GUI_PAGE_KEY));
1255   layout_prefs_apply(OBJECT_GET_DATA(dlg, E_GUI_LAYOUT_PAGE_KEY));
1256   column_prefs_apply(OBJECT_GET_DATA(dlg, E_GUI_COLUMN_PAGE_KEY));
1257   stream_prefs_apply(OBJECT_GET_DATA(dlg, E_GUI_COLORS_PAGE_KEY));
1258
1259 #ifdef HAVE_LIBPCAP
1260 #ifdef _WIN32
1261   /* Is WPcap loaded? */
1262   if (has_wpcap) {
1263 #endif /* _WIN32 */
1264   capture_prefs_apply(OBJECT_GET_DATA(dlg, E_CAPTURE_PAGE_KEY));
1265 #ifdef _WIN32
1266   }
1267 #endif /* _WIN32 */
1268 #endif /* HAVE_LIBPCAP */
1269   printer_prefs_apply(OBJECT_GET_DATA(dlg, E_PRINT_PAGE_KEY));
1270   nameres_prefs_apply(OBJECT_GET_DATA(dlg, E_NAMERES_PAGE_KEY));
1271
1272   /* show/hide the Save button - depending on setting */
1273   save_bt = OBJECT_GET_DATA(prefs_w, E_PREFSW_SAVE_BT_KEY);
1274   if(prefs.gui_use_pref_save) {
1275     gtk_widget_show(save_bt);
1276   } else {
1277     gtk_widget_hide(save_bt);
1278   }
1279 }
1280
1281
1282 /* destroy all preferences ressources from all pages */
1283 static void
1284 prefs_main_destroy_all(GtkWidget *dlg)
1285 {
1286 #if GTK_MAJOR_VERSION >= 2
1287   int page_num;
1288   GtkWidget *frame;
1289
1290   for (page_num = 0;
1291        (frame = gtk_notebook_get_nth_page(OBJECT_GET_DATA(prefs_w, E_PREFSW_NOTEBOOK_KEY), page_num)) != NULL;
1292        page_num++) {
1293                    if(OBJECT_GET_DATA(frame, E_PAGE_ITER_KEY))
1294                gtk_tree_iter_free(OBJECT_GET_DATA(frame, E_PAGE_ITER_KEY));
1295            }
1296 #endif
1297
1298   gui_prefs_destroy(OBJECT_GET_DATA(dlg, E_GUI_PAGE_KEY));
1299   layout_prefs_destroy(OBJECT_GET_DATA(dlg, E_GUI_LAYOUT_PAGE_KEY));
1300   column_prefs_destroy(OBJECT_GET_DATA(dlg, E_GUI_COLUMN_PAGE_KEY));
1301   stream_prefs_destroy(OBJECT_GET_DATA(dlg, E_GUI_COLORS_PAGE_KEY));
1302
1303 #ifdef HAVE_LIBPCAP
1304 #ifdef _WIN32
1305   /* Is WPcap loaded? */
1306   if (has_wpcap) {
1307 #endif /* _WIN32 */
1308   capture_prefs_destroy(OBJECT_GET_DATA(dlg, E_CAPTURE_PAGE_KEY));
1309 #ifdef _WIN32
1310   }
1311 #endif /* _WIN32 */
1312 #endif /* HAVE_LIBPCAP */
1313   printer_prefs_destroy(OBJECT_GET_DATA(dlg, E_PRINT_PAGE_KEY));
1314   nameres_prefs_destroy(OBJECT_GET_DATA(dlg, E_NAMERES_PAGE_KEY));
1315
1316   /* Free up the saved preferences (both for "prefs" and for registered
1317      preferences). */
1318   free_prefs(&saved_prefs);
1319   prefs_modules_foreach(module_prefs_clean, NULL);
1320 }
1321
1322
1323 static void
1324 prefs_main_write(void)
1325 {
1326   int err;
1327   char *pf_dir_path;
1328   char *pf_path;
1329
1330   /* Create the directory that holds personal configuration files, if
1331      necessary.  */
1332   if (create_persconffile_dir(&pf_dir_path) == -1) {
1333      simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1334       "Can't create directory\n\"%s\"\nfor preferences file: %s.", pf_dir_path,
1335       strerror(errno));
1336      g_free(pf_dir_path);
1337   } else {
1338     /* Write the preferencs out. */
1339     err = write_prefs(&pf_path);
1340     if (err != 0) {
1341        simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1342         "Can't open preferences file\n\"%s\": %s.", pf_path,
1343         strerror(err));
1344        g_free(pf_path);
1345     }
1346   }
1347
1348 #ifdef HAVE_AIRPCAP
1349 /* 
1350  * Load the Wireshark decryption keys (just set) and save 
1351  * the changes to the adapters' registry 
1352  */ 
1353 airpcap_load_decryption_keys(airpcap_if_list);
1354 #endif
1355 }
1356
1357
1358 static void
1359 prefs_main_ok_cb(GtkWidget *ok_bt _U_, gpointer parent_w)
1360 {
1361   gboolean must_redissect = FALSE;
1362
1363   if (!prefs_main_fetch_all(parent_w, &must_redissect))
1364     return; /* Errors in some preference setting - already reported */
1365
1366   /* if we don't have a Save button, just save the settings now */
1367   if (!prefs.gui_use_pref_save) {
1368       prefs_main_write();
1369   }
1370
1371   prefs_main_apply_all(parent_w);
1372
1373   /* Fill in capture options with values from the preferences */
1374   prefs_to_capture_opts();
1375
1376         #ifdef HAVE_AIRPCAP
1377         prefs_airpcap_update();
1378         #endif
1379
1380   /* Now destroy the "Preferences" dialog. */
1381   window_destroy(GTK_WIDGET(parent_w));
1382
1383   if (must_redissect) {
1384     /* Redissect all the packets, and re-evaluate the display filter. */
1385     cf_redissect_packets(&cfile);
1386   }
1387
1388 }
1389
1390 static void
1391 prefs_main_apply_cb(GtkWidget *apply_bt _U_, gpointer parent_w)
1392 {
1393   gboolean must_redissect = FALSE;
1394
1395   if (!prefs_main_fetch_all(parent_w, &must_redissect))
1396     return; /* Errors in some preference setting - already reported */
1397
1398   /* if we don't have a Save button, just save the settings now */
1399   if (!prefs.gui_use_pref_save) {
1400       prefs_main_write();
1401   }
1402
1403   prefs_main_apply_all(parent_w);
1404
1405   /* Fill in capture options with values from the preferences */
1406   prefs_to_capture_opts();
1407
1408         #ifdef HAVE_AIRPCAP
1409         prefs_airpcap_update();
1410         #endif
1411
1412   if (must_redissect) {
1413     /* Redissect all the packets, and re-evaluate the display filter. */
1414     cf_redissect_packets(&cfile);
1415   }
1416 }
1417
1418 static void
1419 prefs_main_save_cb(GtkWidget *save_bt _U_, gpointer parent_w)
1420 {
1421   gboolean must_redissect = FALSE;
1422
1423   if (!prefs_main_fetch_all(parent_w, &must_redissect))
1424     return; /* Errors in some preference setting - already reported */
1425
1426   prefs_main_write();
1427
1428   /* Now apply those preferences.
1429      XXX - should we do this?  The user didn't click "OK" or "Apply".
1430      However:
1431
1432         1) by saving the preferences they presumably indicate that they
1433            like them;
1434
1435         2) the next time they fire Wireshark up, those preferences will
1436            apply;
1437
1438         3) we'd have to buffer "must_redissect" so that if they do
1439            "Apply" after this, we know we have to redissect;
1440
1441         4) we did apply the protocol preferences, at least, in the past. */
1442   prefs_main_apply_all(parent_w);
1443
1444   /* Fill in capture options with values from the preferences */
1445   prefs_to_capture_opts();
1446
1447   if (must_redissect) {
1448     /* Redissect all the packets, and re-evaluate the display filter. */
1449     cf_redissect_packets(&cfile);
1450   }
1451 }
1452
1453 static guint
1454 pref_revert(pref_t *pref, gpointer user_data)
1455 {
1456   gboolean *pref_changed_p = user_data;
1457
1458   /* Revert the preference to its saved value. */
1459   switch (pref->type) {
1460
1461   case PREF_UINT:
1462     if (*pref->varp.uint != pref->saved_val.uint) {
1463       *pref_changed_p = TRUE;
1464       *pref->varp.uint = pref->saved_val.uint;
1465     }
1466     break;
1467
1468   case PREF_BOOL:
1469     if (*pref->varp.boolp != pref->saved_val.boolval) {
1470       *pref_changed_p = TRUE;
1471       *pref->varp.boolp = pref->saved_val.boolval;
1472     }
1473     break;
1474
1475   case PREF_ENUM:
1476     if (*pref->varp.enump != pref->saved_val.enumval) {
1477       *pref_changed_p = TRUE;
1478       *pref->varp.enump = pref->saved_val.enumval;
1479     }
1480     break;
1481
1482   case PREF_STRING:
1483     if (strcmp(*pref->varp.string, pref->saved_val.string) != 0) {
1484       *pref_changed_p = TRUE;
1485       g_free((void *)*pref->varp.string);
1486       *pref->varp.string = g_strdup(pref->saved_val.string);
1487     }
1488     break;
1489
1490   case PREF_RANGE:
1491     if (!ranges_are_equal(*pref->varp.range, pref->saved_val.range)) {
1492       *pref_changed_p = TRUE;
1493       g_free(*pref->varp.range);
1494       *pref->varp.range = range_copy(pref->saved_val.range);
1495     }
1496     break;
1497
1498   case PREF_OBSOLETE:
1499     g_assert_not_reached();
1500     break;
1501   }
1502   return 0;
1503 }
1504
1505 static guint
1506 module_prefs_revert(module_t *module, gpointer user_data)
1507 {
1508   gboolean *must_redissect_p = user_data;
1509
1510   /* For all preferences in this module, revert its value to the value
1511      it had when we popped up the Preferences dialog.  Find out whether
1512      this changes any of them. */
1513   module->prefs_changed = FALSE;        /* assume none of them changed */
1514   prefs_pref_foreach(module, pref_revert, &module->prefs_changed);
1515
1516   /* If any of them changed, indicate that we must redissect and refilter
1517      the current capture (if we have one), as the preference change
1518      could cause packets to be dissected differently. */
1519   if (module->prefs_changed)
1520     *must_redissect_p = TRUE;
1521   return 0;     /* keep processing modules */
1522 }
1523
1524 /* cancel button pressed, revert prefs to saved and exit dialog */
1525 static void
1526 prefs_main_cancel_cb(GtkWidget *cancel_bt _U_, gpointer parent_w)
1527 {
1528   gboolean must_redissect = FALSE;
1529
1530   /* Free up the current preferences and copy the saved preferences to the
1531      current preferences. */
1532   free_prefs(&prefs);
1533   copy_prefs(&prefs, &saved_prefs);
1534
1535   /* Now revert the registered preferences. */
1536   prefs_modules_foreach(module_prefs_revert, &must_redissect);
1537
1538   /* Now apply the reverted-to preferences. */
1539   prefs_main_apply_all(parent_w);
1540
1541   window_destroy(GTK_WIDGET(parent_w));
1542
1543   if (must_redissect) {
1544     /* Redissect all the packets, and re-evaluate the display filter. */
1545     cf_redissect_packets(&cfile);
1546   }
1547 }
1548
1549 /* Treat this as a cancel, by calling "prefs_main_cancel_cb()" */
1550 static gboolean
1551 prefs_main_delete_event_cb(GtkWidget *prefs_w, GdkEvent *event _U_,
1552                            gpointer parent_w _U_)
1553 {
1554   prefs_main_cancel_cb(NULL, prefs_w);
1555   return FALSE;
1556 }
1557
1558
1559 /* dialog *is* already destroyed, clean up memory and such */
1560 static void
1561 prefs_main_destroy_cb(GtkWidget *win _U_, gpointer parent_w)
1562 {
1563   prefs_main_destroy_all(parent_w);
1564
1565   /* Note that we no longer have a "Preferences" dialog box. */
1566   prefs_w = NULL;
1567 }
1568
1569 struct properties_data {
1570   const char *title;
1571   module_t *module;
1572 };
1573
1574 static guint
1575 module_search_properties(module_t *module, gpointer user_data)
1576 {
1577   struct properties_data *p = (struct properties_data *)user_data;
1578
1579   /* If this module has the specified title, remember it. */
1580   if (strcmp(module->title, p->title) == 0) {
1581     p->module = module;
1582     return 1;   /* stops the search */
1583   }
1584   return 0;
1585 }
1586
1587
1588 /* select a node in the tree view */
1589 /* XXX - this is almost 100% copied from byte_view_select() in proto_draw.c,
1590  *       find a way to combine both to have a generic function for this */
1591 void
1592 tree_select_node(GtkWidget *tree, prefs_tree_iter *iter)
1593 {
1594 #if GTK_MAJOR_VERSION < 2
1595     GtkCTree     *ctree = GTK_CTREE(tree);
1596     GtkCTreeNode *node = (GtkCTreeNode *) iter;
1597         GtkCTreeNode *parent;
1598 #else
1599         GtkTreeIter  local_iter = *iter;
1600     GtkTreeView  *tree_view = GTK_TREE_VIEW(tree);
1601     GtkTreeModel *model;
1602     GtkTreePath  *first_path, *path;
1603     GtkTreeIter   parent;
1604 #endif
1605
1606 #if GTK_MAJOR_VERSION < 2
1607     /* Expand and select our field's row */
1608     gtk_ctree_expand(ctree, node);
1609     gtk_ctree_select(ctree, node);
1610     /*expand_tree(ctree, node, NULL);*/
1611
1612     /* ... and its parents */
1613     parent = GTK_CTREE_ROW(node)->parent;
1614     while (parent) {
1615         gtk_ctree_expand(ctree, parent);
1616         /*expand_tree(ctree, parent, NULL);*/
1617         parent = GTK_CTREE_ROW(parent)->parent;
1618     }
1619
1620     /* And position the window so the selection is visible.
1621      * Position the selection in the middle of the viewable
1622      * pane. */
1623     gtk_ctree_node_moveto(ctree, node, 0, .5, 0);
1624 #else
1625     model = gtk_tree_view_get_model(tree_view);
1626
1627     /* Expand our field's row */
1628     first_path = gtk_tree_model_get_path(model, &local_iter);
1629     gtk_tree_view_expand_row(tree_view, first_path, FALSE);
1630     /*expand_tree(tree_view, &iter, NULL, NULL);*/
1631
1632     /* ... and its parents */
1633     while (gtk_tree_model_iter_parent(model, &parent, &local_iter)) {
1634         path = gtk_tree_model_get_path(model, &parent);
1635         gtk_tree_view_expand_row(tree_view, path, FALSE);
1636         /*expand_tree(tree_view, &parent, NULL, NULL);*/
1637         local_iter = parent;
1638         gtk_tree_path_free(path);
1639     }
1640
1641     /* select our field's row */
1642     gtk_tree_selection_select_path(gtk_tree_view_get_selection(tree_view),
1643                                    first_path);
1644
1645     /* And position the window so the selection is visible.
1646      * Position the selection in the middle of the viewable
1647      * pane. */
1648     gtk_tree_view_scroll_to_cell(tree_view, first_path, NULL, TRUE, 0.5, 0.0);
1649
1650     gtk_tree_path_free(first_path);
1651 #endif
1652 }
1653
1654
1655 /* search the corresponding protocol page of the currently selected field */
1656 void
1657 properties_cb(GtkWidget *w, gpointer dummy)
1658 {
1659   header_field_info *hfinfo;
1660   const gchar *title;
1661   struct properties_data p;
1662   int page_num;
1663   GtkWidget *sw;
1664   GtkWidget *frame;
1665   module_t *page_module;
1666
1667   if (cfile.finfo_selected == NULL) {
1668     /* There is no field selected */
1669     return;
1670   }
1671
1672   /* Find the title for the protocol for the selected field. */
1673   hfinfo = cfile.finfo_selected->hfinfo;
1674   if (hfinfo->parent == -1)
1675     title = prefs_get_title_by_name(hfinfo->abbrev);
1676   else
1677     title = prefs_get_title_by_name(proto_registrar_get_abbrev(hfinfo->parent));
1678   if (!title)
1679     return;     /* Couldn't find it. XXX - just crash? "Can't happen"? */
1680
1681   /* Find the module for that protocol by searching for one with that title.
1682      XXX - should we just associate protocols with modules directly? */
1683   p.title = title;
1684   p.module = NULL;
1685   prefs_module_list_foreach(protocols_module->prefs, module_search_properties,
1686                             &p);
1687   if (p.module == NULL) {
1688     /* We didn't find it - that protocol probably has no preferences. */
1689     return;
1690   }
1691
1692   /* Create a preferences window, or pop up an existing one. */
1693   if (prefs_w != NULL) {
1694     reactivate_window(prefs_w);
1695   } else {
1696     prefs_cb(w, dummy);
1697   }
1698
1699   /* Search all the pages in that window for the one with the specified
1700      module. */
1701   for (page_num = 0;
1702        (sw = gtk_notebook_get_nth_page(OBJECT_GET_DATA(prefs_w, E_PREFSW_NOTEBOOK_KEY), page_num)) != NULL;
1703        page_num++) {
1704     /* Get the frame from the scrollable window */
1705     frame = OBJECT_GET_DATA(sw, E_PAGESW_FRAME_KEY);
1706     /* Get the module for this page. */
1707     page_module = OBJECT_GET_DATA(frame, E_PAGE_MODULE_KEY);
1708     if (page_module == NULL)
1709       continue; /* It doesn't have one. */
1710     if (page_module == p.module) {
1711           tree_select_node(
1712                   OBJECT_GET_DATA(prefs_w, E_PREFSW_TREE_KEY),
1713                   OBJECT_GET_DATA(frame, E_PAGE_ITER_KEY));
1714           return;
1715         }
1716   }
1717 }
1718
1719 /* Prefs tree selection callback.  The node data has been loaded with
1720    the proper notebook page to load. */
1721 #if GTK_MAJOR_VERSION < 2
1722 static void
1723 prefs_tree_select_cb(GtkCTree *ct, GtkCTreeNode *node, gint col _U_,
1724                      gpointer dummy _U_)
1725 #else
1726 static void
1727 prefs_tree_select_cb(GtkTreeSelection *sel, gpointer dummy _U_)
1728 #endif
1729 {
1730   gint page;
1731 #if GTK_MAJOR_VERSION >= 2
1732   GtkTreeModel *model;
1733   GtkTreeIter   iter;
1734 #endif
1735
1736 #if GTK_MAJOR_VERSION < 2
1737   page = GPOINTER_TO_INT(gtk_ctree_node_get_row_data(ct, node));
1738
1739   if (page >= 0)
1740     gtk_notebook_set_page(OBJECT_GET_DATA(prefs_w, E_PREFSW_NOTEBOOK_KEY), page);
1741 #else
1742   if (gtk_tree_selection_get_selected(sel, &model, &iter))
1743   {
1744     gtk_tree_model_get(model, &iter, 1, &page, -1);
1745     if (page >= 0)
1746       gtk_notebook_set_page(OBJECT_GET_DATA(prefs_w, E_PREFSW_NOTEBOOK_KEY), page);
1747   }
1748 #endif
1749 }