Change to color filters :
[obnox/wireshark/wip.git] / gtk2 / prefs_dlg.c
1 /* prefs_dlg.c
2  * Routines for handling preferences
3  *
4  * $Id: prefs_dlg.c,v 1.4 2002/09/14 10:07:39 oabad Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
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 "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 "capture_prefs.h"
46 #include "nameres_prefs.h"
47 #include "ui_util.h"
48 #include "dlg_utils.h"
49 #include "simple_dialog.h"
50
51 #include "prefs-int.h"
52
53 #ifdef HAVE_LIBPCAP
54 #ifdef WIN32
55 #include "capture-wpcap.h"
56 #endif /* _WIN32 */
57 #endif /* HAVE_LIBPCAP */
58
59 static void     prefs_main_ok_cb(GtkWidget *, gpointer);
60 static void     prefs_main_apply_cb(GtkWidget *, gpointer);
61 static void     prefs_main_save_cb(GtkWidget *, gpointer);
62 static void     prefs_main_cancel_cb(GtkWidget *, gpointer);
63 static gboolean prefs_main_delete_cb(GtkWidget *, gpointer);
64 static void     prefs_main_destroy_cb(GtkWidget *, gpointer);
65 static void     prefs_tree_select_cb(GtkTreeSelection *, gpointer);
66
67 #define E_PRINT_PAGE_KEY   "printer_options_page"
68 #define E_COLUMN_PAGE_KEY  "column_options_page"
69 #define E_STREAM_PAGE_KEY  "tcp_stream_options_page"
70 #define E_GUI_PAGE_KEY     "gui_options_page"
71 #define E_CAPTURE_PAGE_KEY "capture_options_page"
72 #define E_NAMERES_PAGE_KEY "nameres_options_page"
73 #define E_TOOLTIPS_KEY     "tooltips"
74
75 #define FIRST_PROTO_PREFS_PAGE  6
76
77 /*
78  * Keep a static pointer to the notebook to be able to choose the
79  * displayed page.
80  */
81 static GtkWidget *notebook;
82
83 /*
84  * Keep a static pointer to the current "Preferences" window, if any, so that
85  * if somebody tries to do "Edit:Preferences" while there's already a
86  * "Preferences" window up, we just pop up the existing one, rather than
87  * creating a new one.
88  */
89 static GtkWidget *prefs_w;
90
91 /*
92  * Save the value of the preferences as of when the preferences dialog
93  * box was first popped up, so we can revert to those values if the
94  * user selects "Cancel".
95  */
96 static e_prefs saved_prefs;
97
98 struct ct_struct {
99   GtkWidget    *notebook;
100   GtkWidget    *treeview;
101   GtkTreeIter  proto_iter;
102   GtkCTreeNode *node;
103   GtkTooltips  *tooltips;
104   gint         page;
105 };
106
107 static void
108 pref_show(pref_t *pref, gpointer user_data)
109 {
110   GtkWidget *main_tb = user_data;
111   const char *title;
112   char *label_string;
113   char uint_str[10+1];
114
115   /* Give this preference a label which is its title, followed by a colon,
116      and left-align it. */
117   title = pref->title;
118   label_string = g_malloc(strlen(title) + 2);
119   strcpy(label_string, title);
120   strcat(label_string, ":");
121
122   /* Save the current value of the preference, so that we can revert it if
123      the user does "Apply" and then "Cancel", and create the control for
124      editing the preference. */
125   switch (pref->type) {
126
127   case PREF_UINT:
128     pref->saved_val.uint = *pref->varp.uint;
129
130     /* XXX - there are no uint spinbuttons, so we can't use a spinbutton.
131        Even more annoyingly, even if there were, GLib doesn't define
132        G_MAXUINT - but I think ANSI C may define UINT_MAX, so we could
133        use that. */
134     switch (pref->info.base) {
135
136     case 10:
137       sprintf(uint_str, "%u", pref->saved_val.uint);
138       break;
139
140     case 8:
141       sprintf(uint_str, "%o", pref->saved_val.uint);
142       break;
143
144     case 16:
145       sprintf(uint_str, "%x", pref->saved_val.uint);
146       break;
147     }
148     pref->control = create_preference_entry(main_tb, pref->ordinal,
149                                             label_string, pref->description,
150                                             uint_str);
151     break;
152
153   case PREF_BOOL:
154     pref->saved_val.boolval = *pref->varp.boolp;
155     pref->control = create_preference_check_button(main_tb, pref->ordinal,
156                                                label_string, pref->description,
157                                                pref->saved_val.boolval);
158     break;
159
160   case PREF_ENUM:
161     pref->saved_val.enumval = *pref->varp.enump;
162     if (pref->info.enum_info.radio_buttons) {
163       /* Show it as radio buttons. */
164       pref->control = create_preference_radio_buttons(main_tb, pref->ordinal,
165                                                   label_string, pref->description,
166                                                   pref->info.enum_info.enumvals,
167                                                   pref->saved_val.enumval);
168     } else {
169       /* Show it as an option menu. */
170       pref->control = create_preference_option_menu(main_tb, pref->ordinal,
171                                          label_string, pref->description,
172                                          pref->info.enum_info.enumvals,
173                                          pref->saved_val.enumval);
174     }
175     break;
176
177   case PREF_STRING:
178     if (pref->saved_val.string != NULL)
179       g_free(pref->saved_val.string);
180     pref->saved_val.string = g_strdup(*pref->varp.string);
181     pref->control = create_preference_entry(main_tb, pref->ordinal,
182                                             label_string, pref->description,
183                                             pref->saved_val.string);
184     break;
185
186   case PREF_OBSOLETE:
187     g_assert_not_reached();
188     break;
189   }
190   g_free(label_string);
191 }
192
193 #define MAX_TREE_NODE_NAME_LEN 64
194 static void
195 module_prefs_show(module_t *module, gpointer user_data)
196 {
197   struct ct_struct *cts = user_data;
198   GtkWidget        *main_vb, *main_tb, *frame;
199   gchar            label_str[MAX_TREE_NODE_NAME_LEN];
200   GtkTreeStore     *model;
201   GtkTreeIter      iter;
202
203   /* Frame */
204   frame = gtk_frame_new(module->title);
205   gtk_widget_show(frame);
206
207   /* Main vertical box */
208   main_vb = gtk_vbox_new(FALSE, 5);
209   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
210   gtk_container_add(GTK_CONTAINER(frame), main_vb);
211
212   /* Main table */
213   main_tb = gtk_table_new(module->numprefs, 2, FALSE);
214   gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0);
215   gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10);
216   gtk_table_set_col_spacings(GTK_TABLE(main_tb), 15);
217   gtk_object_set_data(GTK_OBJECT(main_tb), E_TOOLTIPS_KEY, cts->tooltips);
218
219   /* Add items for each of the preferences */
220   prefs_pref_foreach(module, pref_show, main_tb);
221
222   gtk_notebook_append_page(GTK_NOTEBOOK(cts->notebook), frame, NULL);
223   strcpy(label_str, module->title);
224   model = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(cts->treeview)));
225   gtk_tree_store_append(model, &iter, &cts->proto_iter);
226   gtk_tree_store_set(model, &iter, 0, label_str, 1, cts->page, -1);
227   cts->page++;
228
229   /* Show 'em what we got */
230   gtk_widget_show_all(main_vb);
231 }
232
233 void
234 prefs_cb(GtkWidget *w _U_, gpointer dummy _U_)
235 {
236   GtkWidget         *main_vb, *top_hb, *bbox, *prefs_nb, *ct_sb, *frame,
237                     *ok_bt, *apply_bt, *save_bt, *cancel_bt;
238   GtkWidget         *print_pg, *column_pg, *stream_pg, *gui_pg;
239 #ifdef HAVE_LIBPCAP
240   GtkWidget         *capture_pg;
241 #endif
242   GtkWidget         *nameres_pg;
243   gchar             label_str[MAX_TREE_NODE_NAME_LEN];
244   struct ct_struct  cts;
245   GtkTreeStore      *store;
246   GtkTreeSelection  *selection;
247   GtkCellRenderer   *renderer;
248   GtkTreeViewColumn *column;
249   gint              col_offset;
250   GtkTreeIter       iter;
251
252   if (prefs_w != NULL) {
253     /* There's already a "Preferences" dialog box; reactivate it. */
254     reactivate_window(prefs_w);
255     return;
256   }
257
258   /* Save the current preferences, so we can revert to those values
259      if the user presses "Cancel". */
260   copy_prefs(&saved_prefs, &prefs);
261
262   prefs_w = dlg_window_new("Ethereal: Preferences");
263   g_signal_connect(G_OBJECT(prefs_w), "delete_event",
264                    G_CALLBACK(prefs_main_delete_cb), NULL);
265   g_signal_connect(G_OBJECT(prefs_w), "destroy",
266                    G_CALLBACK(prefs_main_destroy_cb), NULL);
267
268   /*
269    * Unfortunately, we can't arrange that a GtkTable widget wrap an event box
270    * around a table row, so the spacing between the preference item's label
271    * and its control widgets is inactive and the tooltip doesn't pop up when
272    * the mouse is over it.
273    */
274   cts.tooltips = gtk_tooltips_new();
275
276   /* Container for each row of widgets */
277   main_vb = gtk_vbox_new(FALSE, 5);
278   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
279   gtk_container_add(GTK_CONTAINER(prefs_w), main_vb);
280   gtk_widget_show(main_vb);
281
282   /* Top row: Preferences tree and notebook */
283   top_hb = gtk_hbox_new(FALSE, 10);
284   gtk_container_add(GTK_CONTAINER(main_vb), top_hb);
285   gtk_widget_show(top_hb);
286
287   /* Place a Ctree on the left for preference categories */
288   ct_sb = scrolled_window_new(NULL, NULL);
289   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ct_sb),
290         GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
291   gtk_container_add(GTK_CONTAINER(top_hb), ct_sb);
292   gtk_widget_show(ct_sb);
293
294   store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_INT);
295   cts.treeview = tree_view_new(GTK_TREE_MODEL(store));
296   gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(cts.treeview), FALSE);
297   selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(cts.treeview));
298   gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
299   renderer = gtk_cell_renderer_text_new();
300   col_offset = gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(cts.treeview),
301                                                            -1, "Name", renderer,
302                                                            "text", 0, NULL);
303   column = gtk_tree_view_get_column(GTK_TREE_VIEW(cts.treeview),
304                                     col_offset - 1);
305   gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column),
306                                   GTK_TREE_VIEW_COLUMN_AUTOSIZE);
307   cts.page  = 0;
308   gtk_container_add(GTK_CONTAINER(ct_sb), cts.treeview);
309
310   g_signal_connect(G_OBJECT(selection), "changed",
311                    G_CALLBACK(prefs_tree_select_cb), NULL);
312   gtk_widget_show(cts.treeview);
313
314   /* A notebook widget sans tabs is used to flip between prefs */
315   notebook = prefs_nb = gtk_notebook_new();
316   gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE);
317   gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook), FALSE);
318   gtk_container_add(GTK_CONTAINER(top_hb), prefs_nb);
319   gtk_widget_show(prefs_nb);
320
321   /* Printing prefs */
322   frame = gtk_frame_new("Printing");
323   gtk_widget_show(GTK_WIDGET(frame));
324   print_pg = printer_prefs_show();
325   gtk_container_add(GTK_CONTAINER(frame), print_pg);
326   gtk_object_set_data(GTK_OBJECT(prefs_w), E_PRINT_PAGE_KEY, print_pg);
327   gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
328   strcpy(label_str, "Printing");
329   gtk_tree_store_append(store, &iter, NULL);
330   gtk_tree_store_set(store, &iter, 0, label_str, 1, cts.page, -1);
331   cts.page++;
332
333   /* Column prefs */
334   frame = gtk_frame_new("Columns");
335   gtk_widget_show(GTK_WIDGET(frame));
336   column_pg = column_prefs_show();
337   gtk_container_add(GTK_CONTAINER(frame), column_pg);
338   gtk_object_set_data(GTK_OBJECT(prefs_w), E_COLUMN_PAGE_KEY, column_pg);
339   gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
340   strcpy(label_str, "Columns");
341   gtk_tree_store_append(store, &iter, NULL);
342   gtk_tree_store_set(store, &iter, 0, label_str, 1, cts.page, -1);
343   cts.page++;
344
345   /* TCP Streams prefs */
346   frame = gtk_frame_new("TCP Streams");
347   gtk_widget_show(GTK_WIDGET(frame));
348   stream_pg = stream_prefs_show();
349   gtk_container_add(GTK_CONTAINER(frame), stream_pg);
350   gtk_object_set_data(GTK_OBJECT(prefs_w), E_STREAM_PAGE_KEY, stream_pg);
351   gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
352   strcpy(label_str, "TCP Streams");
353   gtk_tree_store_append(store, &iter, NULL);
354   gtk_tree_store_set(store, &iter, 0, label_str, 1, cts.page, -1);
355   cts.page++;
356
357   /* GUI prefs */
358   frame = gtk_frame_new("User Interface");
359   gtk_widget_show(GTK_WIDGET(frame));
360   gui_pg = gui_prefs_show();
361   gtk_container_add(GTK_CONTAINER(frame), gui_pg);
362   gtk_object_set_data(GTK_OBJECT(prefs_w), E_GUI_PAGE_KEY, gui_pg);
363   gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
364   strcpy(label_str, "User Interface");
365   gtk_tree_store_append(store, &iter, NULL);
366   gtk_tree_store_set(store, &iter, 0, label_str, 1, cts.page, -1);
367   cts.page++;
368
369 #ifdef HAVE_LIBPCAP
370 #ifdef _WIN32
371   /* Is WPcap loaded? */
372   if (has_wpcap) {
373 #endif /* _WIN32 */
374   /* capture prefs */
375   frame = gtk_frame_new("Capture");
376   gtk_widget_show(GTK_WIDGET(frame));
377   capture_pg = capture_prefs_show();
378   gtk_container_add(GTK_CONTAINER(frame), capture_pg);
379   gtk_object_set_data(GTK_OBJECT(prefs_w), E_CAPTURE_PAGE_KEY, capture_pg);
380   gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
381   strcpy(label_str, "Capture");
382   gtk_tree_store_append(store, &iter, NULL);
383   gtk_tree_store_set(store, &iter, 0, label_str, 1, cts.page, -1);
384   cts.page++;
385 #ifdef _WIN32
386   }
387 #endif /* _WIN32 */
388 #endif /* HAVE_LIBPCAP */
389
390   /* Name resolution prefs */
391   frame = gtk_frame_new("Name resolution");
392   gtk_widget_show(GTK_WIDGET(frame));
393   nameres_pg = nameres_prefs_show();
394   gtk_container_add(GTK_CONTAINER(frame), nameres_pg);
395   gtk_object_set_data(GTK_OBJECT(prefs_w), E_NAMERES_PAGE_KEY, nameres_pg);
396   gtk_notebook_append_page (GTK_NOTEBOOK(prefs_nb), frame, NULL);
397   strcpy(label_str, "Name resolution");
398   gtk_tree_store_append(store, &iter, NULL);
399   gtk_tree_store_set(store, &iter, 0, label_str, 1, cts.page, -1);
400   cts.page++;
401
402   /* Registered prefs */
403   cts.notebook = prefs_nb;
404   strcpy(label_str, "Protocols");
405   gtk_tree_store_append(store, &cts.proto_iter, NULL);
406   gtk_tree_store_set(store, &cts.proto_iter, 0, label_str, 1, -1, -1);
407   /* gtk_ctree_node_set_selectable(GTK_CTREE(cts.ctree), cts.node, FALSE); */
408
409   prefs_module_foreach(module_prefs_show, &cts);
410
411
412   /* Button row: OK and cancel buttons */
413   bbox = gtk_hbutton_box_new();
414   gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
415   gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
416   gtk_container_add(GTK_CONTAINER(main_vb), bbox);
417   gtk_widget_show(bbox);
418
419   ok_bt = gtk_button_new_from_stock(GTK_STOCK_OK);
420   g_signal_connect(G_OBJECT(ok_bt), "clicked",
421                    G_CALLBACK(prefs_main_ok_cb), GTK_OBJECT(prefs_w));
422   GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT);
423   gtk_box_pack_start (GTK_BOX (bbox), ok_bt, TRUE, TRUE, 0);
424   gtk_widget_grab_default(ok_bt);
425   gtk_widget_show(ok_bt);
426
427   apply_bt = gtk_button_new_from_stock(GTK_STOCK_APPLY);
428   g_signal_connect(G_OBJECT(apply_bt), "clicked",
429                    G_CALLBACK(prefs_main_apply_cb), GTK_OBJECT(prefs_w));
430   GTK_WIDGET_SET_FLAGS(apply_bt, GTK_CAN_DEFAULT);
431   gtk_box_pack_start(GTK_BOX (bbox), apply_bt, TRUE, TRUE, 0);
432   gtk_widget_show(apply_bt);
433
434   save_bt = gtk_button_new_from_stock(GTK_STOCK_SAVE);
435   g_signal_connect(G_OBJECT(save_bt), "clicked",
436                    G_CALLBACK(prefs_main_save_cb), GTK_OBJECT(prefs_w));
437   GTK_WIDGET_SET_FLAGS(save_bt, GTK_CAN_DEFAULT);
438   gtk_box_pack_start (GTK_BOX (bbox), save_bt, TRUE, TRUE, 0);
439   gtk_widget_show(save_bt);
440
441   cancel_bt = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
442   g_signal_connect(G_OBJECT(cancel_bt), "clicked",
443                    G_CALLBACK(prefs_main_cancel_cb), GTK_OBJECT(prefs_w));
444   GTK_WIDGET_SET_FLAGS(cancel_bt, GTK_CAN_DEFAULT);
445   gtk_box_pack_start (GTK_BOX (bbox), cancel_bt, TRUE, TRUE, 0);
446   gtk_widget_show(cancel_bt);
447
448   /* Catch the "key_press_event" signal in the window, so that we can catch
449      the ESC key being pressed and act as if the "Cancel" button had
450      been selected. */
451   dlg_set_cancel(prefs_w, cancel_bt);
452
453   gtk_widget_show(prefs_w);
454
455   g_object_unref(G_OBJECT(store));
456 }
457
458 static void
459 set_option_label(GtkWidget *main_tb, int table_position,
460     const gchar *label_text, const gchar *tooltip_text, GtkTooltips *tooltips)
461 {
462         GtkWidget *label;
463         GtkWidget *event_box;
464
465         label = gtk_label_new(label_text);
466         gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
467         gtk_widget_show(label);
468
469         event_box = gtk_event_box_new();
470         gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box, 0, 1,
471             table_position, table_position + 1);
472         if (tooltip_text != NULL && tooltips != NULL)
473                 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
474         gtk_container_add(GTK_CONTAINER(event_box), label);
475         gtk_widget_show(event_box);
476 }
477
478 GtkWidget *
479 create_preference_check_button(GtkWidget *main_tb, int table_position,
480     const gchar *label_text, const gchar *tooltip_text, gboolean active)
481 {
482         GtkTooltips *tooltips;
483         GtkWidget *check_box;
484
485         tooltips = gtk_object_get_data(GTK_OBJECT(main_tb), E_TOOLTIPS_KEY);
486
487         set_option_label(main_tb, table_position, label_text, tooltip_text,
488             tooltips);
489
490         check_box = gtk_check_button_new();
491         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_box), active);
492         gtk_table_attach_defaults(GTK_TABLE(main_tb), check_box, 1, 2,
493             table_position, table_position + 1);
494         if (tooltip_text != NULL && tooltips != NULL)
495                 gtk_tooltips_set_tip(tooltips, check_box, tooltip_text, NULL);
496
497         return check_box;
498 }
499
500 GtkWidget *
501 create_preference_radio_buttons(GtkWidget *main_tb, int table_position,
502     const gchar *label_text, const gchar *tooltip_text,
503     const enum_val_t *enumvals, gint current_val)
504 {
505         GtkTooltips *tooltips;
506         GtkWidget *radio_button_hbox, *button = NULL;
507         GSList *rb_group;
508         int index;
509         const enum_val_t *enum_valp;
510         GtkWidget *event_box;
511
512         tooltips = gtk_object_get_data(GTK_OBJECT(main_tb), E_TOOLTIPS_KEY);
513
514         set_option_label(main_tb, table_position, label_text, tooltip_text,
515             tooltips);
516
517         radio_button_hbox = gtk_hbox_new(FALSE, 0);
518         rb_group = NULL;
519         for (enum_valp = enumvals, index = 0; enum_valp->name != NULL;
520             enum_valp++, index++) {
521                 button = gtk_radio_button_new_with_label(rb_group,
522                     enum_valp->name);
523                 gtk_widget_show(button);
524                 if (rb_group == NULL)
525                         rb_group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
526                 gtk_box_pack_start(GTK_BOX(radio_button_hbox), button, FALSE,
527                     FALSE, 10);
528                 if (enum_valp->value == current_val) {
529                         gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button),
530                             TRUE);
531                 }
532         }
533         gtk_widget_show(radio_button_hbox);
534
535         event_box = gtk_event_box_new();
536         gtk_container_add(GTK_CONTAINER(event_box), radio_button_hbox);
537         gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box, 1, 2,
538             table_position, table_position+1);
539         if (tooltip_text != NULL && tooltips != NULL)
540                 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
541         gtk_widget_show(event_box);
542
543         /*
544          * It doesn't matter which of the buttons we return - we fetch
545          * the value by looking at the entire radio button group to
546          * which it belongs, and we can get that from any button.
547          */
548         return button;
549 }
550
551 static gint
552 label_to_enum_val(GtkWidget *label, const enum_val_t *enumvals)
553 {
554         char *label_string;
555         gint enumval;
556
557         /* Get the label's text, and translate it to a value. */
558         gtk_label_get(GTK_LABEL(label), &label_string);
559         enumval = find_val_for_string(label_string, enumvals, 1);
560
561         return enumval;
562 }
563
564 gint
565 fetch_preference_radio_buttons_val(GtkWidget *button,
566     const enum_val_t *enumvals)
567 {
568         GSList *rb_group;
569         GSList *rb_entry;
570
571         /*
572          * Go through the list of of radio buttons in the button's group,
573          * and find the first one that's active.
574          */
575         rb_group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
576         button = NULL;
577         for (rb_entry = rb_group; rb_entry != NULL;
578             rb_entry = g_slist_next(rb_entry)) {
579                 button = rb_entry->data;
580                 if (GTK_TOGGLE_BUTTON(button)->active)
581                         break;
582         }
583
584         /* OK, now return the value corresponding to that button's label. */
585         return label_to_enum_val(GTK_BIN(button)->child, enumvals);
586 }
587
588 GtkWidget *
589 create_preference_option_menu(GtkWidget *main_tb, int table_position,
590     const gchar *label_text, const gchar *tooltip_text,
591     const enum_val_t *enumvals, gint current_val)
592 {
593         GtkTooltips *tooltips;
594         GtkWidget *menu_box, *menu, *menu_item, *option_menu;
595         int menu_index, index;
596         const enum_val_t *enum_valp;
597         GtkWidget *event_box;
598
599         tooltips = gtk_object_get_data(GTK_OBJECT(main_tb), E_TOOLTIPS_KEY);
600
601         set_option_label(main_tb, table_position, label_text, tooltip_text,
602             tooltips);
603
604         /* Create a menu from the enumvals */
605         menu = gtk_menu_new();
606         if (tooltip_text != NULL && tooltips != NULL)
607                 gtk_tooltips_set_tip(tooltips, menu, tooltip_text, NULL);
608         menu_index = -1;
609         for (enum_valp = enumvals, index = 0; enum_valp->name != NULL;
610             enum_valp++, index++) {
611                 menu_item = gtk_menu_item_new_with_label(enum_valp->name);
612                 gtk_menu_append(GTK_MENU(menu), menu_item);
613                 if (enum_valp->value == current_val)
614                         menu_index = index;
615                 gtk_widget_show(menu_item);
616         }
617
618         /* Create the option menu from the menu */
619         option_menu = gtk_option_menu_new();
620         gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), menu);
621
622         /* Set its current value to the variable's current value */
623         if (menu_index != -1)
624                 gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu),
625                     menu_index);
626
627         /*
628          * Put the option menu in an hbox, so that it's only as wide
629          * as the widest entry, rather than being as wide as the table
630          * space.
631          */
632         menu_box = gtk_hbox_new(FALSE, 0);
633         gtk_box_pack_start(GTK_BOX(menu_box), option_menu, FALSE, FALSE, 0);
634
635         event_box = gtk_event_box_new();
636         gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box,
637             1, 2, table_position, table_position + 1);
638         if (tooltip_text != NULL && tooltips != NULL)
639                 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
640         gtk_container_add(GTK_CONTAINER(event_box), menu_box);
641
642         return option_menu;
643 }
644
645 gint
646 fetch_preference_option_menu_val(GtkWidget *optmenu, const enum_val_t *enumvals)
647 {
648         /*
649          * OK, now return the value corresponding to the label for the
650          * currently active entry in the option menu.
651          *
652          * Yes, this is how you get the label for that entry.  See FAQ
653          * 6.8 in the GTK+ FAQ.
654          */
655         return label_to_enum_val(GTK_BIN(optmenu)->child, enumvals);
656 }
657
658 GtkWidget *
659 create_preference_entry(GtkWidget *main_tb, int table_position,
660     const gchar *label_text, const gchar *tooltip_text, char *value)
661 {
662         GtkTooltips *tooltips;
663         GtkWidget *entry;
664
665         tooltips = gtk_object_get_data(GTK_OBJECT(main_tb), E_TOOLTIPS_KEY);
666
667         set_option_label(main_tb, table_position, label_text, tooltip_text,
668             tooltips);
669
670         entry = gtk_entry_new();
671         if (value != NULL)
672                 gtk_entry_set_text(GTK_ENTRY(entry), value);
673         gtk_table_attach_defaults(GTK_TABLE(main_tb), entry, 1, 2,
674             table_position, table_position + 1);
675         if (tooltip_text != NULL && tooltips != NULL)
676                 gtk_tooltips_set_tip(tooltips, entry, tooltip_text, NULL);
677         gtk_widget_show(entry);
678
679         return entry;
680 }
681
682 static void
683 pref_fetch(pref_t *pref, gpointer user_data)
684 {
685   const char *str_val;
686   char *p;
687   guint uval;
688   gboolean bval;
689   gint enumval;
690   gboolean *pref_changed_p = user_data;
691
692   /* Fetch the value of the preference, and set the appropriate variable
693      to it. */
694   switch (pref->type) {
695
696   case PREF_UINT:
697     str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
698     uval = strtoul(str_val, &p, pref->info.base);
699 #if 0
700     if (p == value || *p != '\0')
701       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
702 #endif
703     if (*pref->varp.uint != uval) {
704       *pref_changed_p = TRUE;
705       *pref->varp.uint = uval;
706     }
707     break;
708
709   case PREF_BOOL:
710     bval = GTK_TOGGLE_BUTTON(pref->control)->active;
711     if (*pref->varp.boolp != bval) {
712       *pref_changed_p = TRUE;
713       *pref->varp.boolp = bval;
714     }
715     break;
716
717   case PREF_ENUM:
718     if (pref->info.enum_info.radio_buttons) {
719       enumval = fetch_preference_radio_buttons_val(pref->control,
720           pref->info.enum_info.enumvals);
721     } else {
722       enumval = fetch_preference_option_menu_val(pref->control,
723           pref->info.enum_info.enumvals);
724     }
725
726     if (*pref->varp.enump != enumval) {
727       *pref_changed_p = TRUE;
728       *pref->varp.enump = enumval;
729     }
730     break;
731
732   case PREF_STRING:
733     str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
734     if (*pref->varp.string == NULL || strcmp(*pref->varp.string, str_val) != 0) {
735       *pref_changed_p = TRUE;
736       if (*pref->varp.string != NULL)
737         g_free(*pref->varp.string);
738       *pref->varp.string = g_strdup(str_val);
739     }
740     break;
741
742   case PREF_OBSOLETE:
743     g_assert_not_reached();
744     break;
745   }
746 }
747
748 static void
749 module_prefs_fetch(module_t *module, gpointer user_data)
750 {
751   gboolean *must_redissect_p = user_data;
752
753   /* For all preferences in this module, fetch its value from this
754      module's notebook page.  Find out whether any of them changed. */
755   module->prefs_changed = FALSE;        /* assume none of them changed */
756   prefs_pref_foreach(module, pref_fetch, &module->prefs_changed);
757
758   /* If any of them changed, indicate that we must redissect and refilter
759      the current capture (if we have one), as the preference change
760      could cause packets to be dissected differently. */
761   if (module->prefs_changed)
762     *must_redissect_p = TRUE;
763 }
764
765 static void
766 pref_clean(pref_t *pref, gpointer user_data _U_)
767 {
768   switch (pref->type) {
769
770   case PREF_UINT:
771     break;
772
773   case PREF_BOOL:
774     break;
775
776   case PREF_ENUM:
777     break;
778
779   case PREF_STRING:
780     if (pref->saved_val.string != NULL) {
781       g_free(pref->saved_val.string);
782       pref->saved_val.string = NULL;
783     }
784     break;
785
786   case PREF_OBSOLETE:
787     g_assert_not_reached();
788     break;
789   }
790 }
791
792 static void
793 module_prefs_clean(module_t *module, gpointer user_data _U_)
794 {
795   /* For all preferences in this module, clean up any cruft allocated for
796      use by the GUI code. */
797   prefs_pref_foreach(module, pref_clean, NULL);
798 }
799
800 static void
801 prefs_main_ok_cb(GtkWidget *ok_bt _U_, gpointer parent_w)
802 {
803   gboolean must_redissect = FALSE;
804
805   /* Fetch the preferences (i.e., make sure all the values set in all of
806      the preferences panes have been copied to "prefs" and the registered
807      preferences). */
808   printer_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
809                                           E_PRINT_PAGE_KEY));
810   column_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
811                                          E_COLUMN_PAGE_KEY));
812   stream_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
813                                          E_STREAM_PAGE_KEY));
814   gui_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
815                                       E_GUI_PAGE_KEY));
816 #ifdef HAVE_LIBPCAP
817 #ifdef _WIN32
818   /* Is WPcap loaded? */
819   if (has_wpcap) {
820 #endif /* _WIN32 */
821     capture_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
822                                             E_CAPTURE_PAGE_KEY));
823 #ifdef _WIN32
824   }
825 #endif /* _WIN32 */
826 #endif /* HAVE_LIBPCAP */
827   nameres_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
828                                           E_NAMERES_PAGE_KEY));
829   prefs_module_foreach(module_prefs_fetch, &must_redissect);
830
831   /* Now apply those preferences. */
832   printer_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
833                                           E_PRINT_PAGE_KEY));
834   column_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
835                                          E_COLUMN_PAGE_KEY));
836   stream_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
837                                          E_STREAM_PAGE_KEY));
838   gui_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
839                                       E_GUI_PAGE_KEY));
840 #ifdef HAVE_LIBPCAP
841 #ifdef _WIN32
842   /* Is WPcap loaded? */
843   if (has_wpcap) {
844 #endif /* _WIN32 */
845     capture_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
846                                             E_CAPTURE_PAGE_KEY));
847 #ifdef _WIN32
848   }
849 #endif /* _WIN32 */
850 #endif /* HAVE_LIBPCAP */
851   nameres_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
852                                           E_NAMERES_PAGE_KEY));
853   prefs_apply_all();
854
855   /* Now destroy the "Preferences" dialog. */
856   gtk_widget_destroy(GTK_WIDGET(parent_w));
857
858   if (must_redissect) {
859     /* Redissect all the packets, and re-evaluate the display filter. */
860     redissect_packets(&cfile);
861   }
862 }
863
864 static void
865 prefs_main_apply_cb(GtkWidget *apply_bt _U_, gpointer parent_w)
866 {
867   gboolean must_redissect = FALSE;
868
869   /* Fetch the preferences (i.e., make sure all the values set in all of
870      the preferences panes have been copied to "prefs" and the registered
871      preferences). */
872   printer_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
873                                           E_PRINT_PAGE_KEY));
874   column_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
875                                          E_COLUMN_PAGE_KEY));
876   stream_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
877                                          E_STREAM_PAGE_KEY));
878   gui_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
879 #ifdef HAVE_LIBPCAP
880 #ifdef _WIN32
881   /* Is WPcap loaded? */
882   if (has_wpcap) {
883 #endif /* _WIN32 */
884     capture_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
885                                             E_CAPTURE_PAGE_KEY));
886 #ifdef _WIN32
887   }
888 #endif /* _WIN32 */
889 #endif /* HAVE_LIBPCAP */
890   nameres_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
891                                           E_NAMERES_PAGE_KEY));
892   prefs_module_foreach(module_prefs_fetch, &must_redissect);
893
894   /* Now apply those preferences. */
895   printer_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
896                                           E_PRINT_PAGE_KEY));
897   column_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
898                                          E_COLUMN_PAGE_KEY));
899   stream_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
900                                          E_STREAM_PAGE_KEY));
901   gui_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
902 #ifdef HAVE_LIBPCAP
903 #ifdef _WIN32
904   /* Is WPcap loaded? */
905   if (has_wpcap) {
906 #endif /* _WIN32 */
907     capture_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
908                                             E_CAPTURE_PAGE_KEY));
909 #ifdef _WIN32
910   }
911 #endif /* _WIN32 */
912 #endif /* HAVE_LIBPCAP */
913   nameres_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
914                                           E_NAMERES_PAGE_KEY));
915   prefs_apply_all();
916
917   if (must_redissect) {
918     /* Redissect all the packets, and re-evaluate the display filter. */
919     redissect_packets(&cfile);
920   }
921 }
922
923 static void
924 prefs_main_save_cb(GtkWidget *save_bt _U_, gpointer parent_w)
925 {
926   gboolean must_redissect = FALSE;
927   int err;
928   char *pf_dir_path;
929   char *pf_path;
930
931   /* Fetch the preferences (i.e., make sure all the values set in all of
932      the preferences panes have been copied to "prefs" and the registered
933      preferences). */
934   printer_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
935                                           E_PRINT_PAGE_KEY));
936   column_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
937                                          E_COLUMN_PAGE_KEY));
938   stream_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
939                                          E_STREAM_PAGE_KEY));
940   gui_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
941 #ifdef HAVE_LIBPCAP
942 #ifdef _WIN32
943   /* Is WPcap loaded? */
944   if (has_wpcap) {
945 #endif /* _WIN32 */
946     capture_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
947                                             E_CAPTURE_PAGE_KEY));
948 #ifdef _WIN32
949   }
950 #endif /* _WIN32 */
951 #endif /* HAVE_LIBPCAP */
952   nameres_prefs_fetch(gtk_object_get_data(GTK_OBJECT(parent_w),
953                                           E_NAMERES_PAGE_KEY));
954   prefs_module_foreach(module_prefs_fetch, &must_redissect);
955
956   /* Create the directory that holds personal configuration files, if
957      necessary.  */
958   if (create_persconffile_dir(&pf_dir_path) == -1) {
959      simple_dialog(ESD_TYPE_WARN, NULL,
960       "Can't create directory\n\"%s\"\nfor preferences file: %s.", pf_dir_path,
961       strerror(errno));
962      g_free(pf_dir_path);
963   } else {
964     /* Write the preferencs out. */
965     err = write_prefs(&pf_path);
966     if (err != 0) {
967        simple_dialog(ESD_TYPE_WARN, NULL,
968         "Can't open preferences file\n\"%s\": %s.", pf_path,
969         strerror(err));
970        g_free(pf_path);
971     }
972   }
973
974   /* Now apply those preferences.
975      XXX - should we do this?  The user didn't click "OK" or "Apply".
976      However:
977
978         1) by saving the preferences they presumably indicate that they
979            like them;
980
981         2) the next time they fire Ethereal up, those preferences will
982            apply;
983
984         3) we'd have to buffer "must_redissect" so that if they do
985            "Apply" after this, we know we have to redissect;
986
987         4) we did apply the protocol preferences, at least, in the past. */
988   printer_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
989                                           E_PRINT_PAGE_KEY));
990   column_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
991                                          E_COLUMN_PAGE_KEY));
992   stream_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
993                                          E_STREAM_PAGE_KEY));
994   gui_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
995 #ifdef HAVE_LIBPCAP
996 #ifdef _WIN32
997   /* Is WPcap loaded? */
998   if (has_wpcap) {
999 #endif /* _WIN32 */
1000     capture_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
1001                                             E_CAPTURE_PAGE_KEY));
1002 #ifdef _WIN32
1003   }
1004 #endif /* _WIN32 */
1005 #endif /* HAVE_LIBPCAP */
1006   nameres_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
1007                                           E_NAMERES_PAGE_KEY));
1008   prefs_apply_all();
1009
1010   if (must_redissect) {
1011     /* Redissect all the packets, and re-evaluate the display filter. */
1012     redissect_packets(&cfile);
1013   }
1014 }
1015
1016 static void
1017 pref_revert(pref_t *pref, gpointer user_data)
1018 {
1019   gboolean *pref_changed_p = user_data;
1020
1021   /* Revert the preference to its saved value. */
1022   switch (pref->type) {
1023
1024   case PREF_UINT:
1025     if (*pref->varp.uint != pref->saved_val.uint) {
1026       *pref_changed_p = TRUE;
1027       *pref->varp.uint = pref->saved_val.uint;
1028     }
1029     break;
1030
1031   case PREF_BOOL:
1032     if (*pref->varp.boolp != pref->saved_val.boolval) {
1033       *pref_changed_p = TRUE;
1034       *pref->varp.boolp = pref->saved_val.boolval;
1035     }
1036     break;
1037
1038   case PREF_ENUM:
1039     if (*pref->varp.enump != pref->saved_val.enumval) {
1040       *pref_changed_p = TRUE;
1041       *pref->varp.enump = pref->saved_val.enumval;
1042     }
1043     break;
1044
1045   case PREF_STRING:
1046     if (*pref->varp.string != pref->saved_val.string &&
1047         (*pref->varp.string == NULL ||
1048          pref->saved_val.string == NULL ||
1049          strcmp(*pref->varp.string, pref->saved_val.string) != 0)) {
1050       *pref_changed_p = TRUE;
1051       if (*pref->varp.string != NULL)
1052         g_free(*pref->varp.string);
1053       *pref->varp.string = g_strdup(pref->saved_val.string);
1054     }
1055     break;
1056
1057   case PREF_OBSOLETE:
1058     g_assert_not_reached();
1059     break;
1060   }
1061 }
1062
1063 static void
1064 module_prefs_revert(module_t *module, gpointer user_data)
1065 {
1066   gboolean *must_redissect_p = user_data;
1067
1068   /* For all preferences in this module, revert its value to the value
1069      it had when we popped up the Preferences dialog.  Find out whether
1070      this changes any of them. */
1071   module->prefs_changed = FALSE;        /* assume none of them changed */
1072   prefs_pref_foreach(module, pref_revert, &module->prefs_changed);
1073
1074   /* If any of them changed, indicate that we must redissect and refilter
1075      the current capture (if we have one), as the preference change
1076      could cause packets to be dissected differently. */
1077   if (module->prefs_changed)
1078     *must_redissect_p = TRUE;
1079 }
1080
1081 static void
1082 prefs_main_cancel_cb(GtkWidget *cancel_bt _U_, gpointer parent_w)
1083 {
1084   gboolean must_redissect = FALSE;
1085
1086   /* Free up the current preferences and copy the saved preferences to the
1087      current preferences. */
1088   free_prefs(&prefs);
1089   copy_prefs(&prefs, &saved_prefs);
1090
1091   /* Now revert the registered preferences. */
1092   prefs_module_foreach(module_prefs_revert, &must_redissect);
1093
1094   /* Now apply the reverted-to preferences. */
1095   printer_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
1096                                           E_PRINT_PAGE_KEY));
1097   column_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
1098                                          E_COLUMN_PAGE_KEY));
1099   stream_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
1100                                          E_STREAM_PAGE_KEY));
1101   gui_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w), E_GUI_PAGE_KEY));
1102   nameres_prefs_apply(gtk_object_get_data(GTK_OBJECT(parent_w),
1103                                           E_NAMERES_PAGE_KEY));
1104   prefs_apply_all();
1105
1106   gtk_widget_destroy(GTK_WIDGET(parent_w));
1107
1108   if (must_redissect) {
1109     /* Redissect all the packets, and re-evaluate the display filter. */
1110     redissect_packets(&cfile);
1111   }
1112 }
1113
1114 /* Treat this as a cancel, by calling "prefs_main_cancel_cb()".
1115    XXX - that'll destroy the Preferences dialog; will that upset
1116    a higher-level handler that says "OK, we've been asked to delete
1117    this, so destroy it"? */
1118 static gboolean
1119 prefs_main_delete_cb(GtkWidget *prefs_w, gpointer dummy _U_)
1120 {
1121   prefs_main_cancel_cb(NULL, prefs_w);
1122   return FALSE;
1123 }
1124
1125 static void
1126 prefs_main_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1127 {
1128   /* Let the preference tabs clean up anything they've done. */
1129   printer_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w),
1130                                             E_PRINT_PAGE_KEY));
1131   column_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w),
1132                                            E_COLUMN_PAGE_KEY));
1133   stream_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w),
1134                                            E_STREAM_PAGE_KEY));
1135   gui_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w), E_GUI_PAGE_KEY));
1136 #ifdef HAVE_LIBPCAP
1137 #ifdef _WIN32
1138   /* Is WPcap loaded? */
1139   if (has_wpcap) {
1140 #endif /* _WIN32 */
1141     capture_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w),
1142                                               E_CAPTURE_PAGE_KEY));
1143 #ifdef _WIN32
1144   }
1145 #endif /* _WIN32 */
1146 #endif /* HAVE_LIBPCAP */
1147   nameres_prefs_destroy(gtk_object_get_data(GTK_OBJECT(prefs_w),
1148                                             E_NAMERES_PAGE_KEY));
1149
1150   /* Free up the saved preferences (both for "prefs" and for registered
1151      preferences). */
1152   free_prefs(&saved_prefs);
1153   prefs_module_foreach(module_prefs_clean, NULL);
1154
1155   /* Note that we no longer have a "Preferences" dialog box. */
1156   prefs_w = NULL;
1157 }
1158
1159 struct properties_data {
1160   GtkWidget *w;
1161   int page_num;
1162   char *title;
1163 };
1164
1165 /* XXX this way of searching the correct page number is really ugly ... */
1166 static void
1167 module_search_properties(module_t *module, gpointer user_data)
1168 {
1169   struct properties_data *p = (struct properties_data *)user_data;
1170
1171   if (p->title == NULL) return;
1172   if (strcmp(module->title, p->title) == 0) {
1173     /* found it */
1174     gtk_notebook_set_page(GTK_NOTEBOOK(p->w), p->page_num);
1175     p->title = NULL;
1176   } else {
1177     p->page_num++;
1178   }
1179 }
1180
1181 void
1182 properties_cb(GtkWidget *w, gpointer dummy)
1183 {
1184   gchar *title = NULL;
1185   struct properties_data p;
1186
1187   if (finfo_selected) {
1188     header_field_info *hfinfo = finfo_selected->hfinfo;
1189     if (hfinfo->parent == -1) {
1190       title = (gchar *)prefs_get_title_by_name(hfinfo->abbrev);
1191     } else {
1192       title = (gchar *)
1193         prefs_get_title_by_name(proto_registrar_get_abbrev(hfinfo->parent));
1194     }
1195   } else {
1196     return;
1197   }
1198
1199   if (!title) return;
1200
1201   if (prefs_w != NULL) {
1202     reactivate_window(prefs_w);
1203   } else {
1204     prefs_cb(w, dummy);
1205   }
1206
1207   p.w = notebook;
1208   p.page_num = FIRST_PROTO_PREFS_PAGE;
1209   p.title = title;
1210
1211   prefs_module_foreach(module_search_properties, &p);
1212
1213 }
1214
1215 /* Prefs tree selection callback.  The node data has been loaded with
1216    the proper notebook page to load. */
1217 static void
1218 prefs_tree_select_cb(GtkTreeSelection *sel, gpointer dummy _U_)
1219 {
1220   gint          page;
1221   GtkTreeModel *model;
1222   GtkTreeIter   iter;
1223
1224   if (gtk_tree_selection_get_selected(sel, &model, &iter))
1225   {
1226     gtk_tree_model_get(model, &iter, 1, &page, -1);
1227     if (page >= 0)
1228       gtk_notebook_set_page(GTK_NOTEBOOK(notebook), page);
1229   }
1230 }