Redesigned the menu structure of the former statistics stuff,
[obnox/wireshark/wip.git] / gtk / menu.c
1 /* menu.c
2  * Menu routines
3  *
4  * $Id: menu.c,v 1.167 2004/02/22 18:44:02 ulfl 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 "tap_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 "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 #include "packet_list.h"
67 #include "ethclist.h"
68 #include "recent.h"
69 #include "../ui_util.h"
70 #include "proto_draw.h"
71 #include "simple_dialog.h"
72
73 GtkWidget *popup_menu_object;
74
75 extern void savehex_cb(GtkWidget * w, gpointer data _U_);
76
77 static void
78 clear_menu_recent_capture_file_cmd_cb(GtkWidget *w, gpointer unused _U_);
79
80 typedef struct _menu_item {
81         char    *name;
82     gint    layer;
83         gboolean enabled;
84     GtkItemFactoryCallback callback;
85     gpointer callback_data;
86         gboolean (*selected_packet_enabled)(frame_data *, epan_dissect_t *);
87         gboolean (*selected_tree_row_enabled)(field_info *);
88         GList *children;
89 } menu_item_t;
90
91 static GList *tap_menu_tree_root = NULL;
92
93 static void 
94 merge_all_tap_menus(GList *node);
95
96 #define GTK_MENU_FUNC(a) ((GtkItemFactoryCallback)(a))
97
98 static void menus_init(void);
99 static void set_menu_sensitivity (GtkItemFactory *, const gchar *, gint);
100 static void main_toolbar_show_cb(GtkWidget *w _U_, gpointer d _U_);
101 static void filter_toolbar_show_cb(GtkWidget *w _U_, gpointer d _U_);
102 static void packet_list_show_cb(GtkWidget *w _U_, gpointer d _U_);
103 static void tree_view_show_cb(GtkWidget *w _U_, gpointer d _U_);
104 static void byte_view_show_cb(GtkWidget *w _U_, gpointer d _U_);
105 static void statusbar_show_cb(GtkWidget *w _U_, gpointer d _U_);
106 static void timestamp_absolute_cb(GtkWidget *w _U_, gpointer d _U_);
107 static void timestamp_absolute_date_cb(GtkWidget *w _U_, gpointer d _U_);
108 static void timestamp_relative_cb(GtkWidget *w _U_, gpointer d _U_);
109 static void timestamp_delta_cb(GtkWidget *w _U_, gpointer d _U_);
110 static void name_resolution_mac_cb(GtkWidget *w _U_, gpointer d _U_);
111 static void name_resolution_network_cb(GtkWidget *w _U_, gpointer d _U_);
112 static void name_resolution_transport_cb(GtkWidget *w _U_, gpointer d _U_);
113 static void auto_scroll_live_cb(GtkWidget *w _U_, gpointer d _U_);
114
115 /* This is the GtkItemFactoryEntry structure used to generate new menus.
116        Item 1: The menu path. The letter after the underscore indicates an
117                accelerator key once the menu is open.
118        Item 2: The accelerator key for the entry
119        Item 3: The callback function.
120        Item 4: The callback action.  This changes the parameters with
121                which the function is called.  The default is 0.
122        Item 5: The item type, used to define what kind of an item it is.
123                Here are the possible values:
124
125                NULL               -> "<Item>"
126                ""                 -> "<Item>"
127                "<Title>"          -> create a title item
128                "<Item>"           -> create a simple item
129                "<ImageItem>"      -> create an item holding an image (gtk2)
130                "<StockItem>"      -> create an item holding a stock image (gtk2)
131                "<CheckItem>"      -> create a check item
132                "<ToggleItem>"     -> create a toggle item
133                "<RadioItem>"      -> create a radio item
134                <path>             -> path of a radio item to link against
135                "<Separator>"      -> create a separator
136                "<Tearoff>"        -> create a tearoff separator (gtk2)
137                "<Branch>"         -> create an item to hold sub items (optional)
138                "<LastBranch>"     -> create a right justified branch
139        Item 6: extra data needed for ImageItem and StockItem (gtk2)
140     */
141
142 /* main menu */
143 static GtkItemFactoryEntry menu_items[] =
144 {
145     ITEM_FACTORY_ENTRY("/_File", NULL, NULL, 0, "<Branch>", NULL),
146     ITEM_FACTORY_STOCK_ENTRY("/File/_Open...", "<control>O", file_open_cmd_cb,
147                              0, GTK_STOCK_OPEN),
148     ITEM_FACTORY_ENTRY("/File/Open _Recent", NULL, NULL, 0, "<Branch>", NULL),
149     ITEM_FACTORY_STOCK_ENTRY("/File/_Close", "<control>W", file_close_cmd_cb,
150                              0, GTK_STOCK_CLOSE),
151     ITEM_FACTORY_ENTRY("/File/<separator>", NULL, NULL, 0, "<Separator>", NULL),
152     ITEM_FACTORY_STOCK_ENTRY("/File/_Save", "<control>S", file_save_cmd_cb,
153                              0, GTK_STOCK_SAVE),
154     ITEM_FACTORY_STOCK_ENTRY("/File/Save _As...", "<shift><control>S", file_save_as_cmd_cb,
155                              0, GTK_STOCK_SAVE_AS),
156     ITEM_FACTORY_ENTRY("/File/<separator>", NULL, NULL, 0, "<Separator>", NULL),
157     ITEM_FACTORY_ENTRY("/File/_Export", NULL, NULL, 0, "<Branch>", NULL),
158     ITEM_FACTORY_ENTRY("/File/_Export/_Selected Packet Bytes...", "<control>H", savehex_cb,
159                              0, NULL, NULL),
160     ITEM_FACTORY_ENTRY("/File/<separator>", NULL, NULL, 0, "<Separator>", NULL),
161     ITEM_FACTORY_STOCK_ENTRY("/File/_Print...", "<control>P", file_print_cmd_cb,
162                              0, GTK_STOCK_PRINT),
163     ITEM_FACTORY_ENTRY("/File/<separator>", NULL, NULL, 0, "<Separator>", NULL),
164     ITEM_FACTORY_STOCK_ENTRY("/File/_Quit", "<control>Q", file_quit_cmd_cb,
165                              0, GTK_STOCK_QUIT),
166     ITEM_FACTORY_ENTRY("/_Edit", NULL, NULL, 0, "<Branch>", NULL),
167 #if 0
168     /* Un-#if this when we actually implement Cut/Copy/Paste. */
169     ITEM_FACTORY_STOCK_ENTRY("/Edit/Cut", "<control>X", NULL,
170                              0, GTK_STOCK_CUT),
171     ITEM_FACTORY_STOCK_ENTRY("/Edit/Copy", "<control>C", NULL,
172                              0, GTK_STOCK_COPY),
173     ITEM_FACTORY_STOCK_ENTRY("/Edit/Paste", "<control>V", NULL,
174                              0, GTK_STOCK_PASTE),
175     ITEM_FACTORY_ENTRY("/Edit/<separator>", NULL, NULL, 0, "<Separator>"),
176 #endif
177     ITEM_FACTORY_STOCK_ENTRY("/Edit/_Find Packet...", "<control>F",
178                              find_frame_cb, 0, GTK_STOCK_FIND),
179     ITEM_FACTORY_STOCK_ENTRY("/Edit/Find Ne_xt", "<control>N", find_next_cb,
180                              0, GTK_STOCK_GO_FORWARD),
181     ITEM_FACTORY_STOCK_ENTRY("/Edit/Find Pre_vious", "<control>B",
182                              find_previous_cb, 0, GTK_STOCK_GO_BACK),
183     ITEM_FACTORY_ENTRY("/Edit/<separator>", NULL, NULL, 0, "<Separator>", NULL),
184     ITEM_FACTORY_STOCK_ENTRY("/Edit/Go To Firs_t Packet", NULL,
185                              goto_top_frame_cb, 0, GTK_STOCK_GOTO_TOP),
186     ITEM_FACTORY_STOCK_ENTRY("/Edit/Go To _Last Packet", NULL,
187                              goto_bottom_frame_cb, 0, GTK_STOCK_GOTO_BOTTOM),
188     ITEM_FACTORY_STOCK_ENTRY("/Edit/_Go To Packet...", "<control>G",
189                              goto_frame_cb, 0, GTK_STOCK_JUMP_TO),
190     ITEM_FACTORY_ENTRY("/Edit/Go To _Corresponding Packet", NULL, goto_framenum_cb,
191                        0, NULL, NULL),
192     ITEM_FACTORY_ENTRY("/Edit/<separator>", NULL, NULL, 0, "<Separator>", NULL),
193     ITEM_FACTORY_ENTRY("/Edit/Time _Reference", NULL, NULL, 0, "<Branch>", NULL),
194     ITEM_FACTORY_ENTRY("/Edit/Time Reference/Set Time Reference (toggle)", "<control>T", reftime_frame_cb, 0, NULL, NULL),
195     ITEM_FACTORY_ENTRY("/Edit/Time Reference/Find Next", NULL, reftime_frame_cb, 1, NULL, NULL),
196     ITEM_FACTORY_ENTRY("/Edit/Time Reference/Find Previous", NULL, reftime_frame_cb, 2, NULL, NULL),
197     ITEM_FACTORY_ENTRY("/Edit/_Mark Packet", "<control>M", mark_frame_cb,
198                        0, NULL, NULL),
199     ITEM_FACTORY_ENTRY("/Edit/Mark _All Packets", NULL, mark_all_frames_cb,
200                        0, NULL, NULL),
201     ITEM_FACTORY_ENTRY("/Edit/_Unmark All Packets", NULL, unmark_all_frames_cb,
202                        0, NULL, NULL),
203     ITEM_FACTORY_ENTRY("/Edit/<separator>", NULL, NULL, 0, "<Separator>", NULL),
204     ITEM_FACTORY_STOCK_ENTRY("/Edit/_Preferences...", "<shift><control>P", prefs_cb,
205                              0, GTK_STOCK_PREFERENCES),
206     ITEM_FACTORY_ENTRY("/_View", NULL, NULL, 0, "<Branch>", NULL),
207     ITEM_FACTORY_ENTRY("/View/_Show", NULL, NULL, 0, "<Branch>", NULL),
208     ITEM_FACTORY_ENTRY("/View/Show/Main Toolbar", NULL, main_toolbar_show_cb, 0, "<CheckItem>", NULL),
209     ITEM_FACTORY_ENTRY("/View/Show/Filter Toolbar", NULL, filter_toolbar_show_cb, 0, "<CheckItem>", NULL),
210     ITEM_FACTORY_ENTRY("/View/Show/<separator>", NULL, NULL, 0, "<Separator>", NULL),
211     ITEM_FACTORY_ENTRY("/View/Show/Packet List", NULL, packet_list_show_cb, 0, "<CheckItem>", NULL),
212     ITEM_FACTORY_ENTRY("/View/Show/Packet Details", NULL, tree_view_show_cb, 0, "<CheckItem>", NULL),
213     ITEM_FACTORY_ENTRY("/View/Show/Packet Bytes", NULL, byte_view_show_cb, 0, "<CheckItem>", NULL),
214     ITEM_FACTORY_ENTRY("/View/Show/<separator>", NULL, NULL, 0, "<Separator>", NULL),
215     ITEM_FACTORY_ENTRY("/View/Show/Status Bar", NULL, statusbar_show_cb, 0, "<CheckItem>", NULL),
216     ITEM_FACTORY_ENTRY("/View/_Time Display Format", NULL, NULL, 0, "<Branch>", NULL),
217     ITEM_FACTORY_ENTRY("/View/Time Display Format/Time of Day", NULL, timestamp_absolute_cb, 
218                         0, "<RadioItem>", NULL),
219     ITEM_FACTORY_ENTRY("/View/Time Display Format/Date and Time of Day", NULL, timestamp_absolute_date_cb, 
220                         0, "/View/Time Display Format/Time of Day", NULL),
221     ITEM_FACTORY_ENTRY("/View/Time Display Format/Seconds Since Beginning of Capture", NULL, timestamp_relative_cb, 
222                         0, "/View/Time Display Format/Time of Day", NULL),
223     ITEM_FACTORY_ENTRY("/View/Time Display Format/Seconds Since Previous Packet", NULL, timestamp_delta_cb, 
224                         0, "/View/Time Display Format/Time of Day", NULL),
225     ITEM_FACTORY_ENTRY("/View/_Name Resolution", NULL, NULL, 0, "<Branch>", NULL),
226     ITEM_FACTORY_ENTRY("/View/Name Resolution/Enable for _MAC Layer", NULL, name_resolution_mac_cb, 0, "<CheckItem>", NULL),
227     ITEM_FACTORY_ENTRY("/View/Name Resolution/Enable for _Network Layer", NULL, name_resolution_network_cb, 0, "<CheckItem>", NULL),
228     ITEM_FACTORY_ENTRY("/View/Name Resolution/Enable for _Transport Layer", NULL, name_resolution_transport_cb, 0, "<CheckItem>", NULL),
229     ITEM_FACTORY_ENTRY("/View/Auto Scroll in Live Capture", NULL, auto_scroll_live_cb, 0, "<CheckItem>", NULL),
230     ITEM_FACTORY_ENTRY("/View/<separator>", NULL, NULL, 0, "<Separator>", NULL),
231     ITEM_FACTORY_STOCK_ENTRY("/View/Zoom In", "<control>plus", view_zoom_in_cb,
232                              0, GTK_STOCK_ZOOM_IN),
233     ITEM_FACTORY_STOCK_ENTRY("/View/Zoom Out", "<control>minus", view_zoom_out_cb,
234                              0, GTK_STOCK_ZOOM_OUT),
235     ITEM_FACTORY_STOCK_ENTRY("/View/Normal Size", "<control>equal", view_zoom_100_cb,
236                              0, GTK_STOCK_ZOOM_100),
237     ITEM_FACTORY_ENTRY("/View/<separator>", NULL, NULL, 0, "<Separator>", NULL),
238     ITEM_FACTORY_ENTRY("/View/Collapse _All", NULL, collapse_all_cb,
239                        0, NULL, NULL),
240     ITEM_FACTORY_ENTRY("/View/_Expand All", NULL, expand_all_cb,
241                        0, NULL, NULL),
242     ITEM_FACTORY_ENTRY("/View/<separator>", NULL, NULL, 0, "<Separator>", NULL),
243     ITEM_FACTORY_STOCK_ENTRY("/View/_Coloring Rules...", NULL, color_display_cb,
244                        0, GTK_STOCK_SELECT_COLOR),
245     ITEM_FACTORY_ENTRY("/View/<separator>", NULL, NULL, 0, "<Separator>", NULL),
246     ITEM_FACTORY_ENTRY("/View/_Show Packet In New Window", NULL,
247                        new_window_cb, 0, NULL, NULL),
248     ITEM_FACTORY_STOCK_ENTRY("/View/_Reload", "<control>R", file_reload_cmd_cb,
249                              0, GTK_STOCK_REFRESH),
250 #ifdef HAVE_LIBPCAP
251     ITEM_FACTORY_ENTRY("/_Capture", NULL, NULL, 0, "<Branch>", NULL),
252     ITEM_FACTORY_STOCK_ENTRY("/Capture/_Start...", "<control>K",
253                              capture_prep_cb, 0, ETHEREAL_STOCK_CAPTURE_START),
254     ITEM_FACTORY_STOCK_ENTRY("/Capture/S_top", "<control>E", capture_stop_cb,
255                              0, GTK_STOCK_STOP),
256     ITEM_FACTORY_STOCK_ENTRY("/Capture/_Capture Filters...", NULL, cfilter_dialog_cb,
257                        0, ETHEREAL_STOCK_CAPTURE_FILTER),
258 #endif /* HAVE_LIBPCAP */
259     ITEM_FACTORY_ENTRY("/_Analyze", NULL, NULL, 0, "<Branch>", NULL),
260     ITEM_FACTORY_STOCK_ENTRY("/Analyze/_Display Filters...", NULL, dfilter_dialog_cb,
261                        0, ETHEREAL_STOCK_DISPLAY_FILTER),
262     ITEM_FACTORY_ENTRY("/Analyze/_Match", NULL, NULL, 0, "<Branch>", NULL),
263     ITEM_FACTORY_ENTRY("/Analyze/Match/_Selected", NULL,
264                        match_selected_cb_replace_ptree, 0, NULL, NULL),
265     ITEM_FACTORY_ENTRY("/Analyze/Match/_Not Selected", NULL,
266                        match_selected_cb_not_ptree, 0, NULL, NULL),
267     ITEM_FACTORY_ENTRY("/Analyze/Match/_And Selected", NULL,
268                        match_selected_cb_and_ptree, 0, NULL, NULL),
269     ITEM_FACTORY_ENTRY("/Analyze/Match/_Or Selected", NULL,
270                        match_selected_cb_or_ptree, 0, NULL, NULL),
271     ITEM_FACTORY_ENTRY("/Analyze/Match/A_nd Not Selected", NULL,
272                        match_selected_cb_and_ptree_not, 0, NULL, NULL),
273     ITEM_FACTORY_ENTRY("/Analyze/Match/O_r Not Selected", NULL,
274                        match_selected_cb_or_ptree_not, 0, NULL, NULL),
275     ITEM_FACTORY_ENTRY("/Analyze/_Prepare", NULL, NULL, 0, "<Branch>", NULL),
276     ITEM_FACTORY_ENTRY("/Analyze/Prepare/_Selected", NULL,
277                        prepare_selected_cb_replace_ptree, 0, NULL, NULL),
278     ITEM_FACTORY_ENTRY("/Analyze/Prepare/_Not Selected", NULL,
279                        prepare_selected_cb_not_ptree, 0, NULL, NULL),
280     ITEM_FACTORY_ENTRY("/Analyze/Prepare/_And Selected", NULL,
281                        prepare_selected_cb_and_ptree, 0, NULL, NULL),
282     ITEM_FACTORY_ENTRY("/Analyze/Prepare/_Or Selected", NULL,
283                        prepare_selected_cb_or_ptree, 0, NULL, NULL),
284     ITEM_FACTORY_ENTRY("/Analyze/Prepare/A_nd Not Selected", NULL,
285                        prepare_selected_cb_and_ptree_not, 0, NULL, NULL),
286     ITEM_FACTORY_ENTRY("/Analyze/Prepare/O_r Not Selected", NULL,
287                        prepare_selected_cb_or_ptree_not, 0, NULL, NULL),
288     ITEM_FACTORY_ENTRY("/Analyze/<separator>", NULL, NULL, 0, "<Separator>", NULL),
289     ITEM_FACTORY_ENTRY("/Analyze/_Enabled Protocols...", "<shift><control>R", proto_cb, 0, NULL, NULL),
290     ITEM_FACTORY_ENTRY("/Analyze/Decode _As...", NULL, decode_as_cb,
291                        0, NULL, NULL),
292     ITEM_FACTORY_ENTRY("/Analyze/_User Specified Decodes...", NULL,
293                        decode_show_cb, 0, NULL, NULL),
294     ITEM_FACTORY_ENTRY("/Analyze/<separator>", NULL, NULL, 0, "<Separator>", NULL),
295     ITEM_FACTORY_ENTRY("/Analyze/Summar_y", NULL, summary_open_cb, 0, NULL, NULL),
296     ITEM_FACTORY_ENTRY("/Analyze/Protocol _Hierarchy Statistics", NULL,
297                        proto_hier_stats_cb, 0, NULL, NULL),
298     ITEM_FACTORY_ENTRY("/_Help", NULL, NULL, 0, "<Branch>", NULL),
299     ITEM_FACTORY_STOCK_ENTRY("/Help/_Contents", "F1", help_cb, 0, GTK_STOCK_HELP),
300     ITEM_FACTORY_ENTRY("/Help/_Supported Protocols", NULL, supported_cb, 0, NULL, NULL),
301     ITEM_FACTORY_ENTRY("/Help/<separator>", NULL, NULL, 0, "<Separator>", NULL),
302 #ifdef HAVE_PLUGINS
303     ITEM_FACTORY_ENTRY("/Help/About _Plugins", NULL, tools_plugins_cmd_cb,
304                        0, NULL, NULL),
305 #endif /* HAVE_PLUGINS */
306     ITEM_FACTORY_ENTRY("/Help/_About Ethereal", NULL, about_ethereal,
307                        0, NULL, NULL)
308 };
309
310
311 /* calculate the number of menu_items */
312 static int nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
313
314 /* packet list popup */
315 static GtkItemFactoryEntry packet_list_menu_items[] =
316 {
317     ITEM_FACTORY_ENTRY("/Follow TCP Stream", NULL, follow_stream_cb,
318                        0, NULL, NULL),
319     ITEM_FACTORY_ENTRY("/Decode As...", NULL, decode_as_cb, 0, NULL, NULL),
320     ITEM_FACTORY_ENTRY("/Display Filters...", NULL, dfilter_dialog_cb,
321                        0, NULL, NULL),
322     ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
323     ITEM_FACTORY_ENTRY("/Mark Packet", NULL, mark_frame_cb, 0, NULL, NULL),
324     ITEM_FACTORY_ENTRY("/Time Reference", NULL, NULL, 0, "<Branch>", NULL),
325     ITEM_FACTORY_ENTRY("/Time Reference/Set Time Reference (toggle)", NULL, reftime_frame_cb, 0, NULL, NULL),
326     ITEM_FACTORY_ENTRY("/Time Reference/Find Next", NULL, reftime_frame_cb, 1, NULL, NULL),
327     ITEM_FACTORY_ENTRY("/Time Reference/Find Previous", NULL, reftime_frame_cb, 2, NULL, NULL),
328     ITEM_FACTORY_ENTRY("/Match", NULL, NULL, 0, "<Branch>", NULL),
329     ITEM_FACTORY_ENTRY("/Match/_Selected", NULL,
330                        match_selected_cb_replace_plist, 0, NULL, NULL),
331     ITEM_FACTORY_ENTRY("/Match/_Not Selected", NULL,
332                        match_selected_cb_not_plist, 0, NULL, NULL),
333     ITEM_FACTORY_ENTRY("/Match/_And Selected", NULL,
334                        match_selected_cb_and_plist, 0, NULL, NULL),
335     ITEM_FACTORY_ENTRY("/Match/_Or Selected", NULL, match_selected_cb_or_plist,
336                        0, NULL, NULL),
337     ITEM_FACTORY_ENTRY("/Match/A_nd Not Selected", NULL,
338                        match_selected_cb_and_plist_not, 0, NULL, NULL),
339     ITEM_FACTORY_ENTRY("/Match/O_r Not Selected", NULL,
340                        match_selected_cb_or_plist_not, 0, NULL, NULL),
341     ITEM_FACTORY_ENTRY("/Prepare", NULL, NULL, 0, "<Branch>", NULL),
342     ITEM_FACTORY_ENTRY("/Prepare/_Selected", NULL,
343                        prepare_selected_cb_replace_plist, 0, NULL, NULL),
344     ITEM_FACTORY_ENTRY("/Prepare/_Not Selected", NULL,
345                        prepare_selected_cb_not_plist, 0, NULL, NULL),
346     ITEM_FACTORY_ENTRY("/Prepare/_And Selected", NULL,
347                        prepare_selected_cb_and_plist, 0, NULL, NULL),
348     ITEM_FACTORY_ENTRY("/Prepare/_Or Selected", NULL,
349                        prepare_selected_cb_or_plist, 0, NULL, NULL),
350     ITEM_FACTORY_ENTRY("/Prepare/A_nd Not Selected", NULL,
351                        prepare_selected_cb_and_plist_not, 0, NULL, NULL),
352     ITEM_FACTORY_ENTRY("/Prepare/O_r Not Selected", NULL,
353                        prepare_selected_cb_or_plist_not, 0, NULL, NULL),
354     ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
355     ITEM_FACTORY_ENTRY("/Coloring Rules...", NULL, color_display_cb,
356                        0, NULL, NULL),
357     ITEM_FACTORY_ENTRY("/Print...", NULL, file_print_cmd_cb, 0, NULL, NULL),
358     ITEM_FACTORY_ENTRY("/Show Packet In New Window", NULL, new_window_cb,
359                        0, NULL, NULL),
360 };
361
362 static GtkItemFactoryEntry tree_view_menu_items[] =
363 {
364     ITEM_FACTORY_ENTRY("/Follow TCP Stream", NULL, follow_stream_cb,
365                        0, NULL, NULL),
366     ITEM_FACTORY_ENTRY("/Decode As...", NULL, decode_as_cb, 0, NULL, NULL),
367     ITEM_FACTORY_ENTRY("/Display Filters...", NULL, dfilter_dialog_cb,
368                        0, NULL, NULL),
369     ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
370     ITEM_FACTORY_ENTRY("/_Resolve Name", NULL, resolve_name_cb, 0, NULL, NULL),
371     ITEM_FACTORY_ENTRY("/_Go To Corresponding Packet", NULL, goto_framenum_cb, 0, NULL, NULL),
372     ITEM_FACTORY_ENTRY("/_Export Selected Packet Bytes...", NULL, savehex_cb,
373                        0, NULL, NULL),
374     ITEM_FACTORY_ENTRY("/Protocol Properties...", NULL, properties_cb,
375                        0, NULL, NULL),
376     ITEM_FACTORY_ENTRY("/Match", NULL, NULL, 0, "<Branch>", NULL),
377     ITEM_FACTORY_ENTRY("/Match/_Selected", NULL,
378                        match_selected_cb_replace_ptree, 0, NULL, NULL),
379     ITEM_FACTORY_ENTRY("/Match/_Not Selected", NULL,
380                        match_selected_cb_not_ptree, 0, NULL, NULL),
381     ITEM_FACTORY_ENTRY("/Match/_And Selected", NULL,
382                        match_selected_cb_and_ptree, 0, NULL, NULL),
383     ITEM_FACTORY_ENTRY("/Match/_Or Selected", NULL, match_selected_cb_or_ptree,
384                        0, NULL, NULL),
385     ITEM_FACTORY_ENTRY("/Match/A_nd Not Selected", NULL,
386                        match_selected_cb_and_ptree_not, 0, NULL, NULL),
387     ITEM_FACTORY_ENTRY("/Match/O_r Not Selected", NULL,
388                        match_selected_cb_or_ptree_not, 0, NULL, NULL),
389     ITEM_FACTORY_ENTRY("/Prepare", NULL, NULL, 0, "<Branch>", NULL),
390     ITEM_FACTORY_ENTRY("/Prepare/_Selected", NULL,
391                        prepare_selected_cb_replace_ptree, 0, NULL, NULL),
392     ITEM_FACTORY_ENTRY("/Prepare/_Not Selected", NULL,
393                        prepare_selected_cb_not_ptree, 0, NULL, NULL),
394     ITEM_FACTORY_ENTRY("/Prepare/_And Selected", NULL,
395                        prepare_selected_cb_and_ptree, 0, NULL, NULL),
396     ITEM_FACTORY_ENTRY("/Prepare/_Or Selected", NULL,
397                        prepare_selected_cb_or_ptree, 0, NULL, NULL),
398     ITEM_FACTORY_ENTRY("/Prepare/A_nd Not Selected", NULL,
399                        prepare_selected_cb_and_ptree_not, 0, NULL, NULL),
400     ITEM_FACTORY_ENTRY("/Prepare/O_r Not Selected", NULL,
401                        prepare_selected_cb_or_ptree_not, 0, NULL, NULL),
402     ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
403     ITEM_FACTORY_ENTRY("/Collapse All", NULL, collapse_all_cb, 0, NULL, NULL),
404     ITEM_FACTORY_ENTRY("/Expand All", NULL, expand_all_cb, 0, NULL, NULL)
405 };
406
407 static GtkItemFactoryEntry hexdump_menu_items[] =
408 {
409     ITEM_FACTORY_ENTRY("/Follow TCP Stream", NULL, follow_stream_cb,
410                        0, NULL, NULL),
411     ITEM_FACTORY_ENTRY("/Decode As...", NULL, decode_as_cb, 0, NULL, NULL),
412     ITEM_FACTORY_ENTRY("/Display Filters...", NULL, dfilter_dialog_cb,
413                        0, NULL, NULL),
414     ITEM_FACTORY_ENTRY("/Export Selected Packet Bytes...", NULL, savehex_cb,
415                        0, NULL, NULL)
416 };
417
418 static int initialize = TRUE;
419 static GtkItemFactory *main_menu_factory = NULL;
420 static GtkItemFactory *packet_list_menu_factory = NULL;
421 static GtkItemFactory *tree_view_menu_factory = NULL;
422 static GtkItemFactory *hexdump_menu_factory = NULL;
423
424 static GSList *popup_menu_list = NULL;
425
426 static GtkAccelGroup *grp;
427
428 GtkWidget *
429 main_menu_new(GtkAccelGroup ** table) {
430   GtkWidget *menubar;
431
432   grp = gtk_accel_group_new();
433
434   if (initialize)
435     menus_init();
436
437   menubar = main_menu_factory->widget;
438
439   if (table)
440     *table = grp;
441
442   return menubar;
443 }
444
445 static void
446 menus_init(void) {
447   if (initialize) {
448     initialize = FALSE;
449
450     /* popup */
451     packet_list_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
452     popup_menu_object = gtk_menu_new();
453     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);
454     OBJECT_SET_DATA(popup_menu_object, PM_PACKET_LIST_KEY,
455                     packet_list_menu_factory->widget);
456     popup_menu_list = g_slist_append((GSList *)popup_menu_list, packet_list_menu_factory);
457
458     tree_view_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
459     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);
460     OBJECT_SET_DATA(popup_menu_object, PM_TREE_VIEW_KEY,
461                     tree_view_menu_factory->widget);
462     popup_menu_list = g_slist_append((GSList *)popup_menu_list, tree_view_menu_factory);
463
464     hexdump_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
465     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);
466     OBJECT_SET_DATA(popup_menu_object, PM_HEXDUMP_KEY,
467                     hexdump_menu_factory->widget);
468     popup_menu_list = g_slist_append((GSList *)popup_menu_list, hexdump_menu_factory);
469
470     /* main */
471     main_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", grp);
472     gtk_item_factory_create_items_ac(main_menu_factory, nmenu_items, menu_items, NULL, 2);
473
474     merge_all_tap_menus(tap_menu_tree_root);
475
476     /* Initialize enabled/disabled state of menu items */
477     set_menus_for_unsaved_capture_file(FALSE);
478     set_menus_for_capture_file(FALSE);
479 #if 0
480     /* Un-#if this when we actually implement Cut/Copy/Paste.
481        Then make sure you enable them when they can be done. */
482     set_menu_sensitivity(main_menu_factory, "/Edit/Cut", FALSE);
483     set_menu_sensitivity(main_menu_factory, "/Edit/Copy", FALSE);
484     set_menu_sensitivity(main_menu_factory, "/Edit/Paste", FALSE);
485 #endif
486
487     set_menus_for_captured_packets(FALSE);
488     set_menus_for_selected_packet(&cfile);
489     set_menus_for_selected_tree_row(&cfile);
490
491     /* init with an empty recent files list */
492     clear_menu_recent_capture_file_cmd_cb(NULL, NULL);
493   }
494 }
495
496
497 gint tap_menu_item_add_compare(gconstpointer a, gconstpointer b)
498 {
499     return strcmp(
500         ((const menu_item_t *) a)->name, 
501         ((const menu_item_t *) b)->name);
502 }
503
504
505 /* add a menuitem below the current node */
506 GList * tap_menu_item_add(
507     gint layer, 
508     char *name, 
509     GtkItemFactoryCallback callback,
510     gboolean (*selected_packet_enabled)(frame_data *, epan_dissect_t *),
511     gboolean (*selected_tree_row_enabled)(field_info *),
512     gpointer callback_data,
513         GList *curnode)
514 {
515     menu_item_t *curr;
516         menu_item_t *child;
517
518
519         child = g_malloc(sizeof (menu_item_t));
520     child->layer            = layer;
521         child->name             = name;
522     child->callback         = callback;
523         child->selected_packet_enabled = selected_packet_enabled;
524         child->selected_tree_row_enabled = selected_tree_row_enabled;
525     child->callback_data    = callback_data;
526         child->enabled          = FALSE;
527     child->children         = NULL;
528
529     /* insert the new child node into the parent */
530     curr = curnode->data;
531     curr->children = g_list_insert_sorted(curr->children, child, tap_menu_item_add_compare);
532
533     /* return the new node */
534     /* XXX: improve this */
535     return g_list_find(curr->children, child);
536 }
537
538 /*
539  * Add a new menu item for a tap.
540  * This must be called after we've created the main menu, so it can't
541  * be called from the routine that registers taps - we have to introduce
542  * another per-tap registration routine.
543  *
544  * "callback" gets called when the menu item is selected; it should do
545  * the work of creating the tap window.
546  *
547  * "selected_packet_enabled" gets called by "set_menus_for_selected_packet()";
548  * it's passed a Boolean that's TRUE if a packet is selected and FALSE
549  * otherwise, and should return TRUE if the tap will work now (which
550  * might depend on whether a packet is selected and, if one is, on the
551  * packet) and FALSE if not.
552  *
553  * "selected_tree_row_enabled" gets called by
554  * "set_menus_for_selected_tree_row()"; it's passed a Boolean that's TRUE if
555  * a protocol tree row is selected and FALSE otherwise, and should return
556  * TRUE if the tap will work now (which might depend on whether a tree row
557  * is selected and, if one is, on the tree row) and FALSE if not.
558  */
559 void
560 register_tap_menu_item(
561     char *name, 
562     gint layer, 
563     GtkItemFactoryCallback callback,
564     gboolean (*selected_packet_enabled)(frame_data *, epan_dissect_t *),
565     gboolean (*selected_tree_row_enabled)(field_info *),
566     gpointer callback_data)
567 {
568         static const char toolspath[] = "/Analyze/";
569         /*char *toolspath; */
570         char *p;
571         char *menupath;
572         size_t menupathlen;
573         menu_item_t *child;
574     GList *curnode;
575     GList *childnode;
576
577         /*
578          * The menu path must be relative.
579          */
580         g_assert(*name != '/');
581
582 #if 0
583     switch(layer) {
584     case(REGISTER_TAP_LAYER_GENERIC): toolspath = "/Analyze/"; break;
585     case(REGISTER_TAP_LAYER_PHYSICAL): toolspath = "/Physical/"; break;
586     case(REGISTER_TAP_LAYER_DATA_LINK): toolspath = "/Link/"; break;
587     case(REGISTER_TAP_LAYER_NETWORK): toolspath = "/Network/"; break;
588     case(REGISTER_TAP_LAYER_TRANSPORT): toolspath = "/Transport/"; break;
589     case(REGISTER_TAP_LAYER_SESSION): toolspath = "/Session/"; break;
590     case(REGISTER_TAP_LAYER_PRESENTATION): toolspath = "/Presentation/"; break;
591     case(REGISTER_TAP_LAYER_APPLICATION): toolspath = "/Application/"; break;
592     default:
593         g_assert(0);
594     }
595 #endif
596
597     /* add the (empty) root node, if not already done */
598     if(tap_menu_tree_root == NULL) {
599         child = g_malloc0(sizeof (menu_item_t));
600         tap_menu_tree_root = g_list_append(NULL, child);
601     }
602
603         /*
604          * Create any submenus required.
605          */
606         curnode = tap_menu_tree_root;
607         p = name;
608         while ((p = strchr(p, '/')) != NULL) {
609                 /*
610                  * OK, everything between "name" and "p" is
611                  * a menu relative subtree into which the menu item
612                  * will be placed.
613                  *
614                  * Construct the absolute path name of that subtree.
615                  */
616                 menupathlen = strlen(toolspath) + 1 + (p - name);
617                 menupath = g_malloc(menupathlen);
618                 strcpy(menupath, toolspath);
619                 strncat(menupath, name, p - name);
620
621                 /*
622                  * Does there exist an entry with that path at this
623                  * level of the Analyze menu tree?
624                  */
625         child = curnode->data;
626                 for (childnode = child->children; childnode != NULL; childnode = childnode->next) {
627             child = childnode->data;
628                         if (strcmp(child->name, menupath) == 0)
629                                 break;
630                 }
631                 if (childnode == NULL) {
632                         /*
633                          * No.  Create such an item as a subtree, and
634                          * add it to the Tools menu tree.
635                          */
636             childnode = tap_menu_item_add(
637                 layer, menupath, NULL, NULL ,NULL, NULL, curnode);
638                 } else {
639                         /*
640                          * Yes.  We don't need this "menupath" any longer.
641                          */
642                         g_free(menupath);
643                 }
644                 curnode = childnode;
645
646                 /*
647                  * Skip over the '/' we found.
648                  */
649                 p++;
650         }
651
652         /*
653          * Construct the main menu path for the menu item.
654      */
655         menupathlen = strlen(toolspath) + 1 + strlen(name);
656         menupath = g_malloc(menupathlen);
657         strcpy(menupath, toolspath);
658         strcat(menupath, name);
659
660         /*
661          * Construct an item factory entry for the item, and add it to
662          * the main menu.
663          */
664     tap_menu_item_add(
665         layer, menupath, callback, 
666         selected_packet_enabled, selected_tree_row_enabled, 
667         callback_data, curnode);
668 }
669
670
671 guint merge_tap_menus_layered(GList *node, gint layer) {
672         GtkItemFactoryEntry *entry;
673         GList       *child;
674     guint       added = 0;
675     menu_item_t *node_data = node->data;
676
677         /*
678          * Is this a leaf node or an interior node?
679          */
680         if (node_data->children == NULL) {
681                 /*
682                  * It's a leaf node.
683                  */
684
685             /*
686              * The root node doesn't correspond to a menu tree item; it
687              * has a null name pointer.
688              */
689             if (node_data->name != NULL && layer == node_data->layer) {
690                 entry = g_malloc0(sizeof (GtkItemFactoryEntry));
691                 entry->path = node_data->name;
692                 entry->callback = node_data->callback;
693                 gtk_item_factory_create_item(main_menu_factory, entry, node_data->callback_data, 2);
694                 set_menu_sensitivity(main_menu_factory, node_data->name, FALSE); /* no capture file yet */
695             added++;
696         }
697         } else {
698                 /*
699                  * It's an interior node; call
700                  * "merge_tap_menus_layered()" on all its children 
701                  */
702
703             /*
704              * The root node doesn't correspond to a menu tree item; it
705              * has a null name pointer.
706              */
707             if (node_data->name != NULL && layer == node_data->layer) {
708             entry = g_malloc0(sizeof (GtkItemFactoryEntry));
709                     entry->path = node_data->name;
710                     entry->item_type = "<Branch>";
711                     gtk_item_factory_create_item(main_menu_factory, entry,
712                             NULL, 2);
713                     set_menu_sensitivity(main_menu_factory, node_data->name,
714                             FALSE);     /* no children yet */
715             added++;
716         }
717
718                 for (child = node_data->children; child != NULL; child =
719                     child->next) {
720                         added += merge_tap_menus_layered(child, layer);
721                 }
722         }
723
724     return added;
725 }
726
727
728 void merge_all_tap_menus(GList *node) {
729         GtkItemFactoryEntry *entry;
730         static char toolspath[] = "/Analyze/";
731
732     entry = g_malloc0(sizeof (GtkItemFactoryEntry));
733         entry->path = toolspath;
734         entry->item_type = "<Separator>";
735
736     /* 
737      * merge only the menu items of the specific layer,
738      * and then append a seperator
739      */
740     if (merge_tap_menus_layered(node, REGISTER_TAP_LAYER_GENERIC))
741             gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);
742     if (merge_tap_menus_layered(node, REGISTER_TAP_LAYER_PHYSICAL))
743             gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);
744     if (merge_tap_menus_layered(node, REGISTER_TAP_LAYER_DATA_LINK))
745             gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);
746     if (merge_tap_menus_layered(node, REGISTER_TAP_LAYER_NETWORK))
747             gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);
748     if (merge_tap_menus_layered(node, REGISTER_TAP_LAYER_TRANSPORT))
749             gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);
750     if (merge_tap_menus_layered(node, REGISTER_TAP_LAYER_SESSION))
751             gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);
752     if (merge_tap_menus_layered(node, REGISTER_TAP_LAYER_PRESENTATION))
753             gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);
754     merge_tap_menus_layered(node, REGISTER_TAP_LAYER_APPLICATION);
755 }
756
757
758
759 /*
760  * Enable/disable menu sensitivity.
761  */
762 static void
763 set_menu_sensitivity(GtkItemFactory *ifactory, const gchar *path, gint val)
764 {
765   GSList *menu_list;
766   GtkWidget *menu_item;
767   gchar *dup;
768   gchar *dest;
769
770
771   /* the underscore character regularly confuses things, as it will prevent finding 
772    * the menu_item, so it has to be removed first */
773   dup = g_strdup(path);
774   dest = dup;
775   while(*path) {
776       if (*path != '_') {
777         *dest = *path;
778         dest++;
779       }
780       path++;
781   }
782   *dest = '\0';
783
784   if (ifactory == NULL) {
785     /*
786      * Do it for all pop-up menus.
787      */
788     for (menu_list = popup_menu_list; menu_list != NULL;
789          menu_list = g_slist_next(menu_list))
790       set_menu_sensitivity(menu_list->data, dup, val);
791   } else {
792     /*
793      * Do it for that particular menu.
794      */
795     if ((menu_item = gtk_item_factory_get_widget(ifactory, dup)) != NULL) {
796       if (GTK_IS_MENU(menu_item)) {
797         /*
798          * "dup" refers to a submenu; "gtk_item_factory_get_widget()"
799          * gets the menu, not the item that, when selected, pops up
800          * the submenu.
801          *
802          * We have to change the latter item's sensitivity, so that
803          * it shows up normally if sensitive and grayed-out if
804          * insensitive.
805          */
806         menu_item = gtk_menu_get_attach_widget(GTK_MENU(menu_item));
807       }
808       gtk_widget_set_sensitive(menu_item, val);
809     } else{
810       /* be sure this menu item *is* existing */
811       g_assert_not_reached();
812     }
813   }
814
815   g_free(dup);
816 }
817
818 void
819 set_menu_object_data_meat(GtkItemFactory *ifactory, gchar *path, gchar *key, gpointer data)
820 {
821         GtkWidget *menu = NULL;
822
823         if ((menu = gtk_item_factory_get_widget(ifactory, path)) != NULL)
824                 OBJECT_SET_DATA(menu, key, data);
825 }
826
827 void
828 set_menu_object_data (gchar *path, gchar *key, gpointer data) {
829   GSList *menu_list = popup_menu_list;
830   gchar *shortpath = strrchr(path, '/');
831
832   set_menu_object_data_meat(main_menu_factory, path, key, data);
833   while (menu_list != NULL) {
834         set_menu_object_data_meat(menu_list->data, shortpath, key, data);
835         menu_list = g_slist_next(menu_list);
836   }
837 }
838
839
840 /* Recently used capture files submenu: 
841  * Submenu containing the recently used capture files.
842  * The capture filenames are always kept with the absolute path, to be independant
843  * of the current path. 
844  * They are only stored inside the labels of the submenu (no separate list). */
845
846 #define MENU_RECENT_FILES_PATH "/File/Open Recent"
847 #define MENU_RECENT_FILES_KEY "Recent File Name"
848
849 void
850 update_menu_recent_capture_file1(GtkWidget *widget, gpointer cnt) {
851     gchar *widget_cf_name;
852
853     widget_cf_name = OBJECT_GET_DATA(widget, MENU_RECENT_FILES_KEY);
854
855     /* if this menu item is a file, count it */
856     if (widget_cf_name) {
857         (*(guint *)cnt)++;
858     }
859 }
860
861
862 /* update the menu */
863 void
864 update_menu_recent_capture_file(GtkWidget *submenu_recent_files) {
865     guint cnt = 0;
866
867     gtk_container_foreach(GTK_CONTAINER(submenu_recent_files), 
868                 update_menu_recent_capture_file1, &cnt);
869
870     /* make parent menu item sensitive only, if we have any valid files in the list */
871     set_menu_sensitivity(main_menu_factory, MENU_RECENT_FILES_PATH, cnt);
872 }
873
874
875 /* remove the capture filename from the "Recent Files" menu */
876 void
877 remove_menu_recent_capture_file(GtkWidget *widget, gpointer unused _U_) {
878     GtkWidget *submenu_recent_files;
879     gchar *widget_cf_name;
880
881
882     widget_cf_name = OBJECT_GET_DATA(widget, MENU_RECENT_FILES_KEY);
883     g_free(widget_cf_name);
884
885     /* get the submenu container item */
886     submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
887
888     /* XXX: is this all we need to do, to free the menu item and its label?
889        The reference count of widget will go to 0, so it'll be freed;
890        will that free the label? */
891     gtk_container_remove(GTK_CONTAINER(submenu_recent_files), widget);
892 }
893
894
895 /* callback, if the user pushed the <clear file list> item */
896 static void
897 clear_menu_recent_capture_file_cmd_cb(GtkWidget *w _U_, gpointer unused _U_) {
898     GtkWidget *submenu_recent_files;
899
900
901     submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
902
903     gtk_container_foreach(GTK_CONTAINER(submenu_recent_files), 
904                 remove_menu_recent_capture_file, NULL);
905
906     update_menu_recent_capture_file(submenu_recent_files);
907 }
908
909
910 /* callback, if the user pushed a recent file submenu item */
911 void
912 menu_open_recent_file_cmd(GtkWidget *w)
913 {
914         GtkWidget *submenu_recent_files;
915         GtkWidget *menu_item_child;
916         gchar     *cf_name;
917         int       err;
918
919         submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
920
921         /* get capture filename from the menu item label */
922         menu_item_child = (GTK_BIN(w))->child;
923         gtk_label_get(GTK_LABEL(menu_item_child), &cf_name);
924
925         /* open and read the capture file (this will close an existing file) */
926         if ((err = cf_open(cf_name, FALSE, &cfile)) == 0) {
927                 cf_read(&cfile);
928         } else {
929                 /* the capture file isn't existing any longer, remove menu item */
930                 /* XXX: ask user to remove item, it's maybe only a temporary problem */
931                 remove_menu_recent_capture_file(w, NULL);
932         }
933
934         update_menu_recent_capture_file(submenu_recent_files);
935 }
936
937 static void menu_open_recent_file_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
938 {
939     switch(btn) {
940     case(ESD_BTN_YES):
941         /* save file first */
942         file_save_as_cmd(after_save_open_recent_file, data);
943         break;
944     case(ESD_BTN_NO):
945         cf_close(&cfile);
946         menu_open_recent_file_cmd(data);
947         break;
948     case(ESD_BTN_CANCEL):
949         break;
950     default:
951         g_assert_not_reached();
952     }
953 }
954
955 void
956 menu_open_recent_file_cmd_cb(GtkWidget *widget, gpointer data _U_) {
957   gpointer  dialog;
958
959
960   if((cfile.state != FILE_CLOSED) && !cfile.user_saved) {
961     /* user didn't saved his current file, ask him */
962     dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_YES_NO_CANCEL,
963                 PRIMARY_TEXT_START "Save capture file before opening a new one?" PRIMARY_TEXT_END "\n\n"
964                 "If you open a new capture file without saving, your current capture data will be discarded.");
965     simple_dialog_set_cb(dialog, menu_open_recent_file_answered_cb, widget);
966   } else {
967     /* unchanged file */
968     menu_open_recent_file_cmd(widget);
969   }
970 }
971
972 /* add the capture filename (with an absolute path) to the "Recent Files" menu */
973 void
974 add_menu_recent_capture_file_absolute(gchar *cf_name) {
975         GtkWidget *submenu_recent_files;
976         GList *menu_item_list;
977         GList *li;
978         gchar *widget_cf_name;
979         gchar *normalized_cf_name;
980         GtkWidget *menu_item;
981         guint cnt;
982
983
984
985         normalized_cf_name = g_strdup(cf_name);
986 #ifdef WIN32
987     /* replace all slashes by backslashes */
988     g_strdelimit(normalized_cf_name, "/", '\\');
989 #endif
990
991         /* get the submenu container item */
992         submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
993
994         /* convert container to a GList */
995         menu_item_list = gtk_container_children(GTK_CONTAINER(submenu_recent_files));
996
997         /* iterate through list items of menu_item_list, 
998          * removing special items, a maybe duplicate entry and every item above count_max */
999         cnt = 1;
1000         for (li = g_list_first(menu_item_list); li; li = li->next, cnt++) {
1001                 /* get capture filename */
1002                 menu_item = GTK_WIDGET(li->data);
1003                 widget_cf_name = OBJECT_GET_DATA(menu_item, MENU_RECENT_FILES_KEY);
1004
1005                 /* if this element string is one of our special items (seperator, ...) or
1006                  * already in the list or 
1007                  * this element is above maximum count (too old), remove it */
1008                 if (!widget_cf_name ||
1009 #ifdef WIN32
1010             /* do a case insensitive compare on win32 */
1011 #if GLIB_MAJOR_VERSION < 2
1012             g_strncasecmp(widget_cf_name, normalized_cf_name, 1000) == 0 ||
1013 #else
1014             g_ascii_strncasecmp(widget_cf_name, normalized_cf_name, 1000) == 0 ||
1015 #endif
1016 #else   /* WIN32 */
1017             /* do a case sensitive compare on unix */
1018                     strncmp(widget_cf_name, normalized_cf_name, 1000) == 0 ||
1019 #endif
1020                     cnt >= prefs.gui_recent_files_count_max) {
1021                         remove_menu_recent_capture_file(li->data, NULL);
1022                         cnt--;
1023                 }
1024         }
1025
1026         g_list_free(menu_item_list);
1027
1028         /* add new item at latest position */
1029         menu_item = gtk_menu_item_new_with_label(normalized_cf_name);
1030         OBJECT_SET_DATA(menu_item, MENU_RECENT_FILES_KEY, normalized_cf_name);
1031         gtk_menu_prepend (GTK_MENU(submenu_recent_files), menu_item);
1032         SIGNAL_CONNECT_OBJECT(GTK_OBJECT(menu_item), "activate", 
1033                 menu_open_recent_file_cmd_cb, (GtkObject *) menu_item);
1034         gtk_widget_show (menu_item);
1035
1036         /* add seperator at last position */
1037         menu_item = gtk_menu_item_new();
1038         gtk_menu_append (GTK_MENU(submenu_recent_files), menu_item);
1039         gtk_widget_show (menu_item);
1040
1041         /* add new "clear list" item at last position */
1042         menu_item = gtk_menu_item_new_with_label("<clear file list>");
1043         gtk_menu_append (GTK_MENU(submenu_recent_files), menu_item);
1044         SIGNAL_CONNECT_OBJECT(GTK_OBJECT(menu_item), "activate", 
1045                 clear_menu_recent_capture_file_cmd_cb, (GtkObject *) menu_item);
1046         gtk_widget_show (menu_item);
1047
1048         update_menu_recent_capture_file(submenu_recent_files);
1049 }
1050
1051
1052 /* add the capture filename to the "Recent Files" menu */
1053 /* (will change nothing, if this filename is already in the menu) */
1054 void
1055 add_menu_recent_capture_file(gchar *cf_name) {
1056         gchar *curr;
1057         gchar *absolute;
1058         
1059         
1060         /* if this filename is an absolute path, we can use it directly */
1061         if (g_path_is_absolute(cf_name)) {
1062                 add_menu_recent_capture_file_absolute(cf_name);
1063                 return;
1064         }
1065
1066         /* this filename is not an absolute path, prepend the current dir */
1067         curr = g_get_current_dir();
1068         absolute = g_strdup_printf("%s%s%s", curr, G_DIR_SEPARATOR_S, cf_name);
1069         add_menu_recent_capture_file_absolute(absolute);
1070         g_free(curr);
1071         g_free(absolute);
1072 }
1073
1074
1075 /* write all capture filenames of the menu to the user's recent file */
1076 void
1077 menu_recent_file_write_all(FILE *rf) {
1078         GtkWidget   *submenu_recent_files;
1079     GList       *children;
1080         GList       *child;
1081         gchar       *cf_name;
1082
1083
1084         submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
1085
1086     /* we have to iterate backwards through the children's list,
1087      * so we get the latest item last in the file.
1088      * (don't use gtk_container_foreach() here, it will return the wrong iteration order) */
1089     children = gtk_container_children(GTK_CONTAINER(submenu_recent_files));
1090     child = g_list_last(children);
1091     while(child != NULL) {
1092             /* get capture filename from the menu item label */
1093             cf_name = OBJECT_GET_DATA(child->data, MENU_RECENT_FILES_KEY);
1094             if (cf_name) {
1095                 fprintf (rf, RECENT_KEY_CAPTURE_FILE ": %s\n", cf_name);
1096             }
1097
1098         child = g_list_previous(child);
1099     }
1100
1101         g_list_free(children);
1102 }
1103
1104
1105 static void
1106 main_toolbar_show_cb(GtkWidget *w _U_, gpointer d _U_)
1107 {
1108
1109     /* save current setting in recent */
1110     recent.main_toolbar_show = GTK_CHECK_MENU_ITEM(w)->active;
1111
1112     main_widgets_rearrange();
1113 }
1114
1115
1116 static void
1117 filter_toolbar_show_cb(GtkWidget *w _U_, gpointer d _U_)
1118 {
1119
1120     /* save current setting in recent */
1121     recent.filter_toolbar_show = GTK_CHECK_MENU_ITEM(w)->active;
1122
1123     main_widgets_rearrange();
1124 }
1125
1126
1127 static void
1128 packet_list_show_cb(GtkWidget *w _U_, gpointer d _U_)
1129 {
1130
1131     /* save current setting in recent */
1132     recent.packet_list_show = GTK_CHECK_MENU_ITEM(w)->active;
1133
1134     main_widgets_rearrange();
1135 }
1136
1137
1138 static void
1139 tree_view_show_cb(GtkWidget *w _U_, gpointer d _U_)
1140 {
1141
1142     /* save current setting in recent */
1143     recent.tree_view_show = GTK_CHECK_MENU_ITEM(w)->active;
1144
1145     main_widgets_rearrange();
1146 }
1147
1148
1149 static void
1150 byte_view_show_cb(GtkWidget *w _U_, gpointer d _U_)
1151 {
1152
1153     /* save current setting in recent */
1154     recent.byte_view_show = GTK_CHECK_MENU_ITEM(w)->active;
1155
1156     main_widgets_rearrange();
1157 }
1158
1159
1160 static void
1161 statusbar_show_cb(GtkWidget *w _U_, gpointer d _U_)
1162 {
1163
1164     /* save current setting in recent */
1165     recent.statusbar_show = GTK_CHECK_MENU_ITEM(w)->active;
1166
1167     main_widgets_rearrange();
1168 }
1169
1170
1171 static void 
1172 timestamp_absolute_cb(GtkWidget *w _U_, gpointer d _U_)
1173 {
1174     if (recent.gui_time_format != TS_ABSOLUTE) {
1175         timestamp_type          = TS_ABSOLUTE;
1176         recent.gui_time_format  = timestamp_type;
1177         change_time_formats(&cfile);
1178     }
1179 }
1180
1181 static void 
1182 timestamp_absolute_date_cb(GtkWidget *w _U_, gpointer d _U_)
1183 {
1184     if (recent.gui_time_format != TS_ABSOLUTE_WITH_DATE) {
1185         timestamp_type          = TS_ABSOLUTE_WITH_DATE;
1186         recent.gui_time_format  = timestamp_type;
1187         change_time_formats(&cfile);
1188     }
1189 }
1190
1191 static void 
1192 timestamp_relative_cb(GtkWidget *w _U_, gpointer d _U_)
1193 {
1194     if (recent.gui_time_format != TS_RELATIVE) {
1195         timestamp_type          = TS_RELATIVE;
1196         recent.gui_time_format  = timestamp_type;
1197         change_time_formats(&cfile);
1198     }
1199 }
1200
1201 static void 
1202 timestamp_delta_cb(GtkWidget *w _U_, gpointer d _U_)
1203 {
1204     if (recent.gui_time_format != TS_DELTA) {
1205         timestamp_type          = TS_DELTA;
1206         recent.gui_time_format  = timestamp_type;
1207         change_time_formats(&cfile);
1208     }
1209 }
1210
1211 static void 
1212 name_resolution_mac_cb(GtkWidget *w _U_, gpointer d _U_)
1213 {
1214     if (GTK_CHECK_MENU_ITEM(w)->active) {
1215         g_resolv_flags |= RESOLV_MAC;
1216     } else {
1217         g_resolv_flags &= ~RESOLV_MAC;
1218     }
1219 }
1220
1221 static void 
1222 name_resolution_network_cb(GtkWidget *w _U_, gpointer d _U_)
1223 {
1224     if (GTK_CHECK_MENU_ITEM(w)->active) {
1225         g_resolv_flags |= RESOLV_NETWORK;
1226     } else {
1227         g_resolv_flags &= ~RESOLV_NETWORK;
1228     }
1229 }
1230
1231 static void 
1232 name_resolution_transport_cb(GtkWidget *w _U_, gpointer d _U_)
1233 {
1234     if (GTK_CHECK_MENU_ITEM(w)->active) {
1235         g_resolv_flags |= RESOLV_TRANSPORT;
1236     } else {
1237         g_resolv_flags &= ~RESOLV_TRANSPORT;
1238     }
1239 }
1240
1241 static void 
1242 auto_scroll_live_cb(GtkWidget *w _U_, gpointer d _U_)
1243 {
1244     auto_scroll_live = GTK_CHECK_MENU_ITEM(w)->active;
1245 }
1246
1247
1248 /* the recent file read has finished, update the menu corresponding */
1249 void
1250 menu_recent_read_finished(void) {
1251     GtkWidget *menu = NULL;
1252
1253     menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Show/Main Toolbar");
1254     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.main_toolbar_show);
1255
1256     menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Show/Filter Toolbar");
1257     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.filter_toolbar_show);
1258
1259     menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Show/Packet List");
1260     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.packet_list_show);
1261
1262     menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Show/Packet Details");
1263     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.tree_view_show);
1264
1265     menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Show/Packet Bytes");
1266     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.byte_view_show);
1267
1268     menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Show/Status Bar");
1269     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.statusbar_show);
1270
1271     menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Name Resolution/Enable for MAC Layer");
1272     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), g_resolv_flags & RESOLV_MAC);
1273
1274     menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Name Resolution/Enable for Network Layer");
1275     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), g_resolv_flags & RESOLV_NETWORK);
1276
1277     menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Name Resolution/Enable for Transport Layer");
1278     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), g_resolv_flags & RESOLV_TRANSPORT);
1279
1280     menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Auto Scroll in Live Capture");
1281     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), auto_scroll_live);
1282
1283     main_widgets_rearrange();
1284
1285     /* don't change the time format, if we had a command line value */
1286     if (timestamp_type != TS_NOT_SET) {
1287         recent.gui_time_format = timestamp_type;
1288     }
1289
1290     switch(recent.gui_time_format) {
1291     case(TS_ABSOLUTE):
1292         menu = gtk_item_factory_get_widget(main_menu_factory, 
1293             "/View/Time Display Format/Time of Day");
1294         /* set_active will not trigger the callback when activating an active item! */
1295         recent.gui_time_format = -1;
1296         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), FALSE);
1297         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
1298         break;
1299     case(TS_ABSOLUTE_WITH_DATE):
1300         menu = gtk_item_factory_get_widget(main_menu_factory, 
1301             "/View/Time Display Format/Date and Time of Day");
1302         recent.gui_time_format = -1;
1303         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
1304         break;
1305     case(TS_RELATIVE):
1306         menu = gtk_item_factory_get_widget(main_menu_factory, 
1307             "/View/Time Display Format/Seconds Since Beginning of Capture");
1308         recent.gui_time_format = -1;
1309         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
1310         break;
1311     case(TS_DELTA):
1312         menu = gtk_item_factory_get_widget(main_menu_factory, 
1313             "/View/Time Display Format/Seconds Since Previous Packet");
1314         recent.gui_time_format = -1;
1315         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
1316         break;
1317     default:
1318         g_assert_not_reached();
1319     }
1320 }
1321
1322
1323 gint
1324 popup_menu_handler(GtkWidget *widget, GdkEvent *event, gpointer data)
1325 {
1326     GtkWidget *menu = (GtkWidget *)data;
1327     GdkEventButton *event_button = NULL;
1328     gint row, column;
1329
1330     if(widget == NULL || event == NULL || data == NULL) {
1331         return FALSE;
1332     }
1333
1334     /*
1335      * If we ever want to make the menu differ based on what row
1336      * and/or column we're above, we'd use "eth_clist_get_selection_info()"
1337      * to find the row and column number for the coordinates; a CTree is,
1338      * I guess, like a CList with one column(?) and the expander widget
1339      * as a pixmap.
1340      */
1341     /* Check if we are on packet_list object */
1342     if (widget == OBJECT_GET_DATA(popup_menu_object, E_MPACKET_LIST_KEY)) {
1343         if (packet_list_get_event_row_column(widget, (GdkEventButton *)event,
1344                                              &row, &column)) {
1345             OBJECT_SET_DATA(popup_menu_object, E_MPACKET_LIST_ROW_KEY,
1346                             GINT_TO_POINTER(row));
1347             OBJECT_SET_DATA(popup_menu_object, E_MPACKET_LIST_COL_KEY,
1348                             GINT_TO_POINTER(column));
1349             packet_list_set_selected_row(row);
1350         }
1351     }
1352
1353     /* Check if we are on tree_view object */
1354     if (widget == tree_view) {
1355         tree_view_select(widget, (GdkEventButton *) event);
1356     }
1357
1358     /* Check if we are on byte_view object */
1359     if(widget == get_notebook_bv_ptr(byte_nb_ptr)) {
1360         byte_view_select(widget, (GdkEventButton *) event);
1361     }
1362
1363     if(event->type == GDK_BUTTON_PRESS) {
1364         event_button = (GdkEventButton *) event;
1365
1366         /* To qoute the "Gdk Event Structures" doc:
1367          * "Normally button 1 is the left mouse button, 2 is the middle button, and 3 is the right button" */
1368         if(event_button->button == 3) {
1369             gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
1370                            event_button->button,
1371                            event_button->time);
1372             SIGNAL_EMIT_STOP_BY_NAME(widget, "button_press_event");
1373             return TRUE;
1374         }
1375     }
1376 #if GTK_MAJOR_VERSION >= 2
1377     /* GDK_2BUTTON_PRESS is a doubleclick -> expand/collapse tree row */
1378     /* GTK version 1 seems to be doing this automatically */
1379     if (widget == tree_view && event->type == GDK_2BUTTON_PRESS) {
1380         GtkTreePath      *path;
1381
1382         if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget),
1383                                           (gint) (((GdkEventButton *)event)->x),
1384                                           (gint) (((GdkEventButton *)event)->y),
1385                                           &path, NULL, NULL, NULL))
1386         {
1387             if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(widget), path))
1388                 gtk_tree_view_collapse_row(GTK_TREE_VIEW(widget), path);
1389             else
1390                 gtk_tree_view_expand_row(GTK_TREE_VIEW(widget), path,
1391                                          FALSE);
1392             gtk_tree_path_free(path);
1393         }
1394     }
1395 #endif
1396     return FALSE;
1397 }
1398
1399 /* Enable or disable menu items based on whether you have a capture file
1400    you've finished reading. */
1401 void
1402 set_menus_for_capture_file(gboolean have_capture_file)
1403 {
1404   set_menu_sensitivity(main_menu_factory, "/File/Open...", have_capture_file);
1405   set_menu_sensitivity(main_menu_factory, "/File/Open Recent", have_capture_file);
1406   set_menu_sensitivity(main_menu_factory, "/File/Close", have_capture_file);
1407   set_menu_sensitivity(main_menu_factory, "/File/Save As...",
1408       have_capture_file);
1409   set_menu_sensitivity(main_menu_factory, "/File/Export", have_capture_file);
1410   set_menu_sensitivity(main_menu_factory, "/View/Reload", have_capture_file);
1411   set_toolbar_for_capture_file(have_capture_file);
1412   packets_bar_update();
1413 }
1414
1415 /* Enable or disable menu items based on whether you have an unsaved
1416    capture file you've finished reading. */
1417 void
1418 set_menus_for_unsaved_capture_file(gboolean have_unsaved_capture_file)
1419 {
1420   set_menu_sensitivity(main_menu_factory, "/File/Save",
1421       have_unsaved_capture_file);
1422   set_toolbar_for_unsaved_capture_file(have_unsaved_capture_file);
1423 }
1424
1425 /* Enable or disable menu items based on whether there's a capture in
1426    progress. */
1427 void
1428 set_menus_for_capture_in_progress(gboolean capture_in_progress)
1429 {
1430   set_menu_sensitivity(main_menu_factory, "/File/Open...",
1431       !capture_in_progress);
1432   set_menu_sensitivity(main_menu_factory, "/File/Open Recent", 
1433       !capture_in_progress);
1434 #ifdef HAVE_LIBPCAP
1435   set_menu_sensitivity(main_menu_factory, "/Capture/Start...",
1436       !capture_in_progress);
1437   set_menu_sensitivity(main_menu_factory, "/Capture/Stop",
1438       capture_in_progress);
1439 #endif /* HAVE_LIBPCAP */
1440   set_toolbar_for_capture_in_progress(capture_in_progress);
1441 }
1442
1443 /* Enable or disable menu items based on whether you have some captured
1444    packets. */
1445 static gboolean
1446 walk_menu_tree_for_captured_packets(GList *node,
1447     gboolean have_captured_packets)
1448 {
1449         gboolean    is_enabled;
1450         GList       *child;
1451     menu_item_t *node_data = node->data;
1452
1453         /*
1454          * Is this a leaf node or an interior node?
1455          */
1456         if (node_data->children == NULL) {
1457                 /*
1458                  * It's a leaf node.
1459                  *
1460                  * If it has no "selected_packet_enabled()" or
1461                  * "selected_tree_row_enabled()" routines, we enable
1462                  * it.  This allows tap windows to be popped up even
1463                  * if you have no capture file; this is done to let
1464                  * the user pop up multiple tap windows before reading
1465                  * in a capture file, so that they can be processed in
1466                  * parallel while the capture file is being read rather
1467                  * than one at at time as you pop up the windows, and to
1468                  * let the user pop up tap windows before starting an
1469                  * "Update list of packets in real time" capture, so that
1470                  * the statistics can be displayed while the capture is
1471                  * in progress.
1472                  *
1473                  * If it has either of those routines, we disable it for
1474                  * now - as long as, when a capture is first available,
1475                  * we don't get called after a packet or tree row is
1476                  * selected, that's OK.
1477                  * XXX - that should be done better.
1478                  */
1479                 if (node_data->selected_packet_enabled == NULL &&
1480                     node_data->selected_tree_row_enabled == NULL)
1481                         node_data->enabled = TRUE;
1482                 else
1483                         node_data->enabled = FALSE;
1484         } else {
1485                 /*
1486                  * It's an interior node; call
1487                  * "walk_menu_tree_for_captured_packets()" on all its
1488                  * children and, if any of them are enabled, enable
1489                  * this node, otherwise disable it.
1490                  *
1491                  * XXX - should we just leave all interior nodes enabled?
1492                  * Which is a better UI choice?
1493                  */
1494                 is_enabled = FALSE;
1495                 for (child = node_data->children; child != NULL; child =
1496                     child->next) {
1497                         if (walk_menu_tree_for_captured_packets(child,
1498                             have_captured_packets))
1499                                 is_enabled = TRUE;
1500                 }
1501                 node_data->enabled = is_enabled;
1502         }
1503
1504         /*
1505          * The root node doesn't correspond to a menu tree item; it
1506          * has a null name pointer.
1507          */
1508         if (node_data->name != NULL) {
1509                 set_menu_sensitivity(main_menu_factory, node_data->name,
1510                     node_data->enabled);
1511         }
1512         return node_data->enabled;
1513 }
1514
1515 void
1516 set_menus_for_captured_packets(gboolean have_captured_packets)
1517 {
1518   set_menu_sensitivity(main_menu_factory, "/File/Print...",
1519       have_captured_packets);
1520   set_menu_sensitivity(packet_list_menu_factory, "/Print...",
1521       have_captured_packets);
1522   set_menu_sensitivity(main_menu_factory, "/Edit/Find Packet...",
1523       have_captured_packets);
1524   set_menu_sensitivity(main_menu_factory, "/Edit/Find Next",
1525       have_captured_packets);
1526   set_menu_sensitivity(main_menu_factory, "/Edit/Find Previous",
1527       have_captured_packets);
1528   set_menu_sensitivity(main_menu_factory, "/Edit/Go To First Packet",
1529       have_captured_packets);
1530   set_menu_sensitivity(main_menu_factory, "/Edit/Go To Last Packet",
1531       have_captured_packets);
1532   set_menu_sensitivity(main_menu_factory, "/Edit/Go To Packet...",
1533       have_captured_packets);
1534   set_menu_sensitivity(main_menu_factory, "/View/Zoom In",
1535       have_captured_packets);
1536   set_menu_sensitivity(main_menu_factory, "/View/Zoom Out",
1537       have_captured_packets);
1538   set_menu_sensitivity(main_menu_factory, "/View/Normal Size",
1539       have_captured_packets);
1540   set_menu_sensitivity(main_menu_factory, "/View/Coloring Rules...",
1541       have_captured_packets);
1542   set_menu_sensitivity(packet_list_menu_factory, "/Coloring Rules...",
1543       have_captured_packets);
1544   set_menu_sensitivity(main_menu_factory, "/Analyze/Summary",
1545       have_captured_packets);
1546   set_menu_sensitivity(main_menu_factory, "/Analyze/Protocol Hierarchy Statistics", 
1547       have_captured_packets);
1548       
1549   walk_menu_tree_for_captured_packets(tap_menu_tree_root,
1550       have_captured_packets);
1551   set_toolbar_for_captured_packets(have_captured_packets);
1552   packets_bar_update();
1553 }
1554
1555 /* Enable or disable menu items based on whether a packet is selected and,
1556    if so, on the properties of the packet. */
1557 static gboolean
1558 walk_menu_tree_for_selected_packet(GList *node, frame_data *fd,
1559     epan_dissect_t *edt)
1560 {
1561         gboolean is_enabled;
1562         GList *child;
1563     menu_item_t *node_data = node->data;
1564
1565         /*
1566          * Is this a leaf node or an interior node?
1567          */
1568         if (node_data->children == NULL) {
1569                 /*
1570                  * It's a leaf node.
1571                  *
1572                  * If it has no "selected_packet_enabled()" routine,
1573                  * leave its enabled/disabled status alone - it
1574                  * doesn't depend on whether we have a packet selected
1575                  * or not or on the selected packet.
1576                  *
1577                  * If it has a "selected_packet_enabled()" routine,
1578                  * call it and set the item's enabled/disabled status
1579                  * based on its return value.
1580                  */
1581                 if (node_data->selected_packet_enabled != NULL)
1582                         node_data->enabled = node_data->selected_packet_enabled(fd, edt);
1583         } else {
1584                 /*
1585                  * It's an interior node; call
1586                  * "walk_menu_tree_for_selected_packet()" on all its
1587                  * children and, if any of them are enabled, enable
1588                  * this node, otherwise disable it.
1589                  *
1590                  * XXX - should we just leave all interior nodes enabled?
1591                  * Which is a better UI choice?
1592                  */
1593                 is_enabled = FALSE;
1594                 for (child = node_data->children; child != NULL; child =
1595                     child->next) {
1596                         if (walk_menu_tree_for_selected_packet(child, fd, edt))
1597                                 is_enabled = TRUE;
1598                 }
1599                 node_data->enabled = is_enabled;
1600         }
1601
1602         /*
1603          * The root node doesn't correspond to a menu tree item; it
1604          * has a null name pointer.
1605          */
1606         if (node_data->name != NULL) {
1607                 set_menu_sensitivity(main_menu_factory, node_data->name,
1608                     node_data->enabled);
1609         }
1610         return node_data->enabled;
1611 }
1612
1613 void
1614 set_menus_for_selected_packet(capture_file *cf)
1615 {
1616   set_menu_sensitivity(main_menu_factory, "/Edit/Mark Packet",
1617       cf->current_frame != NULL);
1618   set_menu_sensitivity(packet_list_menu_factory, "/Mark Packet",
1619       cf->current_frame != NULL);
1620   set_menu_sensitivity(main_menu_factory, "/Edit/Time Reference",
1621       cf->current_frame != NULL);
1622   set_menu_sensitivity(packet_list_menu_factory, "/Time Reference",
1623       cf->current_frame != NULL);
1624   set_menu_sensitivity(main_menu_factory, "/Edit/Mark All Packets",
1625       cf->current_frame != NULL);
1626   set_menu_sensitivity(main_menu_factory, "/Edit/Unmark All Packets",
1627       cf->current_frame != NULL);
1628   set_menu_sensitivity(main_menu_factory, "/View/Collapse All",
1629       cf->current_frame != NULL);
1630   set_menu_sensitivity(tree_view_menu_factory, "/Collapse All",
1631       cf->current_frame != NULL);
1632   set_menu_sensitivity(main_menu_factory, "/View/Expand All",
1633       cf->current_frame != NULL);
1634   set_menu_sensitivity(tree_view_menu_factory, "/Expand All",
1635       cf->current_frame != NULL);
1636   set_menu_sensitivity(main_menu_factory, "/View/Show Packet In New Window",
1637       cf->current_frame != NULL);
1638   set_menu_sensitivity(packet_list_menu_factory, "/Show Packet In New Window",
1639       cf->current_frame != NULL);
1640   set_menu_sensitivity(NULL, "/Follow TCP Stream",
1641       cf->current_frame != NULL ? (cf->edt->pi.ipproto == IP_PROTO_TCP) : FALSE);
1642   set_menu_sensitivity(main_menu_factory, "/Analyze/Decode As...",
1643       cf->current_frame != NULL && decode_as_ok());
1644   set_menu_sensitivity(NULL, "/Decode As...",
1645       cf->current_frame != NULL && decode_as_ok());
1646   set_menu_sensitivity(tree_view_menu_factory, "/Resolve Name",
1647       cf->current_frame != NULL && (g_resolv_flags & RESOLV_ALL_ADDRS) != RESOLV_ALL_ADDRS);
1648   set_menu_sensitivity(packet_list_menu_factory, "/Match",
1649       cf->current_frame != NULL);
1650   set_menu_sensitivity(packet_list_menu_factory, "/Prepare",
1651       cf->current_frame != NULL);
1652
1653   walk_menu_tree_for_selected_packet(tap_menu_tree_root, cf->current_frame,
1654       cf->edt);
1655   packets_bar_update();
1656 }
1657
1658 /* Enable or disable menu items based on whether a tree row is selected
1659    and, if so, on the properties of the tree row. */
1660 static gboolean
1661 walk_menu_tree_for_selected_tree_row(GList *node, field_info *fi)
1662 {
1663         gboolean is_enabled;
1664         GList *child;
1665     menu_item_t *node_data = node->data;
1666
1667         /*
1668          * Is this a leaf node or an interior node?
1669          */
1670         if (node_data->children == NULL) {
1671                 /*
1672                  * It's a leaf node.
1673                  *
1674                  * If it has no "selected_tree_row_enabled()" routine,
1675                  * leave its enabled/disabled status alone - it
1676                  * doesn't depend on whether we have a tree row selected
1677                  * or not or on the selected tree row.
1678                  *
1679                  * If it has a "selected_tree_row_enabled()" routine,
1680                  * call it and set the item's enabled/disabled status
1681                  * based on its return value.
1682                  */
1683                 if (node_data->selected_tree_row_enabled != NULL)
1684                         node_data->enabled = node_data->selected_tree_row_enabled(fi);
1685         } else {
1686                 /*
1687                  * It's an interior node; call
1688                  * "walk_menu_tree_for_selected_tree_row()" on all its
1689                  * children and, if any of them are enabled, enable
1690                  * this node, otherwise disable it.
1691                  *
1692                  * XXX - should we just leave all interior nodes enabled?
1693                  * Which is a better UI choice?
1694                  */
1695                 is_enabled = FALSE;
1696                 for (child = node_data->children; child != NULL; child =
1697                     child->next) {
1698                         if (walk_menu_tree_for_selected_tree_row(child, fi))
1699                                 is_enabled = TRUE;
1700                 }
1701                 node_data->enabled = is_enabled;
1702         }
1703
1704         /*
1705          * The root node doesn't correspond to a menu tree item; it
1706          * has a null name pointer.
1707          */
1708         if (node_data->name != NULL) {
1709                 set_menu_sensitivity(main_menu_factory, node_data->name,
1710                     node_data->enabled);
1711         }
1712         return node_data->enabled;
1713 }
1714
1715 void
1716 set_menus_for_selected_tree_row(capture_file *cf)
1717 {
1718   gboolean properties;
1719
1720
1721   set_menu_sensitivity(main_menu_factory, "/File/Export/Selected Packet Bytes...", 
1722       cf->finfo_selected != NULL);  
1723   set_menu_sensitivity(tree_view_menu_factory, "/Export Selected Packet Bytes...", 
1724       cf->finfo_selected != NULL);
1725   set_menu_sensitivity(hexdump_menu_factory, "/Export Selected Packet Bytes...", 
1726       cf->finfo_selected != NULL);
1727   
1728   if (cf->finfo_selected != NULL) {
1729         header_field_info *hfinfo = cf->finfo_selected->hfinfo;
1730         if (hfinfo->parent == -1) {
1731           properties = prefs_is_registered_protocol(hfinfo->abbrev);
1732         } else {
1733           properties = prefs_is_registered_protocol(proto_registrar_get_abbrev(hfinfo->parent));
1734         }
1735         set_menu_sensitivity(main_menu_factory,
1736           "/Edit/Go To Corresponding Packet", hfinfo->type == FT_FRAMENUM);
1737         set_menu_sensitivity(tree_view_menu_factory,
1738           "/Go To Corresponding Packet", hfinfo->type == FT_FRAMENUM);
1739         set_menu_sensitivity(main_menu_factory, "/Analyze/Match",
1740           proto_can_match_selected(cf->finfo_selected, cf->edt));
1741         set_menu_sensitivity(tree_view_menu_factory, "/Match",
1742           proto_can_match_selected(cf->finfo_selected, cf->edt));
1743         set_menu_sensitivity(main_menu_factory, "/Analyze/Prepare",
1744           proto_can_match_selected(cf->finfo_selected, cf->edt));
1745         set_menu_sensitivity(tree_view_menu_factory, "/Prepare",
1746           proto_can_match_selected(cf->finfo_selected, cf->edt));
1747         set_menu_sensitivity(tree_view_menu_factory, "/Protocol Properties...",
1748           properties);
1749   } else {
1750         set_menu_sensitivity(main_menu_factory,
1751             "/Edit/Go To Corresponding Packet", FALSE);
1752         set_menu_sensitivity(tree_view_menu_factory,
1753             "/Go To Corresponding Packet", FALSE);
1754         set_menu_sensitivity(main_menu_factory, "/Analyze/Match", FALSE);
1755         set_menu_sensitivity(tree_view_menu_factory, "/Match", FALSE);
1756         set_menu_sensitivity(main_menu_factory, "/Analyze/Prepare", FALSE);
1757         set_menu_sensitivity(tree_view_menu_factory, "/Prepare", FALSE);
1758         set_menu_sensitivity(tree_view_menu_factory, "/Protocol Properties...",
1759           FALSE);
1760   }
1761
1762   walk_menu_tree_for_selected_tree_row(tap_menu_tree_root, cf->finfo_selected);
1763 }