Damn the torpedos[1], commit it anyway.
[obnox/wireshark/wip.git] / gtk / proto_dlg.c
1 /* proto_dlg.c
2  *
3  * $Id: proto_dlg.c,v 1.8 2001/03/01 21:34:09 gram Exp $
4  *
5  * Laurent Deniel <deniel@worldnet.fr>
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@zing.org>
9  * Copyright 2000 Gerald Combs
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 #include <gtk/gtk.h>
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35
36 #ifdef HAVE_SYS_TYPES_H
37 #include <sys/types.h>
38 #endif
39
40 #include "prefs.h"
41 #include "globals.h"
42 #include "gtkglobals.h"
43 #include "main.h"
44 #include "util.h"
45 #include "ui_util.h"
46 #include "dlg_utils.h"
47 #include "proto_dlg.h"
48
49 static gboolean proto_delete_cb(GtkWidget *, gpointer);
50 static void proto_ok_cb(GtkWidget *, gpointer);
51 static void proto_apply_cb(GtkWidget *, gpointer);
52 static void proto_cancel_cb(GtkWidget *, gpointer);
53 static void proto_destroy_cb(GtkWidget *, gpointer);
54
55 static void show_proto_selection(GtkWidget *main, GtkWidget *container);
56 static gboolean set_proto_selection(GtkWidget *);
57 static gboolean revert_proto_selection(void);
58
59 static void toggle_all_cb(GtkWidget *button, gpointer parent_w);
60 static void enable_all_cb(GtkWidget *button, gpointer parent_w);
61 static void disable_all_cb(GtkWidget *button, gpointer parent_w);
62
63 static GtkWidget *proto_w = NULL;
64
65 /* list of protocols */
66 static GSList *protocol_list = NULL;
67
68 typedef struct protocol_data {
69   char     *name;
70   char     *abbrev;
71   int      hfinfo_index;
72   gboolean was_enabled;
73 } protocol_data_t;
74
75 void proto_cb(GtkWidget *w, gpointer data)
76 {
77
78   GtkWidget *main_vb, *bbox, *proto_nb, *apply_bt, *cancel_bt, *ok_bt, 
79     *label, *scrolled_w, *selection_vb, *button;
80   
81   if (proto_w != NULL) {
82     reactivate_window(proto_w);
83     return;
84   }
85
86   proto_w = dlg_window_new("Ethereal: Protocol");
87   gtk_signal_connect(GTK_OBJECT(proto_w), "delete_event",
88                      GTK_SIGNAL_FUNC(proto_delete_cb), NULL);
89   gtk_signal_connect(GTK_OBJECT(proto_w), "destroy",
90                      GTK_SIGNAL_FUNC(proto_destroy_cb), NULL);
91   gtk_widget_set_usize(GTK_WIDGET(proto_w), DEF_WIDTH * 2/3, DEF_HEIGHT * 2/3);
92
93   /* Container for each row of widgets */
94
95   main_vb = gtk_vbox_new(FALSE, 0);
96   gtk_container_border_width(GTK_CONTAINER(main_vb), 1);
97   gtk_container_add(GTK_CONTAINER(proto_w), main_vb);
98   gtk_widget_show(main_vb);
99
100   /* Protocol topics container */
101   
102   proto_nb = gtk_notebook_new();
103   gtk_container_add(GTK_CONTAINER(main_vb), proto_nb);
104   /* XXX do not know why I need this to fill all space around buttons */
105   gtk_widget_set_usize(GTK_WIDGET(proto_nb), DEF_WIDTH * 2/3 - 50,
106                        DEF_HEIGHT * 2/3 - 50);
107
108   /* Protocol selection panel ("enable/disable" protocols) */
109
110   selection_vb = gtk_vbox_new(FALSE, 0);
111   gtk_container_border_width(GTK_CONTAINER(selection_vb), 1);  
112   label = gtk_label_new("Button pressed: protocol decoding is enabled");
113   gtk_widget_show(label);
114   gtk_box_pack_start(GTK_BOX(selection_vb), label, FALSE, FALSE, 0);
115   scrolled_w = gtk_scrolled_window_new(NULL, NULL);         
116   gtk_container_set_border_width(GTK_CONTAINER(scrolled_w), 1);           
117   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_w),
118                                  GTK_POLICY_AUTOMATIC,
119                                  GTK_POLICY_ALWAYS);
120   set_scrollbar_placement_scrollw(scrolled_w, prefs.gui_scrollbar_on_right);
121   remember_scrolled_window(scrolled_w);
122   gtk_box_pack_start(GTK_BOX(selection_vb), scrolled_w, TRUE, TRUE, 0);
123   show_proto_selection(proto_w, scrolled_w);
124   gtk_widget_show(scrolled_w);
125   gtk_widget_show(selection_vb);
126   label = gtk_label_new("Decoding");
127   gtk_notebook_append_page(GTK_NOTEBOOK(proto_nb), selection_vb, label);
128   label = gtk_label_new("Note that when a protocol is disabled, "
129                         "all linked sub-protocols are as well");
130   gtk_widget_show(label);
131   gtk_box_pack_start(GTK_BOX(selection_vb), label, FALSE, FALSE, 0);
132
133
134   bbox = gtk_hbutton_box_new();
135   gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
136   gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
137   gtk_box_pack_start(GTK_BOX(selection_vb), bbox, FALSE, FALSE, 0);
138   gtk_widget_show(bbox);
139
140   /* Toggle All */
141   button = gtk_button_new_with_label("Toggle All");
142   gtk_signal_connect(GTK_OBJECT(button), "clicked",
143                   GTK_SIGNAL_FUNC(toggle_all_cb), GTK_OBJECT(proto_w));
144   gtk_box_pack_start(GTK_BOX(bbox), button, TRUE, TRUE, 0);
145   gtk_widget_show(button);
146
147   /* Enable All */
148   button = gtk_button_new_with_label("Enable All");
149   gtk_signal_connect(GTK_OBJECT(button), "clicked",
150                   GTK_SIGNAL_FUNC(enable_all_cb), GTK_OBJECT(proto_w));
151   gtk_box_pack_start(GTK_BOX(bbox), button, TRUE, TRUE, 0);
152   gtk_widget_show(button);
153
154   /* Disable All */
155   button = gtk_button_new_with_label("Disable All");
156   gtk_signal_connect(GTK_OBJECT(button), "clicked",
157                   GTK_SIGNAL_FUNC(disable_all_cb), GTK_OBJECT(proto_w));
158   gtk_box_pack_start(GTK_BOX(bbox), button, TRUE, TRUE, 0);
159   gtk_widget_show(button);
160
161
162   /* XXX add other protocol-related panels here ... */
163
164   gtk_widget_show(proto_nb);
165
166   /* Ok, Apply, Cancel Buttons */  
167
168   bbox = gtk_hbutton_box_new();
169   gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
170   gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
171   gtk_container_add(GTK_CONTAINER(main_vb), bbox);
172   gtk_widget_show(bbox);
173
174   ok_bt = gtk_button_new_with_label ("OK");
175   gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
176                      GTK_SIGNAL_FUNC(proto_ok_cb), GTK_OBJECT(proto_w));
177   GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT);
178   gtk_box_pack_start(GTK_BOX (bbox), ok_bt, TRUE, TRUE, 0);
179   gtk_widget_grab_default(ok_bt);
180   gtk_widget_show(ok_bt);
181
182   apply_bt = gtk_button_new_with_label ("Apply");
183   gtk_signal_connect(GTK_OBJECT(apply_bt), "clicked",
184                      GTK_SIGNAL_FUNC(proto_apply_cb), GTK_OBJECT(proto_w));
185   GTK_WIDGET_SET_FLAGS(apply_bt, GTK_CAN_DEFAULT);
186   gtk_box_pack_start(GTK_BOX (bbox), apply_bt, TRUE, TRUE, 0);
187   gtk_widget_show(apply_bt);
188
189   cancel_bt = gtk_button_new_with_label ("Cancel");
190   gtk_signal_connect(GTK_OBJECT(cancel_bt), "clicked",
191                      GTK_SIGNAL_FUNC(proto_cancel_cb), GTK_OBJECT(proto_w));
192   GTK_WIDGET_SET_FLAGS(cancel_bt, GTK_CAN_DEFAULT);
193   gtk_box_pack_start(GTK_BOX (bbox), cancel_bt, TRUE, TRUE, 0);
194   gtk_widget_show(cancel_bt);
195
196   dlg_set_cancel(proto_w, cancel_bt);
197
198   gtk_quit_add_destroy(gtk_main_level(), GTK_OBJECT(proto_w));
199   gtk_widget_show(proto_w);
200
201 } /* proto_cb */
202
203
204 /* Toggle All */
205 static void
206 toggle_all_cb(GtkWidget *button, gpointer parent_w)
207 {
208
209   GSList *entry;
210
211   for (entry = protocol_list; entry != NULL; entry = g_slist_next(entry)) {
212     GtkWidget *button;
213     protocol_data_t *p = entry->data;
214
215     button = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w),
216                                                p->abbrev);
217     /* gtk_toggle_button_toggled() didn't work for me... */
218     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
219                     !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)));
220   }
221 }
222
223 /* Enable/Disable All Helper */
224 static void
225 set_active_all(GtkWidget *button, gpointer parent_w, gboolean new_state)
226 {
227
228   GSList *entry;
229
230   for (entry = protocol_list; entry != NULL; entry = g_slist_next(entry)) {
231     GtkWidget *button;
232     protocol_data_t *p = entry->data;
233
234     button = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w),
235                                                p->abbrev);
236     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), new_state);
237   }
238 }
239
240 /* Enable All */
241 static void
242 enable_all_cb(GtkWidget *button, gpointer parent_w)
243 {
244         set_active_all(button, parent_w, TRUE);
245 }
246
247 /* Disable All */
248 static void
249 disable_all_cb(GtkWidget *button, gpointer parent_w)
250 {
251         set_active_all(button, parent_w, FALSE);
252 }
253
254 static void proto_destroy_cb(GtkWidget *w, gpointer data)
255 {
256   GSList *entry;
257
258   if (proto_w)
259     gtk_widget_destroy(proto_w);
260   proto_w = NULL;
261   
262   /* remove protocol list */
263   if (protocol_list) {
264     for (entry = protocol_list; entry != NULL; entry = g_slist_next(entry)) {
265       g_free(entry->data);
266     }
267     g_slist_free(protocol_list);
268     protocol_list = NULL;    
269   }
270 }
271
272 /* Treat this as a cancel, by calling "proto_cancel_cb()".
273    XXX - that'll destroy the Protocols dialog; will that upset
274    a higher-level handler that says "OK, we've been asked to delete
275    this, so destroy it"? */
276 static gboolean proto_delete_cb(GtkWidget *proto_w, gpointer dummy)
277 {
278   proto_cancel_cb(NULL, proto_w);
279   return FALSE;
280 }
281
282 static void proto_ok_cb(GtkWidget *ok_bt, gpointer parent_w) 
283 {
284   gboolean redissect;
285
286   redissect = set_proto_selection(GTK_WIDGET(parent_w));
287   gtk_widget_destroy(GTK_WIDGET(parent_w));
288   if (redissect)
289     redissect_packets(&cfile);
290 }
291
292 static void proto_apply_cb(GtkWidget *apply_bt, gpointer parent_w) 
293 {
294   if (set_proto_selection(GTK_WIDGET(parent_w)))
295     redissect_packets(&cfile);
296 }
297
298 static void proto_cancel_cb(GtkWidget *cancel_bt, gpointer parent_w) 
299 {
300   gboolean redissect;
301
302   redissect = revert_proto_selection();
303   gtk_widget_destroy(GTK_WIDGET(parent_w));
304   if (redissect)
305     redissect_packets(&cfile);
306 }
307
308 static gboolean set_proto_selection(GtkWidget *parent_w)
309 {
310   GSList *entry;
311   gboolean need_redissect = FALSE;
312
313   for (entry = protocol_list; entry != NULL; entry = g_slist_next(entry)) {
314     GtkWidget *button;
315     protocol_data_t *p = entry->data;
316
317     button = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w),
318                                                p->abbrev);
319     if (proto_is_protocol_enabled(p->hfinfo_index) != GTK_TOGGLE_BUTTON (button)->active) {
320       proto_set_decoding(p->hfinfo_index, GTK_TOGGLE_BUTTON (button)->active);
321       need_redissect = TRUE;
322     }  
323   }
324
325   return need_redissect;
326
327 } /* set_proto_selection */
328
329 static gboolean revert_proto_selection(void)
330 {
331   GSList *entry;
332   gboolean need_redissect = FALSE;
333
334   /*
335    * Undo all the changes we've made to protocol enable flags.
336    */
337   for (entry = protocol_list; entry != NULL; entry = g_slist_next(entry)) {
338     protocol_data_t *p = entry->data;
339
340     if (proto_is_protocol_enabled(p->hfinfo_index) != p->was_enabled) {
341       proto_set_decoding(p->hfinfo_index, p->was_enabled);
342       need_redissect = TRUE;
343     }  
344   }
345
346   return need_redissect;
347
348 } /* revert_proto_selection */
349
350 gint protocol_data_compare(gconstpointer a, gconstpointer b)
351 {
352   return strcmp(((protocol_data_t *)a)->abbrev, 
353                 ((protocol_data_t *)b)->abbrev);
354 }
355
356 static void show_proto_selection(GtkWidget *main, GtkWidget *container)
357 {
358
359 #define NB_COL  7
360
361   GSList *entry;
362   GtkTooltips *tooltips;
363   GtkWidget *table;
364   int i, t = 0, l = 0, nb_line, nb_proto = 0;
365   void *cookie;
366   protocol_data_t *p;
367
368   /* Iterate over all the protocols */
369
370   for (i = proto_get_first_protocol(&cookie); i != -1;
371        i = proto_get_next_protocol(&cookie)) {
372       if (proto_can_disable_protocol(i)) {
373         p = g_malloc(sizeof(protocol_data_t));
374         p->name = proto_get_protocol_name(i);
375         p->abbrev = proto_get_protocol_filter_name(i);
376         p->hfinfo_index = i;
377         p->was_enabled = proto_is_protocol_enabled(i);
378         protocol_list = g_slist_insert_sorted(protocol_list, 
379                                             p, protocol_data_compare);     
380         nb_proto ++;
381       }
382   }
383
384   /* create a table (n x NB_COL) of buttons */
385
386   nb_line = (nb_proto % NB_COL) ? nb_proto / NB_COL + 1 : nb_proto / NB_COL;
387   table = gtk_table_new (nb_line, NB_COL, FALSE);
388   gtk_table_set_row_spacings(GTK_TABLE (table), 1);
389   gtk_table_set_col_spacings(GTK_TABLE (table), 1);
390   gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(container), table);
391   gtk_widget_show(table);
392
393   tooltips = gtk_tooltips_new();
394
395   nb_proto = 0;
396
397   for (entry = protocol_list; entry != NULL; entry = g_slist_next(entry)) {
398     GtkWidget *button;
399
400     p = entry->data;
401     /* button label is the protocol abbrev */
402     button = gtk_toggle_button_new_with_label(p->abbrev);
403     /* tip is the complete protocol name */
404     gtk_tooltips_set_tip(tooltips, button, p->name, NULL);
405     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button),
406                                 proto_is_protocol_enabled(p->hfinfo_index));
407     gtk_object_set_data(GTK_OBJECT(main), p->abbrev, button);
408     gtk_table_attach_defaults (GTK_TABLE (table), button, l, l+1, t, t+1);
409     gtk_widget_show (button);
410     if (++nb_proto % NB_COL) {
411       l++;
412     }
413     else {
414       l = 0;
415       t++;
416     }
417   }
418
419 } /* show_proto_selection */