Added the ethereal capture preferences to the preference file.
[obnox/wireshark/wip.git] / gtk / display_opts.c
1 /* display_opts.c
2  * Routines for packet display windows
3  *
4  * $Id: display_opts.c,v 1.19 2001/04/13 14:59:30 jfoster Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
33 #endif
34
35 #include <gtk/gtk.h>
36
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <string.h>
40
41 #ifdef HAVE_UNISTD_H
42 #include <unistd.h>
43 #endif
44
45 #include <time.h>
46
47 #ifdef HAVE_SYS_SOCKIO_H
48 # include <sys/sockio.h>
49 #endif
50
51 #ifdef NEED_SNPRINTF_H
52 # include "snprintf.h"
53 #endif
54
55 #include "globals.h"
56 #include "resolv.h"
57 #include "timestamp.h"
58 #include "packet.h"
59 #include "file.h"
60 #include "display_opts.h"
61 #include "ui_util.h"
62 #include "dlg_utils.h"
63 #include "prefs.h"
64
65 extern capture_file  cfile;
66 extern GtkWidget *packet_list;
67
68 /* Display callback data keys */
69 #define E_DISPLAY_TIME_ABS_KEY   "display_time_abs"
70 #define E_DISPLAY_DATE_TIME_ABS_KEY "display_date_time_abs"
71 #define E_DISPLAY_TIME_REL_KEY   "display_time_rel"
72 #define E_DISPLAY_TIME_DELTA_KEY "display_time_delta"
73 #define E_DISPLAY_AUTO_SCROLL_KEY "display_auto_scroll"
74 #define E_DISPLAY_NAME_RESOLUTION_KEY "display_name_resolution"
75
76 static void display_opt_ok_cb(GtkWidget *, gpointer);
77 static void display_opt_apply_cb(GtkWidget *, gpointer);
78 static void get_display_options(GtkWidget *);
79 static void update_display(void);
80 static void display_opt_close_cb(GtkWidget *, gpointer);
81 static void display_opt_destroy_cb(GtkWidget *, gpointer);
82
83 /*
84  * Keep a static pointer to the current "Display Options" window, if any,
85  * so that if somebody tries to do "Display:Options" while there's already
86  * a "Display Options" window up, we just pop up the existing one, rather
87  * than creating a new one.
88  */
89 static GtkWidget *display_opt_w;
90
91 static ts_type initial_timestamp_type;
92 static ts_type current_timestamp_type;
93
94 void
95 display_opt_cb(GtkWidget *w, gpointer d) {
96   GtkWidget     *button, *main_vb, *bbox, *ok_bt, *apply_bt, *cancel_bt;
97   GtkAccelGroup *accel_group;
98
99   if (display_opt_w != NULL) {
100     /* There's already a "Display Options" dialog box; reactivate it. */
101     reactivate_window(display_opt_w);
102     return;
103   }
104
105   /* Save the timestamp type value as of when the dialog box was first popped
106      up, so that "Cancel" can put it back if we've changed it with "Apply". */
107   initial_timestamp_type = timestamp_type;
108
109   /* Save the current timestamp type so that we know whether it has changed;
110      we don't want to redisplay the time fields unless we've changed the way 
111      they should be displayed (as redisplaying the time fields could be 
112      expensive - we have to scan through all the packets and rebuild the 
113      packet list).*/
114   current_timestamp_type = timestamp_type;
115
116   display_opt_w = dlg_window_new("Ethereal: Display Options");
117   gtk_signal_connect(GTK_OBJECT(display_opt_w), "destroy",
118         GTK_SIGNAL_FUNC(display_opt_destroy_cb), NULL);
119
120   /* Accelerator group for the accelerators (or, as they're called in
121      Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
122      Ctrl+<key> is an accelerator). */
123   accel_group = gtk_accel_group_new();
124   gtk_window_add_accel_group(GTK_WINDOW(display_opt_w), accel_group);
125
126   /* Container for each row of widgets */
127   main_vb = gtk_vbox_new(FALSE, 3);
128   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
129   gtk_container_add(GTK_CONTAINER(display_opt_w), main_vb);
130   gtk_widget_show(main_vb);
131   
132   button = dlg_radio_button_new_with_label_with_mnemonic(NULL, "_Time of day",
133                                                         accel_group);
134   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button),
135                (timestamp_type == ABSOLUTE));
136   gtk_object_set_data(GTK_OBJECT(display_opt_w), E_DISPLAY_TIME_ABS_KEY,
137                button);
138   gtk_box_pack_start(GTK_BOX(main_vb), button, TRUE, TRUE, 0);
139   
140   gtk_widget_show(button);
141
142   button = dlg_radio_button_new_with_label_with_mnemonic(
143                gtk_radio_button_group(GTK_RADIO_BUTTON(button)),
144                "_Date and time of day", accel_group);
145   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button),
146                (timestamp_type == ABSOLUTE_WITH_DATE));
147   gtk_object_set_data(GTK_OBJECT(display_opt_w), E_DISPLAY_DATE_TIME_ABS_KEY,
148                button);
149   gtk_box_pack_start(GTK_BOX(main_vb), button, TRUE, TRUE, 0);
150   gtk_widget_show(button);
151
152   button = dlg_radio_button_new_with_label_with_mnemonic(
153                gtk_radio_button_group(GTK_RADIO_BUTTON(button)),
154                "Seconds since _beginning of capture", accel_group);
155   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button),
156                (timestamp_type == RELATIVE));
157   gtk_object_set_data(GTK_OBJECT(display_opt_w), E_DISPLAY_TIME_REL_KEY,
158                button);
159   gtk_box_pack_start(GTK_BOX(main_vb), button, TRUE, TRUE, 0);
160   gtk_widget_show(button);
161
162   button = dlg_radio_button_new_with_label_with_mnemonic(
163                gtk_radio_button_group(GTK_RADIO_BUTTON(button)),
164                "Seconds since _previous frame", accel_group);
165   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button),
166                (timestamp_type == DELTA));
167   gtk_object_set_data(GTK_OBJECT(display_opt_w), E_DISPLAY_TIME_DELTA_KEY,
168                 button);
169   gtk_box_pack_start(GTK_BOX(main_vb), button, TRUE, TRUE, 0);
170   gtk_widget_show(button);
171
172   button = dlg_check_button_new_with_label_with_mnemonic(
173                 "_Automatic scrolling in live capture", accel_group);
174   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), prefs.capture_auto_scroll);
175   gtk_object_set_data(GTK_OBJECT(display_opt_w), E_DISPLAY_AUTO_SCROLL_KEY,
176                       button);
177   gtk_box_pack_start(GTK_BOX(main_vb), button, TRUE, TRUE, 0);
178   gtk_widget_show(button);
179
180   button = dlg_check_button_new_with_label_with_mnemonic(
181                 "Enable _name resolution", accel_group);
182   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), prefs.capture_name_resolve);
183   gtk_object_set_data(GTK_OBJECT(display_opt_w), E_DISPLAY_NAME_RESOLUTION_KEY,
184                       button);
185   gtk_box_pack_start(GTK_BOX(main_vb), button, TRUE, TRUE, 0);
186   gtk_widget_show(button);
187     
188   /* Button row: OK, Apply, and Cancel buttons */
189   bbox = gtk_hbutton_box_new();
190   gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
191   gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
192   gtk_container_add(GTK_CONTAINER(main_vb), bbox);
193   gtk_widget_show(bbox);
194
195   ok_bt = gtk_button_new_with_label ("OK");
196   gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
197     GTK_SIGNAL_FUNC(display_opt_ok_cb), GTK_OBJECT(display_opt_w));
198   GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT);
199   gtk_box_pack_start (GTK_BOX (bbox), ok_bt, TRUE, TRUE, 0);
200   gtk_widget_grab_default(ok_bt);
201   gtk_widget_show(ok_bt);
202
203   apply_bt = gtk_button_new_with_label ("Apply");
204   gtk_signal_connect(GTK_OBJECT(apply_bt), "clicked",
205     GTK_SIGNAL_FUNC(display_opt_apply_cb), GTK_OBJECT(display_opt_w));
206   GTK_WIDGET_SET_FLAGS(apply_bt, GTK_CAN_DEFAULT);
207   gtk_box_pack_start (GTK_BOX (bbox), apply_bt, TRUE, TRUE, 0);
208   gtk_widget_show(apply_bt);
209
210   cancel_bt = gtk_button_new_with_label ("Cancel");
211   gtk_signal_connect(GTK_OBJECT(cancel_bt), "clicked",
212     GTK_SIGNAL_FUNC(display_opt_close_cb), GTK_OBJECT(display_opt_w));
213   GTK_WIDGET_SET_FLAGS(cancel_bt, GTK_CAN_DEFAULT);
214   gtk_box_pack_start (GTK_BOX (bbox), cancel_bt, TRUE, TRUE, 0);
215   gtk_widget_show(cancel_bt);
216
217   /* Catch the "key_press_event" signal in the window, so that we can catch
218      the ESC key being pressed and act as if the "Cancel" button had
219      been selected. */
220   dlg_set_cancel(display_opt_w, cancel_bt);
221
222   gtk_widget_show(display_opt_w);
223 }
224
225 static void
226 display_opt_ok_cb(GtkWidget *ok_bt, gpointer parent_w) {
227   get_display_options(GTK_WIDGET(parent_w));
228
229   gtk_widget_destroy(GTK_WIDGET(parent_w));
230
231   update_display();
232 }
233
234 static void
235 display_opt_apply_cb(GtkWidget *ok_bt, gpointer parent_w) {
236   get_display_options(GTK_WIDGET(parent_w));
237
238   update_display();
239 }
240
241 static void
242 get_display_options(GtkWidget *parent_w)
243 {
244   GtkWidget *button;
245
246   button = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w),
247                                               E_DISPLAY_TIME_ABS_KEY);
248   if (GTK_TOGGLE_BUTTON (button)->active)
249     timestamp_type = ABSOLUTE;
250
251   button = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w),
252                                               E_DISPLAY_DATE_TIME_ABS_KEY);
253   if (GTK_TOGGLE_BUTTON (button)->active)
254     timestamp_type = ABSOLUTE_WITH_DATE;
255
256   button = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w),
257                                               E_DISPLAY_TIME_REL_KEY);
258   if (GTK_TOGGLE_BUTTON (button)->active)
259     timestamp_type = RELATIVE;
260
261   button = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w),
262                                               E_DISPLAY_TIME_DELTA_KEY);
263   if (GTK_TOGGLE_BUTTON (button)->active)
264     timestamp_type = DELTA;
265
266   button = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w),
267                                              E_DISPLAY_AUTO_SCROLL_KEY);
268   prefs.capture_auto_scroll = (GTK_TOGGLE_BUTTON (button)->active);
269
270   button = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w),
271                                              E_DISPLAY_NAME_RESOLUTION_KEY);
272   prefs.capture_name_resolve = (GTK_TOGGLE_BUTTON (button)->active);
273
274 }
275
276 static void
277 update_display(void)
278 {
279   if (timestamp_type != current_timestamp_type) {
280       /* Time stamp format changed; update the display.
281
282          XXX - redissecting the packets could actually be faster;
283          we have to find the row number for each frame, in order to
284          update the time stamp columns, and doing that is linear in
285          the row number, which means the whole process is N^2 in
286          the number of rows, whilst redissecting the packets is only
287          linear in the number of rows (assuming you're using our
288          CList code, or the GTK+ 1.2.8 CList code, or other CList
289          code which doesn't have to scan the entire list to find the
290          last element), even though the latter involves doing more work
291          per packet. */
292     current_timestamp_type = timestamp_type;
293     change_time_formats(&cfile);
294   }
295 }
296
297 static void
298 display_opt_close_cb(GtkWidget *close_bt, gpointer parent_w)
299 {
300   /* Revert the timestamp type to the value it has when we started. */
301   timestamp_type = initial_timestamp_type;
302
303   /* Update the display if either of those changed. */
304   update_display();
305
306   gtk_grab_remove(GTK_WIDGET(parent_w));
307   gtk_widget_destroy(GTK_WIDGET(parent_w));
308 }
309
310 static void
311 display_opt_destroy_cb(GtkWidget *win, gpointer user_data)
312 {
313   /* Note that we no longer have a "Display Options" dialog box. */
314   display_opt_w = NULL;
315 }