It was silly of me to require that "forget_scrolled_window()" be called
[obnox/wireshark/wip.git] / gtk / proto_dlg.c
1 /* proto_dlg.c
2  *
3  * $Id: proto_dlg.c,v 1.4 2000/08/17 07:56:44 guy 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 /*
28  * TODO : 
29  *
30  * Modify proto.c to have a better protocol characteristics database
31  * such as ordered list or hash table. This would allow a quick search
32  * knowing the protocol abbreviation and to enhance this stuff by adding
33  * other fields (hfinfo is currently limited since protocols and fields 
34  * share the same structure type).
35  *        
36  */
37
38 #ifdef HAVE_CONFIG_H
39 # include "config.h"
40 #endif
41
42 #include <gtk/gtk.h>
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <string.h>
46
47 #ifdef HAVE_SYS_TYPES_H
48 #include <sys/types.h>
49 #endif
50
51 #include "prefs.h"
52 #include "globals.h"
53 #include "gtkglobals.h"
54 #include "main.h"
55 #include "util.h"
56 #include "ui_util.h"
57 #include "dlg_utils.h"
58 #include "proto_dlg.h"
59
60 static void proto_ok_cb(GtkWidget *, gpointer);
61 static void proto_apply_cb(GtkWidget *, gpointer);
62 static void proto_close_cb(GtkWidget *, gpointer);
63
64 static void show_proto_selection(GtkWidget *main, GtkWidget *container);
65 static gboolean set_proto_selection(GtkWidget *);
66
67 static GtkWidget *proto_w = NULL;
68
69 /* list of protocols */
70 static GSList *protocol_list = NULL;
71
72 typedef struct protocol_data {
73   char  *abbrev;
74   int   hfinfo_index;
75 } protocol_data_t;
76
77 void proto_cb(GtkWidget *w, gpointer data)
78 {
79
80   GtkWidget *main_vb, *bbox, *proto_nb, *apply_bt, *cancel_bt, *ok_bt, 
81     *label, *scrolled_w, *selection_vb;
82   
83   if (proto_w != NULL) {
84     reactivate_window(proto_w);
85     return;
86   }
87
88   proto_w = dlg_window_new();
89   gtk_window_set_title(GTK_WINDOW(proto_w), "Ethereal: Protocol");
90   gtk_signal_connect(GTK_OBJECT(proto_w), "destroy",
91                      GTK_SIGNAL_FUNC(proto_close_cb), NULL);
92   gtk_widget_set_usize(GTK_WIDGET(proto_w), DEF_WIDTH * 2/3, DEF_HEIGHT * 2/3);
93
94   /* Container for each row of widgets */
95
96   main_vb = gtk_vbox_new(FALSE, 0);
97   gtk_container_border_width(GTK_CONTAINER(main_vb), 1);
98   gtk_container_add(GTK_CONTAINER(proto_w), main_vb);
99   gtk_widget_show(main_vb);
100
101   /* Protocol topics container */
102   
103   proto_nb = gtk_notebook_new();
104   gtk_container_add(GTK_CONTAINER(main_vb), proto_nb);
105   /* XXX do not know why I need this to fill all space around buttons */
106   gtk_widget_set_usize(GTK_WIDGET(proto_nb), DEF_WIDTH * 2/3 - 50,
107                        DEF_HEIGHT * 2/3 - 50);
108
109   /* Protocol selection panel ("enable/disable" protocols) */
110
111   selection_vb = gtk_vbox_new(FALSE, 0);
112   gtk_container_border_width(GTK_CONTAINER(selection_vb), 1);  
113   label = gtk_label_new("Button pressed: protocol decoding is enabled");
114   gtk_widget_show(label);
115   gtk_box_pack_start(GTK_BOX(selection_vb), label, FALSE, FALSE, 0);
116   scrolled_w = gtk_scrolled_window_new(NULL, NULL);         
117   gtk_container_set_border_width(GTK_CONTAINER(scrolled_w), 1);           
118   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_w),
119                                  GTK_POLICY_AUTOMATIC,
120                                  GTK_POLICY_ALWAYS);
121   set_scrollbar_placement_scrollw(scrolled_w, prefs.gui_scrollbar_on_right);
122   remember_scrolled_window(scrolled_w);
123   gtk_box_pack_start(GTK_BOX(selection_vb), scrolled_w, TRUE, TRUE, 0);
124   show_proto_selection(proto_w, scrolled_w);
125   gtk_widget_show(scrolled_w);
126   gtk_widget_show(selection_vb);
127   label = gtk_label_new("Decoding");
128   gtk_notebook_append_page(GTK_NOTEBOOK(proto_nb), selection_vb, label);
129   label = gtk_label_new("Note that when a protocol is disabled, "
130                         "all linked sub-protocols are as well");
131   gtk_widget_show(label);
132   gtk_box_pack_start(GTK_BOX(selection_vb), label, FALSE, FALSE, 0);
133
134   /* XXX add other protocol-related panels here ... */
135
136   gtk_widget_show(proto_nb);
137
138   /* Ok, Apply, Cancel Buttons */  
139
140   bbox = gtk_hbutton_box_new();
141   gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
142   gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
143   gtk_container_add(GTK_CONTAINER(main_vb), bbox);
144   gtk_widget_show(bbox);
145
146   ok_bt = gtk_button_new_with_label ("OK");
147   gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
148                      GTK_SIGNAL_FUNC(proto_ok_cb), GTK_OBJECT(proto_w));
149   GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT);
150   gtk_box_pack_start(GTK_BOX (bbox), ok_bt, TRUE, TRUE, 0);
151   gtk_widget_grab_default(ok_bt);
152   gtk_widget_show(ok_bt);
153
154   apply_bt = gtk_button_new_with_label ("Apply");
155   gtk_signal_connect(GTK_OBJECT(apply_bt), "clicked",
156                      GTK_SIGNAL_FUNC(proto_apply_cb), GTK_OBJECT(proto_w));
157   GTK_WIDGET_SET_FLAGS(apply_bt, GTK_CAN_DEFAULT);
158   gtk_box_pack_start(GTK_BOX (bbox), apply_bt, TRUE, TRUE, 0);
159   gtk_widget_show(apply_bt);
160
161   cancel_bt = gtk_button_new_with_label ("Cancel");
162   gtk_signal_connect(GTK_OBJECT(cancel_bt), "clicked",
163                      GTK_SIGNAL_FUNC(proto_close_cb), GTK_OBJECT(proto_w));
164   GTK_WIDGET_SET_FLAGS(cancel_bt, GTK_CAN_DEFAULT);
165   gtk_box_pack_start(GTK_BOX (bbox), cancel_bt, TRUE, TRUE, 0);
166   gtk_widget_show(cancel_bt);
167
168   dlg_set_cancel(proto_w, cancel_bt);
169
170   gtk_quit_add_destroy(gtk_main_level(), GTK_OBJECT(proto_w));
171   gtk_widget_show(proto_w);
172
173 } /* proto_cb */
174
175 static void proto_close_cb(GtkWidget *w, gpointer data)
176 {
177   GSList *entry;
178
179   if (proto_w)
180     gtk_widget_destroy(proto_w);
181   proto_w = NULL;
182   
183   /* remove protocol list */
184   if (protocol_list) {
185     for (entry = protocol_list; entry != NULL; entry = g_slist_next(entry)) {
186       g_free(entry->data);
187     }
188     g_slist_free(protocol_list);
189     protocol_list = NULL;    
190   }
191 }
192
193 static void proto_ok_cb(GtkWidget *ok_bt, gpointer parent_w) 
194 {
195   gboolean redissect;
196   redissect = set_proto_selection(GTK_WIDGET(parent_w));
197   gtk_widget_destroy(GTK_WIDGET(parent_w));
198   if (redissect)
199     redissect_packets(&cfile);
200 }
201
202 static void proto_apply_cb(GtkWidget *ok_bt, gpointer parent_w) 
203 {
204   if (set_proto_selection(GTK_WIDGET(parent_w)))
205     redissect_packets(&cfile);
206 }
207
208 static gboolean set_proto_selection(GtkWidget *parent_w)
209 {
210   GSList *entry;
211   gboolean need_redissect = FALSE;
212
213   for (entry = protocol_list; entry != NULL; entry = g_slist_next(entry)) {
214     GtkWidget *button;
215     header_field_info *hfinfo;
216     protocol_data_t *p = entry->data;
217     hfinfo = proto_registrar_get_nth(p->hfinfo_index);
218     button = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w),
219                                                hfinfo->abbrev);      
220     /* XXX optimization but should not use display field */
221     if (hfinfo->display != GTK_TOGGLE_BUTTON (button)->active) {
222       proto_set_decoding(p->hfinfo_index, GTK_TOGGLE_BUTTON (button)->active);
223       need_redissect = TRUE;
224     }  
225   }
226
227 return need_redissect;
228
229 } /* set_proto_selection */
230
231 gint protocol_data_compare(gconstpointer a, gconstpointer b)
232 {
233   return strcmp(((protocol_data_t *)a)->abbrev, 
234                 ((protocol_data_t *)b)->abbrev);
235 }
236
237 static void show_proto_selection(GtkWidget *main, GtkWidget *container)
238 {
239
240 #define NB_COL  7
241
242   GSList *entry;
243   GtkTooltips *tooltips;
244   GtkWidget *table;
245   int i, t = 0, l = 0, nb_line, nb_proto = 0;
246
247   /* Obtain the number of "true" protocols */
248
249   for (i = 0; i < proto_registrar_n() ; i++) {
250
251     if (proto_registrar_is_protocol(i)) {
252
253       protocol_data_t *p;
254       header_field_info *hfinfo;
255       hfinfo = proto_registrar_get_nth(i);        
256
257       if (strcmp(hfinfo->abbrev, "data") == 0 ||
258           strcmp(hfinfo->abbrev, "text") == 0 ||
259           strcmp(hfinfo->abbrev, "malformed") == 0 ||
260           strcmp(hfinfo->abbrev, "short") == 0 ||
261           strcmp(hfinfo->abbrev, "frame") == 0) continue;
262
263       p = g_malloc(sizeof(protocol_data_t));
264       p->abbrev = hfinfo->abbrev;
265       p->hfinfo_index = i;
266       protocol_list = g_slist_insert_sorted(protocol_list, 
267                                             p, protocol_data_compare);     
268       nb_proto ++;
269     }
270   }
271
272   /* create a table (n x NB_COL) of buttons */
273
274   nb_line = (nb_proto % NB_COL) ? nb_proto / NB_COL + 1 : nb_proto / NB_COL;
275   table = gtk_table_new (nb_line, NB_COL, FALSE);
276   gtk_table_set_row_spacings(GTK_TABLE (table), 1);
277   gtk_table_set_col_spacings(GTK_TABLE (table), 1);
278   gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(container), table);
279   gtk_widget_show(table);
280
281   tooltips = gtk_tooltips_new();
282
283   nb_proto = 0;
284
285   for (entry = protocol_list; entry != NULL; entry = g_slist_next(entry)) {
286     GtkWidget *button;
287     header_field_info *hfinfo;
288     protocol_data_t *p = entry->data;
289     hfinfo = proto_registrar_get_nth(p->hfinfo_index);    
290     /* button label is the protocol abbrev */
291     button = gtk_toggle_button_new_with_label(hfinfo->abbrev);
292     /* tip is the complete protocol name */
293     gtk_tooltips_set_tip(tooltips, button, hfinfo->name, NULL);
294     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), hfinfo->display);
295     gtk_object_set_data(GTK_OBJECT(main), hfinfo->abbrev, button);
296     gtk_table_attach_defaults (GTK_TABLE (table), button, l, l+1, t, t+1);
297     gtk_widget_show (button);
298     if (++nb_proto % NB_COL) {
299       l++;
300     }
301     else {
302       l = 0;
303       t++;
304     }
305   }
306
307 } /* show_proto_selection */