Add Compile BPF to the capture options dialog description.
[obnox/wireshark/wip.git] / gtk / tap_dfilter_dlg.c
1 /* tap_dfilter_dlg.c
2  * Routines for display filter dialog used by gui taps
3  * Copyright 2003 Lars Roland
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 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 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <stdio.h>
31 #include <string.h>
32
33 #ifdef HAVE_SYS_TYPES_H
34 # include <sys/types.h>
35 #endif
36
37 #include <gtk/gtk.h>
38
39 #include <epan/stat_cmd_args.h>
40
41 #include "../simple_dialog.h"
42 #include "../file.h"
43 #include "../globals.h"
44 #include "../stat_menu.h"
45
46 #include "gtk/stock_icons.h"
47 #include "gtk/dlg_utils.h"
48 #include "gtk/filter_dlg.h"
49 #include "gtk/gui_stat_menu.h"
50 #include "gtk/tap_dfilter_dlg.h"
51 #include "gtk/gui_utils.h"
52 #include "gtk/gtkglobals.h"
53 #include "gtk/filter_autocomplete.h"
54
55
56 typedef struct _tap_dfilter_dlg_list_item {
57         GtkWidget *dlg;
58         GtkWidget *filter_entry;
59         tap_dfilter_dlg cont;
60         construct_args_t args;
61         struct _tap_dfilter_dlg_list_item *next;
62 } tap_dfilter_dlg_list_item;
63
64 static tap_dfilter_dlg_list_item *start_dlg_list=NULL;
65 static tap_dfilter_dlg_list_item *end_dlg_list=NULL;
66 static tap_dfilter_dlg_list_item *current_dlg = NULL;
67
68 static void
69 tap_dfilter_dlg_cb(GtkWidget *w, gpointer data);
70
71 /*
72  * Register a stat that has a display filter dialog.
73  * We register it both as a command-line stat and a menu item stat.
74  */
75 void
76 register_dfilter_stat(tap_dfilter_dlg *info, const char *name,
77     register_stat_group_t group)
78 {
79         char *full_name;
80
81         register_stat_cmd_arg(info->init_string, info->tap_init_cb, NULL);
82
83         /*
84          * This menu item will pop up a dialog box, so append "..."
85          * to it.
86          */
87         full_name = g_strdup_printf("%s...", name);
88         register_stat_menu_item(full_name, group, tap_dfilter_dlg_cb, NULL,
89             NULL, info);
90         g_free(full_name);
91 }              
92
93 void tap_dfilter_dlg_update (void)
94 {
95         tap_dfilter_dlg_list_item *dialog = start_dlg_list;
96         char *title;
97         
98         while(dialog != NULL) {
99                 if(dialog->dlg) {
100                         title = g_strdup_printf("Wireshark: %s: %s", dialog->cont.win_title , cf_get_display_name(&cfile));
101                         gtk_window_set_title(GTK_WINDOW(dialog->dlg), title);
102                         g_free(title);
103                 }
104                 dialog = dialog->next;          
105         }
106 }
107
108 static void
109 dlg_destroy_cb(GtkWidget *item _U_, gpointer dialog_data)
110 {       
111         tap_dfilter_dlg_list_item *dlg_data = (tap_dfilter_dlg_list_item *) dialog_data;
112         dlg_data->dlg = NULL;
113 }
114
115 static void
116 tap_dfilter_dlg_start_button_clicked(GtkWidget *item _U_, gpointer dialog_data)
117 {
118         const char *filter;
119         char *str;
120         
121         tap_dfilter_dlg_list_item *dlg_data = (tap_dfilter_dlg_list_item *) dialog_data;
122
123         filter=gtk_entry_get_text(GTK_ENTRY(dlg_data->filter_entry));
124         if(filter[0]==0){
125                 str = g_strdup_printf("%s", dlg_data->cont.init_string);
126         } else {
127                 str = g_strdup_printf("%s,%s", dlg_data->cont.init_string,
128                                       filter);
129         }
130         (dlg_data->cont.tap_init_cb)(str,NULL);
131
132         g_free(str);
133 }
134
135
136 static void
137 tap_dfilter_dlg_cb(GtkWidget *w _U_, gpointer data)
138 {
139         const char *filter;
140         char *title;
141         GtkWidget *dlg_box;
142         GtkWidget *filter_box, *filter_bt;
143         GtkWidget *bbox, *start_button, *cancel_button;
144         
145         tap_dfilter_dlg *dlg_data = (tap_dfilter_dlg *) data;   
146
147         if(dlg_data==NULL)
148                 return;
149                 
150         if(dlg_data->index==-1) {
151                 /* Dialog is not registered */
152                 if(start_dlg_list==NULL) {
153                         start_dlg_list = (tap_dfilter_dlg_list_item *) g_malloc(sizeof (tap_dfilter_dlg_list_item));
154                         end_dlg_list = start_dlg_list;
155                         end_dlg_list->cont.index = 0; /* first entry in list -> index = 0 */
156                 } else {
157                         end_dlg_list->next = (tap_dfilter_dlg_list_item *) g_malloc(sizeof (tap_dfilter_dlg_list_item));
158                         end_dlg_list->next->cont.index = end_dlg_list->cont.index + 1;
159                         end_dlg_list = end_dlg_list->next;
160                 }
161                 end_dlg_list->dlg = NULL;
162                 end_dlg_list->filter_entry = NULL;
163                 end_dlg_list->cont.win_title = dlg_data->win_title;
164                 end_dlg_list->cont.init_string = dlg_data->init_string;
165                 end_dlg_list->cont.tap_init_cb = dlg_data->tap_init_cb;
166                 end_dlg_list->args.title = g_strdup_printf("%s Filter", dlg_data->win_title);
167                 end_dlg_list->args.wants_apply_button = TRUE;
168                 end_dlg_list->args.activate_on_ok = FALSE;
169         end_dlg_list->args.modal_and_transient = FALSE;
170                 end_dlg_list->next = NULL;
171                 dlg_data->index = end_dlg_list->cont.index;
172                 current_dlg = end_dlg_list;
173         } else {
174                 /* Dialog is registered, find it */
175                 current_dlg = start_dlg_list;
176                 while(dlg_data->index != current_dlg->cont.index)
177                 {
178                         if(current_dlg->next == NULL) {
179                                 /* could not find any dialog */
180                                 return;
181                         }
182                         current_dlg = current_dlg->next;
183                 }
184         }
185
186         /* if the window is already open, bring it to front */
187         if(current_dlg->dlg){
188                 gdk_window_raise(current_dlg->dlg->window);
189                 return;
190         }
191
192         title = g_strdup_printf("Wireshark: %s: %s", current_dlg->cont.win_title , cf_get_display_name(&cfile));
193
194         current_dlg->dlg=dlg_window_new(title);
195         gtk_window_set_default_size(GTK_WINDOW(current_dlg->dlg), 300, -1);
196         g_free(title);
197
198         dlg_box=gtk_vbox_new(FALSE, 10);
199         gtk_container_set_border_width(GTK_CONTAINER(dlg_box), 10);
200         gtk_container_add(GTK_CONTAINER(current_dlg->dlg), dlg_box);
201         gtk_widget_show(dlg_box);
202
203         /* Filter box */
204         filter_box=gtk_hbox_new(FALSE, 3);
205
206         /* Filter button */
207         filter_bt=gtk_button_new_from_stock(WIRESHARK_STOCK_DISPLAY_FILTER_ENTRY);
208         g_signal_connect(filter_bt, "clicked", G_CALLBACK(display_filter_construct_cb), &(current_dlg->args));
209         gtk_box_pack_start(GTK_BOX(filter_box), filter_bt, FALSE, TRUE, 0);
210         gtk_widget_show(filter_bt);
211
212         /* Filter entry */
213         current_dlg->filter_entry=gtk_entry_new();
214         g_signal_connect(current_dlg->filter_entry, "changed", G_CALLBACK(filter_te_syntax_check_cb), NULL);
215         g_object_set_data(G_OBJECT(filter_box), E_FILT_AUTOCOMP_PTR_KEY, NULL);
216         g_signal_connect(current_dlg->filter_entry, "key-press-event", G_CALLBACK (filter_string_te_key_pressed_cb), NULL);
217         g_signal_connect(current_dlg->dlg, "key-press-event", G_CALLBACK (filter_parent_dlg_key_pressed_cb), NULL);
218
219         /* filter prefs dialog */
220         g_object_set_data(G_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, current_dlg->filter_entry);
221         /* filter prefs dialog */
222         
223         gtk_box_pack_start(GTK_BOX(filter_box), current_dlg->filter_entry, TRUE, TRUE, 0);
224         filter=gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget));
225         if(filter){
226                 gtk_entry_set_text(GTK_ENTRY(current_dlg->filter_entry), filter);
227         } else {
228                 colorize_filter_te_as_empty(current_dlg->filter_entry);
229         }
230         gtk_widget_show(current_dlg->filter_entry);
231
232         gtk_box_pack_start(GTK_BOX(dlg_box), filter_box, TRUE, TRUE, 0);
233         gtk_widget_show(filter_box);
234
235         /* button box */
236         bbox = dlg_button_row_new(WIRESHARK_STOCK_CREATE_STAT, GTK_STOCK_CANCEL, NULL);
237         gtk_box_pack_start(GTK_BOX(dlg_box), bbox, FALSE, FALSE, 0);
238         gtk_widget_show(bbox);
239
240         start_button = g_object_get_data(G_OBJECT(bbox), WIRESHARK_STOCK_CREATE_STAT);
241         g_signal_connect(start_button, "clicked",
242                               G_CALLBACK(tap_dfilter_dlg_start_button_clicked), current_dlg);
243
244         cancel_button = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CANCEL);
245         window_set_cancel_button(current_dlg->dlg, cancel_button, window_cancel_button_cb);
246
247         /* Catch the "activate" signal on the filter text entry, so that
248            if the user types Return there, we act as if the "Create Stat"
249            button had been selected, as happens if Return is typed if
250            some widget that *doesn't* handle the Return key has the input
251            focus. */
252         dlg_set_activate(current_dlg->filter_entry, start_button);
253
254         /* Give the initial focus to the "Filter" entry box. */
255         gtk_widget_grab_focus(current_dlg->filter_entry);
256
257         gtk_widget_grab_default(start_button );
258
259         g_signal_connect(current_dlg->dlg, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
260         g_signal_connect(current_dlg->dlg, "destroy", G_CALLBACK(dlg_destroy_cb), current_dlg);
261
262         gtk_widget_show_all(current_dlg->dlg);
263         window_present(current_dlg->dlg);
264 }