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