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