bd3a4dc95ea839c314f4f2d3a391c16b22565bbc
[obnox/wireshark/wip.git] / gtk / toolbar.c
1 /* toolbar.c
2  * The main toolbar
3  * Copyright 2003, Ulf Lamping <ulf.lamping@web.de>
4  *
5  * $Id$
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
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 a "main" toolbar for Ethereal (suitable for gtk1 and
28  * gtk2).
29  *
30  * As it is desirable to have the same toolbar implementation for gtk1 and gtk2 
31  * in Ethereal, only those library calls available in the gtk1 libraries 
32  * are used inside this file.
33  *
34  * Hint: gtk2 in comparison to gtk1 has a better way to handle with "common"
35  * icons; gtk2 calls this kind of icons "stock-icons"
36  * (stock-icons including: icons for "open", "save", "print", ...).
37  * The gtk2 version of this code uses them.
38  */
39
40 #ifdef HAVE_CONFIG_H
41 #include "config.h"
42 #endif
43
44 #include <gtk/gtk.h>
45
46 #ifdef HAVE_LIBPCAP
47 #include "capture_dlg.h"
48 #endif /* HAVE_LIBPCAP */
49 #include "filter_dlg.h"
50 #include "file_dlg.h"
51 #include "find_dlg.h"
52 #include "goto_dlg.h"
53 #include "color.h"
54 #include "color_dlg.h"
55 #include "prefs.h"
56 #include "prefs_dlg.h"
57 #include "main.h"
58 #include "help_dlg.h"
59 #include "gtkglobals.h"
60 #include "toolbar.h"
61 #include "keys.h"
62 #include "compat_macros.h"
63 #include "recent.h"
64
65 /* All of the icons used here are coming (or are derived) from GTK2 stock icons.
66  * They were converted using "The Gimp" with standard conversion from png to xpm.
67  * All stock icons can be (currently) found at: 
68  * "ftp://ftp.gtk.org/pub/gtk/v2.0/gtk+-2.0.6.tar.bz2"
69  * in the directory "gtk+-2.0.6\gtk\stock-icons" */
70 #if GTK_MAJOR_VERSION < 2
71 #ifdef HAVE_LIBPCAP
72 #include "../image/toolbar/stock_stop_24.xpm"
73 #endif /* HAVE_LIBPCAP */
74 #include "../image/toolbar/stock_save_as_24.xpm"
75 #include "../image/toolbar/stock_close_24.xpm"
76 #include "../image/toolbar/stock_refresh_24.xpm"
77 #include "../image/toolbar/stock_print_24.xpm"
78 #include "../image/toolbar/stock_search_24.xpm"
79 #include "../image/toolbar/stock_left_arrow_24.xpm"
80 #include "../image/toolbar/stock_right_arrow_24.xpm"
81 #include "../image/toolbar/stock_jump_to_24.xpm"
82 #include "../image/toolbar/stock_top_24.xpm"
83 #include "../image/toolbar/stock_bottom_24.xpm"
84 #include "../image/toolbar/stock_zoom_in_24.xpm"
85 #include "../image/toolbar/stock_zoom_out_24.xpm"
86 #include "../image/toolbar/stock_zoom_1_24.xpm"
87 #include "../image/toolbar/stock_colorselector_24.xpm"
88 #include "../image/toolbar/stock_help_24.xpm"
89 #endif /* GTK_MAJOR_VERSION */
90
91 /* these icons are derived from the original stock icons */
92 #ifdef HAVE_LIBPCAP
93 #include "../image/toolbar/capture_24.xpm"
94 #include "../image/toolbar/cfilter_24.xpm"
95 #endif /* HAVE_LIBPCAP */
96 #include "../image/toolbar/dfilter_24.xpm"
97 /* these icons are standard stock icons, but used for ethereal specific stock icon labels */
98 #if GTK_MAJOR_VERSION >= 2
99 #include "../image/toolbar/stock_add_24.xpm"
100 #endif
101 #include "../image/toolbar/stock_open_24.xpm"
102 #if GTK_MAJOR_VERSION >= 2
103 #include "../image/toolbar/stock_ok_20.xpm"
104 #endif
105 #include "../image/toolbar/stock_save_24.xpm"
106 #include "../image/toolbar/stock_preferences_24.xpm"
107 #if GTK_MAJOR_VERSION >= 2
108 #include "../image/toolbar/stock_properties_24.xpm"
109 #endif
110
111
112 /* XXX: add this key to some .h file, as it adds a key to the top level Widget? */
113 #define E_TB_MAIN_KEY             "toolbar_main"
114
115
116 static gboolean toolbar_init = FALSE;
117
118 #ifdef HAVE_LIBPCAP
119 static GtkWidget *new_button, *stop_button;
120 static GtkWidget *capture_filter_button;
121 #endif /* HAVE_LIBPCAP */
122 static GtkWidget *open_button, *save_button, *save_as_button, *close_button, *reload_button;
123 static GtkWidget *print_button, *find_button, *find_next_button, *find_prev_button;
124 static GtkWidget *go_to_button, *go_to_top_button, *go_to_bottom_button;
125 static GtkWidget *display_filter_button;
126 static GtkWidget *zoom_in_button, *zoom_out_button, *zoom_100_button;
127 static GtkWidget *color_display_button, *prefs_button, *help_button;
128
129 #if GTK_MAJOR_VERSION >= 2
130 typedef struct stock_pixmap_tag{
131     const char *    name;
132     char **         xpm_data;
133 } stock_pixmap_t;
134
135 /* generate application specific stock items */
136 static void ethereal_stock_icons(void) {
137     GtkIconFactory * factory;
138     gint32 i;
139
140
141     /* register non-standard pixmaps with the gtk-stock engine */
142     static const GtkStockItem stock_items[] = {
143 #ifdef HAVE_LIBPCAP
144         { ETHEREAL_STOCK_CAPTURE_START,         ETHEREAL_STOCK_LABEL_CAPTURE_START,         0, 0, NULL },
145         { ETHEREAL_STOCK_CAPTURE_FILTER,        ETHEREAL_STOCK_LABEL_CAPTURE_FILTER,        0, 0, NULL },
146         { ETHEREAL_STOCK_CAPTURE_FILTER_ENTRY,  ETHEREAL_STOCK_LABEL_CAPTURE_FILTER_ENTRY,  0, 0, NULL },
147 #endif
148         { ETHEREAL_STOCK_DISPLAY_FILTER,        ETHEREAL_STOCK_LABEL_DISPLAY_FILTER,        0, 0, NULL },
149         { ETHEREAL_STOCK_DISPLAY_FILTER_ENTRY,  ETHEREAL_STOCK_LABEL_DISPLAY_FILTER_ENTRY,  0, 0, NULL },
150         { ETHEREAL_STOCK_PREFS,                 ETHEREAL_STOCK_LABEL_PREFS,                 0, 0, NULL },
151         { ETHEREAL_STOCK_BROWSE,                ETHEREAL_STOCK_LABEL_BROWSE,                0, 0, NULL },
152         { ETHEREAL_STOCK_CREATE_STAT,           ETHEREAL_STOCK_LABEL_CREATE_STAT,           0, 0, NULL },
153         { ETHEREAL_STOCK_EXPORT,                ETHEREAL_STOCK_LABEL_EXPORT,                0, 0, NULL },
154         { ETHEREAL_STOCK_IMPORT,                ETHEREAL_STOCK_LABEL_IMPORT,                0, 0, NULL },
155         { ETHEREAL_STOCK_EDIT,                  ETHEREAL_STOCK_LABEL_EDIT,                  0, 0, NULL },
156         { ETHEREAL_STOCK_ADD_EXPRESSION,        ETHEREAL_STOCK_LABEL_ADD_EXPRESSION,        0, 0, NULL },
157         { ETHEREAL_STOCK_DONT_SAVE,             ETHEREAL_STOCK_LABEL_DONT_SAVE,             0, 0, NULL }
158     };
159
160     static const stock_pixmap_t pixmaps[] = {
161 #ifdef HAVE_LIBPCAP
162         { ETHEREAL_STOCK_CAPTURE_START,         capture_24_xpm },
163         { ETHEREAL_STOCK_CAPTURE_FILTER,        cfilter_24_xpm },
164         { ETHEREAL_STOCK_CAPTURE_FILTER_ENTRY,  cfilter_24_xpm },
165 #endif
166         { ETHEREAL_STOCK_DISPLAY_FILTER,        dfilter_24_xpm },
167         { ETHEREAL_STOCK_DISPLAY_FILTER_ENTRY,  dfilter_24_xpm },
168         { ETHEREAL_STOCK_PREFS,                 stock_preferences_24_xpm },
169         { ETHEREAL_STOCK_BROWSE,                stock_open_24_xpm },
170         { ETHEREAL_STOCK_CREATE_STAT,           stock_ok_20_xpm },
171         { ETHEREAL_STOCK_EXPORT,                stock_save_24_xpm },    /* XXX: needs a better icon */
172         { ETHEREAL_STOCK_IMPORT,                stock_save_24_xpm },    /* XXX: needs a better icon */
173         { ETHEREAL_STOCK_EDIT,                  stock_properties_24_xpm },
174         { ETHEREAL_STOCK_ADD_EXPRESSION,        stock_add_24_xpm },
175         { NULL, NULL }
176     };
177
178     /* Register our stock items */
179     gtk_stock_add (stock_items, G_N_ELEMENTS (stock_items));
180
181     /* Add our custom icon factory to the list of defaults */
182     factory = gtk_icon_factory_new();
183     gtk_icon_factory_add_default(factory);
184
185     /* Create the stock items to add into our icon factory */
186     for (i = 0; pixmaps[i].name != NULL; i++) {
187         GdkPixbuf * pixbuf;
188         GtkIconSet *icon_set;
189
190         pixbuf = gdk_pixbuf_new_from_xpm_data((const char **) (pixmaps[i].xpm_data));
191         g_assert(pixbuf);
192         icon_set = gtk_icon_set_new_from_pixbuf (pixbuf);
193         gtk_icon_factory_add (factory, pixmaps[i].name, icon_set);
194         gtk_icon_set_unref (icon_set);
195         g_object_unref (G_OBJECT (pixbuf));
196     }
197
198     /* Drop our reference to the factory, GTK will hold a reference.*/
199     g_object_unref (G_OBJECT (factory));
200 }
201 #endif
202
203
204 /*
205  * Redraw all toolbars (currently only the main toolbar)
206  */
207 void
208 toolbar_redraw_all(void)
209 {
210     GtkWidget     *main_tb;
211
212     main_tb = OBJECT_GET_DATA(top_level, E_TB_MAIN_KEY);
213
214     gtk_toolbar_set_style(GTK_TOOLBAR(main_tb),
215                           prefs.gui_toolbar_main_style);
216
217 #if GTK_MAJOR_VERSION < 2
218     /* In GTK+ 1.2[.x], the toolbar takes the maximum vertical size it ever
219      * had, even if you change the style in such a way as to reduce its
220      * height, unless we queue a resize (which resizes ALL elements in the
221      * top-level container).
222      *
223      * In GTK+ 2.x, this isn't necessary - it does the right thing. */
224     gtk_container_queue_resize(GTK_CONTAINER(top_level));
225 #endif /* GTK_MAJOR_VERSION */
226 }
227
228 /* Enable or disable toolbar items based on whether you have a capture file
229    you've finished reading. */
230 void set_toolbar_for_capture_file(gboolean have_capture_file) {
231     if (toolbar_init) {
232         gtk_widget_set_sensitive(save_button, have_capture_file);
233         gtk_widget_set_sensitive(save_as_button, have_capture_file);
234         gtk_widget_set_sensitive(close_button, have_capture_file);
235         gtk_widget_set_sensitive(reload_button, have_capture_file);
236     }
237 }
238
239 /* Enable or disable menu items based on whether you have an unsaved
240    capture file you've finished reading. */
241 void set_toolbar_for_unsaved_capture_file(gboolean have_unsaved_capture_file) {
242     if (toolbar_init) {
243         if(have_unsaved_capture_file) {
244             gtk_widget_hide(save_as_button);
245             gtk_widget_show(save_button);
246         } else {
247             gtk_widget_show(save_as_button);
248             gtk_widget_hide(save_button);
249         }
250         /*gtk_widget_set_sensitive(save_button, have_unsaved_capture_file);
251         gtk_widget_set_sensitive(save_as_button, !have_unsaved_capture_file);*/
252     }
253 }
254
255
256 /* XXX - this is a quick and dirty hack to get the current state of capturing.
257  * this has to be improved, and should be reside somewhere in the capture engine. */
258 gboolean g_is_capture_in_progress = FALSE;
259
260 gboolean
261 is_capture_in_progress(void)
262 {
263     return g_is_capture_in_progress;
264 }
265
266 /* set toolbar state "have a capture in progress" */
267 void set_toolbar_for_capture_in_progress(gboolean capture_in_progress) {
268
269     g_is_capture_in_progress = capture_in_progress;
270
271     if (toolbar_init) {
272 #ifdef HAVE_LIBPCAP
273         gtk_widget_set_sensitive(new_button, !capture_in_progress);
274         if (capture_in_progress) {
275             gtk_widget_hide(new_button);
276             gtk_widget_show(stop_button);
277         } else {
278             gtk_widget_show(new_button);
279             gtk_widget_hide(stop_button);
280         }
281 #endif /* HAVE_LIBPCAP */
282         gtk_widget_set_sensitive(open_button, !capture_in_progress);
283     }
284 }
285
286 /* set toolbar state "have packets captured" */
287 void set_toolbar_for_captured_packets(gboolean have_captured_packets) {
288
289     if (toolbar_init) {
290         gtk_widget_set_sensitive(print_button, have_captured_packets);
291         gtk_widget_set_sensitive(find_button, have_captured_packets);
292         gtk_widget_set_sensitive(find_next_button, have_captured_packets);
293         gtk_widget_set_sensitive(find_prev_button, have_captured_packets);
294         gtk_widget_set_sensitive(go_to_button, have_captured_packets);
295         gtk_widget_set_sensitive(go_to_top_button, have_captured_packets);
296         gtk_widget_set_sensitive(go_to_bottom_button, have_captured_packets);
297         gtk_widget_set_sensitive(zoom_in_button, have_captured_packets);
298         gtk_widget_set_sensitive(zoom_out_button, have_captured_packets);
299         gtk_widget_set_sensitive(zoom_100_button, have_captured_packets);        
300         /* XXX - I don't see a reason why this should be done (as it is in the
301          * menus) */
302         /* gtk_widget_set_sensitive(color_display_button, have_captured_packets);*/
303     }
304 }
305
306
307 /* helper function: add a separator to the toolbar */
308 static void toolbar_append_separator(GtkWidget *toolbar) {
309 #if GTK_MAJOR_VERSION < 2
310     /* XXX - the usage of a gtk_separator doesn't seem to work for a toolbar.
311      * (at least in the win32 port of gtk 1.3)
312      * So simply add a few spaces */
313     gtk_toolbar_append_space(GTK_TOOLBAR(toolbar)); /* space after item */
314     gtk_toolbar_append_space(GTK_TOOLBAR(toolbar)); /* space after item */
315 #else
316     /* GTK 2 uses (as it should be) a seperator when adding this space */
317     gtk_toolbar_append_space(GTK_TOOLBAR(toolbar));
318 #endif /* GTK_MAJOR_VERSION */
319 }
320
321
322
323 #if GTK_MAJOR_VERSION < 2
324 #define toolbar_item(new_item, window, toolbar, stock, tooltip, xpm, callback) { \
325     icon = gdk_pixmap_create_from_xpm_d(window->window, &mask, &window->style->white, xpm); \
326     iconw = gtk_pixmap_new(icon, mask); \
327     new_item = gtk_toolbar_append_item(GTK_TOOLBAR (toolbar), \
328         stock, tooltip, "Private", iconw, GTK_SIGNAL_FUNC(callback), NULL);\
329     }
330 #else
331 #define toolbar_item(new_item, window, toolbar, stock, tooltip, xpm, callback) { \
332     new_item = gtk_toolbar_insert_stock(GTK_TOOLBAR(toolbar), \
333         stock, tooltip, "Private", G_CALLBACK(callback), NULL, -1);\
334     }
335 #endif /* GTK_MAJOR_VERSION */
336
337
338 /*
339  * Create all toolbars (currently only the main toolbar)
340  */
341 GtkWidget *
342 toolbar_new(void)
343 {
344     GtkWidget *main_tb;
345     GtkWidget *window = top_level;
346 #if GTK_MAJOR_VERSION < 2
347     GdkPixmap *icon;
348     GtkWidget *iconw;
349     GdkBitmap * mask;
350 #endif /* GTK_MAJOR_VERSION */
351
352     
353 #if GTK_MAJOR_VERSION >= 2
354     /* create application specific stock icons */
355     ethereal_stock_icons();
356 #endif
357
358     /* this function should be only called once! */
359     g_assert(!toolbar_init);
360
361     /* we need to realize the window because we use pixmaps for 
362      * items on the toolbar in the context of it */
363     /* (coming from the gtk example, please don't ask me why ;-) */
364     gtk_widget_realize(window);
365
366     /* toolbar will be horizontal, with both icons and text (as default here) */
367     /* (this will usually be overwritten by the preferences setting) */
368 #if GTK_MAJOR_VERSION < 2
369     main_tb = gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL,
370                                GTK_TOOLBAR_BOTH);
371     gtk_toolbar_set_space_size(GTK_TOOLBAR(main_tb), 3);
372     /* the "space lines" in GTK1 looks ugly, so don't use them */
373     /* gtk_toolbar_set_space_style(GTK_TOOLBAR(main_tb), GTK_TOOLBAR_SPACE_LINE); */
374 #else
375     main_tb = gtk_toolbar_new();
376     gtk_toolbar_set_orientation(GTK_TOOLBAR(main_tb),
377                                 GTK_ORIENTATION_HORIZONTAL);
378 #endif /* GTK_MAJOR_VERSION */
379
380     OBJECT_SET_DATA(top_level, E_TB_MAIN_KEY, main_tb);
381
382
383 #ifdef HAVE_LIBPCAP
384     /* either start OR stop button can be valid at a time, so no space 
385      * between them is needed here (stop button is hidden by default) */
386
387     toolbar_item(new_button, window, main_tb, 
388         ETHEREAL_STOCK_CAPTURE_START, "Start a new live capture...", capture_24_xpm, capture_prep_cb);
389     toolbar_item(stop_button, window, main_tb, 
390         GTK_STOCK_STOP, "Stop the running live capture", stock_stop_24_xpm, capture_stop_cb);
391     toolbar_append_separator(main_tb);
392 #endif /* HAVE_LIBPCAP */
393
394     toolbar_item(open_button, window, main_tb, 
395         GTK_STOCK_OPEN, "Open a capture file...", stock_open_24_xpm, file_open_cmd_cb);
396     toolbar_item(save_button, window, main_tb, 
397         GTK_STOCK_SAVE, "Save this capture file...", stock_save_24_xpm, file_save_cmd_cb);
398     toolbar_item(save_as_button, window, main_tb, 
399         GTK_STOCK_SAVE_AS, "Save this capture file as...", stock_save_as_24_xpm, file_save_as_cmd_cb);
400     toolbar_item(close_button, window, main_tb, 
401         GTK_STOCK_CLOSE, "Close this capture file", stock_close_24_xpm, file_close_cmd_cb);
402     toolbar_item(reload_button, window, main_tb, 
403         GTK_STOCK_REFRESH, "Reload this capture file", stock_refresh_24_xpm, file_reload_cmd_cb);
404     toolbar_item(print_button, window, main_tb, 
405         GTK_STOCK_PRINT, "Print packet(s)...", stock_print_24_xpm, file_print_cmd_cb);
406     toolbar_append_separator(main_tb);
407
408     toolbar_item(find_button, window, main_tb, 
409         GTK_STOCK_FIND, "Find a packet...", stock_search_24_xpm, find_frame_cb);
410     toolbar_item(find_prev_button, window, main_tb, 
411         GTK_STOCK_GO_BACK, "Find the previous matching packet", stock_left_arrow_24_xpm, find_previous_cb);
412     toolbar_item(find_next_button, window, main_tb, 
413         GTK_STOCK_GO_FORWARD, "Find the next matching packet", stock_right_arrow_24_xpm, find_next_cb);
414     toolbar_append_separator(main_tb);
415
416     toolbar_item(go_to_button, window, main_tb, 
417         GTK_STOCK_JUMP_TO, "Go to the packet with number...", stock_jump_to_24_xpm, goto_frame_cb);
418     toolbar_item(go_to_top_button, window, main_tb, 
419         GTK_STOCK_GOTO_TOP, "Go to the first packet", stock_top_24_xpm, goto_top_frame_cb);
420     toolbar_item(go_to_bottom_button, window, main_tb, 
421         GTK_STOCK_GOTO_BOTTOM, "Go to the last packet", stock_bottom_24_xpm, goto_bottom_frame_cb);
422     toolbar_append_separator(main_tb);
423
424     toolbar_item(zoom_in_button, window, main_tb, 
425         GTK_STOCK_ZOOM_IN, "Zoom in", stock_zoom_in_24_xpm, view_zoom_in_cb);
426     toolbar_item(zoom_out_button, window, main_tb, 
427         GTK_STOCK_ZOOM_OUT, "Zoom out", stock_zoom_out_24_xpm, view_zoom_out_cb);
428     toolbar_item(zoom_100_button, window, main_tb, 
429         GTK_STOCK_ZOOM_100, "Zoom 100%", stock_zoom_1_24_xpm, view_zoom_100_cb);
430     toolbar_append_separator(main_tb);
431     
432 #ifdef HAVE_LIBPCAP
433     toolbar_item(capture_filter_button, window, main_tb, 
434         ETHEREAL_STOCK_CAPTURE_FILTER, "Edit capture filter...", cfilter_24_xpm, cfilter_dialog_cb);
435 #endif /* HAVE_LIBPCAP */
436     toolbar_item(display_filter_button, window, main_tb, 
437         ETHEREAL_STOCK_DISPLAY_FILTER, "Edit/apply display filter...", dfilter_24_xpm, dfilter_dialog_cb);
438     toolbar_item(color_display_button, window, main_tb, 
439         GTK_STOCK_SELECT_COLOR, "Edit coloring rules...", stock_colorselector_24_xpm, color_display_cb);
440     /* the preference button uses it's own Stock icon label "Prefs", as "Preferences" is too long */
441     toolbar_item(prefs_button, window, main_tb, 
442         ETHEREAL_STOCK_PREFS, "Edit preferences...", stock_preferences_24_xpm, prefs_cb);
443     toolbar_append_separator(main_tb);
444
445     toolbar_item(help_button, window, main_tb, 
446         GTK_STOCK_HELP, "Show some help...", stock_help_24_xpm, help_cb);
447
448     /* disable all "sensitive" items by default */
449     toolbar_init = TRUE;
450     set_toolbar_for_unsaved_capture_file(FALSE);
451     set_toolbar_for_captured_packets(FALSE);
452     set_toolbar_for_capture_file(FALSE);
453 #ifdef HAVE_LIBPCAP
454     set_toolbar_for_capture_in_progress(FALSE);
455 #endif /* HAVE_LIBPCAP */
456
457     /* make current preferences effective */
458     toolbar_redraw_all();
459
460     return main_tb;
461 }
462
463 void
464 set_toolbar_object_data(gchar *key, gpointer data)
465 {
466     OBJECT_SET_DATA(open_button, key, data);
467     OBJECT_SET_DATA(reload_button, key, data);
468 }