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