FIRST_PROTO_PREFS_PAGE needs to be incremented by 2 in order for
[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.25 2002/01/21 07:37:41 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 #ifdef HAVE_SYS_TYPES_H
30 # include <sys/types.h>
31 #endif
32
33 #include <gtk/gtk.h>
34
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <string.h>
38
39 #ifdef HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42
43 #include <time.h>
44
45 #ifdef HAVE_SYS_SOCKIO_H
46 # include <sys/sockio.h>
47 #endif
48
49 #ifdef NEED_SNPRINTF_H
50 # include "snprintf.h"
51 #endif
52
53 #include "globals.h"
54 #include <epan/resolv.h>
55 #include <epan/timestamp.h>
56 #include <epan/packet.h>
57 #include "file.h"
58 #include "display_opts.h"
59 #include "ui_util.h"
60 #include "dlg_utils.h"
61
62 extern capture_file  cfile;
63
64 /* Display callback data keys */
65 #define E_DISPLAY_TIME_ABS_KEY          "display_time_abs"
66 #define E_DISPLAY_DATE_TIME_ABS_KEY     "display_date_time_abs"
67 #define E_DISPLAY_TIME_REL_KEY          "display_time_rel"
68 #define E_DISPLAY_TIME_DELTA_KEY        "display_time_delta"
69 #ifdef HAVE_LIBPCAP
70 #define E_DISPLAY_AUTO_SCROLL_KEY       "display_auto_scroll"
71 #endif
72 #define E_DISPLAY_M_NAME_RESOLUTION_KEY "display_mac_name_resolution"
73 #define E_DISPLAY_N_NAME_RESOLUTION_KEY "display_network_name_resolution"
74 #define E_DISPLAY_T_NAME_RESOLUTION_KEY "display_transport_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 #ifdef HAVE_LIBPCAP
173   button = dlg_check_button_new_with_label_with_mnemonic(
174                 "_Automatic scrolling in live capture", accel_group);
175   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), auto_scroll_live);
176   gtk_object_set_data(GTK_OBJECT(display_opt_w), E_DISPLAY_AUTO_SCROLL_KEY,
177                       button);
178   gtk_box_pack_start(GTK_BOX(main_vb), button, TRUE, TRUE, 0);
179   gtk_widget_show(button);
180 #endif
181
182   button = dlg_check_button_new_with_label_with_mnemonic(
183                 "Enable _MAC name resolution", accel_group);
184   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button),
185                 g_resolv_flags & RESOLV_MAC);
186   gtk_object_set_data(GTK_OBJECT(display_opt_w), E_DISPLAY_M_NAME_RESOLUTION_KEY,
187                       button);
188   gtk_box_pack_start(GTK_BOX(main_vb), button, TRUE, TRUE, 0);
189   gtk_widget_show(button);
190     
191   button = dlg_check_button_new_with_label_with_mnemonic(
192                 "Enable _network name resolution", accel_group);
193   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button),
194                 g_resolv_flags & RESOLV_NETWORK);
195   gtk_object_set_data(GTK_OBJECT(display_opt_w), E_DISPLAY_N_NAME_RESOLUTION_KEY,
196                       button);
197   gtk_box_pack_start(GTK_BOX(main_vb), button, TRUE, TRUE, 0);
198   gtk_widget_show(button);
199     
200   button = dlg_check_button_new_with_label_with_mnemonic(
201                 "Enable _transport name resolution", accel_group);
202   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button),
203                 g_resolv_flags & RESOLV_TRANSPORT);
204   gtk_object_set_data(GTK_OBJECT(display_opt_w), E_DISPLAY_T_NAME_RESOLUTION_KEY,
205                       button);
206   gtk_box_pack_start(GTK_BOX(main_vb), button, TRUE, TRUE, 0);
207   gtk_widget_show(button);
208     
209   /* Button row: OK, Apply, and Cancel buttons */
210   bbox = gtk_hbutton_box_new();
211   gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
212   gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
213   gtk_container_add(GTK_CONTAINER(main_vb), bbox);
214   gtk_widget_show(bbox);
215
216   ok_bt = gtk_button_new_with_label ("OK");
217   gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
218     GTK_SIGNAL_FUNC(display_opt_ok_cb), GTK_OBJECT(display_opt_w));
219   GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT);
220   gtk_box_pack_start (GTK_BOX (bbox), ok_bt, TRUE, TRUE, 0);
221   gtk_widget_grab_default(ok_bt);
222   gtk_widget_show(ok_bt);
223
224   apply_bt = gtk_button_new_with_label ("Apply");
225   gtk_signal_connect(GTK_OBJECT(apply_bt), "clicked",
226     GTK_SIGNAL_FUNC(display_opt_apply_cb), GTK_OBJECT(display_opt_w));
227   GTK_WIDGET_SET_FLAGS(apply_bt, GTK_CAN_DEFAULT);
228   gtk_box_pack_start (GTK_BOX (bbox), apply_bt, TRUE, TRUE, 0);
229   gtk_widget_show(apply_bt);
230
231   cancel_bt = gtk_button_new_with_label ("Cancel");
232   gtk_signal_connect(GTK_OBJECT(cancel_bt), "clicked",
233     GTK_SIGNAL_FUNC(display_opt_close_cb), GTK_OBJECT(display_opt_w));
234   GTK_WIDGET_SET_FLAGS(cancel_bt, GTK_CAN_DEFAULT);
235   gtk_box_pack_start (GTK_BOX (bbox), cancel_bt, TRUE, TRUE, 0);
236   gtk_widget_show(cancel_bt);
237
238   /* Catch the "key_press_event" signal in the window, so that we can catch
239      the ESC key being pressed and act as if the "Cancel" button had
240      been selected. */
241   dlg_set_cancel(display_opt_w, cancel_bt);
242
243   gtk_widget_show(display_opt_w);
244 }
245
246 static void
247 display_opt_ok_cb(GtkWidget *ok_bt, gpointer parent_w) {
248   get_display_options(GTK_WIDGET(parent_w));
249
250   gtk_widget_destroy(GTK_WIDGET(parent_w));
251
252   update_display();
253 }
254
255 static void
256 display_opt_apply_cb(GtkWidget *ok_bt, gpointer parent_w) {
257   get_display_options(GTK_WIDGET(parent_w));
258
259   update_display();
260 }
261
262 static void
263 get_display_options(GtkWidget *parent_w)
264 {
265   GtkWidget *button;
266
267   button = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w),
268                                               E_DISPLAY_TIME_ABS_KEY);
269   if (GTK_TOGGLE_BUTTON (button)->active)
270     timestamp_type = ABSOLUTE;
271
272   button = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w),
273                                               E_DISPLAY_DATE_TIME_ABS_KEY);
274   if (GTK_TOGGLE_BUTTON (button)->active)
275     timestamp_type = ABSOLUTE_WITH_DATE;
276
277   button = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w),
278                                               E_DISPLAY_TIME_REL_KEY);
279   if (GTK_TOGGLE_BUTTON (button)->active)
280     timestamp_type = RELATIVE;
281
282   button = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w),
283                                               E_DISPLAY_TIME_DELTA_KEY);
284   if (GTK_TOGGLE_BUTTON (button)->active)
285     timestamp_type = DELTA;
286
287 #ifdef HAVE_LIBPCAP
288   button = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w),
289                                              E_DISPLAY_AUTO_SCROLL_KEY);
290   auto_scroll_live = (GTK_TOGGLE_BUTTON (button)->active);
291 #endif
292
293   g_resolv_flags = RESOLV_NONE;
294   button = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w),
295                                              E_DISPLAY_M_NAME_RESOLUTION_KEY);
296   g_resolv_flags |= (GTK_TOGGLE_BUTTON (button)->active ? RESOLV_MAC : RESOLV_NONE);
297   button = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w),
298                                              E_DISPLAY_N_NAME_RESOLUTION_KEY);
299   g_resolv_flags |= (GTK_TOGGLE_BUTTON (button)->active ? RESOLV_NETWORK : RESOLV_NONE);
300   button = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w),
301                                              E_DISPLAY_T_NAME_RESOLUTION_KEY);
302   g_resolv_flags |= (GTK_TOGGLE_BUTTON (button)->active ? RESOLV_TRANSPORT : RESOLV_NONE);
303
304 }
305
306 static void
307 update_display(void)
308 {
309   if (timestamp_type != current_timestamp_type) {
310       /* Time stamp format changed; update the display.
311
312          XXX - redissecting the packets could actually be faster;
313          we have to find the row number for each frame, in order to
314          update the time stamp columns, and doing that is linear in
315          the row number, which means the whole process is N^2 in
316          the number of rows, whilst redissecting the packets is only
317          linear in the number of rows (assuming you're using our
318          CList code, or the GTK+ 1.2.8 CList code, or other CList
319          code which doesn't have to scan the entire list to find the
320          last element), even though the latter involves doing more work
321          per packet. */
322     current_timestamp_type = timestamp_type;
323     change_time_formats(&cfile);
324   }
325 }
326
327 static void
328 display_opt_close_cb(GtkWidget *close_bt, gpointer parent_w)
329 {
330   /* Revert the timestamp type to the value it has when we started. */
331   timestamp_type = initial_timestamp_type;
332
333   /* Update the display if either of those changed. */
334   update_display();
335
336   gtk_grab_remove(GTK_WIDGET(parent_w));
337   gtk_widget_destroy(GTK_WIDGET(parent_w));
338 }
339
340 static void
341 display_opt_destroy_cb(GtkWidget *win, gpointer user_data)
342 {
343   /* Note that we no longer have a "Display Options" dialog box. */
344   display_opt_w = NULL;
345 }