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>
40 #include <epan/timestamp.h>
41 #include <epan/ipproto.h>
43 #include "about_dlg.h"
44 #include "capture_dlg.h"
45 #include "color_dlg.h"
46 #include "filter_dlg.h"
47 #include "dlg_utils.h"
51 #include "summary_dlg.h"
52 #include "prefs_dlg.h"
53 #include "packet_win.h"
55 #include "follow_dlg.h"
56 #include "decode_as_dlg.h"
58 #include "supported_protos_dlg.h"
59 #include "proto_dlg.h"
60 #include "proto_hier_stats_dlg.h"
62 #include <epan/plugins.h>
63 #include <epan/epan_dissect.h>
64 #include "compat_macros.h"
66 #include "gtkglobals.h"
69 #include "packet_list.h"
72 #include "../ui_util.h"
73 #include "proto_draw.h"
74 #include "conversations_table.h"
75 #include "hostlist_table.h"
76 #include "simple_dialog.h"
77 #include "packet_history.h"
79 GtkWidget *popup_menu_object;
82 clear_menu_recent_capture_file_cmd_cb(GtkWidget *w, gpointer unused _U_);
84 typedef struct _menu_item {
88 GtkItemFactoryCallback callback;
89 gpointer callback_data;
90 gboolean (*selected_packet_enabled)(frame_data *, epan_dissect_t *);
91 gboolean (*selected_tree_row_enabled)(field_info *);
95 static GList *tap_menu_tree_root = NULL;
98 merge_all_tap_menus(GList *node);
100 #define GTK_MENU_FUNC(a) ((GtkItemFactoryCallback)(a))
102 static void menus_init(void);
103 static void set_menu_sensitivity (GtkItemFactory *, const gchar *, gint);
104 static void main_toolbar_show_cb(GtkWidget *w _U_, gpointer d _U_);
105 static void filter_toolbar_show_cb(GtkWidget *w _U_, gpointer d _U_);
106 static void packet_list_show_cb(GtkWidget *w _U_, gpointer d _U_);
107 static void tree_view_show_cb(GtkWidget *w _U_, gpointer d _U_);
108 static void byte_view_show_cb(GtkWidget *w _U_, gpointer d _U_);
109 static void statusbar_show_cb(GtkWidget *w _U_, gpointer d _U_);
110 static void timestamp_absolute_cb(GtkWidget *w _U_, gpointer d _U_);
111 static void timestamp_absolute_date_cb(GtkWidget *w _U_, gpointer d _U_);
112 static void timestamp_relative_cb(GtkWidget *w _U_, gpointer d _U_);
113 static void timestamp_delta_cb(GtkWidget *w _U_, gpointer d _U_);
114 static void name_resolution_mac_cb(GtkWidget *w _U_, gpointer d _U_);
115 static void name_resolution_network_cb(GtkWidget *w _U_, gpointer d _U_);
116 static void name_resolution_transport_cb(GtkWidget *w _U_, gpointer d _U_);
118 static void auto_scroll_live_cb(GtkWidget *w _U_, gpointer d _U_);
121 /* This is the GtkItemFactoryEntry structure used to generate new menus.
122 Item 1: The menu path. The letter after the underscore indicates an
123 accelerator key once the menu is open.
124 Item 2: The accelerator key for the entry
125 Item 3: The callback function.
126 Item 4: The callback action. This changes the parameters with
127 which the function is called. The default is 0.
128 Item 5: The item type, used to define what kind of an item it is.
129 Here are the possible values:
133 "<Title>" -> create a title item
134 "<Item>" -> create a simple item
135 "<ImageItem>" -> create an item holding an image (gtk2)
136 "<StockItem>" -> create an item holding a stock image (gtk2)
137 "<CheckItem>" -> create a check item
138 "<ToggleItem>" -> create a toggle item
139 "<RadioItem>" -> create a radio item
140 <path> -> path of a radio item to link against
141 "<Separator>" -> create a separator
142 "<Tearoff>" -> create a tearoff separator (gtk2)
143 "<Branch>" -> create an item to hold sub items (optional)
144 "<LastBranch>" -> create a right justified branch
145 Item 6: extra data needed for ImageItem and StockItem (gtk2)
148 /* As a general GUI guideline, we try to follow the Gnome Human Interface Guidelines, which can be found at:
149 http://developer.gnome.org/projects/gup/hig/1.0/index.html
151 Please note: there are some differences between the Gnome HIG menu suggestions and our implementation:
153 File/Open Recent: the Gnome HIG suggests putting the list of recently used files as elements into the File menuitem.
154 As this is ok for only a few items, this will become unhandy for 10 or even more list entries.
155 For this reason, we use a submenu for this.
157 File/Close: the Gnome HIG suggests putting this item just above the Quit item.
158 This results in unintuitive behaviour as both Close and Quit items are very near together.
159 By putting the Close item near the open item(s), it better suggests that it will close the
160 currently opened/captured file only.
165 static GtkItemFactoryEntry menu_items[] =
167 ITEM_FACTORY_ENTRY("/_File", NULL, NULL, 0, "<Branch>", NULL),
168 ITEM_FACTORY_STOCK_ENTRY("/File/_Open...", "<control>O", file_open_cmd_cb,
170 ITEM_FACTORY_ENTRY("/File/Open _Recent", NULL, NULL, 0, "<Branch>", NULL),
171 ITEM_FACTORY_ENTRY("/File/_Merge...", NULL, file_merge_cmd_cb, 0, NULL, NULL),
172 ITEM_FACTORY_STOCK_ENTRY("/File/_Close", "<control>W", file_close_cmd_cb,
174 ITEM_FACTORY_ENTRY("/File/<separator>", NULL, NULL, 0, "<Separator>", NULL),
175 ITEM_FACTORY_STOCK_ENTRY("/File/_Save", "<control>S", file_save_cmd_cb,
177 ITEM_FACTORY_STOCK_ENTRY("/File/Save _As...", "<shift><control>S", file_save_as_cmd_cb,
178 0, GTK_STOCK_SAVE_AS),
179 ITEM_FACTORY_ENTRY("/File/<separator>", NULL, NULL, 0, "<Separator>", NULL),
180 ITEM_FACTORY_ENTRY("/File/_Export", NULL, NULL, 0, "<Branch>", NULL),
181 ITEM_FACTORY_ENTRY("/File/Export/as \"Plain _Text\" file...", NULL, export_text_cmd_cb,
183 ITEM_FACTORY_ENTRY("/File/Export/as \"_PostScript\" file...", NULL, export_ps_cmd_cb,
185 ITEM_FACTORY_ENTRY("/File/Export/as XML - \"P_SML\" (packet summary) file...", NULL, export_psml_cmd_cb,
187 ITEM_FACTORY_ENTRY("/File/Export/as XML - \"P_DML\" (packet details) file...", NULL, export_pdml_cmd_cb,
189 ITEM_FACTORY_ENTRY("/File/Export/<separator>", NULL, NULL, 0, "<Separator>", NULL),
190 ITEM_FACTORY_ENTRY("/File/Export/Selected Packet _Bytes...", "<control>H", savehex_cb,
192 ITEM_FACTORY_ENTRY("/File/<separator>", NULL, NULL, 0, "<Separator>", NULL),
193 ITEM_FACTORY_STOCK_ENTRY("/File/_Print...", "<control>P", file_print_cmd_cb,
195 ITEM_FACTORY_ENTRY("/File/<separator>", NULL, NULL, 0, "<Separator>", NULL),
196 ITEM_FACTORY_STOCK_ENTRY("/File/_Quit", "<control>Q", file_quit_cmd_cb,
198 ITEM_FACTORY_ENTRY("/_Edit", NULL, NULL, 0, "<Branch>", NULL),
200 /* Un-#if this when we actually implement Cut/Copy/Paste. */
201 ITEM_FACTORY_STOCK_ENTRY("/Edit/Cut", "<control>X", NULL,
203 ITEM_FACTORY_STOCK_ENTRY("/Edit/Copy", "<control>C", NULL,
205 ITEM_FACTORY_STOCK_ENTRY("/Edit/Paste", "<control>V", NULL,
207 ITEM_FACTORY_ENTRY("/Edit/<separator>", NULL, NULL, 0, "<Separator>"),
209 ITEM_FACTORY_STOCK_ENTRY("/Edit/_Find Packet...", "<control>F",
210 find_frame_cb, 0, GTK_STOCK_FIND),
211 ITEM_FACTORY_ENTRY("/Edit/Find Ne_xt", "<control>N", find_next_cb, 0, NULL, NULL),
212 ITEM_FACTORY_ENTRY("/Edit/Find Pre_vious", "<control>B", find_previous_cb, 0, NULL, NULL),
213 ITEM_FACTORY_ENTRY("/Edit/<separator>", NULL, NULL, 0, "<Separator>", NULL),
214 ITEM_FACTORY_ENTRY("/Edit/_Time Reference", NULL, NULL, 0, "<Branch>", NULL),
215 ITEM_FACTORY_ENTRY("/Edit/Time Reference/Set Time Reference (toggle)", "<control>T", reftime_frame_cb, REFTIME_TOGGLE, NULL, NULL),
216 ITEM_FACTORY_ENTRY("/Edit/Time Reference/Find Next", NULL, reftime_frame_cb, REFTIME_FIND_NEXT, NULL, NULL),
217 ITEM_FACTORY_ENTRY("/Edit/Time Reference/Find Previous", NULL, reftime_frame_cb, REFTIME_FIND_PREV, NULL, NULL),
218 ITEM_FACTORY_ENTRY("/Edit/_Mark Packet (toggle)", "<control>M", mark_frame_cb,
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/_Back", "<alt>Left",
277 history_back_cb, 0, GTK_STOCK_GO_BACK),
278 ITEM_FACTORY_STOCK_ENTRY("/Go/_Forward", "<alt>Right",
279 history_forward_cb, 0, GTK_STOCK_GO_FORWARD),
280 ITEM_FACTORY_STOCK_ENTRY("/Go/_Go to Packet...", "<control>G",
281 goto_frame_cb, 0, GTK_STOCK_JUMP_TO),
282 ITEM_FACTORY_ENTRY("/Go/Go to _Corresponding Packet", NULL, goto_framenum_cb,
284 ITEM_FACTORY_ENTRY("/Go/<separator>", NULL, NULL, 0, "<Separator>", NULL),
285 ITEM_FACTORY_STOCK_ENTRY("/Go/F_irst Packet", NULL,
286 goto_top_frame_cb, 0, GTK_STOCK_GOTO_TOP),
287 ITEM_FACTORY_STOCK_ENTRY("/Go/_Last Packet", NULL,
288 goto_bottom_frame_cb, 0, GTK_STOCK_GOTO_BOTTOM),
290 ITEM_FACTORY_ENTRY("/_Capture", NULL, NULL, 0, "<Branch>", NULL),
291 ITEM_FACTORY_STOCK_ENTRY("/Capture/_Start...", "<control>K",
292 capture_prep_cb, 0, ETHEREAL_STOCK_CAPTURE_START),
293 ITEM_FACTORY_STOCK_ENTRY("/Capture/S_top", "<control>E", capture_stop_cb,
295 ITEM_FACTORY_ENTRY("/Capture/_Interfaces...", NULL,
296 capture_if_cb, 0, NULL, NULL),
297 ITEM_FACTORY_STOCK_ENTRY("/Capture/_Capture Filters...", NULL, cfilter_dialog_cb,
298 0, ETHEREAL_STOCK_CAPTURE_FILTER),
299 #endif /* HAVE_LIBPCAP */
300 ITEM_FACTORY_ENTRY("/_Analyze", NULL, NULL, 0, "<Branch>", NULL),
301 ITEM_FACTORY_STOCK_ENTRY("/Analyze/_Display Filters...", NULL, dfilter_dialog_cb,
302 0, ETHEREAL_STOCK_DISPLAY_FILTER),
303 ITEM_FACTORY_ENTRY("/Analyze/Appl_y as Filter", NULL, NULL, 0, "<Branch>", NULL),
304 ITEM_FACTORY_ENTRY("/Analyze/Apply as Filter/_Selected", NULL, match_selected_ptree_cb,
305 MATCH_SELECTED_REPLACE|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
306 ITEM_FACTORY_ENTRY("/Analyze/Apply as Filter/_Not Selected", NULL, match_selected_ptree_cb,
307 MATCH_SELECTED_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
308 ITEM_FACTORY_ENTRY("/Analyze/Apply as Filter/... _and Selected", NULL, match_selected_ptree_cb,
309 MATCH_SELECTED_AND|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
310 ITEM_FACTORY_ENTRY("/Analyze/Apply as Filter/... _or Selected", NULL, match_selected_ptree_cb,
311 MATCH_SELECTED_OR|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
312 ITEM_FACTORY_ENTRY("/Analyze/Apply as Filter/... a_nd not Selected", NULL, match_selected_ptree_cb,
313 MATCH_SELECTED_AND_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
314 ITEM_FACTORY_ENTRY("/Analyze/Apply as Filter/... o_r not Selected", NULL, match_selected_ptree_cb,
315 MATCH_SELECTED_OR_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
316 ITEM_FACTORY_ENTRY("/Analyze/_Prepare a Filter", NULL, NULL, 0, "<Branch>", NULL),
317 ITEM_FACTORY_ENTRY("/Analyze/Prepare a Filter/_Selected", NULL, match_selected_ptree_cb,
318 MATCH_SELECTED_REPLACE, NULL, NULL),
319 ITEM_FACTORY_ENTRY("/Analyze/Prepare a Filter/_Not Selected", NULL, match_selected_ptree_cb,
320 MATCH_SELECTED_NOT, NULL, NULL),
321 ITEM_FACTORY_ENTRY("/Analyze/Prepare a Filter/... _and Selected", NULL, match_selected_ptree_cb,
322 MATCH_SELECTED_AND, NULL, NULL),
323 ITEM_FACTORY_ENTRY("/Analyze/Prepare a Filter/... _or Selected", NULL, match_selected_ptree_cb,
324 MATCH_SELECTED_OR, NULL, NULL),
325 ITEM_FACTORY_ENTRY("/Analyze/Prepare a Filter/... a_nd not Selected", NULL, match_selected_ptree_cb,
326 MATCH_SELECTED_AND_NOT, NULL, NULL),
327 ITEM_FACTORY_ENTRY("/Analyze/Prepare a Filter/... o_r not Selected", NULL, match_selected_ptree_cb,
328 MATCH_SELECTED_OR_NOT, NULL, NULL),
329 ITEM_FACTORY_ENTRY("/Analyze/<separator>", NULL, NULL, 0, "<Separator>", NULL),
330 ITEM_FACTORY_ENTRY("/Analyze/_Enabled Protocols...", "<shift><control>R", proto_cb, 0, NULL, NULL),
331 ITEM_FACTORY_ENTRY("/Analyze/Decode _As...", NULL, decode_as_cb,
333 ITEM_FACTORY_ENTRY("/Analyze/_User Specified Decodes...", NULL,
334 decode_show_cb, 0, NULL, NULL),
335 ITEM_FACTORY_ENTRY("/Analyze/<separator>", NULL, NULL, 0, "<Separator>", NULL),
336 ITEM_FACTORY_ENTRY("/Analyze/_Follow TCP Stream", NULL,
337 follow_stream_cb, 0, NULL, NULL),
338 ITEM_FACTORY_ENTRY("/_Statistics", NULL, NULL, 0, "<Branch>", NULL),
339 ITEM_FACTORY_ENTRY("/Statistics/_Summary", NULL, summary_open_cb, 0, NULL, NULL),
340 ITEM_FACTORY_ENTRY("/Statistics/_Protocol Hierarchy", NULL,
341 proto_hier_stats_cb, 0, NULL, NULL),
342 ITEM_FACTORY_ENTRY("/Statistics/Conversations", NULL,
343 init_conversation_notebook_cb, 0, NULL, NULL),
344 ITEM_FACTORY_ENTRY("/Statistics/Endpoints", NULL,
345 init_hostlist_notebook_cb, 0, NULL, NULL),
346 ITEM_FACTORY_ENTRY("/_Help", NULL, NULL, 0, "<Branch>", NULL),
347 ITEM_FACTORY_STOCK_ENTRY("/Help/_Contents", "F1", topic_menu_cb, HELP_CONTENT, GTK_STOCK_HELP),
348 ITEM_FACTORY_ENTRY("/Help/_Supported Protocols", NULL, supported_cb, 0, NULL, NULL),
349 #if (GLIB_MAJOR_VERSION >= 2)
350 #ifdef ETHEREAL_EUG_DIR
351 ITEM_FACTORY_ENTRY("/Help/User's Guide", NULL, url_page_menu_cb, HELP_CONTENT, NULL, NULL),
353 ITEM_FACTORY_ENTRY("/Help/Manual Pages", NULL, NULL, 0, "<Branch>", NULL),
354 ITEM_FACTORY_ENTRY("/Help/Manual Pages/Ethereal", NULL, topic_menu_cb, LOCALPAGE_MAN_ETHEREAL, NULL, NULL),
355 ITEM_FACTORY_ENTRY("/Help/Manual Pages/Ethereal Filter", NULL, topic_menu_cb, LOCALPAGE_MAN_ETHEREAL_FILTER, NULL, NULL),
356 ITEM_FACTORY_ENTRY("/Help/Manual Pages/<separator>", NULL, NULL, 0, "<Separator>", NULL),
357 ITEM_FACTORY_ENTRY("/Help/Manual Pages/Tethereal", NULL, topic_menu_cb, LOCALPAGE_MAN_TETHEREAL, NULL, NULL),
358 ITEM_FACTORY_ENTRY("/Help/Manual Pages/Mergecap", NULL, topic_menu_cb, LOCALPAGE_MAN_MERGECAP, NULL, NULL),
359 ITEM_FACTORY_ENTRY("/Help/Manual Pages/Editcap", NULL, topic_menu_cb, LOCALPAGE_MAN_EDITCAP, NULL, NULL),
360 ITEM_FACTORY_ENTRY("/Help/Manual Pages/Text2pcap", NULL, topic_menu_cb, LOCALPAGE_MAN_TEXT2PCAP, NULL, NULL),
361 ITEM_FACTORY_ENTRY("/Help/Ethereal Online", NULL, NULL, 0, "<Branch>", NULL),
362 ITEM_FACTORY_STOCK_ENTRY("/Help/Ethereal Online/Home Page", NULL, topic_menu_cb, ONLINEPAGE_HOME, GTK_STOCK_HOME),
363 ITEM_FACTORY_ENTRY("/Help/Ethereal Online/Wiki", NULL, topic_menu_cb, ONLINEPAGE_WIKI, NULL, NULL),
364 ITEM_FACTORY_ENTRY("/Help/Ethereal Online/User's Guide", NULL, topic_menu_cb, ONLINEPAGE_USERGUIDE, NULL, NULL),
365 ITEM_FACTORY_ENTRY("/Help/Ethereal Online/FAQ's", NULL, topic_menu_cb, ONLINEPAGE_FAQ, NULL, NULL),
366 ITEM_FACTORY_ENTRY("/Help/Ethereal Online/Downloads", NULL, topic_menu_cb, ONLINEPAGE_DOWNLOAD, NULL, NULL),
367 ITEM_FACTORY_ENTRY("/Help/Ethereal Online/Example Files", NULL, topic_menu_cb, ONLINEPAGE_SAMPLE_FILES, NULL, NULL),
369 ITEM_FACTORY_ENTRY("/Help/<separator>", NULL, NULL, 0, "<Separator>", NULL),
370 ITEM_FACTORY_ENTRY("/Help/_About Ethereal", NULL, about_ethereal_cb,
375 /* calculate the number of menu_items */
376 static int nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
378 /* packet list popup */
379 static GtkItemFactoryEntry packet_list_menu_items[] =
381 ITEM_FACTORY_ENTRY("/Mark Packet (toggle)", NULL, mark_frame_cb, 0, NULL, NULL),
382 ITEM_FACTORY_ENTRY("/Time Reference", NULL, NULL, 0, "<Branch>", NULL),
383 ITEM_FACTORY_ENTRY("/Time Reference/Set Time Reference (toggle)", NULL, reftime_frame_cb, REFTIME_TOGGLE, NULL, NULL),
384 ITEM_FACTORY_ENTRY("/Time Reference/Find Next", NULL, reftime_frame_cb, REFTIME_FIND_NEXT, NULL, NULL),
385 ITEM_FACTORY_ENTRY("/Time Reference/Find Previous", NULL, reftime_frame_cb, REFTIME_FIND_PREV, NULL, NULL),
387 ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
389 ITEM_FACTORY_ENTRY("/Apply as Filter", NULL, NULL, 0, "<Branch>", NULL),
390 ITEM_FACTORY_ENTRY("/Apply as Filter/_Selected", NULL, match_selected_plist_cb,
391 MATCH_SELECTED_REPLACE|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
392 ITEM_FACTORY_ENTRY("/Apply as Filter/_Not Selected", NULL, match_selected_plist_cb,
393 MATCH_SELECTED_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
394 ITEM_FACTORY_ENTRY("/Apply as Filter/... _and Selected", NULL, match_selected_plist_cb,
395 MATCH_SELECTED_AND|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
396 ITEM_FACTORY_ENTRY("/Apply as Filter/... _or Selected", NULL, match_selected_plist_cb,
397 MATCH_SELECTED_OR|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
398 ITEM_FACTORY_ENTRY("/Apply as Filter/... a_nd not Selected", NULL, match_selected_plist_cb,
399 MATCH_SELECTED_AND_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
400 ITEM_FACTORY_ENTRY("/Apply as Filter/... o_r not Selected", NULL, match_selected_plist_cb,
401 MATCH_SELECTED_OR_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
403 ITEM_FACTORY_ENTRY("/Prepare a Filter", NULL, NULL, 0, "<Branch>", NULL),
404 ITEM_FACTORY_ENTRY("/Prepare a Filter/_Selected", NULL, match_selected_plist_cb,
405 MATCH_SELECTED_REPLACE, NULL, NULL),
406 ITEM_FACTORY_ENTRY("/Prepare a Filter/_Not Selected", NULL, match_selected_plist_cb,
407 MATCH_SELECTED_NOT, NULL, NULL),
408 ITEM_FACTORY_ENTRY("/Prepare a Filter/... _and Selected", NULL, match_selected_plist_cb,
409 MATCH_SELECTED_AND, NULL, NULL),
410 ITEM_FACTORY_ENTRY("/Prepare a Filter/... _or Selected", NULL, match_selected_plist_cb,
411 MATCH_SELECTED_OR, NULL, NULL),
412 ITEM_FACTORY_ENTRY("/Prepare a Filter/... a_nd not Selected", NULL, match_selected_plist_cb,
413 MATCH_SELECTED_AND_NOT, NULL, NULL),
414 ITEM_FACTORY_ENTRY("/Prepare a Filter/... o_r not Selected", NULL, match_selected_plist_cb,
415 MATCH_SELECTED_OR_NOT, NULL, NULL),
417 ITEM_FACTORY_ENTRY("/Follow TCP Stream", NULL, follow_stream_cb,
420 ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
422 ITEM_FACTORY_ENTRY("/Decode As...", NULL, decode_as_cb, 0, NULL, NULL),
423 ITEM_FACTORY_ENTRY("/Print...", NULL, file_print_selected_cmd_cb, 0, NULL, NULL),
424 ITEM_FACTORY_ENTRY("/Show Packet in New Window", NULL, new_window_cb,
428 static GtkItemFactoryEntry tree_view_menu_items[] =
430 ITEM_FACTORY_ENTRY("/Expand All", NULL, expand_all_cb, 0, NULL, NULL),
431 ITEM_FACTORY_ENTRY("/Collapse All", NULL, collapse_all_cb, 0, NULL, NULL),
433 ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
435 ITEM_FACTORY_ENTRY("/Apply as Filter", NULL, NULL, 0, "<Branch>", NULL),
436 ITEM_FACTORY_ENTRY("/Apply as Filter/_Selected", NULL, match_selected_ptree_cb,
437 MATCH_SELECTED_REPLACE|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
438 ITEM_FACTORY_ENTRY("/Apply as Filter/_Not Selected", NULL, match_selected_ptree_cb,
439 MATCH_SELECTED_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
440 ITEM_FACTORY_ENTRY("/Apply as Filter/... _and Selected", NULL, match_selected_ptree_cb,
441 MATCH_SELECTED_AND|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
442 ITEM_FACTORY_ENTRY("/Apply as Filter/... _or Selected", NULL, match_selected_ptree_cb,
443 MATCH_SELECTED_OR|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
444 ITEM_FACTORY_ENTRY("/Apply as Filter/... a_nd not Selected", NULL, match_selected_ptree_cb,
445 MATCH_SELECTED_AND_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
446 ITEM_FACTORY_ENTRY("/Apply as Filter/... o_r not Selected", NULL, match_selected_ptree_cb,
447 MATCH_SELECTED_OR_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
449 ITEM_FACTORY_ENTRY("/Prepare a Filter", NULL, NULL, 0, "<Branch>", NULL),
450 ITEM_FACTORY_ENTRY("/Prepare a Filter/_Selected", NULL, match_selected_ptree_cb,
451 MATCH_SELECTED_REPLACE, NULL, NULL),
452 ITEM_FACTORY_ENTRY("/Prepare a Filter/_Not Selected", NULL, match_selected_ptree_cb,
453 MATCH_SELECTED_NOT, NULL, NULL),
454 ITEM_FACTORY_ENTRY("/Prepare a Filter/... _and Selected", NULL, match_selected_ptree_cb,
455 MATCH_SELECTED_AND, NULL, NULL),
456 ITEM_FACTORY_ENTRY("/Prepare a Filter/... _or Selected", NULL, match_selected_ptree_cb,
457 MATCH_SELECTED_OR, NULL, NULL),
458 ITEM_FACTORY_ENTRY("/Prepare a Filter/... a_nd not Selected", NULL, match_selected_ptree_cb,
459 MATCH_SELECTED_AND_NOT, NULL, NULL),
460 ITEM_FACTORY_ENTRY("/Prepare a Filter/... o_r not Selected", NULL, match_selected_ptree_cb,
461 MATCH_SELECTED_OR_NOT, NULL, NULL),
463 ITEM_FACTORY_ENTRY("/Follow TCP Stream", NULL, follow_stream_cb,
466 ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
468 ITEM_FACTORY_STOCK_ENTRY("/Wiki Protocol Page", NULL, selected_ptree_info_cb,
470 ITEM_FACTORY_STOCK_ENTRY("/Filter Field Reference", NULL, selected_ptree_ref_cb,
472 ITEM_FACTORY_ENTRY("/Protocol Preferences...", NULL, properties_cb,
474 ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
475 ITEM_FACTORY_ENTRY("/Decode As...", NULL, decode_as_cb, 0, NULL, NULL),
476 ITEM_FACTORY_ENTRY("/_Resolve Name", NULL, resolve_name_cb, 0, NULL, NULL),
477 ITEM_FACTORY_ENTRY("/_Go to Corresponding Packet", NULL, goto_framenum_cb, 0, NULL, NULL),
480 static GtkItemFactoryEntry hexdump_menu_items[] =
482 ITEM_FACTORY_ENTRY("/Copy", NULL, copy_hex_cb,
484 ITEM_FACTORY_ENTRY("/Export Selected Packet Bytes...", NULL, savehex_cb,
488 static int initialize = TRUE;
489 static GtkItemFactory *main_menu_factory = NULL;
490 static GtkItemFactory *packet_list_menu_factory = NULL;
491 static GtkItemFactory *tree_view_menu_factory = NULL;
492 static GtkItemFactory *hexdump_menu_factory = NULL;
494 static GSList *popup_menu_list = NULL;
496 static GtkAccelGroup *grp;
499 main_menu_new(GtkAccelGroup ** table) {
502 grp = gtk_accel_group_new();
507 menubar = main_menu_factory->widget;
521 packet_list_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
522 popup_menu_object = gtk_menu_new();
523 gtk_item_factory_create_items_ac(packet_list_menu_factory, sizeof(packet_list_menu_items)/sizeof(packet_list_menu_items[0]), packet_list_menu_items, popup_menu_object, 2);
524 OBJECT_SET_DATA(popup_menu_object, PM_PACKET_LIST_KEY,
525 packet_list_menu_factory->widget);
526 popup_menu_list = g_slist_append((GSList *)popup_menu_list, packet_list_menu_factory);
528 tree_view_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
529 gtk_item_factory_create_items_ac(tree_view_menu_factory, sizeof(tree_view_menu_items)/sizeof(tree_view_menu_items[0]), tree_view_menu_items, popup_menu_object, 2);
530 OBJECT_SET_DATA(popup_menu_object, PM_TREE_VIEW_KEY,
531 tree_view_menu_factory->widget);
532 popup_menu_list = g_slist_append((GSList *)popup_menu_list, tree_view_menu_factory);
534 hexdump_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
535 gtk_item_factory_create_items_ac(hexdump_menu_factory, sizeof(hexdump_menu_items)/sizeof(hexdump_menu_items[0]), hexdump_menu_items, popup_menu_object, 2);
536 OBJECT_SET_DATA(popup_menu_object, PM_HEXDUMP_KEY,
537 hexdump_menu_factory->widget);
538 popup_menu_list = g_slist_append((GSList *)popup_menu_list, hexdump_menu_factory);
541 main_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", grp);
542 gtk_item_factory_create_items_ac(main_menu_factory, nmenu_items, menu_items, NULL, 2);
544 merge_all_tap_menus(tap_menu_tree_root);
546 /* Initialize enabled/disabled state of menu items */
547 set_menus_for_unsaved_capture_file(FALSE);
548 set_menus_for_capture_file(FALSE);
550 /* Un-#if this when we actually implement Cut/Copy/Paste.
551 Then make sure you enable them when they can be done. */
552 set_menu_sensitivity(main_menu_factory, "/Edit/Cut", FALSE);
553 set_menu_sensitivity(main_menu_factory, "/Edit/Copy", FALSE);
554 set_menu_sensitivity(main_menu_factory, "/Edit/Paste", FALSE);
557 set_menus_for_captured_packets(FALSE);
558 set_menus_for_selected_packet(&cfile);
559 set_menus_for_selected_tree_row(&cfile);
561 /* init with an empty recent files list */
562 clear_menu_recent_capture_file_cmd_cb(NULL, NULL);
567 gint tap_menu_item_add_compare(gconstpointer a, gconstpointer b)
570 ((const menu_item_t *) a)->name,
571 ((const menu_item_t *) b)->name);
575 /* add a menuitem below the current node */
576 GList * tap_menu_item_add(
579 GtkItemFactoryCallback callback,
580 gboolean (*selected_packet_enabled)(frame_data *, epan_dissect_t *),
581 gboolean (*selected_tree_row_enabled)(field_info *),
582 gpointer callback_data,
589 child = g_malloc(sizeof (menu_item_t));
590 child->group = group;
592 child->callback = callback;
593 child->selected_packet_enabled = selected_packet_enabled;
594 child->selected_tree_row_enabled = selected_tree_row_enabled;
595 child->callback_data = callback_data;
596 child->enabled = FALSE;
597 child->children = NULL;
599 /* insert the new child node into the parent */
600 curr = curnode->data;
601 curr->children = g_list_insert_sorted(curr->children, child, tap_menu_item_add_compare);
603 /* return the new node */
604 /* XXX: improve this */
605 return g_list_find(curr->children, child);
609 * Add a new menu item for a tap.
610 * This must be called after we've created the main menu, so it can't
611 * be called from the routine that registers taps - we have to introduce
612 * another per-tap registration routine.
614 * "callback" gets called when the menu item is selected; it should do
615 * the work of creating the tap window.
617 * "selected_packet_enabled" gets called by "set_menus_for_selected_packet()";
618 * it's passed a Boolean that's TRUE if a packet is selected and FALSE
619 * otherwise, and should return TRUE if the tap will work now (which
620 * might depend on whether a packet is selected and, if one is, on the
621 * packet) and FALSE if not.
623 * "selected_tree_row_enabled" gets called by
624 * "set_menus_for_selected_tree_row()"; it's passed a Boolean that's TRUE if
625 * a protocol tree row is selected and FALSE otherwise, and should return
626 * TRUE if the tap will work now (which might depend on whether a tree row
627 * is selected and, if one is, on the tree row) and FALSE if not.
630 register_tap_menu_item(
632 REGISTER_TAP_GROUP_E group,
633 GtkItemFactoryCallback callback,
634 gboolean (*selected_packet_enabled)(frame_data *, epan_dissect_t *),
635 gboolean (*selected_tree_row_enabled)(field_info *),
636 gpointer callback_data)
638 /*static const char toolspath[] = "/Statistics/";*/
648 * The menu path must be relative.
650 g_assert(*name != '/');
653 case(REGISTER_TAP_GROUP_GENERIC): toolspath = "/Statistics/"; break;
654 case(REGISTER_TAP_GROUP_CONVERSATION_LIST): toolspath = "/Statistics/_Conversation List/"; break;
655 case(REGISTER_TAP_GROUP_ENDPOINT_LIST): toolspath = "/Statistics/_Endpoint List/"; break;
656 case(REGISTER_TAP_GROUP_RESPONSE_TIME): toolspath = "/Statistics/Service _Response Time/"; break;
657 case(REGISTER_TAP_GROUP_NONE): toolspath = "/Statistics/"; break;
663 /* add the (empty) root node, if not already done */
664 if(tap_menu_tree_root == NULL) {
665 child = g_malloc0(sizeof (menu_item_t));
666 tap_menu_tree_root = g_list_append(NULL, child);
670 * Create any submenus required.
672 curnode = tap_menu_tree_root;
674 while ((p = strchr(p, '/')) != NULL) {
676 * OK, everything between "name" and "p" is
677 * a menu relative subtree into which the menu item
680 * Construct the absolute path name of that subtree.
682 menupathlen = strlen(toolspath) + 1 + (p - name);
683 menupath = g_malloc(menupathlen);
684 strcpy(menupath, toolspath);
685 strncat(menupath, name, p - name);
688 * Does there exist an entry with that path at this
689 * level of the Analyze menu tree?
691 child = curnode->data;
692 for (childnode = child->children; childnode != NULL; childnode = childnode->next) {
693 child = childnode->data;
694 if (strcmp(child->name, menupath) == 0)
697 if (childnode == NULL) {
699 * No. Create such an item as a subtree, and
700 * add it to the Tools menu tree.
702 childnode = tap_menu_item_add(
703 menupath, group, NULL, NULL ,NULL, NULL, curnode);
706 * Yes. We don't need this "menupath" any longer.
713 * Skip over the '/' we found.
719 * Construct the main menu path for the menu item.
721 menupathlen = strlen(toolspath) + 1 + strlen(name);
722 menupath = g_malloc(menupathlen);
723 strcpy(menupath, toolspath);
724 strcat(menupath, name);
727 * Construct an item factory entry for the item, and add it to
731 menupath, group, callback,
732 selected_packet_enabled, selected_tree_row_enabled,
733 callback_data, curnode);
737 guint merge_tap_menus_layered(GList *node, gint group) {
738 GtkItemFactoryEntry *entry;
741 menu_item_t *node_data = node->data;
744 * Is this a leaf node or an interior node?
746 if (node_data->children == NULL) {
752 * The root node doesn't correspond to a menu tree item; it
753 * has a null name pointer.
755 if (node_data->name != NULL && group == node_data->group) {
756 entry = g_malloc0(sizeof (GtkItemFactoryEntry));
757 entry->path = node_data->name;
758 entry->callback = node_data->callback;
759 gtk_item_factory_create_item(main_menu_factory, entry, node_data->callback_data, 2);
760 set_menu_sensitivity(main_menu_factory, node_data->name, FALSE); /* no capture file yet */
765 * It's an interior node; call
766 * "merge_tap_menus_layered()" on all its children
770 * The root node doesn't correspond to a menu tree item; it
771 * has a null name pointer.
773 if (node_data->name != NULL && group == node_data->group) {
774 entry = g_malloc0(sizeof (GtkItemFactoryEntry));
775 entry->path = node_data->name;
776 entry->item_type = "<Branch>";
777 gtk_item_factory_create_item(main_menu_factory, entry,
779 set_menu_sensitivity(main_menu_factory, node_data->name,
780 FALSE); /* no children yet */
784 for (child = node_data->children; child != NULL; child =
786 added += merge_tap_menus_layered(child, group);
794 void merge_all_tap_menus(GList *node) {
795 GtkItemFactoryEntry *entry;
797 entry = g_malloc0(sizeof (GtkItemFactoryEntry));
798 entry->item_type = "<Separator>";
799 entry->path = "/Statistics/";
802 * merge only the menu items of the specific group,
803 * and then append a seperator
805 if (merge_tap_menus_layered(node, REGISTER_TAP_GROUP_GENERIC)) {
806 gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);
808 if (merge_tap_menus_layered(node, REGISTER_TAP_GROUP_CONVERSATION_LIST)) {
809 /*gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);*/
811 if (merge_tap_menus_layered(node, REGISTER_TAP_GROUP_ENDPOINT_LIST)) {
812 /*gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);*/
814 if (merge_tap_menus_layered(node, REGISTER_TAP_GROUP_RESPONSE_TIME)) {
815 gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);
817 if (merge_tap_menus_layered(node, REGISTER_TAP_GROUP_NONE)) {
818 /*gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);*/
825 * Enable/disable menu sensitivity.
828 set_menu_sensitivity(GtkItemFactory *ifactory, const gchar *path, gint val)
831 GtkWidget *menu_item;
836 /* the underscore character regularly confuses things, as it will prevent finding
837 * the menu_item, so it has to be removed first */
838 dup = g_strdup(path);
849 if (ifactory == NULL) {
851 * Do it for all pop-up menus.
853 for (menu_list = popup_menu_list; menu_list != NULL;
854 menu_list = g_slist_next(menu_list))
855 set_menu_sensitivity(menu_list->data, dup, val);
858 * Do it for that particular menu.
860 if ((menu_item = gtk_item_factory_get_widget(ifactory, dup)) != NULL) {
861 if (GTK_IS_MENU(menu_item)) {
863 * "dup" refers to a submenu; "gtk_item_factory_get_widget()"
864 * gets the menu, not the item that, when selected, pops up
867 * We have to change the latter item's sensitivity, so that
868 * it shows up normally if sensitive and grayed-out if
871 menu_item = gtk_menu_get_attach_widget(GTK_MENU(menu_item));
873 gtk_widget_set_sensitive(menu_item, val);
875 /* be sure this menu item *is* existing */
876 g_assert_not_reached();
884 set_menu_object_data_meat(GtkItemFactory *ifactory, gchar *path, gchar *key, gpointer data)
886 GtkWidget *menu = NULL;
888 if ((menu = gtk_item_factory_get_widget(ifactory, path)) != NULL)
889 OBJECT_SET_DATA(menu, key, data);
893 set_menu_object_data (gchar *path, gchar *key, gpointer data) {
894 GSList *menu_list = popup_menu_list;
895 gchar *shortpath = strrchr(path, '/');
897 set_menu_object_data_meat(main_menu_factory, path, key, data);
898 while (menu_list != NULL) {
899 set_menu_object_data_meat(menu_list->data, shortpath, key, data);
900 menu_list = g_slist_next(menu_list);
905 /* Recently used capture files submenu:
906 * Submenu containing the recently used capture files.
907 * The capture filenames are always kept with the absolute path, to be independant
908 * of the current path.
909 * They are only stored inside the labels of the submenu (no separate list). */
911 #define MENU_RECENT_FILES_PATH "/File/Open Recent"
912 #define MENU_RECENT_FILES_KEY "Recent File Name"
915 update_menu_recent_capture_file1(GtkWidget *widget, gpointer cnt) {
916 gchar *widget_cf_name;
918 widget_cf_name = OBJECT_GET_DATA(widget, MENU_RECENT_FILES_KEY);
920 /* if this menu item is a file, count it */
921 if (widget_cf_name) {
927 /* update the menu */
929 update_menu_recent_capture_file(GtkWidget *submenu_recent_files) {
932 gtk_container_foreach(GTK_CONTAINER(submenu_recent_files),
933 update_menu_recent_capture_file1, &cnt);
935 /* make parent menu item sensitive only, if we have any valid files in the list */
936 set_menu_sensitivity(main_menu_factory, MENU_RECENT_FILES_PATH, cnt);
940 /* remove the capture filename from the "Recent Files" menu */
942 remove_menu_recent_capture_file(GtkWidget *widget, gpointer unused _U_) {
943 GtkWidget *submenu_recent_files;
944 gchar *widget_cf_name;
947 widget_cf_name = OBJECT_GET_DATA(widget, MENU_RECENT_FILES_KEY);
948 g_free(widget_cf_name);
950 /* get the submenu container item */
951 submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
953 /* XXX: is this all we need to do, to free the menu item and its label?
954 The reference count of widget will go to 0, so it'll be freed;
955 will that free the label? */
956 gtk_container_remove(GTK_CONTAINER(submenu_recent_files), widget);
960 /* callback, if the user pushed the <Clear File List> item */
962 clear_menu_recent_capture_file_cmd_cb(GtkWidget *w _U_, gpointer unused _U_) {
963 GtkWidget *submenu_recent_files;
966 submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
968 gtk_container_foreach(GTK_CONTAINER(submenu_recent_files),
969 remove_menu_recent_capture_file, NULL);
971 update_menu_recent_capture_file(submenu_recent_files);
975 /* callback, if the user pushed a recent file submenu item */
977 menu_open_recent_file_cmd(GtkWidget *w)
979 GtkWidget *submenu_recent_files;
980 GtkWidget *menu_item_child;
984 submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
986 /* get capture filename from the menu item label */
987 menu_item_child = (GTK_BIN(w))->child;
988 gtk_label_get(GTK_LABEL(menu_item_child), &cf_name);
990 /* open and read the capture file (this will close an existing file) */
991 if ((err = cf_open(cf_name, FALSE, &cfile)) == 0) {
994 /* the capture file isn't existing any longer, remove menu item */
995 /* XXX: ask user to remove item, it's maybe only a temporary problem */
996 remove_menu_recent_capture_file(w, NULL);
999 update_menu_recent_capture_file(submenu_recent_files);
1002 static void menu_open_recent_file_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
1006 /* save file first */
1007 file_save_as_cmd(after_save_open_recent_file, data);
1011 menu_open_recent_file_cmd(data);
1013 case(ESD_BTN_CANCEL):
1016 g_assert_not_reached();
1021 menu_open_recent_file_cmd_cb(GtkWidget *widget, gpointer data _U_) {
1025 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
1026 /* user didn't saved his current file, ask him */
1027 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_YES_NO_CANCEL,
1028 PRIMARY_TEXT_START "Save capture file before opening a new one?" PRIMARY_TEXT_END "\n\n"
1029 "If you open a new capture file without saving, your current capture data will be discarded.");
1030 simple_dialog_set_cb(dialog, menu_open_recent_file_answered_cb, widget);
1032 /* unchanged file */
1033 menu_open_recent_file_cmd(widget);
1037 /* add the capture filename (with an absolute path) to the "Recent Files" menu */
1039 add_menu_recent_capture_file_absolute(gchar *cf_name) {
1040 GtkWidget *submenu_recent_files;
1041 GList *menu_item_list;
1043 gchar *widget_cf_name;
1044 gchar *normalized_cf_name;
1045 GtkWidget *menu_item;
1050 normalized_cf_name = g_strdup(cf_name);
1052 /* replace all slashes by backslashes */
1053 g_strdelimit(normalized_cf_name, "/", '\\');
1056 /* get the submenu container item */
1057 submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
1059 /* convert container to a GList */
1060 menu_item_list = gtk_container_children(GTK_CONTAINER(submenu_recent_files));
1062 /* iterate through list items of menu_item_list,
1063 * removing special items, a maybe duplicate entry and every item above count_max */
1065 for (li = g_list_first(menu_item_list); li; li = li->next, cnt++) {
1066 /* get capture filename */
1067 menu_item = GTK_WIDGET(li->data);
1068 widget_cf_name = OBJECT_GET_DATA(menu_item, MENU_RECENT_FILES_KEY);
1070 /* if this element string is one of our special items (seperator, ...) or
1071 * already in the list or
1072 * this element is above maximum count (too old), remove it */
1073 if (!widget_cf_name ||
1075 /* do a case insensitive compare on win32 */
1076 #if GLIB_MAJOR_VERSION < 2
1077 g_strncasecmp(widget_cf_name, normalized_cf_name, 1000) == 0 ||
1079 g_ascii_strncasecmp(widget_cf_name, normalized_cf_name, 1000) == 0 ||
1082 /* do a case sensitive compare on unix */
1083 strncmp(widget_cf_name, normalized_cf_name, 1000) == 0 ||
1085 cnt >= prefs.gui_recent_files_count_max) {
1086 remove_menu_recent_capture_file(li->data, NULL);
1091 g_list_free(menu_item_list);
1093 /* add new item at latest position */
1094 menu_item = gtk_menu_item_new_with_label(normalized_cf_name);
1095 OBJECT_SET_DATA(menu_item, MENU_RECENT_FILES_KEY, normalized_cf_name);
1096 gtk_menu_prepend (GTK_MENU(submenu_recent_files), menu_item);
1097 SIGNAL_CONNECT_OBJECT(GTK_OBJECT(menu_item), "activate",
1098 menu_open_recent_file_cmd_cb, (GtkObject *) menu_item);
1099 gtk_widget_show (menu_item);
1101 /* add seperator at last position */
1102 menu_item = gtk_menu_item_new();
1103 gtk_menu_append (GTK_MENU(submenu_recent_files), menu_item);
1104 gtk_widget_show (menu_item);
1106 /* add new "clear list" item at last position */
1107 #if GTK_MAJOR_VERSION < 2
1108 menu_item = gtk_menu_item_new_with_label("<Clear File List>");
1110 menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_CLEAR, NULL);
1112 gtk_menu_append (GTK_MENU(submenu_recent_files), menu_item);
1113 SIGNAL_CONNECT_OBJECT(GTK_OBJECT(menu_item), "activate",
1114 clear_menu_recent_capture_file_cmd_cb, (GtkObject *) menu_item);
1115 gtk_widget_show (menu_item);
1117 update_menu_recent_capture_file(submenu_recent_files);
1121 /* add the capture filename to the "Recent Files" menu */
1122 /* (will change nothing, if this filename is already in the menu) */
1124 add_menu_recent_capture_file(gchar *cf_name) {
1129 /* if this filename is an absolute path, we can use it directly */
1130 if (g_path_is_absolute(cf_name)) {
1131 add_menu_recent_capture_file_absolute(cf_name);
1135 /* this filename is not an absolute path, prepend the current dir */
1136 curr = g_get_current_dir();
1137 absolute = g_strdup_printf("%s%s%s", curr, G_DIR_SEPARATOR_S, cf_name);
1138 add_menu_recent_capture_file_absolute(absolute);
1144 /* write all capture filenames of the menu to the user's recent file */
1146 menu_recent_file_write_all(FILE *rf) {
1147 GtkWidget *submenu_recent_files;
1153 submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
1155 /* we have to iterate backwards through the children's list,
1156 * so we get the latest item last in the file.
1157 * (don't use gtk_container_foreach() here, it will return the wrong iteration order) */
1158 children = gtk_container_children(GTK_CONTAINER(submenu_recent_files));
1159 child = g_list_last(children);
1160 while(child != NULL) {
1161 /* get capture filename from the menu item label */
1162 cf_name = OBJECT_GET_DATA(child->data, MENU_RECENT_FILES_KEY);
1164 fprintf (rf, RECENT_KEY_CAPTURE_FILE ": %s\n", cf_name);
1167 child = g_list_previous(child);
1170 g_list_free(children);
1175 main_toolbar_show_cb(GtkWidget *w _U_, gpointer d _U_)
1178 /* save current setting in recent */
1179 recent.main_toolbar_show = GTK_CHECK_MENU_ITEM(w)->active;
1181 main_widgets_show_or_hide();
1186 filter_toolbar_show_cb(GtkWidget *w _U_, gpointer d _U_)
1189 /* save current setting in recent */
1190 recent.filter_toolbar_show = GTK_CHECK_MENU_ITEM(w)->active;
1192 main_widgets_show_or_hide();
1197 packet_list_show_cb(GtkWidget *w _U_, gpointer d _U_)
1200 /* save current setting in recent */
1201 recent.packet_list_show = GTK_CHECK_MENU_ITEM(w)->active;
1203 main_widgets_show_or_hide();
1208 tree_view_show_cb(GtkWidget *w _U_, gpointer d _U_)
1211 /* save current setting in recent */
1212 recent.tree_view_show = GTK_CHECK_MENU_ITEM(w)->active;
1214 main_widgets_show_or_hide();
1219 byte_view_show_cb(GtkWidget *w _U_, gpointer d _U_)
1222 /* save current setting in recent */
1223 recent.byte_view_show = GTK_CHECK_MENU_ITEM(w)->active;
1225 main_widgets_show_or_hide();
1230 statusbar_show_cb(GtkWidget *w _U_, gpointer d _U_)
1233 /* save current setting in recent */
1234 recent.statusbar_show = GTK_CHECK_MENU_ITEM(w)->active;
1236 main_widgets_show_or_hide();
1241 timestamp_absolute_cb(GtkWidget *w _U_, gpointer d _U_)
1243 if (recent.gui_time_format != TS_ABSOLUTE) {
1244 set_timestamp_setting(TS_ABSOLUTE);
1245 recent.gui_time_format = TS_ABSOLUTE;
1246 change_time_formats(&cfile);
1251 timestamp_absolute_date_cb(GtkWidget *w _U_, gpointer d _U_)
1253 if (recent.gui_time_format != TS_ABSOLUTE_WITH_DATE) {
1254 set_timestamp_setting(TS_ABSOLUTE_WITH_DATE);
1255 recent.gui_time_format = TS_ABSOLUTE_WITH_DATE;
1256 change_time_formats(&cfile);
1261 timestamp_relative_cb(GtkWidget *w _U_, gpointer d _U_)
1263 if (recent.gui_time_format != TS_RELATIVE) {
1264 set_timestamp_setting(TS_RELATIVE);
1265 recent.gui_time_format = TS_RELATIVE;
1266 change_time_formats(&cfile);
1271 timestamp_delta_cb(GtkWidget *w _U_, gpointer d _U_)
1273 if (recent.gui_time_format != TS_DELTA) {
1274 set_timestamp_setting(TS_DELTA);
1275 recent.gui_time_format = TS_DELTA;
1276 change_time_formats(&cfile);
1281 menu_name_resolution_changed(void)
1283 GtkWidget *menu = NULL;
1285 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Name Resolution/Enable for MAC Layer");
1286 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), g_resolv_flags & RESOLV_MAC);
1288 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Name Resolution/Enable for Network Layer");
1289 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), g_resolv_flags & RESOLV_NETWORK);
1291 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Name Resolution/Enable for Transport Layer");
1292 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), g_resolv_flags & RESOLV_TRANSPORT);
1296 name_resolution_mac_cb(GtkWidget *w _U_, gpointer d _U_)
1298 if (GTK_CHECK_MENU_ITEM(w)->active) {
1299 g_resolv_flags |= RESOLV_MAC;
1301 g_resolv_flags &= ~RESOLV_MAC;
1306 name_resolution_network_cb(GtkWidget *w _U_, gpointer d _U_)
1308 if (GTK_CHECK_MENU_ITEM(w)->active) {
1309 g_resolv_flags |= RESOLV_NETWORK;
1311 g_resolv_flags &= ~RESOLV_NETWORK;
1316 name_resolution_transport_cb(GtkWidget *w _U_, gpointer d _U_)
1318 if (GTK_CHECK_MENU_ITEM(w)->active) {
1319 g_resolv_flags |= RESOLV_TRANSPORT;
1321 g_resolv_flags &= ~RESOLV_TRANSPORT;
1327 auto_scroll_live_cb(GtkWidget *w _U_, gpointer d _U_)
1329 auto_scroll_live = GTK_CHECK_MENU_ITEM(w)->active;
1333 /* the recent file read has finished, update the menu corresponding */
1335 menu_recent_read_finished(void) {
1336 GtkWidget *menu = NULL;
1338 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Main Toolbar");
1339 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.main_toolbar_show);
1341 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Filter Toolbar");
1342 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.filter_toolbar_show);
1344 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Statusbar");
1345 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.statusbar_show);
1347 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Packet List");
1348 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.packet_list_show);
1350 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Packet Details");
1351 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.tree_view_show);
1353 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Packet Bytes");
1354 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.byte_view_show);
1356 menu_name_resolution_changed();
1359 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Auto Scroll in Live Capture");
1360 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), auto_scroll_live);
1363 main_widgets_rearrange();
1365 /* don't change the time format, if we had a command line value */
1366 if (get_timestamp_setting() != TS_NOT_SET) {
1367 recent.gui_time_format = get_timestamp_setting();
1370 switch(recent.gui_time_format) {
1372 menu = gtk_item_factory_get_widget(main_menu_factory,
1373 "/View/Time Display Format/Time of Day");
1374 /* set_active will not trigger the callback when activating an active item! */
1375 recent.gui_time_format = -1;
1376 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), FALSE);
1377 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
1379 case(TS_ABSOLUTE_WITH_DATE):
1380 menu = gtk_item_factory_get_widget(main_menu_factory,
1381 "/View/Time Display Format/Date and Time of Day");
1382 recent.gui_time_format = -1;
1383 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
1386 menu = gtk_item_factory_get_widget(main_menu_factory,
1387 "/View/Time Display Format/Seconds Since Beginning of Capture");
1388 recent.gui_time_format = -1;
1389 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
1392 menu = gtk_item_factory_get_widget(main_menu_factory,
1393 "/View/Time Display Format/Seconds Since Previous Packet");
1394 recent.gui_time_format = -1;
1395 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
1398 g_assert_not_reached();
1404 popup_menu_handler(GtkWidget *widget, GdkEvent *event, gpointer data)
1406 GtkWidget *menu = (GtkWidget *)data;
1407 GdkEventButton *event_button = NULL;
1410 if(widget == NULL || event == NULL || data == NULL) {
1415 * If we ever want to make the menu differ based on what row
1416 * and/or column we're above, we'd use "eth_clist_get_selection_info()"
1417 * to find the row and column number for the coordinates; a CTree is,
1418 * I guess, like a CList with one column(?) and the expander widget
1421 /* Check if we are on packet_list object */
1422 if (widget == OBJECT_GET_DATA(popup_menu_object, E_MPACKET_LIST_KEY)) {
1423 if (packet_list_get_event_row_column(widget, (GdkEventButton *)event,
1425 OBJECT_SET_DATA(popup_menu_object, E_MPACKET_LIST_ROW_KEY,
1426 GINT_TO_POINTER(row));
1427 OBJECT_SET_DATA(popup_menu_object, E_MPACKET_LIST_COL_KEY,
1428 GINT_TO_POINTER(column));
1429 packet_list_set_selected_row(row);
1433 /* Check if we are on tree_view object */
1434 if (widget == tree_view) {
1435 tree_view_select(widget, (GdkEventButton *) event);
1438 /* Check if we are on byte_view object */
1439 if(widget == get_notebook_bv_ptr(byte_nb_ptr)) {
1440 byte_view_select(widget, (GdkEventButton *) event);
1443 /* context menu handler (but the byte view notebook pages have their own handler) */
1444 if(event->type == GDK_BUTTON_PRESS && widget != byte_nb_ptr) {
1445 event_button = (GdkEventButton *) event;
1447 /* To qoute the "Gdk Event Structures" doc:
1448 * "Normally button 1 is the left mouse button, 2 is the middle button, and 3 is the right button" */
1449 if(event_button->button == 3) {
1450 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
1451 event_button->button,
1452 event_button->time);
1453 SIGNAL_EMIT_STOP_BY_NAME(widget, "button_press_event");
1457 #if GTK_MAJOR_VERSION >= 2
1458 /* GDK_2BUTTON_PRESS is a doubleclick -> expand/collapse tree row */
1459 /* GTK version 1 seems to be doing this automatically */
1460 if (widget == tree_view && event->type == GDK_2BUTTON_PRESS) {
1463 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget),
1464 (gint) (((GdkEventButton *)event)->x),
1465 (gint) (((GdkEventButton *)event)->y),
1466 &path, NULL, NULL, NULL))
1468 if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(widget), path))
1469 gtk_tree_view_collapse_row(GTK_TREE_VIEW(widget), path);
1471 gtk_tree_view_expand_row(GTK_TREE_VIEW(widget), path,
1473 gtk_tree_path_free(path);
1480 /* Enable or disable menu items based on whether you have a capture file
1481 you've finished reading. */
1483 set_menus_for_capture_file(gboolean have_capture_file)
1485 set_menu_sensitivity(main_menu_factory, "/File/Open...", have_capture_file);
1486 set_menu_sensitivity(main_menu_factory, "/File/Open Recent", have_capture_file);
1487 set_menu_sensitivity(main_menu_factory, "/File/Merge...", have_capture_file);
1488 set_menu_sensitivity(main_menu_factory, "/File/Close", have_capture_file);
1489 set_menu_sensitivity(main_menu_factory, "/File/Save As...",
1491 set_menu_sensitivity(main_menu_factory, "/File/Export", have_capture_file);
1492 set_menu_sensitivity(main_menu_factory, "/View/Reload", have_capture_file);
1493 set_toolbar_for_capture_file(have_capture_file);
1494 packets_bar_update();
1497 /* Enable or disable menu items based on whether you have an unsaved
1498 capture file you've finished reading. */
1500 set_menus_for_unsaved_capture_file(gboolean have_unsaved_capture_file)
1502 set_menu_sensitivity(main_menu_factory, "/File/Save",
1503 have_unsaved_capture_file);
1504 set_toolbar_for_unsaved_capture_file(have_unsaved_capture_file);
1507 /* Enable or disable menu items based on whether there's a capture in
1510 set_menus_for_capture_in_progress(gboolean capture_in_progress)
1512 set_menu_sensitivity(main_menu_factory, "/File/Open...",
1513 !capture_in_progress);
1514 set_menu_sensitivity(main_menu_factory, "/File/Open Recent",
1515 !capture_in_progress);
1517 set_menu_sensitivity(main_menu_factory, "/Capture/Start...",
1518 !capture_in_progress);
1519 set_menu_sensitivity(main_menu_factory, "/Capture/Stop",
1520 capture_in_progress);
1521 set_toolbar_for_capture_in_progress(capture_in_progress);
1523 set_capture_if_dialog_for_capture_in_progress(capture_in_progress);
1524 #endif /* HAVE_LIBPCAP */
1527 /* Enable or disable menu items based on whether you have some captured
1530 walk_menu_tree_for_captured_packets(GList *node,
1531 gboolean have_captured_packets)
1533 gboolean is_enabled;
1535 menu_item_t *node_data = node->data;
1538 * Is this a leaf node or an interior node?
1540 if (node_data->children == NULL) {
1544 * If it has no "selected_packet_enabled()" or
1545 * "selected_tree_row_enabled()" routines, we enable
1546 * it. This allows tap windows to be popped up even
1547 * if you have no capture file; this is done to let
1548 * the user pop up multiple tap windows before reading
1549 * in a capture file, so that they can be processed in
1550 * parallel while the capture file is being read rather
1551 * than one at at time as you pop up the windows, and to
1552 * let the user pop up tap windows before starting an
1553 * "Update list of packets in real time" capture, so that
1554 * the statistics can be displayed while the capture is
1557 * If it has either of those routines, we disable it for
1558 * now - as long as, when a capture is first available,
1559 * we don't get called after a packet or tree row is
1560 * selected, that's OK.
1561 * XXX - that should be done better.
1563 if (node_data->selected_packet_enabled == NULL &&
1564 node_data->selected_tree_row_enabled == NULL)
1565 node_data->enabled = TRUE;
1567 node_data->enabled = FALSE;
1570 * It's an interior node; call
1571 * "walk_menu_tree_for_captured_packets()" on all its
1572 * children and, if any of them are enabled, enable
1573 * this node, otherwise disable it.
1575 * XXX - should we just leave all interior nodes enabled?
1576 * Which is a better UI choice?
1579 for (child = node_data->children; child != NULL; child =
1581 if (walk_menu_tree_for_captured_packets(child,
1582 have_captured_packets))
1585 node_data->enabled = is_enabled;
1589 * The root node doesn't correspond to a menu tree item; it
1590 * has a null name pointer.
1592 if (node_data->name != NULL) {
1593 set_menu_sensitivity(main_menu_factory, node_data->name,
1594 node_data->enabled);
1596 return node_data->enabled;
1600 set_menus_for_captured_packets(gboolean have_captured_packets)
1602 set_menu_sensitivity(main_menu_factory, "/File/Print...",
1603 have_captured_packets);
1604 set_menu_sensitivity(packet_list_menu_factory, "/Print...",
1605 have_captured_packets);
1606 set_menu_sensitivity(main_menu_factory, "/Edit/Find Packet...",
1607 have_captured_packets);
1608 set_menu_sensitivity(main_menu_factory, "/Edit/Find Next",
1609 have_captured_packets);
1610 set_menu_sensitivity(main_menu_factory, "/Edit/Find Previous",
1611 have_captured_packets);
1612 set_menu_sensitivity(main_menu_factory, "/View/Zoom In",
1613 have_captured_packets);
1614 set_menu_sensitivity(main_menu_factory, "/View/Zoom Out",
1615 have_captured_packets);
1616 set_menu_sensitivity(main_menu_factory, "/View/Normal Size",
1617 have_captured_packets);
1618 set_menu_sensitivity(main_menu_factory, "/Go/Go to Packet...",
1619 have_captured_packets);
1620 set_menu_sensitivity(main_menu_factory, "/Go/First Packet",
1621 have_captured_packets);
1622 set_menu_sensitivity(main_menu_factory, "/Go/Last Packet",
1623 have_captured_packets);
1624 set_menu_sensitivity(main_menu_factory, "/Statistics/Summary",
1625 have_captured_packets);
1626 set_menu_sensitivity(main_menu_factory, "/Statistics/Protocol Hierarchy",
1627 have_captured_packets);
1629 walk_menu_tree_for_captured_packets(tap_menu_tree_root,
1630 have_captured_packets);
1631 set_toolbar_for_captured_packets(have_captured_packets);
1632 packets_bar_update();
1635 /* Enable or disable menu items based on whether a packet is selected and,
1636 if so, on the properties of the packet. */
1638 walk_menu_tree_for_selected_packet(GList *node, frame_data *fd,
1639 epan_dissect_t *edt)
1641 gboolean is_enabled;
1643 menu_item_t *node_data = node->data;
1646 * Is this a leaf node or an interior node?
1648 if (node_data->children == NULL) {
1652 * If it has no "selected_packet_enabled()" routine,
1653 * leave its enabled/disabled status alone - it
1654 * doesn't depend on whether we have a packet selected
1655 * or not or on the selected packet.
1657 * If it has a "selected_packet_enabled()" routine,
1658 * call it and set the item's enabled/disabled status
1659 * based on its return value.
1661 if (node_data->selected_packet_enabled != NULL)
1662 node_data->enabled = node_data->selected_packet_enabled(fd, edt);
1665 * It's an interior node; call
1666 * "walk_menu_tree_for_selected_packet()" on all its
1667 * children and, if any of them are enabled, enable
1668 * this node, otherwise disable it.
1670 * XXX - should we just leave all interior nodes enabled?
1671 * Which is a better UI choice?
1674 for (child = node_data->children; child != NULL; child =
1676 if (walk_menu_tree_for_selected_packet(child, fd, edt))
1679 node_data->enabled = is_enabled;
1683 * The root node doesn't correspond to a menu tree item; it
1684 * has a null name pointer.
1686 if (node_data->name != NULL) {
1687 set_menu_sensitivity(main_menu_factory, node_data->name,
1688 node_data->enabled);
1690 return node_data->enabled;
1694 set_menus_for_selected_packet(capture_file *cf)
1696 set_menu_sensitivity(main_menu_factory, "/Edit/Mark Packet (toggle)",
1697 cf->current_frame != NULL);
1698 set_menu_sensitivity(packet_list_menu_factory, "/Mark Packet (toggle)",
1699 cf->current_frame != NULL);
1700 set_menu_sensitivity(main_menu_factory, "/Edit/Time Reference",
1701 cf->current_frame != NULL);
1702 set_menu_sensitivity(packet_list_menu_factory, "/Time Reference",
1703 cf->current_frame != NULL);
1704 set_menu_sensitivity(main_menu_factory, "/Edit/Mark All Packets",
1705 cf->current_frame != NULL);
1706 set_menu_sensitivity(main_menu_factory, "/Edit/Unmark All Packets",
1707 cf->current_frame != NULL);
1708 set_menu_sensitivity(main_menu_factory, "/View/Collapse All",
1709 cf->current_frame != NULL);
1710 set_menu_sensitivity(tree_view_menu_factory, "/Collapse All",
1711 cf->current_frame != NULL);
1712 set_menu_sensitivity(main_menu_factory, "/View/Expand All",
1713 cf->current_frame != NULL);
1714 set_menu_sensitivity(tree_view_menu_factory, "/Expand All",
1715 cf->current_frame != NULL);
1716 set_menu_sensitivity(main_menu_factory, "/View/Show Packet in New Window",
1717 cf->current_frame != NULL);
1718 set_menu_sensitivity(packet_list_menu_factory, "/Show Packet in New Window",
1719 cf->current_frame != NULL);
1720 set_menu_sensitivity(main_menu_factory, "/Analyze/Follow TCP Stream",
1721 cf->current_frame != NULL ? (cf->edt->pi.ipproto == IP_PROTO_TCP) : FALSE);
1722 set_menu_sensitivity(packet_list_menu_factory, "/Follow TCP Stream",
1723 cf->current_frame != NULL ? (cf->edt->pi.ipproto == IP_PROTO_TCP) : FALSE);
1724 set_menu_sensitivity(tree_view_menu_factory, "/Follow TCP Stream",
1725 cf->current_frame != NULL ? (cf->edt->pi.ipproto == IP_PROTO_TCP) : FALSE);
1726 set_menu_sensitivity(main_menu_factory, "/Analyze/Decode As...",
1727 cf->current_frame != NULL && decode_as_ok());
1728 set_menu_sensitivity(packet_list_menu_factory, "/Decode As...",
1729 cf->current_frame != NULL && decode_as_ok());
1730 set_menu_sensitivity(tree_view_menu_factory, "/Decode As...",
1731 cf->current_frame != NULL && decode_as_ok());
1732 set_menu_sensitivity(main_menu_factory, "/View/Name Resolution/Resolve Name",
1733 cf->current_frame != NULL && (g_resolv_flags & RESOLV_ALL_ADDRS) != RESOLV_ALL_ADDRS);
1734 set_menu_sensitivity(tree_view_menu_factory, "/Resolve Name",
1735 cf->current_frame != NULL && (g_resolv_flags & RESOLV_ALL_ADDRS) != RESOLV_ALL_ADDRS);
1736 set_menu_sensitivity(packet_list_menu_factory, "/Apply as Filter",
1737 cf->current_frame != NULL);
1738 set_menu_sensitivity(packet_list_menu_factory, "/Prepare a Filter",
1739 cf->current_frame != NULL);
1741 walk_menu_tree_for_selected_packet(tap_menu_tree_root, cf->current_frame,
1743 packets_bar_update();
1746 /* Enable or disable menu items based on whether a tree row is selected
1747 and, if so, on the properties of the tree row. */
1749 walk_menu_tree_for_selected_tree_row(GList *node, field_info *fi)
1751 gboolean is_enabled;
1753 menu_item_t *node_data = node->data;
1756 * Is this a leaf node or an interior node?
1758 if (node_data->children == NULL) {
1762 * If it has no "selected_tree_row_enabled()" routine,
1763 * leave its enabled/disabled status alone - it
1764 * doesn't depend on whether we have a tree row selected
1765 * or not or on the selected tree row.
1767 * If it has a "selected_tree_row_enabled()" routine,
1768 * call it and set the item's enabled/disabled status
1769 * based on its return value.
1771 if (node_data->selected_tree_row_enabled != NULL)
1772 node_data->enabled = node_data->selected_tree_row_enabled(fi);
1775 * It's an interior node; call
1776 * "walk_menu_tree_for_selected_tree_row()" on all its
1777 * children and, if any of them are enabled, enable
1778 * this node, otherwise disable it.
1780 * XXX - should we just leave all interior nodes enabled?
1781 * Which is a better UI choice?
1784 for (child = node_data->children; child != NULL; child =
1786 if (walk_menu_tree_for_selected_tree_row(child, fi))
1789 node_data->enabled = is_enabled;
1793 * The root node doesn't correspond to a menu tree item; it
1794 * has a null name pointer.
1796 if (node_data->name != NULL) {
1797 set_menu_sensitivity(main_menu_factory, node_data->name,
1798 node_data->enabled);
1800 return node_data->enabled;
1804 set_menus_for_selected_tree_row(capture_file *cf)
1806 gboolean properties;
1809 set_menu_sensitivity(main_menu_factory, "/File/Export/Selected Packet Bytes...",
1810 cf->finfo_selected != NULL);
1811 set_menu_sensitivity(hexdump_menu_factory, "/Copy",
1812 cf->finfo_selected != NULL);
1813 set_menu_sensitivity(hexdump_menu_factory, "/Export Selected Packet Bytes...",
1814 cf->finfo_selected != NULL);
1816 if (cf->finfo_selected != NULL) {
1817 header_field_info *hfinfo = cf->finfo_selected->hfinfo;
1818 if (hfinfo->parent == -1) {
1819 properties = prefs_is_registered_protocol(hfinfo->abbrev);
1821 properties = prefs_is_registered_protocol(proto_registrar_get_abbrev(hfinfo->parent));
1823 set_menu_sensitivity(main_menu_factory,
1824 "/Go/Go to Corresponding Packet", hfinfo->type == FT_FRAMENUM);
1825 set_menu_sensitivity(tree_view_menu_factory,
1826 "/Go to Corresponding Packet", hfinfo->type == FT_FRAMENUM);
1827 set_menu_sensitivity(main_menu_factory, "/Analyze/Apply as Filter",
1828 proto_can_match_selected(cf->finfo_selected, cf->edt));
1829 set_menu_sensitivity(tree_view_menu_factory, "/Apply as Filter",
1830 proto_can_match_selected(cf->finfo_selected, cf->edt));
1831 set_menu_sensitivity(main_menu_factory, "/Analyze/Prepare a Filter",
1832 proto_can_match_selected(cf->finfo_selected, cf->edt));
1833 set_menu_sensitivity(tree_view_menu_factory, "/Prepare a Filter",
1834 proto_can_match_selected(cf->finfo_selected, cf->edt));
1835 set_menu_sensitivity(tree_view_menu_factory, "/Protocol Preferences...",
1837 set_menu_sensitivity(main_menu_factory, "/View/Expand Tree", cf->finfo_selected->tree_type != -1);
1838 // set_menu_sensitivity(tree_view_menu_factory, "/Expand Tree", cf->finfo_selected->tree_type != -1);
1839 set_menu_sensitivity(tree_view_menu_factory, "/Wiki Protocol Page",
1841 set_menu_sensitivity(tree_view_menu_factory, "/Filter Field Reference",
1844 set_menu_sensitivity(main_menu_factory,
1845 "/Go/Go to Corresponding Packet", FALSE);
1846 set_menu_sensitivity(tree_view_menu_factory,
1847 "/Go to Corresponding Packet", FALSE);
1848 set_menu_sensitivity(main_menu_factory, "/Analyze/Apply as Filter", FALSE);
1849 set_menu_sensitivity(tree_view_menu_factory, "/Apply as Filter", FALSE);
1850 set_menu_sensitivity(main_menu_factory, "/Analyze/Prepare a Filter", FALSE);
1851 set_menu_sensitivity(tree_view_menu_factory, "/Prepare a Filter", FALSE);
1852 set_menu_sensitivity(tree_view_menu_factory, "/Protocol Preferences...",
1854 set_menu_sensitivity(main_menu_factory, "/View/Expand Tree", FALSE);
1855 set_menu_sensitivity(tree_view_menu_factory, "/Wiki Protocol Page",
1857 set_menu_sensitivity(tree_view_menu_factory, "/Filter Field Reference",
1861 walk_menu_tree_for_selected_tree_row(tap_menu_tree_root, cf->finfo_selected);
1864 void set_menus_for_packet_history(gboolean back_history, gboolean forward_history) {
1866 set_menu_sensitivity(main_menu_factory, "/Go/Back", back_history);
1867 set_menu_sensitivity(main_menu_factory, "/Go/Forward", forward_history);
1869 set_toolbar_for_packet_history(back_history, forward_history);