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