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