Use gtk compatibility macros (from compat_macros.h) instead of some gtk+
[obnox/wireshark/wip.git] / gtk / menu.c
1 /* menu.c
2  * Menu routines
3  *
4  * $Id: menu.c,v 1.126 2003/12/16 18:43:34 oabad Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <gtk/gtk.h>
30
31 #include <string.h>
32 #include <stdio.h>
33
34 #include "main.h"
35 #include "menu.h"
36 #include <epan/packet.h>
37 #include <epan/resolv.h>
38 #include "prefs.h"
39 #include "capture_dlg.h"
40 #include "color_dlg.h"
41 #include "filter_prefs.h"
42 #include "file_dlg.h"
43 #include "find_dlg.h"
44 #include "goto_dlg.h"
45 #include "summary_dlg.h"
46 #include "display_opts.h"
47 #include "prefs_dlg.h"
48 #include "packet_win.h"
49 #include "print.h"
50 #include "follow_dlg.h"
51 #include "decode_as_dlg.h"
52 #include "help_dlg.h"
53 #include "supported_protos_dlg.h"
54 #include "proto_dlg.h"
55 #include "proto_hier_stats_dlg.h"
56 #include "keys.h"
57 #include <epan/plugins.h>
58 #include "tcp_graph.h"
59 #include <epan/epan_dissect.h>
60 #include "compat_macros.h"
61 #include "toolbar.h"
62 #include "gtkglobals.h"
63 #include "register.h"
64 #include "../tap.h"
65 #include "../menu.h"
66 #include "../ipproto.h"
67
68 GtkWidget *popup_menu_object;
69
70 extern void savehex_cb(GtkWidget * w, gpointer data _U_);
71
72 #define GTK_MENU_FUNC(a) ((GtkItemFactoryCallback)(a))
73
74 static void menus_init(void);
75 static void set_menu_sensitivity (GtkItemFactory *, gchar *, gint);
76
77 /* This is the GtkItemFactoryEntry structure used to generate new menus.
78        Item 1: The menu path. The letter after the underscore indicates an
79                accelerator key once the menu is open.
80        Item 2: The accelerator key for the entry
81        Item 3: The callback function.
82        Item 4: The callback action.  This changes the parameters with
83                which the function is called.  The default is 0.
84        Item 5: The item type, used to define what kind of an item it is.
85                Here are the possible values:
86
87                NULL               -> "<Item>"
88                ""                 -> "<Item>"
89                "<Title>"          -> create a title item
90                "<Item>"           -> create a simple item
91                "<ImageItem>"      -> create an item holding an image (gtk2)
92                "<StockItem>"      -> create an item holding a stock image (gtk2)
93                "<CheckItem>"      -> create a check item
94                "<ToggleItem>"     -> create a toggle item
95                "<RadioItem>"      -> create a radio item
96                <path>             -> path of a radio item to link against
97                "<Separator>"      -> create a separator
98                "<Tearoff>"        -> create a tearoff separator (gtk2)
99                "<Branch>"         -> create an item to hold sub items (optional)
100                "<LastBranch>"     -> create a right justified branch
101        Item 6: extra data needed for ImageItem and StockItem (gtk2)
102     */
103
104 /* main menu */
105 static GtkItemFactoryEntry menu_items[] =
106 {
107     ITEM_FACTORY_ENTRY("/_File", NULL, NULL, 0, "<Branch>", NULL),
108     ITEM_FACTORY_STOCK_ENTRY("/File/_Open...", "<control>O", file_open_cmd_cb,
109                              0, GTK_STOCK_OPEN),
110     ITEM_FACTORY_ENTRY("/File/Open _Recent", NULL, NULL, 0, "<Branch>", NULL),
111     ITEM_FACTORY_STOCK_ENTRY("/File/_Close", "<control>W", file_close_cmd_cb,
112                              0, GTK_STOCK_CLOSE),
113     ITEM_FACTORY_ENTRY("/File/<separator>", NULL, NULL, 0, "<Separator>", NULL),
114     ITEM_FACTORY_STOCK_ENTRY("/File/_Save", "<control>S", file_save_cmd_cb,
115                              0, GTK_STOCK_SAVE),
116     ITEM_FACTORY_STOCK_ENTRY("/File/Save _As...", "<shift><control>S", file_save_as_cmd_cb,
117                              0, GTK_STOCK_SAVE_AS),
118     ITEM_FACTORY_ENTRY("/File/<separator>", NULL, NULL, 0, "<Separator>", NULL),
119     ITEM_FACTORY_ENTRY("/File/_Export", NULL, NULL, 0, "<Branch>", NULL),
120     ITEM_FACTORY_ENTRY("/File/_Export/_Raw Packet Data...", "<control>H", savehex_cb,
121                              0, NULL, NULL),
122     ITEM_FACTORY_ENTRY("/File/<separator>", NULL, NULL, 0, "<Separator>", NULL),
123     ITEM_FACTORY_STOCK_ENTRY("/File/_Print...", "<control>P", file_print_cmd_cb,
124                              0, GTK_STOCK_PRINT),
125     ITEM_FACTORY_ENTRY("/File/<separator>", NULL, NULL, 0, "<Separator>", NULL),
126     ITEM_FACTORY_STOCK_ENTRY("/File/_Quit", "<control>Q", file_quit_cmd_cb,
127                              0, GTK_STOCK_QUIT),
128     ITEM_FACTORY_ENTRY("/_Edit", NULL, NULL, 0, "<Branch>", NULL),
129 #if 0
130     /* Un-#if this when we actually implement Cut/Copy/Paste. */
131     ITEM_FACTORY_STOCK_ENTRY("/Edit/Cut", "<control>X", NULL,
132                              0, GTK_STOCK_CUT),
133     ITEM_FACTORY_STOCK_ENTRY("/Edit/Copy", "<control>C", NULL,
134                              0, GTK_STOCK_COPY),
135     ITEM_FACTORY_STOCK_ENTRY("/Edit/Paste", "<control>V", NULL,
136                              0, GTK_STOCK_PASTE),
137     ITEM_FACTORY_ENTRY("/Edit/<separator>", NULL, NULL, 0, "<Separator>"),
138 #endif
139     ITEM_FACTORY_STOCK_ENTRY("/Edit/_Find Packet...", "<control>F",
140                              find_frame_cb, 0, GTK_STOCK_FIND),
141     ITEM_FACTORY_STOCK_ENTRY("/Edit/Find Ne_xt", "<control>N", find_next_cb,
142                              0, GTK_STOCK_GO_FORWARD),
143     ITEM_FACTORY_STOCK_ENTRY("/Edit/Find Pre_vious", "<control>B",
144                              find_previous_cb, 0, GTK_STOCK_GO_BACK),
145     ITEM_FACTORY_ENTRY("/Edit/<separator>", NULL, NULL, 0, "<Separator>", NULL),
146     ITEM_FACTORY_STOCK_ENTRY("/Edit/_Go To Packet...", "<control>G",
147                              goto_frame_cb, 0, GTK_STOCK_JUMP_TO),
148     ITEM_FACTORY_ENTRY("/Edit/Go To _Corresponding Packet", NULL, goto_framenum_cb,
149                        0, NULL, NULL),
150     ITEM_FACTORY_ENTRY("/Edit/<separator>", NULL, NULL, 0, "<Separator>", NULL),
151     ITEM_FACTORY_ENTRY("/Edit/Time _Reference", NULL, NULL, 0, "<Branch>", NULL),
152     ITEM_FACTORY_ENTRY("/Edit/Time Reference/Set Time Reference (toggle)", "<control>T", reftime_frame_cb, 0, NULL, NULL),
153     ITEM_FACTORY_ENTRY("/Edit/Time Reference/Find Next", NULL, reftime_frame_cb, 1, NULL, NULL),
154     ITEM_FACTORY_ENTRY("/Edit/Time Reference/Find Previous", NULL, reftime_frame_cb, 2, NULL, NULL),
155     ITEM_FACTORY_ENTRY("/Edit/_Mark Packet", "<control>M", mark_frame_cb,
156                        0, NULL, NULL),
157     ITEM_FACTORY_ENTRY("/Edit/Mark _All Packets", NULL, mark_all_frames_cb,
158                        0, NULL, NULL),
159     ITEM_FACTORY_ENTRY("/Edit/_Unmark All Packets", NULL, unmark_all_frames_cb,
160                        0, NULL, NULL),
161     ITEM_FACTORY_ENTRY("/Edit/<separator>", NULL, NULL, 0, "<Separator>", NULL),
162     ITEM_FACTORY_STOCK_ENTRY("/Edit/_Preferences...", "<shift><control>P", prefs_cb,
163                              0, GTK_STOCK_PREFERENCES),
164     ITEM_FACTORY_ENTRY("/_View", NULL, NULL, 0, "<Branch>", NULL),
165 #if 0
166         /* XXX: the show/hide functionality of the GUI elements is currently not implemented */
167     ITEM_FACTORY_ENTRY("/View/_Show", NULL, NULL, 0, "<Branch>", NULL),
168     ITEM_FACTORY_ENTRY("/View/_Show/Main Toolbar", NULL, NULL, 0, "<CheckItem>", NULL),
169     ITEM_FACTORY_ENTRY("/View/_Show/Filter Toolbar", NULL, NULL, 0, "<CheckItem>", NULL),
170     ITEM_FACTORY_ENTRY("/View/_Show/Status Bar", NULL, NULL, 0, "<CheckItem>", NULL),
171     ITEM_FACTORY_ENTRY("/View/_Show/Packet List", NULL, NULL, 0, "<CheckItem>", NULL),
172     ITEM_FACTORY_ENTRY("/View/_Show/Packet Dissection", NULL, NULL, 0, "<CheckItem>", NULL),
173     ITEM_FACTORY_ENTRY("/View/_Show/Packet Data", NULL, NULL, 0, "<CheckItem>", NULL),
174         /* XXX: the settings in the "Options" dialog could be seperated into the following menu items. */
175         /* before this, some effort must be taken to transfer the functionality of this dialog to the menu items */
176         /* (getting the current values, handling the radioitems, ...) */
177     ITEM_FACTORY_ENTRY("/View/_Time Display Format", NULL, NULL, 0, "<Branch>", NULL),
178     ITEM_FACTORY_ENTRY("/View/_Time Display Format/Time of day", NULL, NULL, 0, "<RadioItem>", NULL),
179     ITEM_FACTORY_ENTRY("/View/_Time Display Format/Date and time of day", NULL, NULL, 0, "<RadioItem>", NULL),
180     ITEM_FACTORY_ENTRY("/View/_Time Display Format/Seconds since beginning of capture", NULL, NULL, 0, "<RadioItem>", NULL),
181     ITEM_FACTORY_ENTRY("/View/_Time Display Format/Seconds since previous capture", NULL, NULL, 0, "<RadioItem>", NULL),
182     ITEM_FACTORY_ENTRY("/View/_Name Resolution", NULL, NULL, 0, "<Branch>", NULL),
183     ITEM_FACTORY_ENTRY("/View/_Name Resolution/Enable MAC", NULL, NULL, 0, "<CheckItem>", NULL),
184     ITEM_FACTORY_ENTRY("/View/_Name Resolution/Enable Network", NULL, NULL, 0, "<CheckItem>", NULL),
185     ITEM_FACTORY_ENTRY("/View/_Name Resolution/Enable Transport", NULL, NULL, 0, "<CheckItem>", NULL),
186 #else
187     ITEM_FACTORY_ENTRY("/View/_Options...", NULL, display_opt_cb,
188                        0, NULL, NULL),
189 #endif
190     ITEM_FACTORY_ENTRY("/View/<separator>", NULL, NULL, 0, "<Separator>", NULL),
191     ITEM_FACTORY_ENTRY("/View/Collapse _All", NULL, collapse_all_cb,
192                        0, NULL, NULL),
193     ITEM_FACTORY_ENTRY("/View/_Expand All", NULL, expand_all_cb,
194                        0, NULL, NULL),
195     ITEM_FACTORY_ENTRY("/View/<separator>", NULL, NULL, 0, "<Separator>", NULL),
196     ITEM_FACTORY_STOCK_ENTRY("/View/_Coloring Rules...", NULL, color_display_cb,
197                        0, GTK_STOCK_SELECT_COLOR),
198     ITEM_FACTORY_ENTRY("/View/<separator>", NULL, NULL, 0, "<Separator>", NULL),
199     ITEM_FACTORY_ENTRY("/View/_Show Packet In New Window", NULL,
200                        new_window_cb, 0, NULL, NULL),
201     ITEM_FACTORY_STOCK_ENTRY("/View/_Reload", "<control>R", file_reload_cmd_cb,
202                              0, GTK_STOCK_REFRESH),
203 #ifdef HAVE_LIBPCAP
204     ITEM_FACTORY_ENTRY("/_Capture", NULL, NULL, 0, "<Branch>", NULL),
205     ITEM_FACTORY_STOCK_ENTRY("/Capture/_Start...", "<control>K",
206                              capture_prep_cb, 0, ETHEREAL_STOCK_CAPTURE_START),
207   /*
208    * XXX - this doesn't yet work in Win32.
209    */
210 #ifndef _WIN32
211     ITEM_FACTORY_STOCK_ENTRY("/Capture/S_top", "<control>E", capture_stop_cb,
212                              0, GTK_STOCK_STOP),
213 #endif /* _WIN32 */
214     ITEM_FACTORY_STOCK_ENTRY("/Capture/_Capture Filters...", NULL, cfilter_dialog_cb,
215                        0, ETHEREAL_STOCK_CAPTURE_FILTER),
216 #endif /* HAVE_LIBPCAP */
217     ITEM_FACTORY_ENTRY("/_Analyze", NULL, NULL, 0, "<Branch>", NULL),
218     ITEM_FACTORY_STOCK_ENTRY("/Analyze/_Display Filters...", NULL, dfilter_dialog_cb,
219                        0, ETHEREAL_STOCK_DISPLAY_FILTER),
220     ITEM_FACTORY_ENTRY("/Analyze/_Match", NULL, NULL, 0, "<Branch>", NULL),
221     ITEM_FACTORY_ENTRY("/Analyze/Match/_Selected", NULL,
222                        match_selected_cb_replace_ptree, 0, NULL, NULL),
223     ITEM_FACTORY_ENTRY("/Analyze/Match/_Not Selected", NULL,
224                        match_selected_cb_not_ptree, 0, NULL, NULL),
225     ITEM_FACTORY_ENTRY("/Analyze/Match/_And Selected", NULL,
226                        match_selected_cb_and_ptree, 0, NULL, NULL),
227     ITEM_FACTORY_ENTRY("/Analyze/Match/_Or Selected", NULL,
228                        match_selected_cb_or_ptree, 0, NULL, NULL),
229     ITEM_FACTORY_ENTRY("/Analyze/Match/A_nd Not Selected", NULL,
230                        match_selected_cb_and_ptree_not, 0, NULL, NULL),
231     ITEM_FACTORY_ENTRY("/Analyze/Match/O_r Not Selected", NULL,
232                        match_selected_cb_or_ptree_not, 0, NULL, NULL),
233     ITEM_FACTORY_ENTRY("/Analyze/_Prepare", NULL, NULL, 0, "<Branch>", NULL),
234     ITEM_FACTORY_ENTRY("/Analyze/Prepare/_Selected", NULL,
235                        prepare_selected_cb_replace_ptree, 0, NULL, NULL),
236     ITEM_FACTORY_ENTRY("/Analyze/Prepare/_Not Selected", NULL,
237                        prepare_selected_cb_not_ptree, 0, NULL, NULL),
238     ITEM_FACTORY_ENTRY("/Analyze/Prepare/_And Selected", NULL,
239                        prepare_selected_cb_and_ptree, 0, NULL, NULL),
240     ITEM_FACTORY_ENTRY("/Analyze/Prepare/_Or Selected", NULL,
241                        prepare_selected_cb_or_ptree, 0, NULL, NULL),
242     ITEM_FACTORY_ENTRY("/Analyze/Prepare/A_nd Not Selected", NULL,
243                        prepare_selected_cb_and_ptree_not, 0, NULL, NULL),
244     ITEM_FACTORY_ENTRY("/Analyze/Prepare/O_r Not Selected", NULL,
245                        prepare_selected_cb_or_ptree_not, 0, NULL, NULL),
246     ITEM_FACTORY_ENTRY("/Analyze/<separator>", NULL, NULL, 0, "<Separator>", NULL),
247     ITEM_FACTORY_ENTRY("/Analyze/_Enabled Protocols...", "<shift><control>R", proto_cb, 0, NULL, NULL),
248     ITEM_FACTORY_ENTRY("/Analyze/Decode _As...", NULL, decode_as_cb,
249                        0, NULL, NULL),
250     ITEM_FACTORY_ENTRY("/Analyze/_User Specified Decodes", NULL,
251                        decode_show_cb, 0, NULL, NULL),
252     ITEM_FACTORY_ENTRY("/Analyze/<separator>", NULL, NULL, 0, "<Separator>", NULL),
253     ITEM_FACTORY_ENTRY("/Analyze/_Follow TCP Stream", NULL, follow_stream_cb,
254                        0, NULL, NULL),
255 /*  {"/Analyze/Graph", NULL, NULL, 0, NULL}, future use */
256     ITEM_FACTORY_ENTRY("/Analyze/_TCP Stream Analysis", NULL, NULL,
257                        0, "<Branch>", NULL),
258     ITEM_FACTORY_ENTRY("/Analyze/TCP Stream Analysis/Time-Sequence Graph (Stevens)",
259                        NULL, tcp_graph_cb, 0, NULL, NULL),
260     ITEM_FACTORY_ENTRY("/Analyze/TCP Stream Analysis/Time-Sequence Graph (tcptrace)",
261                        NULL, tcp_graph_cb, 1, NULL, NULL),
262     ITEM_FACTORY_ENTRY("/Analyze/TCP Stream Analysis/Throughput Graph", NULL,
263                        tcp_graph_cb, 2, NULL, NULL),
264     ITEM_FACTORY_ENTRY("/Analyze/TCP Stream Analysis/RTT Graph", NULL,
265                        tcp_graph_cb, 3, NULL, NULL),
266     ITEM_FACTORY_ENTRY("/Analyze/<separator>", NULL, NULL, 0, "<Separator>", NULL),
267     ITEM_FACTORY_ENTRY("/Analyze/_Summary", NULL, summary_open_cb, 0, NULL, NULL),
268     ITEM_FACTORY_ENTRY("/Analyze/Protocol _Hierarchy Statistics", NULL,
269                        proto_hier_stats_cb, 0, NULL, NULL),
270     ITEM_FACTORY_ENTRY("/_Help", NULL, NULL, 0, "<Branch>", NULL),
271     ITEM_FACTORY_STOCK_ENTRY("/Help/_Contents", "F1", help_cb, 0, GTK_STOCK_HELP),
272     ITEM_FACTORY_ENTRY("/Help/_Supported Protocols", NULL, supported_cb, 0, NULL, NULL),
273     ITEM_FACTORY_ENTRY("/Help/<separator>", NULL, NULL, 0, "<Separator>", NULL),
274 #ifdef HAVE_PLUGINS
275     ITEM_FACTORY_ENTRY("/Help/About _Plugins", NULL, tools_plugins_cmd_cb,
276                        0, NULL, NULL),
277 #endif /* HAVE_PLUGINS */
278     ITEM_FACTORY_ENTRY("/Help/_About Ethereal", NULL, about_ethereal,
279                        0, NULL, NULL)
280 };
281
282
283 /* calculate the number of menu_items */
284 static int nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
285
286 /* packet list popup */
287 static GtkItemFactoryEntry packet_list_menu_items[] =
288 {
289     ITEM_FACTORY_ENTRY("/Follow TCP Stream", NULL, follow_stream_cb,
290                        0, NULL, NULL),
291     ITEM_FACTORY_ENTRY("/Decode As...", NULL, decode_as_cb, 0, NULL, NULL),
292     ITEM_FACTORY_ENTRY("/Display Filters...", NULL, dfilter_dialog_cb,
293                        0, NULL, NULL),
294     ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
295     ITEM_FACTORY_ENTRY("/Mark Packet", NULL, mark_frame_cb, 0, NULL, NULL),
296     ITEM_FACTORY_ENTRY("/Time Reference", NULL, NULL, 0, "<Branch>", NULL),
297     ITEM_FACTORY_ENTRY("/Time Reference/Set Time Reference (toggle)", NULL, reftime_frame_cb, 0, NULL, NULL),
298     ITEM_FACTORY_ENTRY("/Time Reference/Find Next", NULL, reftime_frame_cb, 1, NULL, NULL),
299     ITEM_FACTORY_ENTRY("/Time Reference/Find Previous", NULL, reftime_frame_cb, 2, NULL, NULL),
300     ITEM_FACTORY_ENTRY("/Match", NULL, NULL, 0, "<Branch>", NULL),
301     ITEM_FACTORY_ENTRY("/Match/_Selected", NULL,
302                        match_selected_cb_replace_plist, 0, NULL, NULL),
303     ITEM_FACTORY_ENTRY("/Match/_Not Selected", NULL,
304                        match_selected_cb_not_plist, 0, NULL, NULL),
305     ITEM_FACTORY_ENTRY("/Match/_And Selected", NULL,
306                        match_selected_cb_and_plist, 0, NULL, NULL),
307     ITEM_FACTORY_ENTRY("/Match/_Or Selected", NULL, match_selected_cb_or_plist,
308                        0, NULL, NULL),
309     ITEM_FACTORY_ENTRY("/Match/A_nd Not Selected", NULL,
310                        match_selected_cb_and_plist_not, 0, NULL, NULL),
311     ITEM_FACTORY_ENTRY("/Match/O_r Not Selected", NULL,
312                        match_selected_cb_or_plist_not, 0, NULL, NULL),
313     ITEM_FACTORY_ENTRY("/Prepare", NULL, NULL, 0, "<Branch>", NULL),
314     ITEM_FACTORY_ENTRY("/Prepare/_Selected", NULL,
315                        prepare_selected_cb_replace_plist, 0, NULL, NULL),
316     ITEM_FACTORY_ENTRY("/Prepare/_Not Selected", NULL,
317                        prepare_selected_cb_not_plist, 0, NULL, NULL),
318     ITEM_FACTORY_ENTRY("/Prepare/_And Selected", NULL,
319                        prepare_selected_cb_and_plist, 0, NULL, NULL),
320     ITEM_FACTORY_ENTRY("/Prepare/_Or Selected", NULL,
321                        prepare_selected_cb_or_plist, 0, NULL, NULL),
322     ITEM_FACTORY_ENTRY("/Prepare/A_nd Not Selected", NULL,
323                        prepare_selected_cb_and_plist_not, 0, NULL, NULL),
324     ITEM_FACTORY_ENTRY("/Prepare/O_r Not Selected", NULL,
325                        prepare_selected_cb_or_plist_not, 0, NULL, NULL),
326     ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
327     ITEM_FACTORY_ENTRY("/Coloring Rules...", NULL, color_display_cb,
328                        0, NULL, NULL),
329     ITEM_FACTORY_ENTRY("/Print...", NULL, file_print_cmd_cb, 0, NULL, NULL),
330     ITEM_FACTORY_ENTRY("/Show Packet In New Window", NULL, new_window_cb,
331                        0, NULL, NULL),
332 };
333
334 static GtkItemFactoryEntry tree_view_menu_items[] =
335 {
336     ITEM_FACTORY_ENTRY("/Follow TCP Stream", NULL, follow_stream_cb,
337                        0, NULL, NULL),
338     ITEM_FACTORY_ENTRY("/Decode As...", NULL, decode_as_cb, 0, NULL, NULL),
339     ITEM_FACTORY_ENTRY("/Display Filters...", NULL, dfilter_dialog_cb,
340                        0, NULL, NULL),
341     ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
342     ITEM_FACTORY_ENTRY("/_Resolve Name", NULL, resolve_name_cb, 0, NULL, NULL),
343     ITEM_FACTORY_ENTRY("/_Go To Corresponding Packet", NULL, goto_framenum_cb, 0, NULL, NULL),
344     ITEM_FACTORY_ENTRY("/Protocol Properties...", NULL, properties_cb,
345                        0, NULL, NULL),
346     ITEM_FACTORY_ENTRY("/Match", NULL, NULL, 0, "<Branch>", NULL),
347     ITEM_FACTORY_ENTRY("/Match/_Selected", NULL,
348                        match_selected_cb_replace_ptree, 0, NULL, NULL),
349     ITEM_FACTORY_ENTRY("/Match/_Not Selected", NULL,
350                        match_selected_cb_not_ptree, 0, NULL, NULL),
351     ITEM_FACTORY_ENTRY("/Match/_And Selected", NULL,
352                        match_selected_cb_and_ptree, 0, NULL, NULL),
353     ITEM_FACTORY_ENTRY("/Match/_Or Selected", NULL, match_selected_cb_or_ptree,
354                        0, NULL, NULL),
355     ITEM_FACTORY_ENTRY("/Match/A_nd Not Selected", NULL,
356                        match_selected_cb_and_ptree_not, 0, NULL, NULL),
357     ITEM_FACTORY_ENTRY("/Match/O_r Not Selected", NULL,
358                        match_selected_cb_or_ptree_not, 0, NULL, NULL),
359     ITEM_FACTORY_ENTRY("/Prepare", NULL, NULL, 0, "<Branch>", NULL),
360     ITEM_FACTORY_ENTRY("/Prepare/_Selected", NULL,
361                        prepare_selected_cb_replace_ptree, 0, NULL, NULL),
362     ITEM_FACTORY_ENTRY("/Prepare/_Not Selected", NULL,
363                        prepare_selected_cb_not_ptree, 0, NULL, NULL),
364     ITEM_FACTORY_ENTRY("/Prepare/_And Selected", NULL,
365                        prepare_selected_cb_and_ptree, 0, NULL, NULL),
366     ITEM_FACTORY_ENTRY("/Prepare/_Or Selected", NULL,
367                        prepare_selected_cb_or_ptree, 0, NULL, NULL),
368     ITEM_FACTORY_ENTRY("/Prepare/A_nd Not Selected", NULL,
369                        prepare_selected_cb_and_ptree_not, 0, NULL, NULL),
370     ITEM_FACTORY_ENTRY("/Prepare/O_r Not Selected", NULL,
371                        prepare_selected_cb_or_ptree_not, 0, NULL, NULL),
372     ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
373     ITEM_FACTORY_ENTRY("/Collapse All", NULL, collapse_all_cb, 0, NULL, NULL),
374     ITEM_FACTORY_ENTRY("/Expand All", NULL, expand_all_cb, 0, NULL, NULL)
375 };
376
377 static GtkItemFactoryEntry hexdump_menu_items[] =
378 {
379     ITEM_FACTORY_ENTRY("/Follow TCP Stream", NULL, follow_stream_cb,
380                        0, NULL, NULL),
381     ITEM_FACTORY_ENTRY("/Decode As...", NULL, decode_as_cb, 0, NULL, NULL),
382     ITEM_FACTORY_ENTRY("/Display Filters...", NULL, dfilter_dialog_cb,
383                        0, NULL, NULL),
384     ITEM_FACTORY_ENTRY("/Save Highlighted Data...", NULL, savehex_cb,
385                        0, NULL, NULL)
386 };
387
388 static int initialize = TRUE;
389 static GtkItemFactory *main_menu_factory = NULL;
390 static GtkItemFactory *packet_list_menu_factory = NULL;
391 static GtkItemFactory *tree_view_menu_factory = NULL;
392 static GtkItemFactory *hexdump_menu_factory = NULL;
393
394 static GSList *popup_menu_list = NULL;
395
396 static GtkAccelGroup *grp;
397
398 void
399 get_main_menu(GtkWidget ** menubar, GtkAccelGroup ** table) {
400
401   grp = gtk_accel_group_new();
402
403   if (initialize)
404     menus_init();
405
406   if (menubar)
407     *menubar = main_menu_factory->widget;
408
409   if (table)
410     *table = grp;
411 }
412
413 static void
414 menus_init(void) {
415
416   if (initialize) {
417     initialize = FALSE;
418
419     /* popup */
420     packet_list_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
421     popup_menu_object = gtk_menu_new();
422     gtk_item_factory_create_items_ac(packet_list_menu_factory, sizeof(packet_list_menu_items)/sizeof(packet_list_menu_items[0]), packet_list_menu_items, popup_menu_object, 2);
423     OBJECT_SET_DATA(popup_menu_object, PM_PACKET_LIST_KEY,
424                     packet_list_menu_factory->widget);
425     popup_menu_list = g_slist_append((GSList *)popup_menu_list, packet_list_menu_factory);
426
427     tree_view_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
428     gtk_item_factory_create_items_ac(tree_view_menu_factory, sizeof(tree_view_menu_items)/sizeof(tree_view_menu_items[0]), tree_view_menu_items, popup_menu_object, 2);
429     OBJECT_SET_DATA(popup_menu_object, PM_TREE_VIEW_KEY,
430                     tree_view_menu_factory->widget);
431     popup_menu_list = g_slist_append((GSList *)popup_menu_list, tree_view_menu_factory);
432
433     hexdump_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
434     gtk_item_factory_create_items_ac(hexdump_menu_factory, sizeof(hexdump_menu_items)/sizeof(hexdump_menu_items[0]), hexdump_menu_items, popup_menu_object, 2);
435     OBJECT_SET_DATA(popup_menu_object, PM_HEXDUMP_KEY,
436                     hexdump_menu_factory->widget);
437     popup_menu_list = g_slist_append((GSList *)popup_menu_list, hexdump_menu_factory);
438
439     /* main */
440     main_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", grp);
441     gtk_item_factory_create_items_ac(main_menu_factory, nmenu_items, menu_items, NULL, 2);
442     register_all_tap_menus();   /* must be done after creating the main menu */
443
444     /* Initialize enabled/disabled state of menu items */
445     set_menus_for_unsaved_capture_file(FALSE);
446     set_menus_for_capture_file(FALSE);
447 #if 0
448     /* Un-#if this when we actually implement Cut/Copy/Paste.
449        Then make sure you enable them when they can be done. */
450     set_menu_sensitivity(main_menu_factory, "/Edit/Cut", FALSE);
451     set_menu_sensitivity(main_menu_factory, "/Edit/Copy", FALSE);
452     set_menu_sensitivity(main_menu_factory, "/Edit/Paste", FALSE);
453 #endif
454
455     set_menus_for_captured_packets(FALSE);
456     set_menus_for_selected_packet(&cfile);
457     set_menus_for_selected_tree_row(&cfile);
458   }
459 }
460
461 typedef struct _menu_item {
462         char    *name;
463         gboolean enabled;
464         gboolean (*selected_packet_enabled)(frame_data *, epan_dissect_t *);
465         gboolean (*selected_tree_row_enabled)(field_info *);
466         struct _menu_item *parent;
467         struct _menu_item *children;
468         struct _menu_item *next;
469 } menu_item_t;
470
471 static menu_item_t tap_menu_tree_root;
472
473 /*
474  * Add a new menu item for a tap.
475  * This must be called after we've created the main menu, so it can't
476  * be called from the routine that registers taps - we have to introduce
477  * another per-tap registration routine.
478  *
479  * "callback" gets called when the menu item is selected; it should do
480  * the work of creating the tap window.
481  *
482  * "selected_packet_enabled" gets called by "set_menus_for_selected_packet()";
483  * it's passed a Boolean that's TRUE if a packet is selected and FALSE
484  * otherwise, and should return TRUE if the tap will work now (which
485  * might depend on whether a packet is selected and, if one is, on the
486  * packet) and FALSE if not.
487  *
488  * "selected_tree_row_enabled" gets called by
489  * "set_menus_for_selected_tree_row()"; it's passed a Boolean that's TRUE if
490  * a protocol tree row is selected and FALSE otherwise, and should return
491  * TRUE if the tap will work now (which might depend on whether a tree row
492  * is selected and, if one is, on the tree row) and FALSE if not.
493  */
494 void
495 register_tap_menu_item(char *name, GtkItemFactoryCallback callback,
496     gboolean (*selected_packet_enabled)(frame_data *, epan_dissect_t *),
497     gboolean (*selected_tree_row_enabled)(field_info *))
498 {
499         static const char toolspath[] = "/Analyze/";
500         char *p;
501         char *menupath;
502         size_t menupathlen;
503         GtkItemFactoryEntry *entry;
504         menu_item_t *curnode, *child;
505
506         /*
507          * The menu path must be relative.
508          */
509         g_assert(*name != '/');
510
511         /*
512          * Create any submenus required.
513          */
514         curnode = &tap_menu_tree_root;
515         p = name;
516         while ((p = strchr(p, '/')) != NULL) {
517                 /*
518                  * OK, everything between "name" and "p" is
519                  * a menu relative subtree into which the menu item
520                  * will be placed.
521                  *
522                  * Construct the absolute path name of that subtree.
523                  */
524                 menupathlen = sizeof toolspath + (p - name);
525                 menupath = g_malloc(menupathlen);
526                 strcpy(menupath, toolspath);
527                 strncat(menupath, name, p - name);
528
529                 /*
530                  * Does there exist an entry with that path at this
531                  * level of the Tools menu tree?
532                  */
533                 for (child = curnode->children; child != NULL;
534                     child = child->next) {
535                         if (strcmp(child->name, menupath) == 0)
536                                 break;
537                 }
538                 if (child == NULL) {
539                         /*
540                          * No.  Create such an item as a subtree, and
541                          * add it to the Tools menu tree.
542                          */
543                         entry = g_malloc0(sizeof (GtkItemFactoryEntry));
544                         entry->path = menupath;
545                         entry->item_type = "<Branch>";
546                         gtk_item_factory_create_item(main_menu_factory, entry,
547                             NULL, 2);
548                         set_menu_sensitivity(main_menu_factory, menupath,
549                             FALSE);     /* no children yet */
550                         child = g_malloc(sizeof (menu_item_t));
551                         child->name = menupath;
552                         child->selected_packet_enabled = NULL;
553                         child->selected_tree_row_enabled = NULL;
554                         child->enabled = FALSE; /* no children yet */
555                         child->parent = curnode;
556                         child->children = NULL;
557                         child->next = curnode->children;
558                         curnode->children = child;
559                 } else {
560                         /*
561                          * Yes.  We don't need "menupath" any more.
562                          */
563                         g_free(menupath);
564                 }
565                 curnode = child;
566
567                 /*
568                  * Skip over the '/' we found.
569                  */
570                 p++;
571         }
572
573         /*
574          * Construct the main menu path for the menu item.
575          *
576          * "sizeof toolspath" includes the trailing '\0', so the sum
577          * of that and the length of "name" is enough to hold a string
578          * containing their concatenation.
579          */
580         menupathlen = sizeof toolspath + strlen(name);
581         menupath = g_malloc(menupathlen);
582         strcpy(menupath, toolspath);
583         strcat(menupath, name);
584
585         /*
586          * Construct an item factory entry for the item, and add it to
587          * the main menu.
588          */
589         entry = g_malloc0(sizeof (GtkItemFactoryEntry));
590         entry->path = menupath;
591         entry->callback = callback;
592         gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);
593         set_menu_sensitivity(main_menu_factory, menupath, FALSE); /* no capture file yet */
594         child = g_malloc(sizeof (menu_item_t));
595         child->name = menupath;
596         child->enabled = FALSE; /* no capture file yet, hence no taps yet */
597         child->selected_packet_enabled = selected_packet_enabled;
598         child->selected_tree_row_enabled = selected_tree_row_enabled;
599         child->parent = curnode;
600         child->children = NULL;
601         child->next = curnode->children;
602         curnode->children = child;
603 }
604
605 /*
606  * Enable/disable menu sensitivity.
607  */
608 static void
609 set_menu_sensitivity(GtkItemFactory *ifactory, gchar *path, gint val)
610 {
611   GSList *menu_list;
612   GtkWidget *menu_item;
613
614   if (ifactory == NULL) {
615     /*
616      * Do it for all pop-up menus.
617      */
618     for (menu_list = popup_menu_list; menu_list != NULL;
619          menu_list = g_slist_next(menu_list))
620       set_menu_sensitivity(menu_list->data, path, val);
621   } else {
622     /*
623      * Do it for that particular menu.
624      */
625     if ((menu_item = gtk_item_factory_get_widget(ifactory, path)) != NULL) {
626       if (GTK_IS_MENU(menu_item)) {
627         /*
628          * "path" refers to a submenu; "gtk_item_factory_get_widget()"
629          * gets the menu, not the item that, when selected, pops up
630          * the submenu.
631          *
632          * We have to change the latter item's sensitivity, so that
633          * it shows up normally if sensitive and grayed-out if
634          * insensitive.
635          */
636         menu_item = gtk_menu_get_attach_widget(GTK_MENU(menu_item));
637       } 
638       gtk_widget_set_sensitive(menu_item, val);
639     }
640   }
641 }
642
643 void
644 set_menu_object_data_meat(GtkItemFactory *ifactory, gchar *path, gchar *key, gpointer data)
645 {
646         GtkWidget *menu = NULL;
647
648         if ((menu = gtk_item_factory_get_widget(ifactory, path)) != NULL)
649                 OBJECT_SET_DATA(menu, key, data);
650 }
651
652 void
653 set_menu_object_data (gchar *path, gchar *key, gpointer data) {
654   GSList *menu_list = popup_menu_list;
655   gchar *shortpath = strrchr(path, '/');
656
657   set_menu_object_data_meat(main_menu_factory, path, key, data);
658   while (menu_list != NULL) {
659         set_menu_object_data_meat(menu_list->data, shortpath, key, data);
660         menu_list = g_slist_next(menu_list);
661   }
662 }
663
664
665 /* Recently used capture files submenu: 
666  * Submenu containing the recently used capture files.
667  * The capture filenames are always kept with the absolute path, to be independant
668  * of the current path. 
669  * They are only stored inside the labels of the submenu (no separate list). */
670
671 /* the maximum number of entries in the recent capture files list */
672 static guint recent_files_count_max = 10;
673
674 #define MENU_RECENT_FILES_PATH "/File/Open Recent"
675
676 /* remove the capture filename from the "Recent Files" menu */
677 void
678 remove_menu_recent_capture_file(gpointer data_item) {
679     GtkWidget *submenu_recent_files;
680
681
682         /* get the submenu container item */
683         submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
684
685         /* XXX: is this all we need to do, to destroy the menu item and its label? */
686         gtk_container_remove(GTK_CONTAINER(submenu_recent_files), data_item);
687         gtk_widget_destroy(data_item);
688 }
689
690
691 /* callback, if the user pushed a recent file submenu item */
692 void
693 menu_open_recent_file_cmd_cb(GtkWidget *w, gpointer data _U_)
694 {
695         int        err;
696         GtkWidget *menu_item_child;
697         gchar     *cf_name;
698
699
700         /* get capture filename from the menu item label */
701         menu_item_child = (GTK_BIN(w))->child;
702         gtk_label_get(GTK_LABEL(menu_item_child), &cf_name);
703
704         /* open and read the capture file (this will close an existing file) */
705     if ((err = cf_open(cf_name, FALSE, &cfile)) == 0) {
706                 cf_read(&cfile, &err);
707     } else {
708         /* the capture file isn't existing any longer, remove menu item */
709         /* XXX: ask user to remove item, it's maybe only a temporary problem */
710         remove_menu_recent_capture_file(w);
711         }
712 }
713
714
715 /* add the capture filename (with an absolute path) to the "Recent Files" menu */
716 void
717 add_menu_recent_capture_file_absolute(gchar *cf_name) {
718         GtkWidget *submenu_recent_files;
719         GList *menu_item_list;
720         GList *li;
721         gchar *widget_cf_name;
722         GtkWidget *menu_item;
723         guint cnt;
724
725
726         /* get the submenu container item */
727         submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
728
729         /* convert container to a GList */
730         menu_item_list = gtk_container_children(GTK_CONTAINER(submenu_recent_files));
731
732         /* iterate through list items of menu_item_list, 
733          * removing a maybe duplicate entry and every item above count_max */
734         li = g_list_first(menu_item_list);
735     for (cnt = 1; li; li = li->next, cnt++) {
736                 /* get capture filename from the menu item label */
737                 menu_item = (GtkWidget *) li->data;
738                 gtk_label_get(GTK_LABEL(GTK_BIN(menu_item)->child), &widget_cf_name);
739
740                 /* if this element string is already in the list, or 
741                  * this element is above maximum count (too old), remove it */
742                 if (strncmp(widget_cf_name, cf_name, 1000) == 0 ||
743                                 cnt >= recent_files_count_max) {
744             remove_menu_recent_capture_file(li->data);
745                         cnt--;
746                 }
747         }
748
749         g_list_free(menu_item_list);
750
751         /* add new item at latest position */
752         menu_item = gtk_menu_item_new_with_label(cf_name);
753         gtk_menu_prepend (GTK_MENU(submenu_recent_files), menu_item);
754         
755         SIGNAL_CONNECT_OBJECT(GTK_OBJECT(menu_item), "activate", 
756                 menu_open_recent_file_cmd_cb, (GtkObject *) menu_item);
757         gtk_widget_show (menu_item);
758 }
759
760
761 /* add the capture filename to the "Recent Files" menu */
762 /* (will change nothing, if this filename is already in the menu) */
763 void
764 add_menu_recent_capture_file(gchar *cf_name) {
765         gchar *curr;
766         gchar *absolute;
767         
768         
769         /* if this filename is an absolute path, we can use it directly */
770         if (g_path_is_absolute(cf_name)) {
771                 add_menu_recent_capture_file_absolute(cf_name);
772                 return;
773         }
774
775         /* this filename is not an absolute path, prepend the current dir */
776         curr = g_get_current_dir();
777         absolute = g_strdup_printf("%s%s%s", curr, G_DIR_SEPARATOR_S, cf_name);
778         add_menu_recent_capture_file_absolute(absolute);
779         g_free(curr);
780         g_free(absolute);
781 }
782
783
784
785 /* write a single menu item widget label to the user's recent file */
786 /* helper, for menu_recent_file_write_all() */
787 void menu_recent_file_write(GtkWidget *widget, gpointer data) {
788         GtkWidget *menu_item_child;
789         gchar     *cf_name;
790         FILE      *rf = (FILE *) data;
791
792
793         /* get capture filename from the menu item label */
794         menu_item_child = (GTK_BIN(widget))->child;
795         gtk_label_get(GTK_LABEL(menu_item_child), &cf_name);
796
797         fprintf (rf, RECENT_KEY_CAPTURE_FILE ": %s\n", cf_name);
798 }
799
800
801 /* write all capture filenames of the menu to the user's recent file */
802 void
803 menu_recent_file_write_all(FILE *rf) {
804         GtkWidget *submenu_recent_files;
805
806
807         submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
808
809         gtk_container_foreach(GTK_CONTAINER(submenu_recent_files), 
810                 menu_recent_file_write, rf);
811 }
812
813
814 gint
815 popup_menu_handler(GtkWidget *widget, GdkEvent *event, gpointer data)
816 {
817     GtkWidget *menu = NULL;
818     GdkEventButton *event_button = NULL;
819     GtkCList *packet_list = NULL;
820     gint row, column;
821
822     if(widget == NULL || event == NULL || data == NULL) {
823         return FALSE;
824     }
825
826     /*
827      * If we ever want to make the menu differ based on what row
828      * and/or column we're above, we'd use "gtk_clist_get_selection_info()"
829      * to find the row and column number for the coordinates; a CTree is,
830      * I guess, like a CList with one column(?) and the expander widget
831      * as a pixmap.
832      */
833     /* Check if we are on packet_list object */
834     if (widget == OBJECT_GET_DATA(popup_menu_object, E_MPACKET_LIST_KEY)) {
835         packet_list=GTK_CLIST(widget);
836         if (gtk_clist_get_selection_info(GTK_CLIST(packet_list),
837                                          ((GdkEventButton *)event)->x,
838                                          ((GdkEventButton *)event)->y,&row,&column)) {
839             OBJECT_SET_DATA(popup_menu_object, E_MPACKET_LIST_ROW_KEY,
840                             GINT_TO_POINTER(row));
841             OBJECT_SET_DATA(popup_menu_object, E_MPACKET_LIST_COL_KEY,
842                             GINT_TO_POINTER(column));
843         }
844     }
845     menu = (GtkWidget *)data;
846     if(event->type == GDK_BUTTON_PRESS) {
847         event_button = (GdkEventButton *) event;
848
849         if(event_button->button == 3) {
850             gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
851                            event_button->button,
852                            event_button->time);
853             SIGNAL_EMIT_STOP_BY_NAME(widget, "button_press_event");
854             return TRUE;
855         }
856     }
857 #if GTK_MAJOR_VERSION >= 2
858     if (widget == tree_view && event->type == GDK_2BUTTON_PRESS) {
859         GtkTreePath      *path;
860
861         if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget),
862                                           ((GdkEventButton *)event)->x,
863                                           ((GdkEventButton *)event)->y,
864                                           &path, NULL, NULL, NULL))
865         {
866             if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(widget), path))
867                 gtk_tree_view_collapse_row(GTK_TREE_VIEW(widget), path);
868             else
869                 gtk_tree_view_expand_row(GTK_TREE_VIEW(widget), path,
870                                          FALSE);
871             gtk_tree_path_free(path);
872         }
873     }
874 #endif
875     return FALSE;
876 }
877
878 /* Enable or disable menu items based on whether you have a capture file
879    you've finished reading. */
880 void
881 set_menus_for_capture_file(gboolean have_capture_file)
882 {
883   set_menu_sensitivity(main_menu_factory, "/File/Open...", have_capture_file);
884   set_menu_sensitivity(main_menu_factory, "/File/Save As...",
885       have_capture_file);
886   set_menu_sensitivity(main_menu_factory, "/File/Close", have_capture_file);
887   set_menu_sensitivity(main_menu_factory, "/View/Reload", have_capture_file);
888   set_toolbar_for_capture_file(have_capture_file);
889 }
890
891 /* Enable or disable menu items based on whether you have an unsaved
892    capture file you've finished reading. */
893 void
894 set_menus_for_unsaved_capture_file(gboolean have_unsaved_capture_file)
895 {
896   set_menu_sensitivity(main_menu_factory, "/File/Save",
897       have_unsaved_capture_file);
898   set_toolbar_for_unsaved_capture_file(have_unsaved_capture_file);
899 }
900
901 /* Enable or disable menu items based on whether there's a capture in
902    progress. */
903 void
904 set_menus_for_capture_in_progress(gboolean capture_in_progress)
905 {
906   set_menu_sensitivity(main_menu_factory, "/File/Open...",
907       !capture_in_progress);
908 #ifdef HAVE_LIBPCAP
909   set_menu_sensitivity(main_menu_factory, "/Capture/Start...",
910       !capture_in_progress);
911   /*
912    * XXX - this doesn't yet work in Win32.
913    */
914 #ifndef _WIN32
915   set_menu_sensitivity(main_menu_factory, "/Capture/Stop",
916       capture_in_progress);
917 #endif
918 #endif /* HAVE_LIBPCAP */
919   set_toolbar_for_capture_in_progress(capture_in_progress);
920 }
921
922 /* Enable or disable menu items based on whether you have some captured
923    packets. */
924 static gboolean
925 walk_menu_tree_for_captured_packets(menu_item_t *node,
926     gboolean have_captured_packets)
927 {
928         gboolean is_enabled;
929         menu_item_t *child;
930
931         /*
932          * Is this a leaf node or an interior node?
933          */
934         if (node->children == NULL) {
935                 /*
936                  * It's a leaf node.
937                  *
938                  * If it has no "selected_packet_enabled()" or
939                  * "selected_tree_row_enabled()" routines, we enable
940                  * it.  This allows tap windows to be popped up even
941                  * if you have no capture file; this is done to let
942                  * the user pop up multiple tap windows before reading
943                  * in a capture file, so that they can be processed in
944                  * parallel while the capture file is being read rather
945                  * than one at at time as you pop up the windows, and to
946                  * let the user pop up tap windows before starting an
947                  * "Update list of packets in real time" capture, so that
948                  * the statistics can be displayed while the capture is
949                  * in progress.
950                  *
951                  * If it has either of those routines, we disable it for
952                  * now - as long as, when a capture is first available,
953                  * we don't get called after a packet or tree row is
954                  * selected, that's OK.
955                  * XXX - that should be done better.
956                  */
957                 if (node->selected_packet_enabled == NULL &&
958                     node->selected_tree_row_enabled == NULL)
959                         node->enabled = TRUE;
960                 else
961                         node->enabled = FALSE;
962         } else {
963                 /*
964                  * It's an interior node; call
965                  * "walk_menu_tree_for_captured_packets()" on all its
966                  * children and, if any of them are enabled, enable
967                  * this node, otherwise disable it.
968                  *
969                  * XXX - should we just leave all interior nodes enabled?
970                  * Which is a better UI choice?
971                  */
972                 is_enabled = FALSE;
973                 for (child = node->children; child != NULL; child =
974                     child->next) {
975                         if (walk_menu_tree_for_captured_packets(child,
976                             have_captured_packets))
977                                 is_enabled = TRUE;
978                 }
979                 node->enabled = is_enabled;
980         }
981
982         /*
983          * The root node doesn't correspond to a menu tree item; it
984          * has a null name pointer.
985          */
986         if (node->name != NULL) {
987                 set_menu_sensitivity(main_menu_factory, node->name,
988                     node->enabled);
989         }
990         return node->enabled;
991 }
992
993 void
994 set_menus_for_captured_packets(gboolean have_captured_packets)
995 {
996   set_menu_sensitivity(main_menu_factory, "/File/Print...",
997       have_captured_packets);
998   set_menu_sensitivity(packet_list_menu_factory, "/Print...",
999       have_captured_packets);
1000   set_menu_sensitivity(main_menu_factory, "/Edit/Find Packet...",
1001       have_captured_packets);
1002   set_menu_sensitivity(main_menu_factory, "/Edit/Find Next",
1003       have_captured_packets);
1004   set_menu_sensitivity(main_menu_factory, "/Edit/Find Previous",
1005       have_captured_packets);
1006   set_menu_sensitivity(main_menu_factory, "/Edit/Go To Packet...",
1007       have_captured_packets);
1008   set_menu_sensitivity(main_menu_factory, "/View/Coloring Rules...",
1009       have_captured_packets);
1010   set_menu_sensitivity(packet_list_menu_factory, "/Coloring Rules...",
1011       have_captured_packets);
1012   set_menu_sensitivity(main_menu_factory, "/Analyze/Summary",
1013       have_captured_packets);
1014   set_menu_sensitivity(main_menu_factory,
1015       "/Analyze/Protocol Hierarchy Statistics", have_captured_packets);
1016   set_menu_sensitivity(packet_list_menu_factory, "/Match",
1017       have_captured_packets);
1018   set_menu_sensitivity(packet_list_menu_factory, "/Prepare",
1019       have_captured_packets);
1020   walk_menu_tree_for_captured_packets(&tap_menu_tree_root,
1021       have_captured_packets);
1022   set_toolbar_for_captured_packets(have_captured_packets);
1023 }
1024
1025 /* Enable or disable menu items based on whether a packet is selected and,
1026    if so, on the properties of the packet. */
1027 static gboolean
1028 walk_menu_tree_for_selected_packet(menu_item_t *node, frame_data *fd,
1029     epan_dissect_t *edt)
1030 {
1031         gboolean is_enabled;
1032         menu_item_t *child;
1033
1034         /*
1035          * Is this a leaf node or an interior node?
1036          */
1037         if (node->children == NULL) {
1038                 /*
1039                  * It's a leaf node.
1040                  *
1041                  * If it has no "selected_packet_enabled()" routine,
1042                  * leave its enabled/disabled status alone - it
1043                  * doesn't depend on whether we have a packet selected
1044                  * or not or on the selected packet.
1045                  *
1046                  * If it has a "selected_packet_enabled()" routine,
1047                  * call it and set the item's enabled/disabled status
1048                  * based on its return value.
1049                  */
1050                 if (node->selected_packet_enabled != NULL)
1051                         node->enabled = node->selected_packet_enabled(fd, edt);
1052         } else {
1053                 /*
1054                  * It's an interior node; call
1055                  * "walk_menu_tree_for_selected_packet()" on all its
1056                  * children and, if any of them are enabled, enable
1057                  * this node, otherwise disable it.
1058                  *
1059                  * XXX - should we just leave all interior nodes enabled?
1060                  * Which is a better UI choice?
1061                  */
1062                 is_enabled = FALSE;
1063                 for (child = node->children; child != NULL; child =
1064                     child->next) {
1065                         if (walk_menu_tree_for_selected_packet(child, fd, edt))
1066                                 is_enabled = TRUE;
1067                 }
1068                 node->enabled = is_enabled;
1069         }
1070
1071         /*
1072          * The root node doesn't correspond to a menu tree item; it
1073          * has a null name pointer.
1074          */
1075         if (node->name != NULL) {
1076                 set_menu_sensitivity(main_menu_factory, node->name,
1077                     node->enabled);
1078         }
1079         return node->enabled;
1080 }
1081
1082 void
1083 set_menus_for_selected_packet(capture_file *cf)
1084 {
1085   set_menu_sensitivity(main_menu_factory, "/File/Print Packet",
1086       cf->current_frame != NULL);
1087   set_menu_sensitivity(packet_list_menu_factory, "/Print Packet",
1088       cf->current_frame != NULL);
1089   set_menu_sensitivity(main_menu_factory, "/Edit/Mark Packet",
1090       cf->current_frame != NULL);
1091   set_menu_sensitivity(main_menu_factory, "/Edit/Time Reference",
1092       cf->current_frame != NULL);
1093   set_menu_sensitivity(packet_list_menu_factory, "/Mark Packet",
1094       cf->current_frame != NULL);
1095   set_menu_sensitivity(main_menu_factory, "/Edit/Mark All Packets",
1096       cf->current_frame != NULL);
1097   set_menu_sensitivity(main_menu_factory, "/Edit/Unmark All Packets",
1098       cf->current_frame != NULL);
1099   set_menu_sensitivity(main_menu_factory, "/View/Collapse All",
1100       cf->current_frame != NULL);
1101   set_menu_sensitivity(tree_view_menu_factory, "/Collapse All",
1102       cf->current_frame != NULL);
1103   set_menu_sensitivity(main_menu_factory, "/View/Expand All",
1104       cf->current_frame != NULL);
1105   set_menu_sensitivity(tree_view_menu_factory, "/Expand All",
1106       cf->current_frame != NULL);
1107   set_menu_sensitivity(main_menu_factory, "/View/Show Packet In New Window",
1108       cf->current_frame != NULL);
1109   set_menu_sensitivity(packet_list_menu_factory, "/Show Packet In New Window",
1110       cf->current_frame != NULL);
1111   set_menu_sensitivity(main_menu_factory, "/Analyze/Follow TCP Stream",
1112       cf->current_frame != NULL ? (cf->edt->pi.ipproto == IP_PROTO_TCP) : FALSE);
1113   set_menu_sensitivity(NULL, "/Follow TCP Stream",
1114       cf->current_frame != NULL ? (cf->edt->pi.ipproto == IP_PROTO_TCP) : FALSE);
1115   set_menu_sensitivity(main_menu_factory, "/Analyze/Decode As...",
1116       cf->current_frame != NULL && decode_as_ok());
1117   set_menu_sensitivity(NULL, "/Decode As...",
1118       cf->current_frame != NULL && decode_as_ok());
1119   set_menu_sensitivity(tree_view_menu_factory, "/Resolve Name",
1120       cf->current_frame != NULL && g_resolv_flags == 0);
1121   set_menu_sensitivity(main_menu_factory, "/Analyze/TCP Stream Analysis",
1122       cf->current_frame != NULL ? (cf->edt->pi.ipproto == IP_PROTO_TCP) : FALSE);
1123   walk_menu_tree_for_selected_packet(&tap_menu_tree_root, cf->current_frame,
1124       cf->edt);
1125 }
1126
1127 /* Enable or disable menu items based on whether a tree row is selected
1128    and, if so, on the properties of the tree row. */
1129 static gboolean
1130 walk_menu_tree_for_selected_tree_row(menu_item_t *node, field_info *fi)
1131 {
1132         gboolean is_enabled;
1133         menu_item_t *child;
1134
1135         /*
1136          * Is this a leaf node or an interior node?
1137          */
1138         if (node->children == NULL) {
1139                 /*
1140                  * It's a leaf node.
1141                  *
1142                  * If it has no "selected_tree_row_enabled()" routine,
1143                  * leave its enabled/disabled status alone - it
1144                  * doesn't depend on whether we have a tree row selected
1145                  * or not or on the selected tree row.
1146                  *
1147                  * If it has a "selected_tree_row_enabled()" routine,
1148                  * call it and set the item's enabled/disabled status
1149                  * based on its return value.
1150                  */
1151                 if (node->selected_tree_row_enabled != NULL)
1152                         node->enabled = node->selected_tree_row_enabled(fi);
1153         } else {
1154                 /*
1155                  * It's an interior node; call
1156                  * "walk_menu_tree_for_selected_tree_row()" on all its
1157                  * children and, if any of them are enabled, enable
1158                  * this node, otherwise disable it.
1159                  *
1160                  * XXX - should we just leave all interior nodes enabled?
1161                  * Which is a better UI choice?
1162                  */
1163                 is_enabled = FALSE;
1164                 for (child = node->children; child != NULL; child =
1165                     child->next) {
1166                         if (walk_menu_tree_for_selected_tree_row(child, fi))
1167                                 is_enabled = TRUE;
1168                 }
1169                 node->enabled = is_enabled;
1170         }
1171
1172         /*
1173          * The root node doesn't correspond to a menu tree item; it
1174          * has a null name pointer.
1175          */
1176         if (node->name != NULL) {
1177                 set_menu_sensitivity(main_menu_factory, node->name,
1178                     node->enabled);
1179         }
1180         return node->enabled;
1181 }
1182
1183 void
1184 set_menus_for_selected_tree_row(capture_file *cf)
1185 {
1186   gboolean properties;
1187
1188   if (cf->finfo_selected != NULL) {
1189         header_field_info *hfinfo = cf->finfo_selected->hfinfo;
1190         if (hfinfo->parent == -1) {
1191           properties = prefs_is_registered_protocol(hfinfo->abbrev);
1192         } else {
1193           properties = prefs_is_registered_protocol(proto_registrar_get_abbrev(hfinfo->parent));
1194         }
1195         set_menu_sensitivity(main_menu_factory,
1196           "/Edit/Go To Corresponding Packet", hfinfo->type == FT_FRAMENUM);
1197         set_menu_sensitivity(tree_view_menu_factory,
1198           "/Go To Corresponding Packet", hfinfo->type == FT_FRAMENUM);
1199         set_menu_sensitivity(main_menu_factory, "/Analyze/Match",
1200           proto_can_match_selected(cf->finfo_selected, cf->edt));
1201         set_menu_sensitivity(tree_view_menu_factory, "/Match",
1202           proto_can_match_selected(cf->finfo_selected, cf->edt));
1203         set_menu_sensitivity(main_menu_factory, "/Analyze/Prepare",
1204           proto_can_match_selected(cf->finfo_selected, cf->edt));
1205         set_menu_sensitivity(tree_view_menu_factory, "/Prepare",
1206           proto_can_match_selected(cf->finfo_selected, cf->edt));
1207         set_menu_sensitivity(tree_view_menu_factory, "/Protocol Properties...",
1208           properties);
1209   } else {
1210         set_menu_sensitivity(main_menu_factory,
1211             "/Edit/Go To Corresponding Packet", FALSE);
1212         set_menu_sensitivity(tree_view_menu_factory,
1213             "/Go To Corresponding Packet", FALSE);
1214         set_menu_sensitivity(main_menu_factory, "/Analyze/Match", FALSE);
1215         set_menu_sensitivity(tree_view_menu_factory, "/Match", FALSE);
1216         set_menu_sensitivity(main_menu_factory, "/Analyze/Prepare", FALSE);
1217         set_menu_sensitivity(tree_view_menu_factory, "/Prepare", FALSE);
1218         set_menu_sensitivity(tree_view_menu_factory, "/Protocol Properties...",
1219           FALSE);
1220   }
1221
1222   walk_menu_tree_for_selected_tree_row(&tap_menu_tree_root, cf->finfo_selected);
1223 }