Use GTK+'s GtkMessageDialog for the questions we ask in the process of
[metze/wireshark/wip.git] / ui / gtk / main_toolbar.c
1 /* main_toolbar.c
2  * The main toolbar
3  * Copyright 2003, Ulf Lamping <ulf.lamping@web.de>
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 /*
27  * This file implements the "main" toolbar for Wireshark.
28  */
29
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #include <gtk/gtk.h>
35
36 #include <epan/prefs.h>
37 #include <epan/dfilter/dfilter.h>
38
39 #include "../cfile.h"
40 #include "../color_filters.h"
41
42 #include "ui/recent.h"
43
44 #ifdef HAVE_LIBPCAP
45 #include "ui/gtk/capture_dlg.h"
46 #include "ui/gtk/capture_if_dlg.h"
47 #endif /* HAVE_LIBPCAP */
48 #include "ui/gtk/filter_dlg.h"
49 #include "ui/gtk/capture_file_dlg.h"
50 #include "ui/gtk/find_dlg.h"
51 #include "ui/gtk/goto_dlg.h"
52 #include "ui/gtk/color_dlg.h"
53 #include "ui/gtk/prefs_dlg.h"
54 #include "ui/gtk/main.h"
55 #include "ui/gtk/menus.h"
56 #include "ui/gtk/main_toolbar.h"
57 #include "ui/gtk/help_dlg.h"
58 #include "ui/gtk/gtkglobals.h"
59 #include "ui/gtk/stock_icons.h"
60 #include "ui/gtk/keys.h"
61 #include "ui/gtk/packet_history.h"
62 #include "ui/gtk/new_packet_list.h"
63
64 #include "ui/gtk/old-gtk-compat.h"
65
66 static gboolean toolbar_init = FALSE;
67
68 #ifdef HAVE_LIBPCAP
69 static GtkToolItem *capture_options_button, *new_button, *stop_button, *clear_button, *if_button;
70 static GtkToolItem *capture_filter_button, *autoscroll_button;
71 #endif /* HAVE_LIBPCAP */
72 static GtkToolItem *open_button, *save_button, *close_button, *reload_button;
73 static GtkToolItem *print_button, *find_button, *history_forward_button, *history_back_button;
74 static GtkToolItem *go_to_button, *go_to_top_button, *go_to_bottom_button;
75 static GtkToolItem *display_filter_button;
76 static GtkToolItem *zoom_in_button, *zoom_out_button, *zoom_100_button, *colorize_button;
77 static GtkToolItem *resize_columns_button;
78 static GtkToolItem *color_display_button, *prefs_button, *help_button;
79
80 #define SAVE_BUTTON_TOOLTIP_TEXT "Save this capture file..."
81 #define SAVE_AS_BUTTON_TOOLTIP_TEXT "Save this capture file as..."
82
83
84 /*
85  * Redraw all toolbars 
86  */
87 void
88 toolbar_redraw_all(void)
89 {
90     GtkWidget     *main_tb;
91     GtkWidget     *filter_tb;
92
93     main_tb = g_object_get_data(G_OBJECT(top_level), E_TB_MAIN_KEY);
94
95     gtk_toolbar_set_style(GTK_TOOLBAR(main_tb),
96                           prefs.gui_toolbar_main_style);
97
98         filter_tb = g_object_get_data(G_OBJECT(top_level), E_TB_FILTER_KEY);
99
100         /* In case the filter toolbar hasn't been built */
101         if(filter_tb)
102                 gtk_toolbar_set_style(GTK_TOOLBAR(filter_tb),
103                           prefs.gui_toolbar_filter_style);
104 }
105
106 /* Enable or disable toolbar items based on whether you have a capture file
107    and, if so, whether you've finished reading it and whether there's stuff
108    in it that hasn't yet been saved to a permanent file. */
109 void set_toolbar_for_capture_file(capture_file *cf) {
110     if (toolbar_init) {
111         if (cf == NULL || cf->state == FILE_READ_IN_PROGRESS) {
112             /* We have no open capture file, or we have one but we're in
113                the process of reading it.  Disable everything having to
114                do with the file*/
115             if (strcmp(gtk_tool_button_get_stock_id(GTK_TOOL_BUTTON(save_button)), GTK_STOCK_SAVE_AS) != 0) {
116                 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(save_button), GTK_STOCK_SAVE_AS);
117                 gtk_widget_set_tooltip_text(GTK_WIDGET(save_button), SAVE_AS_BUTTON_TOOLTIP_TEXT);
118                 g_object_set_data(G_OBJECT(save_button), "save", GINT_TO_POINTER(0));
119             }
120             gtk_widget_set_sensitive(GTK_WIDGET(save_button), FALSE);
121             gtk_widget_set_sensitive(GTK_WIDGET(close_button), FALSE);
122             gtk_widget_set_sensitive(GTK_WIDGET(reload_button), FALSE);
123         } else {
124             /* We have an open capture file and we're finished reading it.
125                Enable "Save As", "Close", and "Reload"; enable "Save" iff
126                it has stuff not saved to a permanent file (and we support
127                saving in its format). */
128             if (cf->is_tempfile || cf->unsaved_changes) {
129                 if (strcmp(gtk_tool_button_get_stock_id(GTK_TOOL_BUTTON(save_button)), GTK_STOCK_SAVE) != 0) {
130                     gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(save_button), GTK_STOCK_SAVE);
131                     gtk_widget_set_tooltip_text(GTK_WIDGET(save_button),SAVE_BUTTON_TOOLTIP_TEXT);
132                     g_object_set_data(G_OBJECT(save_button), "save", GINT_TO_POINTER(1));
133                 }
134             } else {
135                 if (strcmp(gtk_tool_button_get_stock_id(GTK_TOOL_BUTTON(save_button)), GTK_STOCK_SAVE_AS) != 0) {
136                     gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(save_button), GTK_STOCK_SAVE_AS);
137                     gtk_widget_set_tooltip_text(GTK_WIDGET(save_button), SAVE_AS_BUTTON_TOOLTIP_TEXT);
138                     g_object_set_data(G_OBJECT(save_button), "save", GINT_TO_POINTER(0));
139                 }
140             }
141             gtk_widget_set_sensitive(GTK_WIDGET(save_button),
142                                      (cf->is_tempfile || cf->unsaved_changes) && cf_can_save_as(cf));
143             gtk_widget_set_sensitive(GTK_WIDGET(close_button), TRUE);
144             gtk_widget_set_sensitive(GTK_WIDGET(reload_button), TRUE);
145         }
146     }
147 }
148
149 /* fudge to call correct file_save or file_save_as fcn based upon the
150    value of the "save" key associated with the save button
151 */
152
153 static void file_save_or_save_as_cmd_cb(GtkWidget *w, gpointer data) {
154     if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(save_button),"save")) == 1) {
155         file_save_cmd_cb(w, data);
156     }
157     else {
158         file_save_as_cmd_cb(w, data);
159     }
160 }
161
162 /** The packet history has changed, we need to update the menu.
163  *
164  * @param back_history some back history entries available
165  * @param forward_history some forward history entries available
166  */
167 void set_toolbar_for_packet_history(gboolean back_history, gboolean forward_history) {
168     gtk_widget_set_sensitive(GTK_WIDGET(history_back_button), back_history);
169     gtk_widget_set_sensitive(GTK_WIDGET(history_forward_button), forward_history);
170 }
171
172
173 /* set toolbar state "have a capture in progress" */
174 void set_toolbar_for_capture_in_progress(gboolean capture_in_progress) {
175
176     if (toolbar_init) {
177 #ifdef HAVE_LIBPCAP
178         gtk_widget_set_sensitive(GTK_WIDGET(capture_options_button), !capture_in_progress);
179         gtk_widget_set_sensitive(GTK_WIDGET(new_button), !capture_in_progress);
180         gtk_widget_set_sensitive(GTK_WIDGET(stop_button), capture_in_progress);
181         gtk_widget_set_sensitive(GTK_WIDGET(clear_button), capture_in_progress);
182         /*if (capture_in_progress) {
183             gtk_widget_hide(GTK_WIDGET(new_button));
184             gtk_widget_show(GTK_WIDGET(stop_button));
185         } else {
186             gtk_widget_show(GTK_WIDGET(new_button));
187             gtk_widget_hide(GTK_WIDGET(stop_button));
188         }*/
189 #endif /* HAVE_LIBPCAP */
190         gtk_widget_set_sensitive(GTK_WIDGET(open_button), !capture_in_progress);
191     }
192 }
193
194 /* set toolbar state "have packets captured" */
195 void set_toolbar_for_captured_packets(gboolean have_captured_packets) {
196
197     if (toolbar_init) {
198         gtk_widget_set_sensitive(GTK_WIDGET(print_button),
199                                  have_captured_packets);
200         gtk_widget_set_sensitive(GTK_WIDGET(find_button),
201                                  have_captured_packets);
202         gtk_widget_set_sensitive(GTK_WIDGET(history_back_button),
203                                  have_captured_packets);
204         gtk_widget_set_sensitive(GTK_WIDGET(history_forward_button),
205                                  have_captured_packets);
206         gtk_widget_set_sensitive(GTK_WIDGET(go_to_button),
207                                  have_captured_packets);
208         gtk_widget_set_sensitive(GTK_WIDGET(go_to_top_button),
209                                  have_captured_packets);
210         gtk_widget_set_sensitive(GTK_WIDGET(go_to_bottom_button),
211                                  have_captured_packets);
212         gtk_widget_set_sensitive(GTK_WIDGET(zoom_in_button),
213                                  have_captured_packets);
214         gtk_widget_set_sensitive(GTK_WIDGET(zoom_out_button),
215                                  have_captured_packets);
216         gtk_widget_set_sensitive(GTK_WIDGET(zoom_100_button),
217                                  have_captured_packets);
218         gtk_widget_set_sensitive(GTK_WIDGET(resize_columns_button),
219                                  have_captured_packets);
220
221         /* XXX - I don't see a reason why this should be done (as it is in the
222          * menus) */
223         /* gtk_widget_set_sensitive(GTK_WIDGET(color_display_button),
224            have_captured_packets);*/
225     }
226 }
227
228
229 /* helper function: add a separator to the toolbar */
230 static void toolbar_append_separator(GtkWidget *toolbar) {
231     GtkToolItem *tool_item = gtk_separator_tool_item_new();
232     gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_item, -1);
233     gtk_widget_show(GTK_WIDGET(tool_item));
234 }
235
236
237
238 #define toolbar_item(new_item, toolbar, stock, tooltip_text, callback, user_data) { \
239     new_item = gtk_tool_button_new_from_stock(stock); \
240     gtk_widget_set_tooltip_text(GTK_WIDGET(new_item), tooltip_text); \
241     g_signal_connect(new_item, "clicked", G_CALLBACK(callback), user_data); \
242     gtk_toolbar_insert(GTK_TOOLBAR(toolbar), new_item, -1); \
243     gtk_widget_show(GTK_WIDGET(new_item)); \
244     }
245
246 #define toolbar_toggle_button(new_item, window, toolbar, stock, tooltip_text, callback, user_data) { \
247     new_item = gtk_toggle_tool_button_new_from_stock(stock); \
248     gtk_widget_set_tooltip_text(GTK_WIDGET(new_item), tooltip_text);    \
249     g_signal_connect(new_item, "toggled", G_CALLBACK(callback), user_data); \
250     gtk_toolbar_insert(GTK_TOOLBAR(toolbar), new_item, -1); \
251     gtk_widget_show_all(GTK_WIDGET(new_item)); \
252     }
253
254 #define TOGGLE_BUTTON               GTK_TOGGLE_TOOL_BUTTON
255 #define TOGGLE_BUTTON_GET_ACTIVE    gtk_toggle_tool_button_get_active
256 #define TOGGLE_BUTTON_SET_ACTIVE    gtk_toggle_tool_button_set_active
257
258 static void
259 colorize_toggle_cb(GtkWidget *toggle_button, gpointer user_data _U_)  {
260     menu_colorize_changed(TOGGLE_BUTTON_GET_ACTIVE(TOGGLE_BUTTON(toggle_button)));
261 }
262
263 void
264 toolbar_colorize_changed(gboolean packet_list_colorize) {
265     if(TOGGLE_BUTTON_GET_ACTIVE(TOGGLE_BUTTON(colorize_button)) != packet_list_colorize) {
266         TOGGLE_BUTTON_SET_ACTIVE(TOGGLE_BUTTON(colorize_button), packet_list_colorize);
267     }
268 }
269
270 #ifdef HAVE_LIBPCAP
271 static void
272 auto_scroll_live_toggle_cb(GtkWidget *autoscroll_button_lcl, gpointer user_data _U_) {
273     menu_auto_scroll_live_changed(TOGGLE_BUTTON_GET_ACTIVE(TOGGLE_BUTTON(autoscroll_button_lcl)));
274 }
275
276 void
277 toolbar_auto_scroll_live_changed(gboolean auto_scroll_live_lcl) {
278     if(TOGGLE_BUTTON_GET_ACTIVE(TOGGLE_BUTTON(autoscroll_button)) != auto_scroll_live_lcl) {
279         TOGGLE_BUTTON_SET_ACTIVE(TOGGLE_BUTTON(autoscroll_button), auto_scroll_live_lcl);
280     }
281 }
282 #endif
283
284
285 /*
286  * Create all toolbars (currently only the main toolbar)
287  */
288 GtkWidget *
289 toolbar_new(void)
290 {
291     GtkWidget *main_tb;
292     GtkWidget *window = top_level;
293
294     /* this function should be only called once! */
295     g_assert(!toolbar_init);
296
297     /* we need to realize the window because we use pixmaps for
298      * items on the toolbar in the context of it */
299     /* (coming from the gtk example, please don't ask me why ;-) */
300     gtk_widget_realize(window);
301
302     /* toolbar will be horizontal, with both icons and text (as default here) */
303     /* (this will usually be overwritten by the preferences setting) */
304     main_tb = gtk_toolbar_new();
305     gtk_orientable_set_orientation(GTK_ORIENTABLE(main_tb),
306                                 GTK_ORIENTATION_HORIZONTAL);
307
308     g_object_set_data(G_OBJECT(top_level), E_TB_MAIN_KEY, main_tb);
309
310
311 #ifdef HAVE_LIBPCAP
312     toolbar_item(if_button, main_tb,
313         WIRESHARK_STOCK_CAPTURE_INTERFACES, "List the available capture interfaces...", capture_if_cb, NULL);
314
315     toolbar_item(capture_options_button, main_tb,
316         WIRESHARK_STOCK_CAPTURE_OPTIONS, "Show the capture options...", capture_prep_cb, NULL);
317
318     toolbar_item(new_button, main_tb,
319         WIRESHARK_STOCK_CAPTURE_START, "Start a new live capture", capture_start_cb, NULL);
320
321     toolbar_item(stop_button, main_tb,
322         WIRESHARK_STOCK_CAPTURE_STOP, "Stop the running live capture", capture_stop_cb, NULL);
323
324     toolbar_item(clear_button, main_tb,
325         WIRESHARK_STOCK_CAPTURE_RESTART, "Restart the running live capture", capture_restart_cb, NULL);
326
327     toolbar_append_separator(main_tb);
328 #endif /* HAVE_LIBPCAP */
329
330     toolbar_item(open_button, main_tb,
331         GTK_STOCK_OPEN, "Open a capture file...", file_open_cmd_cb, NULL);
332
333     /* Only create a separate button in GTK < 2.4.  With GTK 2.4+, we will
334      * just modify the save_button to read/show save or save as as needed.
335      * We'll also fudge in an object key ("save") for the save button with data which  specifies
336      * whether the button is currently "save" (1)or "save as" (0).
337      * The fcn file_save_or_save_as_cmd_cb
338      * will then call the appropriate file_save_cmd_cb or file_save_as_cmd_cb
339      */
340
341     toolbar_item(save_button, main_tb,
342         GTK_STOCK_SAVE, SAVE_BUTTON_TOOLTIP_TEXT, file_save_or_save_as_cmd_cb, NULL);
343     g_object_set_data(G_OBJECT(save_button), "save", GINT_TO_POINTER(1));
344
345     toolbar_item(close_button, main_tb,
346         GTK_STOCK_CLOSE, "Close this capture file", file_close_cmd_cb, NULL);
347
348     toolbar_item(reload_button, main_tb,
349         GTK_STOCK_REFRESH, "Reload this capture file", file_reload_cmd_cb, NULL);
350
351     toolbar_item(print_button, main_tb,
352         GTK_STOCK_PRINT, "Print packet(s)...", file_print_cmd_cb, NULL);
353
354     toolbar_append_separator(main_tb);
355
356     toolbar_item(find_button, main_tb,
357         GTK_STOCK_FIND, "Find a packet...", find_frame_cb, NULL);
358
359     toolbar_item(history_back_button, main_tb,
360         GTK_STOCK_GO_BACK, "Go back in packet history", history_back_cb, NULL);
361
362     toolbar_item(history_forward_button, main_tb,
363         GTK_STOCK_GO_FORWARD, "Go forward in packet history", history_forward_cb, NULL);
364
365     toolbar_item(go_to_button, main_tb,
366         GTK_STOCK_JUMP_TO, "Go to the packet with number...", goto_frame_cb, NULL);
367
368     toolbar_item(go_to_top_button, main_tb,
369         GTK_STOCK_GOTO_TOP, "Go to the first packet", goto_top_frame_cb, NULL);
370
371     toolbar_item(go_to_bottom_button, main_tb,
372         GTK_STOCK_GOTO_BOTTOM, "Go to the last packet", goto_bottom_frame_cb, NULL);
373
374     toolbar_append_separator(main_tb);
375
376     toolbar_toggle_button(colorize_button, window, main_tb,
377         WIRESHARK_STOCK_COLORIZE, "Colorize Packet List", colorize_toggle_cb, NULL);
378
379 #ifdef HAVE_LIBPCAP
380     toolbar_toggle_button(autoscroll_button, window, main_tb,
381         WIRESHARK_STOCK_AUTOSCROLL, "Auto Scroll Packet List in Live Capture", auto_scroll_live_toggle_cb, NULL);
382 #endif
383
384     toolbar_append_separator(main_tb);
385
386     toolbar_item(zoom_in_button, main_tb,
387         GTK_STOCK_ZOOM_IN, "Zoom in", view_zoom_in_cb, NULL);
388
389     toolbar_item(zoom_out_button, main_tb,
390         GTK_STOCK_ZOOM_OUT, "Zoom out", view_zoom_out_cb, NULL);
391
392     toolbar_item(zoom_100_button, main_tb,
393         GTK_STOCK_ZOOM_100, "Zoom 100%", view_zoom_100_cb, NULL);
394
395     toolbar_item(resize_columns_button, main_tb,
396     WIRESHARK_STOCK_RESIZE_COLUMNS, "Resize All Columns", new_packet_list_resize_columns_cb, NULL);
397
398     toolbar_append_separator(main_tb);
399
400 #ifdef HAVE_LIBPCAP
401     toolbar_item(capture_filter_button, main_tb,
402         WIRESHARK_STOCK_CAPTURE_FILTER, "Edit capture filter...", cfilter_dialog_cb, NULL);
403 #endif /* HAVE_LIBPCAP */
404
405     toolbar_item(display_filter_button, main_tb,
406         WIRESHARK_STOCK_DISPLAY_FILTER, "Edit/apply display filter...", dfilter_dialog_cb, NULL);
407
408     toolbar_item(color_display_button, main_tb,
409         GTK_STOCK_SELECT_COLOR, "Edit coloring rules...", color_display_cb, NULL);
410
411     /* the preference button uses it's own Stock icon label "Prefs", as "Preferences" is too long */
412     toolbar_item(prefs_button, main_tb,
413         GTK_STOCK_PREFERENCES, "Edit preferences...", prefs_cb, NULL);
414
415     toolbar_append_separator(main_tb);
416
417     toolbar_item(help_button, main_tb,
418         GTK_STOCK_HELP, "Show some help...", topic_cb, GINT_TO_POINTER(HELP_CONTENT));
419
420     /* disable all "sensitive" items by default */
421     toolbar_init = TRUE;
422     set_toolbar_for_captured_packets(FALSE);
423     set_toolbar_for_capture_file(NULL);
424 #ifdef HAVE_LIBPCAP
425     set_toolbar_for_capture_in_progress(FALSE);
426 #endif /* HAVE_LIBPCAP */
427
428     /* make current preferences effective */
429     toolbar_redraw_all();
430
431     return main_tb;
432 }
433
434 void
435 set_toolbar_object_data(gchar *key, gpointer data)
436 {
437     g_object_set_data(G_OBJECT(open_button), key, data);
438     g_object_set_data(G_OBJECT(reload_button), key, data);
439 }