6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
8 * Copyright 1998 Gerald Combs
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.
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.
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.
36 #include <epan/packet.h>
37 #include <epan/addr_resolv.h>
38 #include <epan/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"
47 #include "summary_dlg.h"
48 #include "prefs_dlg.h"
49 #include "packet_win.h"
51 #include "follow_dlg.h"
52 #include "decode_as_dlg.h"
54 #include "supported_protos_dlg.h"
55 #include "proto_dlg.h"
56 #include "proto_hier_stats_dlg.h"
58 #include <epan/plugins.h>
59 #include <epan/epan_dissect.h>
60 #include "compat_macros.h"
62 #include "gtkglobals.h"
66 #include "../ipproto.h"
67 #include "packet_list.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>
77 GtkWidget *popup_menu_object;
80 clear_menu_recent_capture_file_cmd_cb(GtkWidget *w, gpointer unused _U_);
82 typedef struct _menu_item {
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 *);
93 static GList *tap_menu_tree_root = NULL;
96 merge_all_tap_menus(GList *node);
98 #define GTK_MENU_FUNC(a) ((GtkItemFactoryCallback)(a))
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_);
116 static void auto_scroll_live_cb(GtkWidget *w _U_, gpointer d _U_);
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:
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)
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
149 Please note: there are some differences between the Gnome HIG menu suggestions and our implementation:
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.
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.
163 static GtkItemFactoryEntry menu_items[] =
165 ITEM_FACTORY_ENTRY("/_File", NULL, NULL, 0, "<Branch>", NULL),
166 ITEM_FACTORY_STOCK_ENTRY("/File/_Open...", "<control>O", file_open_cmd_cb,
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,
172 ITEM_FACTORY_ENTRY("/File/<separator>", NULL, NULL, 0, "<Separator>", NULL),
173 ITEM_FACTORY_STOCK_ENTRY("/File/_Save", "<control>S", file_save_cmd_cb,
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,
181 ITEM_FACTORY_ENTRY("/File/Export/as \"_PostScript\" file...", NULL, export_ps_cmd_cb,
183 ITEM_FACTORY_ENTRY("/File/Export/as XML - \"P_SML\" (packet summary) file...", NULL, export_psml_cmd_cb,
185 ITEM_FACTORY_ENTRY("/File/Export/as XML - \"P_DML\" (packet details) file...", NULL, export_pdml_cmd_cb,
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,
190 ITEM_FACTORY_ENTRY("/File/<separator>", NULL, NULL, 0, "<Separator>", NULL),
191 ITEM_FACTORY_STOCK_ENTRY("/File/_Print...", "<control>P", file_print_cmd_cb,
193 ITEM_FACTORY_ENTRY("/File/<separator>", NULL, NULL, 0, "<Separator>", NULL),
194 ITEM_FACTORY_STOCK_ENTRY("/File/_Quit", "<control>Q", file_quit_cmd_cb,
196 ITEM_FACTORY_ENTRY("/_Edit", NULL, NULL, 0, "<Branch>", NULL),
198 /* Un-#if this when we actually implement Cut/Copy/Paste. */
199 ITEM_FACTORY_STOCK_ENTRY("/Edit/Cut", "<control>X", NULL,
201 ITEM_FACTORY_STOCK_ENTRY("/Edit/Copy", "<control>C", NULL,
203 ITEM_FACTORY_STOCK_ENTRY("/Edit/Paste", "<control>V", NULL,
205 ITEM_FACTORY_ENTRY("/Edit/<separator>", NULL, NULL, 0, "<Separator>"),
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,
220 ITEM_FACTORY_ENTRY("/Edit/Mark _All Packets", NULL, mark_all_frames_cb,
222 ITEM_FACTORY_ENTRY("/Edit/_Unmark All Packets", NULL, unmark_all_frames_cb,
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),
252 ITEM_FACTORY_ENTRY("/View/Auto Scroll in Li_ve Capture", NULL, auto_scroll_live_cb, 0, "<CheckItem>", NULL),
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,
264 ITEM_FACTORY_ENTRY("/View/_Expand All", NULL, expand_all_cb,
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,
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),
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,
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,
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),
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/Wiki", NULL, url_page_menu_cb, ONLINEPAGE_WIKI, NULL, NULL),
360 ITEM_FACTORY_ENTRY("/Help/Ethereal Online/User's Guide", NULL, url_page_menu_cb, ONLINEPAGE_USERGUIDE, NULL, NULL),
361 ITEM_FACTORY_ENTRY("/Help/Ethereal Online/FAQ's", NULL, url_page_menu_cb, ONLINEPAGE_FAQ, NULL, NULL),
362 ITEM_FACTORY_ENTRY("/Help/Ethereal Online/Downloads", NULL, url_page_menu_cb, ONLINEPAGE_DOWNLOAD, NULL, NULL),
363 ITEM_FACTORY_ENTRY("/Help/Ethereal Online/Example Files", NULL, url_page_menu_cb, ONLINEPAGE_SAMPLE_FILES, NULL, NULL),
365 ITEM_FACTORY_ENTRY("/Help/<separator>", NULL, NULL, 0, "<Separator>", NULL),
366 ITEM_FACTORY_ENTRY("/Help/_About Ethereal", NULL, about_ethereal_cb,
371 /* calculate the number of menu_items */
372 static int nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
374 /* packet list popup */
375 static GtkItemFactoryEntry packet_list_menu_items[] =
377 ITEM_FACTORY_ENTRY("/Follow TCP Stream", NULL, follow_stream_cb,
379 ITEM_FACTORY_ENTRY("/Decode As...", NULL, decode_as_cb, 0, NULL, NULL),
380 ITEM_FACTORY_ENTRY("/Display Filters...", NULL, dfilter_dialog_cb,
382 ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
383 ITEM_FACTORY_ENTRY("/Mark Packet", NULL, mark_frame_cb, 0, NULL, NULL),
384 ITEM_FACTORY_ENTRY("/Time Reference", NULL, NULL, 0, "<Branch>", NULL),
385 ITEM_FACTORY_ENTRY("/Time Reference/Set Time Reference (toggle)", NULL, reftime_frame_cb, REFTIME_TOGGLE, NULL, NULL),
386 ITEM_FACTORY_ENTRY("/Time Reference/Find Next", NULL, reftime_frame_cb, REFTIME_FIND_NEXT, NULL, NULL),
387 ITEM_FACTORY_ENTRY("/Time Reference/Find Previous", NULL, reftime_frame_cb, REFTIME_FIND_PREV, NULL, NULL),
388 ITEM_FACTORY_ENTRY("/Apply as Filter", NULL, NULL, 0, "<Branch>", NULL),
389 ITEM_FACTORY_ENTRY("/Apply as Filter/_Selected", NULL, match_selected_plist_cb,
390 MATCH_SELECTED_REPLACE|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
391 ITEM_FACTORY_ENTRY("/Apply as Filter/_Not Selected", NULL, match_selected_plist_cb,
392 MATCH_SELECTED_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
393 ITEM_FACTORY_ENTRY("/Apply as Filter/... _and Selected", NULL, match_selected_plist_cb,
394 MATCH_SELECTED_AND|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
395 ITEM_FACTORY_ENTRY("/Apply as Filter/... _or Selected", NULL, match_selected_plist_cb,
396 MATCH_SELECTED_OR|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
397 ITEM_FACTORY_ENTRY("/Apply as Filter/... a_nd not Selected", NULL, match_selected_plist_cb,
398 MATCH_SELECTED_AND_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
399 ITEM_FACTORY_ENTRY("/Apply as Filter/... o_r not Selected", NULL, match_selected_plist_cb,
400 MATCH_SELECTED_OR_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
402 ITEM_FACTORY_ENTRY("/Prepare a Filter", NULL, NULL, 0, "<Branch>", NULL),
403 ITEM_FACTORY_ENTRY("/Prepare a Filter/_Selected", NULL, match_selected_plist_cb,
404 MATCH_SELECTED_REPLACE, NULL, NULL),
405 ITEM_FACTORY_ENTRY("/Prepare a Filter/_Not Selected", NULL, match_selected_plist_cb,
406 MATCH_SELECTED_NOT, NULL, NULL),
407 ITEM_FACTORY_ENTRY("/Prepare a Filter/... _and Selected", NULL, match_selected_plist_cb,
408 MATCH_SELECTED_AND, NULL, NULL),
409 ITEM_FACTORY_ENTRY("/Prepare a Filter/... _or Selected", NULL, match_selected_plist_cb,
410 MATCH_SELECTED_OR, NULL, NULL),
411 ITEM_FACTORY_ENTRY("/Prepare a Filter/... a_nd not Selected", NULL, match_selected_plist_cb,
412 MATCH_SELECTED_AND_NOT, NULL, NULL),
413 ITEM_FACTORY_ENTRY("/Prepare a Filter/... o_r not Selected", NULL, match_selected_plist_cb,
414 MATCH_SELECTED_OR_NOT, NULL, NULL),
416 ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
417 ITEM_FACTORY_ENTRY("/Coloring Rules...", NULL, color_display_cb,
419 ITEM_FACTORY_ENTRY("/Print...", NULL, file_print_cmd_cb, 0, NULL, NULL),
420 ITEM_FACTORY_ENTRY("/Show Packet in New Window", NULL, new_window_cb,
424 static GtkItemFactoryEntry tree_view_menu_items[] =
426 ITEM_FACTORY_ENTRY("/Follow TCP Stream", NULL, follow_stream_cb,
428 ITEM_FACTORY_ENTRY("/Decode As...", NULL, decode_as_cb, 0, NULL, NULL),
429 ITEM_FACTORY_ENTRY("/Display Filters...", NULL, dfilter_dialog_cb,
431 ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
432 ITEM_FACTORY_ENTRY("/_Resolve Name", NULL, resolve_name_cb, 0, NULL, NULL),
433 ITEM_FACTORY_ENTRY("/_Go to Corresponding Packet", NULL, goto_framenum_cb, 0, NULL, NULL),
434 ITEM_FACTORY_ENTRY("/_Export Selected Packet Bytes...", NULL, savehex_cb,
436 ITEM_FACTORY_ENTRY("/Protocol Preferences...", NULL, properties_cb,
438 ITEM_FACTORY_ENTRY("/Apply as Filter", NULL, NULL, 0, "<Branch>", NULL),
439 ITEM_FACTORY_ENTRY("/Apply as Filter/_Selected", NULL, match_selected_ptree_cb,
440 MATCH_SELECTED_REPLACE|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
441 ITEM_FACTORY_ENTRY("/Apply as Filter/_Not Selected", NULL, match_selected_ptree_cb,
442 MATCH_SELECTED_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
443 ITEM_FACTORY_ENTRY("/Apply as Filter/... _and Selected", NULL, match_selected_ptree_cb,
444 MATCH_SELECTED_AND|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
445 ITEM_FACTORY_ENTRY("/Apply as Filter/... _or Selected", NULL, match_selected_ptree_cb,
446 MATCH_SELECTED_OR|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
447 ITEM_FACTORY_ENTRY("/Apply as Filter/... a_nd not Selected", NULL, match_selected_ptree_cb,
448 MATCH_SELECTED_AND_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
449 ITEM_FACTORY_ENTRY("/Apply as Filter/... o_r not Selected", NULL, match_selected_ptree_cb,
450 MATCH_SELECTED_OR_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
452 ITEM_FACTORY_ENTRY("/Prepare a Filter", NULL, NULL, 0, "<Branch>", NULL),
453 ITEM_FACTORY_ENTRY("/Prepare a Filter/_Selected", NULL, match_selected_ptree_cb,
454 MATCH_SELECTED_REPLACE, NULL, NULL),
455 ITEM_FACTORY_ENTRY("/Prepare a Filter/_Not Selected", NULL, match_selected_ptree_cb,
456 MATCH_SELECTED_NOT, NULL, NULL),
457 ITEM_FACTORY_ENTRY("/Prepare a Filter/... _and Selected", NULL, match_selected_ptree_cb,
458 MATCH_SELECTED_AND, NULL, NULL),
459 ITEM_FACTORY_ENTRY("/Prepare a Filter/... _or Selected", NULL, match_selected_ptree_cb,
460 MATCH_SELECTED_OR, NULL, NULL),
461 ITEM_FACTORY_ENTRY("/Prepare a Filter/... a_nd not Selected", NULL, match_selected_ptree_cb,
462 MATCH_SELECTED_AND_NOT, NULL, NULL),
463 ITEM_FACTORY_ENTRY("/Prepare a Filter/... o_r not Selected", NULL, match_selected_ptree_cb,
464 MATCH_SELECTED_OR_NOT, NULL, NULL),
465 ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
466 ITEM_FACTORY_ENTRY("/Collapse All", NULL, collapse_all_cb, 0, NULL, NULL),
467 ITEM_FACTORY_ENTRY("/Expand All", NULL, expand_all_cb, 0, NULL, NULL),
468 ITEM_FACTORY_ENTRY("/Expand Tree", NULL, expand_tree_cb, 0, NULL, NULL)
471 static GtkItemFactoryEntry hexdump_menu_items[] =
473 ITEM_FACTORY_ENTRY("/Follow TCP Stream", NULL, follow_stream_cb,
475 ITEM_FACTORY_ENTRY("/Decode As...", NULL, decode_as_cb, 0, NULL, NULL),
476 ITEM_FACTORY_ENTRY("/Display Filters...", NULL, dfilter_dialog_cb,
478 ITEM_FACTORY_ENTRY("/Export Selected Packet Bytes...", NULL, savehex_cb,
480 ITEM_FACTORY_ENTRY("/Copy Packet Bytes into Clipboard", NULL, copy_hex_cb,
484 static int initialize = TRUE;
485 static GtkItemFactory *main_menu_factory = NULL;
486 static GtkItemFactory *packet_list_menu_factory = NULL;
487 static GtkItemFactory *tree_view_menu_factory = NULL;
488 static GtkItemFactory *hexdump_menu_factory = NULL;
490 static GSList *popup_menu_list = NULL;
492 static GtkAccelGroup *grp;
495 main_menu_new(GtkAccelGroup ** table) {
498 grp = gtk_accel_group_new();
503 menubar = main_menu_factory->widget;
517 packet_list_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
518 popup_menu_object = gtk_menu_new();
519 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);
520 OBJECT_SET_DATA(popup_menu_object, PM_PACKET_LIST_KEY,
521 packet_list_menu_factory->widget);
522 popup_menu_list = g_slist_append((GSList *)popup_menu_list, packet_list_menu_factory);
524 tree_view_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
525 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);
526 OBJECT_SET_DATA(popup_menu_object, PM_TREE_VIEW_KEY,
527 tree_view_menu_factory->widget);
528 popup_menu_list = g_slist_append((GSList *)popup_menu_list, tree_view_menu_factory);
530 hexdump_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
531 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);
532 OBJECT_SET_DATA(popup_menu_object, PM_HEXDUMP_KEY,
533 hexdump_menu_factory->widget);
534 popup_menu_list = g_slist_append((GSList *)popup_menu_list, hexdump_menu_factory);
537 main_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", grp);
538 gtk_item_factory_create_items_ac(main_menu_factory, nmenu_items, menu_items, NULL, 2);
540 merge_all_tap_menus(tap_menu_tree_root);
542 /* Initialize enabled/disabled state of menu items */
543 set_menus_for_unsaved_capture_file(FALSE);
544 set_menus_for_capture_file(FALSE);
546 /* Un-#if this when we actually implement Cut/Copy/Paste.
547 Then make sure you enable them when they can be done. */
548 set_menu_sensitivity(main_menu_factory, "/Edit/Cut", FALSE);
549 set_menu_sensitivity(main_menu_factory, "/Edit/Copy", FALSE);
550 set_menu_sensitivity(main_menu_factory, "/Edit/Paste", FALSE);
553 set_menus_for_captured_packets(FALSE);
554 set_menus_for_selected_packet(&cfile);
555 set_menus_for_selected_tree_row(&cfile);
557 /* init with an empty recent files list */
558 clear_menu_recent_capture_file_cmd_cb(NULL, NULL);
563 gint tap_menu_item_add_compare(gconstpointer a, gconstpointer b)
566 ((const menu_item_t *) a)->name,
567 ((const menu_item_t *) b)->name);
571 /* add a menuitem below the current node */
572 GList * tap_menu_item_add(
575 GtkItemFactoryCallback callback,
576 gboolean (*selected_packet_enabled)(frame_data *, epan_dissect_t *),
577 gboolean (*selected_tree_row_enabled)(field_info *),
578 gpointer callback_data,
585 child = g_malloc(sizeof (menu_item_t));
586 child->group = group;
588 child->callback = callback;
589 child->selected_packet_enabled = selected_packet_enabled;
590 child->selected_tree_row_enabled = selected_tree_row_enabled;
591 child->callback_data = callback_data;
592 child->enabled = FALSE;
593 child->children = NULL;
595 /* insert the new child node into the parent */
596 curr = curnode->data;
597 curr->children = g_list_insert_sorted(curr->children, child, tap_menu_item_add_compare);
599 /* return the new node */
600 /* XXX: improve this */
601 return g_list_find(curr->children, child);
605 * Add a new menu item for a tap.
606 * This must be called after we've created the main menu, so it can't
607 * be called from the routine that registers taps - we have to introduce
608 * another per-tap registration routine.
610 * "callback" gets called when the menu item is selected; it should do
611 * the work of creating the tap window.
613 * "selected_packet_enabled" gets called by "set_menus_for_selected_packet()";
614 * it's passed a Boolean that's TRUE if a packet is selected and FALSE
615 * otherwise, and should return TRUE if the tap will work now (which
616 * might depend on whether a packet is selected and, if one is, on the
617 * packet) and FALSE if not.
619 * "selected_tree_row_enabled" gets called by
620 * "set_menus_for_selected_tree_row()"; it's passed a Boolean that's TRUE if
621 * a protocol tree row is selected and FALSE otherwise, and should return
622 * TRUE if the tap will work now (which might depend on whether a tree row
623 * is selected and, if one is, on the tree row) and FALSE if not.
626 register_tap_menu_item(
628 REGISTER_TAP_GROUP_E group,
629 GtkItemFactoryCallback callback,
630 gboolean (*selected_packet_enabled)(frame_data *, epan_dissect_t *),
631 gboolean (*selected_tree_row_enabled)(field_info *),
632 gpointer callback_data)
634 /*static const char toolspath[] = "/Statistics/";*/
644 * The menu path must be relative.
646 g_assert(*name != '/');
649 case(REGISTER_TAP_GROUP_GENERIC): toolspath = "/Statistics/"; break;
650 case(REGISTER_TAP_GROUP_CONVERSATION_LIST): toolspath = "/Statistics/_Conversation List/"; break;
651 case(REGISTER_TAP_GROUP_ENDPOINT_LIST): toolspath = "/Statistics/_Endpoint List/"; break;
652 case(REGISTER_TAP_GROUP_RESPONSE_TIME): toolspath = "/Statistics/Service _Response Time/"; break;
653 case(REGISTER_TAP_GROUP_NONE): toolspath = "/Statistics/"; break;
659 /* add the (empty) root node, if not already done */
660 if(tap_menu_tree_root == NULL) {
661 child = g_malloc0(sizeof (menu_item_t));
662 tap_menu_tree_root = g_list_append(NULL, child);
666 * Create any submenus required.
668 curnode = tap_menu_tree_root;
670 while ((p = strchr(p, '/')) != NULL) {
672 * OK, everything between "name" and "p" is
673 * a menu relative subtree into which the menu item
676 * Construct the absolute path name of that subtree.
678 menupathlen = strlen(toolspath) + 1 + (p - name);
679 menupath = g_malloc(menupathlen);
680 strcpy(menupath, toolspath);
681 strncat(menupath, name, p - name);
684 * Does there exist an entry with that path at this
685 * level of the Analyze menu tree?
687 child = curnode->data;
688 for (childnode = child->children; childnode != NULL; childnode = childnode->next) {
689 child = childnode->data;
690 if (strcmp(child->name, menupath) == 0)
693 if (childnode == NULL) {
695 * No. Create such an item as a subtree, and
696 * add it to the Tools menu tree.
698 childnode = tap_menu_item_add(
699 menupath, group, NULL, NULL ,NULL, NULL, curnode);
702 * Yes. We don't need this "menupath" any longer.
709 * Skip over the '/' we found.
715 * Construct the main menu path for the menu item.
717 menupathlen = strlen(toolspath) + 1 + strlen(name);
718 menupath = g_malloc(menupathlen);
719 strcpy(menupath, toolspath);
720 strcat(menupath, name);
723 * Construct an item factory entry for the item, and add it to
727 menupath, group, callback,
728 selected_packet_enabled, selected_tree_row_enabled,
729 callback_data, curnode);
733 guint merge_tap_menus_layered(GList *node, gint group) {
734 GtkItemFactoryEntry *entry;
737 menu_item_t *node_data = node->data;
740 * Is this a leaf node or an interior node?
742 if (node_data->children == NULL) {
748 * The root node doesn't correspond to a menu tree item; it
749 * has a null name pointer.
751 if (node_data->name != NULL && group == node_data->group) {
752 entry = g_malloc0(sizeof (GtkItemFactoryEntry));
753 entry->path = node_data->name;
754 entry->callback = node_data->callback;
755 gtk_item_factory_create_item(main_menu_factory, entry, node_data->callback_data, 2);
756 set_menu_sensitivity(main_menu_factory, node_data->name, FALSE); /* no capture file yet */
761 * It's an interior node; call
762 * "merge_tap_menus_layered()" on all its children
766 * The root node doesn't correspond to a menu tree item; it
767 * has a null name pointer.
769 if (node_data->name != NULL && group == node_data->group) {
770 entry = g_malloc0(sizeof (GtkItemFactoryEntry));
771 entry->path = node_data->name;
772 entry->item_type = "<Branch>";
773 gtk_item_factory_create_item(main_menu_factory, entry,
775 set_menu_sensitivity(main_menu_factory, node_data->name,
776 FALSE); /* no children yet */
780 for (child = node_data->children; child != NULL; child =
782 added += merge_tap_menus_layered(child, group);
790 void merge_all_tap_menus(GList *node) {
791 GtkItemFactoryEntry *entry;
793 entry = g_malloc0(sizeof (GtkItemFactoryEntry));
794 entry->item_type = "<Separator>";
795 entry->path = "/Statistics/";
798 * merge only the menu items of the specific group,
799 * and then append a seperator
801 if (merge_tap_menus_layered(node, REGISTER_TAP_GROUP_GENERIC)) {
802 gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);
804 if (merge_tap_menus_layered(node, REGISTER_TAP_GROUP_CONVERSATION_LIST)) {
805 /*gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);*/
807 if (merge_tap_menus_layered(node, REGISTER_TAP_GROUP_ENDPOINT_LIST)) {
808 /*gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);*/
810 if (merge_tap_menus_layered(node, REGISTER_TAP_GROUP_RESPONSE_TIME)) {
811 gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);
813 if (merge_tap_menus_layered(node, REGISTER_TAP_GROUP_NONE)) {
814 /*gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);*/
821 * Enable/disable menu sensitivity.
824 set_menu_sensitivity(GtkItemFactory *ifactory, const gchar *path, gint val)
827 GtkWidget *menu_item;
832 /* the underscore character regularly confuses things, as it will prevent finding
833 * the menu_item, so it has to be removed first */
834 dup = g_strdup(path);
845 if (ifactory == NULL) {
847 * Do it for all pop-up menus.
849 for (menu_list = popup_menu_list; menu_list != NULL;
850 menu_list = g_slist_next(menu_list))
851 set_menu_sensitivity(menu_list->data, dup, val);
854 * Do it for that particular menu.
856 if ((menu_item = gtk_item_factory_get_widget(ifactory, dup)) != NULL) {
857 if (GTK_IS_MENU(menu_item)) {
859 * "dup" refers to a submenu; "gtk_item_factory_get_widget()"
860 * gets the menu, not the item that, when selected, pops up
863 * We have to change the latter item's sensitivity, so that
864 * it shows up normally if sensitive and grayed-out if
867 menu_item = gtk_menu_get_attach_widget(GTK_MENU(menu_item));
869 gtk_widget_set_sensitive(menu_item, val);
871 /* be sure this menu item *is* existing */
872 g_assert_not_reached();
880 set_menu_object_data_meat(GtkItemFactory *ifactory, gchar *path, gchar *key, gpointer data)
882 GtkWidget *menu = NULL;
884 if ((menu = gtk_item_factory_get_widget(ifactory, path)) != NULL)
885 OBJECT_SET_DATA(menu, key, data);
889 set_menu_object_data (gchar *path, gchar *key, gpointer data) {
890 GSList *menu_list = popup_menu_list;
891 gchar *shortpath = strrchr(path, '/');
893 set_menu_object_data_meat(main_menu_factory, path, key, data);
894 while (menu_list != NULL) {
895 set_menu_object_data_meat(menu_list->data, shortpath, key, data);
896 menu_list = g_slist_next(menu_list);
901 /* Recently used capture files submenu:
902 * Submenu containing the recently used capture files.
903 * The capture filenames are always kept with the absolute path, to be independant
904 * of the current path.
905 * They are only stored inside the labels of the submenu (no separate list). */
907 #define MENU_RECENT_FILES_PATH "/File/Open Recent"
908 #define MENU_RECENT_FILES_KEY "Recent File Name"
911 update_menu_recent_capture_file1(GtkWidget *widget, gpointer cnt) {
912 gchar *widget_cf_name;
914 widget_cf_name = OBJECT_GET_DATA(widget, MENU_RECENT_FILES_KEY);
916 /* if this menu item is a file, count it */
917 if (widget_cf_name) {
923 /* update the menu */
925 update_menu_recent_capture_file(GtkWidget *submenu_recent_files) {
928 gtk_container_foreach(GTK_CONTAINER(submenu_recent_files),
929 update_menu_recent_capture_file1, &cnt);
931 /* make parent menu item sensitive only, if we have any valid files in the list */
932 set_menu_sensitivity(main_menu_factory, MENU_RECENT_FILES_PATH, cnt);
936 /* remove the capture filename from the "Recent Files" menu */
938 remove_menu_recent_capture_file(GtkWidget *widget, gpointer unused _U_) {
939 GtkWidget *submenu_recent_files;
940 gchar *widget_cf_name;
943 widget_cf_name = OBJECT_GET_DATA(widget, MENU_RECENT_FILES_KEY);
944 g_free(widget_cf_name);
946 /* get the submenu container item */
947 submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
949 /* XXX: is this all we need to do, to free the menu item and its label?
950 The reference count of widget will go to 0, so it'll be freed;
951 will that free the label? */
952 gtk_container_remove(GTK_CONTAINER(submenu_recent_files), widget);
956 /* callback, if the user pushed the <Clear File List> item */
958 clear_menu_recent_capture_file_cmd_cb(GtkWidget *w _U_, gpointer unused _U_) {
959 GtkWidget *submenu_recent_files;
962 submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
964 gtk_container_foreach(GTK_CONTAINER(submenu_recent_files),
965 remove_menu_recent_capture_file, NULL);
967 update_menu_recent_capture_file(submenu_recent_files);
971 /* callback, if the user pushed a recent file submenu item */
973 menu_open_recent_file_cmd(GtkWidget *w)
975 GtkWidget *submenu_recent_files;
976 GtkWidget *menu_item_child;
980 submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
982 /* get capture filename from the menu item label */
983 menu_item_child = (GTK_BIN(w))->child;
984 gtk_label_get(GTK_LABEL(menu_item_child), &cf_name);
986 /* open and read the capture file (this will close an existing file) */
987 if ((err = cf_open(cf_name, FALSE, &cfile)) == 0) {
990 /* the capture file isn't existing any longer, remove menu item */
991 /* XXX: ask user to remove item, it's maybe only a temporary problem */
992 remove_menu_recent_capture_file(w, NULL);
995 update_menu_recent_capture_file(submenu_recent_files);
998 static void menu_open_recent_file_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
1002 /* save file first */
1003 file_save_as_cmd(after_save_open_recent_file, data);
1007 menu_open_recent_file_cmd(data);
1009 case(ESD_BTN_CANCEL):
1012 g_assert_not_reached();
1017 menu_open_recent_file_cmd_cb(GtkWidget *widget, gpointer data _U_) {
1021 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
1022 /* user didn't saved his current file, ask him */
1023 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_YES_NO_CANCEL,
1024 PRIMARY_TEXT_START "Save capture file before opening a new one?" PRIMARY_TEXT_END "\n\n"
1025 "If you open a new capture file without saving, your current capture data will be discarded.");
1026 simple_dialog_set_cb(dialog, menu_open_recent_file_answered_cb, widget);
1028 /* unchanged file */
1029 menu_open_recent_file_cmd(widget);
1033 /* add the capture filename (with an absolute path) to the "Recent Files" menu */
1035 add_menu_recent_capture_file_absolute(gchar *cf_name) {
1036 GtkWidget *submenu_recent_files;
1037 GList *menu_item_list;
1039 gchar *widget_cf_name;
1040 gchar *normalized_cf_name;
1041 GtkWidget *menu_item;
1046 normalized_cf_name = g_strdup(cf_name);
1048 /* replace all slashes by backslashes */
1049 g_strdelimit(normalized_cf_name, "/", '\\');
1052 /* get the submenu container item */
1053 submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
1055 /* convert container to a GList */
1056 menu_item_list = gtk_container_children(GTK_CONTAINER(submenu_recent_files));
1058 /* iterate through list items of menu_item_list,
1059 * removing special items, a maybe duplicate entry and every item above count_max */
1061 for (li = g_list_first(menu_item_list); li; li = li->next, cnt++) {
1062 /* get capture filename */
1063 menu_item = GTK_WIDGET(li->data);
1064 widget_cf_name = OBJECT_GET_DATA(menu_item, MENU_RECENT_FILES_KEY);
1066 /* if this element string is one of our special items (seperator, ...) or
1067 * already in the list or
1068 * this element is above maximum count (too old), remove it */
1069 if (!widget_cf_name ||
1071 /* do a case insensitive compare on win32 */
1072 #if GLIB_MAJOR_VERSION < 2
1073 g_strncasecmp(widget_cf_name, normalized_cf_name, 1000) == 0 ||
1075 g_ascii_strncasecmp(widget_cf_name, normalized_cf_name, 1000) == 0 ||
1078 /* do a case sensitive compare on unix */
1079 strncmp(widget_cf_name, normalized_cf_name, 1000) == 0 ||
1081 cnt >= prefs.gui_recent_files_count_max) {
1082 remove_menu_recent_capture_file(li->data, NULL);
1087 g_list_free(menu_item_list);
1089 /* add new item at latest position */
1090 menu_item = gtk_menu_item_new_with_label(normalized_cf_name);
1091 OBJECT_SET_DATA(menu_item, MENU_RECENT_FILES_KEY, normalized_cf_name);
1092 gtk_menu_prepend (GTK_MENU(submenu_recent_files), menu_item);
1093 SIGNAL_CONNECT_OBJECT(GTK_OBJECT(menu_item), "activate",
1094 menu_open_recent_file_cmd_cb, (GtkObject *) menu_item);
1095 gtk_widget_show (menu_item);
1097 /* add seperator at last position */
1098 menu_item = gtk_menu_item_new();
1099 gtk_menu_append (GTK_MENU(submenu_recent_files), menu_item);
1100 gtk_widget_show (menu_item);
1102 /* add new "clear list" item at last position */
1103 #if GTK_MAJOR_VERSION < 2
1104 menu_item = gtk_menu_item_new_with_label("<Clear File List>");
1106 menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_CLEAR, NULL);
1108 gtk_menu_append (GTK_MENU(submenu_recent_files), menu_item);
1109 SIGNAL_CONNECT_OBJECT(GTK_OBJECT(menu_item), "activate",
1110 clear_menu_recent_capture_file_cmd_cb, (GtkObject *) menu_item);
1111 gtk_widget_show (menu_item);
1113 update_menu_recent_capture_file(submenu_recent_files);
1117 /* add the capture filename to the "Recent Files" menu */
1118 /* (will change nothing, if this filename is already in the menu) */
1120 add_menu_recent_capture_file(gchar *cf_name) {
1125 /* if this filename is an absolute path, we can use it directly */
1126 if (g_path_is_absolute(cf_name)) {
1127 add_menu_recent_capture_file_absolute(cf_name);
1131 /* this filename is not an absolute path, prepend the current dir */
1132 curr = g_get_current_dir();
1133 absolute = g_strdup_printf("%s%s%s", curr, G_DIR_SEPARATOR_S, cf_name);
1134 add_menu_recent_capture_file_absolute(absolute);
1140 /* write all capture filenames of the menu to the user's recent file */
1142 menu_recent_file_write_all(FILE *rf) {
1143 GtkWidget *submenu_recent_files;
1149 submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
1151 /* we have to iterate backwards through the children's list,
1152 * so we get the latest item last in the file.
1153 * (don't use gtk_container_foreach() here, it will return the wrong iteration order) */
1154 children = gtk_container_children(GTK_CONTAINER(submenu_recent_files));
1155 child = g_list_last(children);
1156 while(child != NULL) {
1157 /* get capture filename from the menu item label */
1158 cf_name = OBJECT_GET_DATA(child->data, MENU_RECENT_FILES_KEY);
1160 fprintf (rf, RECENT_KEY_CAPTURE_FILE ": %s\n", cf_name);
1163 child = g_list_previous(child);
1166 g_list_free(children);
1171 main_toolbar_show_cb(GtkWidget *w _U_, gpointer d _U_)
1174 /* save current setting in recent */
1175 recent.main_toolbar_show = GTK_CHECK_MENU_ITEM(w)->active;
1177 main_widgets_show_or_hide();
1182 filter_toolbar_show_cb(GtkWidget *w _U_, gpointer d _U_)
1185 /* save current setting in recent */
1186 recent.filter_toolbar_show = GTK_CHECK_MENU_ITEM(w)->active;
1188 main_widgets_show_or_hide();
1193 packet_list_show_cb(GtkWidget *w _U_, gpointer d _U_)
1196 /* save current setting in recent */
1197 recent.packet_list_show = GTK_CHECK_MENU_ITEM(w)->active;
1199 main_widgets_show_or_hide();
1204 tree_view_show_cb(GtkWidget *w _U_, gpointer d _U_)
1207 /* save current setting in recent */
1208 recent.tree_view_show = GTK_CHECK_MENU_ITEM(w)->active;
1210 main_widgets_show_or_hide();
1215 byte_view_show_cb(GtkWidget *w _U_, gpointer d _U_)
1218 /* save current setting in recent */
1219 recent.byte_view_show = GTK_CHECK_MENU_ITEM(w)->active;
1221 main_widgets_show_or_hide();
1226 statusbar_show_cb(GtkWidget *w _U_, gpointer d _U_)
1229 /* save current setting in recent */
1230 recent.statusbar_show = GTK_CHECK_MENU_ITEM(w)->active;
1232 main_widgets_show_or_hide();
1237 timestamp_absolute_cb(GtkWidget *w _U_, gpointer d _U_)
1239 if (recent.gui_time_format != TS_ABSOLUTE) {
1240 set_timestamp_setting(TS_ABSOLUTE);
1241 recent.gui_time_format = TS_ABSOLUTE;
1242 change_time_formats(&cfile);
1247 timestamp_absolute_date_cb(GtkWidget *w _U_, gpointer d _U_)
1249 if (recent.gui_time_format != TS_ABSOLUTE_WITH_DATE) {
1250 set_timestamp_setting(TS_ABSOLUTE_WITH_DATE);
1251 recent.gui_time_format = TS_ABSOLUTE_WITH_DATE;
1252 change_time_formats(&cfile);
1257 timestamp_relative_cb(GtkWidget *w _U_, gpointer d _U_)
1259 if (recent.gui_time_format != TS_RELATIVE) {
1260 set_timestamp_setting(TS_RELATIVE);
1261 recent.gui_time_format = TS_RELATIVE;
1262 change_time_formats(&cfile);
1267 timestamp_delta_cb(GtkWidget *w _U_, gpointer d _U_)
1269 if (recent.gui_time_format != TS_DELTA) {
1270 set_timestamp_setting(TS_DELTA);
1271 recent.gui_time_format = TS_DELTA;
1272 change_time_formats(&cfile);
1277 menu_name_resolution_changed(void)
1279 GtkWidget *menu = NULL;
1281 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Name Resolution/Enable for MAC Layer");
1282 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), g_resolv_flags & RESOLV_MAC);
1284 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Name Resolution/Enable for Network Layer");
1285 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), g_resolv_flags & RESOLV_NETWORK);
1287 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Name Resolution/Enable for Transport Layer");
1288 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), g_resolv_flags & RESOLV_TRANSPORT);
1292 name_resolution_mac_cb(GtkWidget *w _U_, gpointer d _U_)
1294 if (GTK_CHECK_MENU_ITEM(w)->active) {
1295 g_resolv_flags |= RESOLV_MAC;
1297 g_resolv_flags &= ~RESOLV_MAC;
1302 name_resolution_network_cb(GtkWidget *w _U_, gpointer d _U_)
1304 if (GTK_CHECK_MENU_ITEM(w)->active) {
1305 g_resolv_flags |= RESOLV_NETWORK;
1307 g_resolv_flags &= ~RESOLV_NETWORK;
1312 name_resolution_transport_cb(GtkWidget *w _U_, gpointer d _U_)
1314 if (GTK_CHECK_MENU_ITEM(w)->active) {
1315 g_resolv_flags |= RESOLV_TRANSPORT;
1317 g_resolv_flags &= ~RESOLV_TRANSPORT;
1323 auto_scroll_live_cb(GtkWidget *w _U_, gpointer d _U_)
1325 auto_scroll_live = GTK_CHECK_MENU_ITEM(w)->active;
1329 /* the recent file read has finished, update the menu corresponding */
1331 menu_recent_read_finished(void) {
1332 GtkWidget *menu = NULL;
1334 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Main Toolbar");
1335 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.main_toolbar_show);
1337 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Filter Toolbar");
1338 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.filter_toolbar_show);
1340 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Statusbar");
1341 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.statusbar_show);
1343 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Packet List");
1344 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.packet_list_show);
1346 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Packet Details");
1347 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.tree_view_show);
1349 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Packet Bytes");
1350 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.byte_view_show);
1352 menu_name_resolution_changed();
1355 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Auto Scroll in Live Capture");
1356 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), auto_scroll_live);
1359 main_widgets_rearrange();
1361 /* don't change the time format, if we had a command line value */
1362 if (get_timestamp_setting() != TS_NOT_SET) {
1363 recent.gui_time_format = get_timestamp_setting();
1366 switch(recent.gui_time_format) {
1368 menu = gtk_item_factory_get_widget(main_menu_factory,
1369 "/View/Time Display Format/Time of Day");
1370 /* set_active will not trigger the callback when activating an active item! */
1371 recent.gui_time_format = -1;
1372 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), FALSE);
1373 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
1375 case(TS_ABSOLUTE_WITH_DATE):
1376 menu = gtk_item_factory_get_widget(main_menu_factory,
1377 "/View/Time Display Format/Date and Time of Day");
1378 recent.gui_time_format = -1;
1379 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
1382 menu = gtk_item_factory_get_widget(main_menu_factory,
1383 "/View/Time Display Format/Seconds Since Beginning of Capture");
1384 recent.gui_time_format = -1;
1385 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
1388 menu = gtk_item_factory_get_widget(main_menu_factory,
1389 "/View/Time Display Format/Seconds Since Previous Packet");
1390 recent.gui_time_format = -1;
1391 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
1394 g_assert_not_reached();
1400 popup_menu_handler(GtkWidget *widget, GdkEvent *event, gpointer data)
1402 GtkWidget *menu = (GtkWidget *)data;
1403 GdkEventButton *event_button = NULL;
1406 if(widget == NULL || event == NULL || data == NULL) {
1411 * If we ever want to make the menu differ based on what row
1412 * and/or column we're above, we'd use "eth_clist_get_selection_info()"
1413 * to find the row and column number for the coordinates; a CTree is,
1414 * I guess, like a CList with one column(?) and the expander widget
1417 /* Check if we are on packet_list object */
1418 if (widget == OBJECT_GET_DATA(popup_menu_object, E_MPACKET_LIST_KEY)) {
1419 if (packet_list_get_event_row_column(widget, (GdkEventButton *)event,
1421 OBJECT_SET_DATA(popup_menu_object, E_MPACKET_LIST_ROW_KEY,
1422 GINT_TO_POINTER(row));
1423 OBJECT_SET_DATA(popup_menu_object, E_MPACKET_LIST_COL_KEY,
1424 GINT_TO_POINTER(column));
1425 packet_list_set_selected_row(row);
1429 /* Check if we are on tree_view object */
1430 if (widget == tree_view) {
1431 tree_view_select(widget, (GdkEventButton *) event);
1434 /* Check if we are on byte_view object */
1435 if(widget == get_notebook_bv_ptr(byte_nb_ptr)) {
1436 byte_view_select(widget, (GdkEventButton *) event);
1439 /* context menu handler (but the byte view notebook pages have their own handler) */
1440 if(event->type == GDK_BUTTON_PRESS && widget != byte_nb_ptr) {
1441 event_button = (GdkEventButton *) event;
1443 /* To qoute the "Gdk Event Structures" doc:
1444 * "Normally button 1 is the left mouse button, 2 is the middle button, and 3 is the right button" */
1445 if(event_button->button == 3) {
1446 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
1447 event_button->button,
1448 event_button->time);
1449 SIGNAL_EMIT_STOP_BY_NAME(widget, "button_press_event");
1453 #if GTK_MAJOR_VERSION >= 2
1454 /* GDK_2BUTTON_PRESS is a doubleclick -> expand/collapse tree row */
1455 /* GTK version 1 seems to be doing this automatically */
1456 if (widget == tree_view && event->type == GDK_2BUTTON_PRESS) {
1459 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget),
1460 (gint) (((GdkEventButton *)event)->x),
1461 (gint) (((GdkEventButton *)event)->y),
1462 &path, NULL, NULL, NULL))
1464 if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(widget), path))
1465 gtk_tree_view_collapse_row(GTK_TREE_VIEW(widget), path);
1467 gtk_tree_view_expand_row(GTK_TREE_VIEW(widget), path,
1469 gtk_tree_path_free(path);
1476 /* Enable or disable menu items based on whether you have a capture file
1477 you've finished reading. */
1479 set_menus_for_capture_file(gboolean have_capture_file)
1481 set_menu_sensitivity(main_menu_factory, "/File/Open...", have_capture_file);
1482 set_menu_sensitivity(main_menu_factory, "/File/Open Recent", have_capture_file);
1483 set_menu_sensitivity(main_menu_factory, "/File/Merge...", have_capture_file);
1484 set_menu_sensitivity(main_menu_factory, "/File/Close", have_capture_file);
1485 set_menu_sensitivity(main_menu_factory, "/File/Save As...",
1487 set_menu_sensitivity(main_menu_factory, "/File/Export", have_capture_file);
1488 set_menu_sensitivity(main_menu_factory, "/View/Reload", have_capture_file);
1489 set_toolbar_for_capture_file(have_capture_file);
1490 packets_bar_update();
1493 /* Enable or disable menu items based on whether you have an unsaved
1494 capture file you've finished reading. */
1496 set_menus_for_unsaved_capture_file(gboolean have_unsaved_capture_file)
1498 set_menu_sensitivity(main_menu_factory, "/File/Save",
1499 have_unsaved_capture_file);
1500 set_toolbar_for_unsaved_capture_file(have_unsaved_capture_file);
1503 /* Enable or disable menu items based on whether there's a capture in
1506 set_menus_for_capture_in_progress(gboolean capture_in_progress)
1508 set_menu_sensitivity(main_menu_factory, "/File/Open...",
1509 !capture_in_progress);
1510 set_menu_sensitivity(main_menu_factory, "/File/Open Recent",
1511 !capture_in_progress);
1513 set_menu_sensitivity(main_menu_factory, "/Capture/Start...",
1514 !capture_in_progress);
1515 set_menu_sensitivity(main_menu_factory, "/Capture/Stop",
1516 capture_in_progress);
1517 #endif /* HAVE_LIBPCAP */
1518 set_toolbar_for_capture_in_progress(capture_in_progress);
1520 set_capture_if_dialog_for_capture_in_progress(capture_in_progress);
1523 /* Enable or disable menu items based on whether you have some captured
1526 walk_menu_tree_for_captured_packets(GList *node,
1527 gboolean have_captured_packets)
1529 gboolean is_enabled;
1531 menu_item_t *node_data = node->data;
1534 * Is this a leaf node or an interior node?
1536 if (node_data->children == NULL) {
1540 * If it has no "selected_packet_enabled()" or
1541 * "selected_tree_row_enabled()" routines, we enable
1542 * it. This allows tap windows to be popped up even
1543 * if you have no capture file; this is done to let
1544 * the user pop up multiple tap windows before reading
1545 * in a capture file, so that they can be processed in
1546 * parallel while the capture file is being read rather
1547 * than one at at time as you pop up the windows, and to
1548 * let the user pop up tap windows before starting an
1549 * "Update list of packets in real time" capture, so that
1550 * the statistics can be displayed while the capture is
1553 * If it has either of those routines, we disable it for
1554 * now - as long as, when a capture is first available,
1555 * we don't get called after a packet or tree row is
1556 * selected, that's OK.
1557 * XXX - that should be done better.
1559 if (node_data->selected_packet_enabled == NULL &&
1560 node_data->selected_tree_row_enabled == NULL)
1561 node_data->enabled = TRUE;
1563 node_data->enabled = FALSE;
1566 * It's an interior node; call
1567 * "walk_menu_tree_for_captured_packets()" on all its
1568 * children and, if any of them are enabled, enable
1569 * this node, otherwise disable it.
1571 * XXX - should we just leave all interior nodes enabled?
1572 * Which is a better UI choice?
1575 for (child = node_data->children; child != NULL; child =
1577 if (walk_menu_tree_for_captured_packets(child,
1578 have_captured_packets))
1581 node_data->enabled = is_enabled;
1585 * The root node doesn't correspond to a menu tree item; it
1586 * has a null name pointer.
1588 if (node_data->name != NULL) {
1589 set_menu_sensitivity(main_menu_factory, node_data->name,
1590 node_data->enabled);
1592 return node_data->enabled;
1596 set_menus_for_captured_packets(gboolean have_captured_packets)
1598 set_menu_sensitivity(main_menu_factory, "/File/Print...",
1599 have_captured_packets);
1600 set_menu_sensitivity(packet_list_menu_factory, "/Print...",
1601 have_captured_packets);
1602 set_menu_sensitivity(main_menu_factory, "/Edit/Find Packet...",
1603 have_captured_packets);
1604 set_menu_sensitivity(main_menu_factory, "/Edit/Find Next",
1605 have_captured_packets);
1606 set_menu_sensitivity(main_menu_factory, "/Edit/Find Previous",
1607 have_captured_packets);
1608 set_menu_sensitivity(main_menu_factory, "/View/Zoom In",
1609 have_captured_packets);
1610 set_menu_sensitivity(main_menu_factory, "/View/Zoom Out",
1611 have_captured_packets);
1612 set_menu_sensitivity(main_menu_factory, "/View/Normal Size",
1613 have_captured_packets);
1614 set_menu_sensitivity(packet_list_menu_factory, "/Coloring Rules...",
1615 have_captured_packets);
1616 set_menu_sensitivity(main_menu_factory, "/Go/Go to Packet...",
1617 have_captured_packets);
1618 set_menu_sensitivity(main_menu_factory, "/Go/First Packet",
1619 have_captured_packets);
1620 set_menu_sensitivity(main_menu_factory, "/Go/Last Packet",
1621 have_captured_packets);
1622 set_menu_sensitivity(main_menu_factory, "/Statistics/Summary",
1623 have_captured_packets);
1624 set_menu_sensitivity(main_menu_factory, "/Statistics/Protocol Hierarchy",
1625 have_captured_packets);
1627 walk_menu_tree_for_captured_packets(tap_menu_tree_root,
1628 have_captured_packets);
1629 set_toolbar_for_captured_packets(have_captured_packets);
1630 packets_bar_update();
1633 /* Enable or disable menu items based on whether a packet is selected and,
1634 if so, on the properties of the packet. */
1636 walk_menu_tree_for_selected_packet(GList *node, frame_data *fd,
1637 epan_dissect_t *edt)
1639 gboolean is_enabled;
1641 menu_item_t *node_data = node->data;
1644 * Is this a leaf node or an interior node?
1646 if (node_data->children == NULL) {
1650 * If it has no "selected_packet_enabled()" routine,
1651 * leave its enabled/disabled status alone - it
1652 * doesn't depend on whether we have a packet selected
1653 * or not or on the selected packet.
1655 * If it has a "selected_packet_enabled()" routine,
1656 * call it and set the item's enabled/disabled status
1657 * based on its return value.
1659 if (node_data->selected_packet_enabled != NULL)
1660 node_data->enabled = node_data->selected_packet_enabled(fd, edt);
1663 * It's an interior node; call
1664 * "walk_menu_tree_for_selected_packet()" on all its
1665 * children and, if any of them are enabled, enable
1666 * this node, otherwise disable it.
1668 * XXX - should we just leave all interior nodes enabled?
1669 * Which is a better UI choice?
1672 for (child = node_data->children; child != NULL; child =
1674 if (walk_menu_tree_for_selected_packet(child, fd, edt))
1677 node_data->enabled = is_enabled;
1681 * The root node doesn't correspond to a menu tree item; it
1682 * has a null name pointer.
1684 if (node_data->name != NULL) {
1685 set_menu_sensitivity(main_menu_factory, node_data->name,
1686 node_data->enabled);
1688 return node_data->enabled;
1692 set_menus_for_selected_packet(capture_file *cf)
1694 set_menu_sensitivity(main_menu_factory, "/Edit/Mark Packet",
1695 cf->current_frame != NULL);
1696 set_menu_sensitivity(packet_list_menu_factory, "/Mark Packet",
1697 cf->current_frame != NULL);
1698 set_menu_sensitivity(main_menu_factory, "/Edit/Time Reference",
1699 cf->current_frame != NULL);
1700 set_menu_sensitivity(packet_list_menu_factory, "/Time Reference",
1701 cf->current_frame != NULL);
1702 set_menu_sensitivity(main_menu_factory, "/Edit/Mark All Packets",
1703 cf->current_frame != NULL);
1704 set_menu_sensitivity(main_menu_factory, "/Edit/Unmark All Packets",
1705 cf->current_frame != NULL);
1706 set_menu_sensitivity(main_menu_factory, "/View/Collapse All",
1707 cf->current_frame != NULL);
1708 set_menu_sensitivity(tree_view_menu_factory, "/Collapse All",
1709 cf->current_frame != NULL);
1710 set_menu_sensitivity(main_menu_factory, "/View/Expand All",
1711 cf->current_frame != NULL);
1712 set_menu_sensitivity(tree_view_menu_factory, "/Expand All",
1713 cf->current_frame != NULL);
1714 set_menu_sensitivity(main_menu_factory, "/View/Show Packet in New Window",
1715 cf->current_frame != NULL);
1716 set_menu_sensitivity(packet_list_menu_factory, "/Show Packet in New Window",
1717 cf->current_frame != NULL);
1718 set_menu_sensitivity(main_menu_factory, "/Analyze/Follow TCP Stream",
1719 cf->current_frame != NULL ? (cf->edt->pi.ipproto == IP_PROTO_TCP) : FALSE);
1720 set_menu_sensitivity(NULL, "/Follow TCP Stream",
1721 cf->current_frame != NULL ? (cf->edt->pi.ipproto == IP_PROTO_TCP) : FALSE);
1722 set_menu_sensitivity(main_menu_factory, "/Analyze/Decode As...",
1723 cf->current_frame != NULL && decode_as_ok());
1724 set_menu_sensitivity(NULL, "/Decode As...",
1725 cf->current_frame != NULL && decode_as_ok());
1726 set_menu_sensitivity(main_menu_factory, "/View/Name Resolution/Resolve Name",
1727 cf->current_frame != NULL && (g_resolv_flags & RESOLV_ALL_ADDRS) != RESOLV_ALL_ADDRS);
1728 set_menu_sensitivity(tree_view_menu_factory, "/Resolve Name",
1729 cf->current_frame != NULL && (g_resolv_flags & RESOLV_ALL_ADDRS) != RESOLV_ALL_ADDRS);
1730 set_menu_sensitivity(packet_list_menu_factory, "/Apply as Filter",
1731 cf->current_frame != NULL);
1732 set_menu_sensitivity(packet_list_menu_factory, "/Prepare a Filter",
1733 cf->current_frame != NULL);
1735 walk_menu_tree_for_selected_packet(tap_menu_tree_root, cf->current_frame,
1737 packets_bar_update();
1740 /* Enable or disable menu items based on whether a tree row is selected
1741 and, if so, on the properties of the tree row. */
1743 walk_menu_tree_for_selected_tree_row(GList *node, field_info *fi)
1745 gboolean is_enabled;
1747 menu_item_t *node_data = node->data;
1750 * Is this a leaf node or an interior node?
1752 if (node_data->children == NULL) {
1756 * If it has no "selected_tree_row_enabled()" routine,
1757 * leave its enabled/disabled status alone - it
1758 * doesn't depend on whether we have a tree row selected
1759 * or not or on the selected tree row.
1761 * If it has a "selected_tree_row_enabled()" routine,
1762 * call it and set the item's enabled/disabled status
1763 * based on its return value.
1765 if (node_data->selected_tree_row_enabled != NULL)
1766 node_data->enabled = node_data->selected_tree_row_enabled(fi);
1769 * It's an interior node; call
1770 * "walk_menu_tree_for_selected_tree_row()" on all its
1771 * children and, if any of them are enabled, enable
1772 * this node, otherwise disable it.
1774 * XXX - should we just leave all interior nodes enabled?
1775 * Which is a better UI choice?
1778 for (child = node_data->children; child != NULL; child =
1780 if (walk_menu_tree_for_selected_tree_row(child, fi))
1783 node_data->enabled = is_enabled;
1787 * The root node doesn't correspond to a menu tree item; it
1788 * has a null name pointer.
1790 if (node_data->name != NULL) {
1791 set_menu_sensitivity(main_menu_factory, node_data->name,
1792 node_data->enabled);
1794 return node_data->enabled;
1798 set_menus_for_selected_tree_row(capture_file *cf)
1800 gboolean properties;
1803 set_menu_sensitivity(main_menu_factory, "/File/Export/Selected Packet Bytes...",
1804 cf->finfo_selected != NULL);
1805 set_menu_sensitivity(tree_view_menu_factory, "/Export Selected Packet Bytes...",
1806 cf->finfo_selected != NULL);
1807 set_menu_sensitivity(hexdump_menu_factory, "/Export Selected Packet Bytes...",
1808 cf->finfo_selected != NULL);
1810 if (cf->finfo_selected != NULL) {
1811 header_field_info *hfinfo = cf->finfo_selected->hfinfo;
1812 if (hfinfo->parent == -1) {
1813 properties = prefs_is_registered_protocol(hfinfo->abbrev);
1815 properties = prefs_is_registered_protocol(proto_registrar_get_abbrev(hfinfo->parent));
1817 set_menu_sensitivity(main_menu_factory,
1818 "/Go/Go to Corresponding Packet", hfinfo->type == FT_FRAMENUM);
1819 set_menu_sensitivity(tree_view_menu_factory,
1820 "/Go to Corresponding Packet", hfinfo->type == FT_FRAMENUM);
1821 set_menu_sensitivity(main_menu_factory, "/Analyze/Apply as Filter",
1822 proto_can_match_selected(cf->finfo_selected, cf->edt));
1823 set_menu_sensitivity(tree_view_menu_factory, "/Apply as Filter",
1824 proto_can_match_selected(cf->finfo_selected, cf->edt));
1825 set_menu_sensitivity(main_menu_factory, "/Analyze/Prepare a Filter",
1826 proto_can_match_selected(cf->finfo_selected, cf->edt));
1827 set_menu_sensitivity(tree_view_menu_factory, "/Prepare a Filter",
1828 proto_can_match_selected(cf->finfo_selected, cf->edt));
1829 set_menu_sensitivity(tree_view_menu_factory, "/Protocol Preferences...",
1831 set_menu_sensitivity(main_menu_factory, "/View/Expand Tree", cf->finfo_selected->tree_type != -1);
1832 set_menu_sensitivity(tree_view_menu_factory, "/Expand Tree", cf->finfo_selected->tree_type != -1);
1834 set_menu_sensitivity(main_menu_factory,
1835 "/Go/Go to Corresponding Packet", FALSE);
1836 set_menu_sensitivity(tree_view_menu_factory,
1837 "/Go to Corresponding Packet", FALSE);
1838 set_menu_sensitivity(main_menu_factory, "/Analyze/Apply as Filter", FALSE);
1839 set_menu_sensitivity(tree_view_menu_factory, "/Apply as Filter", FALSE);
1840 set_menu_sensitivity(main_menu_factory, "/Analyze/Prepare a Filter", FALSE);
1841 set_menu_sensitivity(tree_view_menu_factory, "/Prepare a Filter", FALSE);
1842 set_menu_sensitivity(tree_view_menu_factory, "/Protocol Preferences...",
1844 set_menu_sensitivity(main_menu_factory, "/View/Expand Tree", FALSE);
1845 set_menu_sensitivity(tree_view_menu_factory, "/Expand Tree", FALSE);
1848 walk_menu_tree_for_selected_tree_row(tap_menu_tree_root, cf->finfo_selected);