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