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