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/Resize Columns", NULL, packet_list_resize_columns_cb,
264 ITEM_FACTORY_ENTRY("/View/Collapse _All", NULL, collapse_all_cb,
266 ITEM_FACTORY_ENTRY("/View/_Expand All", NULL, expand_all_cb,
268 ITEM_FACTORY_ENTRY("/View/Expand Tree", NULL, expand_tree_cb, 0, NULL, NULL),
269 ITEM_FACTORY_ENTRY("/View/<separator>", NULL, NULL, 0, "<Separator>", NULL),
270 ITEM_FACTORY_STOCK_ENTRY("/View/_Coloring Rules...", NULL, color_display_cb,
271 0, GTK_STOCK_SELECT_COLOR),
272 ITEM_FACTORY_ENTRY("/View/<separator>", NULL, NULL, 0, "<Separator>", NULL),
273 ITEM_FACTORY_ENTRY("/View/Show Packet in New _Window", NULL,
274 new_window_cb, 0, NULL, NULL),
275 ITEM_FACTORY_STOCK_ENTRY("/View/_Reload", "<control>R", file_reload_cmd_cb,
276 0, GTK_STOCK_REFRESH),
277 ITEM_FACTORY_ENTRY("/_Go", NULL, NULL, 0, "<Branch>", NULL),
278 ITEM_FACTORY_STOCK_ENTRY("/Go/_Back", "<alt>Left",
279 history_back_cb, 0, GTK_STOCK_GO_BACK),
280 ITEM_FACTORY_STOCK_ENTRY("/Go/_Forward", "<alt>Right",
281 history_forward_cb, 0, GTK_STOCK_GO_FORWARD),
282 ITEM_FACTORY_STOCK_ENTRY("/Go/_Go to Packet...", "<control>G",
283 goto_frame_cb, 0, GTK_STOCK_JUMP_TO),
284 ITEM_FACTORY_ENTRY("/Go/Go to _Corresponding Packet", NULL, goto_framenum_cb,
286 ITEM_FACTORY_ENTRY("/Go/<separator>", NULL, NULL, 0, "<Separator>", NULL),
287 ITEM_FACTORY_STOCK_ENTRY("/Go/F_irst Packet", NULL,
288 goto_top_frame_cb, 0, GTK_STOCK_GOTO_TOP),
289 ITEM_FACTORY_STOCK_ENTRY("/Go/_Last Packet", NULL,
290 goto_bottom_frame_cb, 0, GTK_STOCK_GOTO_BOTTOM),
292 ITEM_FACTORY_ENTRY("/_Capture", NULL, NULL, 0, "<Branch>", NULL),
293 ITEM_FACTORY_STOCK_ENTRY("/Capture/_Start...", "<control>K",
294 capture_prep_cb, 0, ETHEREAL_STOCK_CAPTURE_START),
295 ITEM_FACTORY_STOCK_ENTRY("/Capture/S_top", "<control>E", capture_stop_cb,
297 ITEM_FACTORY_ENTRY("/Capture/_Interfaces...", NULL,
298 capture_if_cb, 0, NULL, NULL),
299 ITEM_FACTORY_STOCK_ENTRY("/Capture/_Capture Filters...", NULL, cfilter_dialog_cb,
300 0, ETHEREAL_STOCK_CAPTURE_FILTER),
301 #endif /* HAVE_LIBPCAP */
302 ITEM_FACTORY_ENTRY("/_Analyze", NULL, NULL, 0, "<Branch>", NULL),
303 ITEM_FACTORY_STOCK_ENTRY("/Analyze/_Display Filters...", NULL, dfilter_dialog_cb,
304 0, ETHEREAL_STOCK_DISPLAY_FILTER),
305 ITEM_FACTORY_ENTRY("/Analyze/Appl_y as Filter", NULL, NULL, 0, "<Branch>", NULL),
306 ITEM_FACTORY_ENTRY("/Analyze/Apply as Filter/_Selected", NULL, match_selected_ptree_cb,
307 MATCH_SELECTED_REPLACE|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
308 ITEM_FACTORY_ENTRY("/Analyze/Apply as Filter/_Not Selected", NULL, match_selected_ptree_cb,
309 MATCH_SELECTED_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
310 ITEM_FACTORY_ENTRY("/Analyze/Apply as Filter/... _and Selected", NULL, match_selected_ptree_cb,
311 MATCH_SELECTED_AND|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
312 ITEM_FACTORY_ENTRY("/Analyze/Apply as Filter/... _or Selected", NULL, match_selected_ptree_cb,
313 MATCH_SELECTED_OR|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
314 ITEM_FACTORY_ENTRY("/Analyze/Apply as Filter/... a_nd not Selected", NULL, match_selected_ptree_cb,
315 MATCH_SELECTED_AND_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
316 ITEM_FACTORY_ENTRY("/Analyze/Apply as Filter/... o_r not Selected", NULL, match_selected_ptree_cb,
317 MATCH_SELECTED_OR_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
318 ITEM_FACTORY_ENTRY("/Analyze/_Prepare a Filter", NULL, NULL, 0, "<Branch>", NULL),
319 ITEM_FACTORY_ENTRY("/Analyze/Prepare a Filter/_Selected", NULL, match_selected_ptree_cb,
320 MATCH_SELECTED_REPLACE, NULL, NULL),
321 ITEM_FACTORY_ENTRY("/Analyze/Prepare a Filter/_Not Selected", NULL, match_selected_ptree_cb,
322 MATCH_SELECTED_NOT, NULL, NULL),
323 ITEM_FACTORY_ENTRY("/Analyze/Prepare a Filter/... _and Selected", NULL, match_selected_ptree_cb,
324 MATCH_SELECTED_AND, NULL, NULL),
325 ITEM_FACTORY_ENTRY("/Analyze/Prepare a Filter/... _or Selected", NULL, match_selected_ptree_cb,
326 MATCH_SELECTED_OR, NULL, NULL),
327 ITEM_FACTORY_ENTRY("/Analyze/Prepare a Filter/... a_nd not Selected", NULL, match_selected_ptree_cb,
328 MATCH_SELECTED_AND_NOT, NULL, NULL),
329 ITEM_FACTORY_ENTRY("/Analyze/Prepare a Filter/... o_r not Selected", NULL, match_selected_ptree_cb,
330 MATCH_SELECTED_OR_NOT, NULL, NULL),
331 ITEM_FACTORY_ENTRY("/Analyze/<separator>", NULL, NULL, 0, "<Separator>", NULL),
332 ITEM_FACTORY_ENTRY("/Analyze/_Enabled Protocols...", "<shift><control>R", proto_cb, 0, NULL, NULL),
333 ITEM_FACTORY_ENTRY("/Analyze/Decode _As...", NULL, decode_as_cb,
335 ITEM_FACTORY_ENTRY("/Analyze/_User Specified Decodes...", NULL,
336 decode_show_cb, 0, NULL, NULL),
337 ITEM_FACTORY_ENTRY("/Analyze/<separator>", NULL, NULL, 0, "<Separator>", NULL),
338 ITEM_FACTORY_ENTRY("/Analyze/_Follow TCP Stream", NULL,
339 follow_stream_cb, 0, NULL, NULL),
340 ITEM_FACTORY_ENTRY("/_Statistics", NULL, NULL, 0, "<Branch>", NULL),
341 ITEM_FACTORY_ENTRY("/Statistics/_Summary", NULL, summary_open_cb, 0, NULL, NULL),
342 ITEM_FACTORY_ENTRY("/Statistics/_Protocol Hierarchy", NULL,
343 proto_hier_stats_cb, 0, NULL, NULL),
344 ITEM_FACTORY_ENTRY("/Statistics/Conversations", NULL,
345 init_conversation_notebook_cb, 0, NULL, NULL),
346 ITEM_FACTORY_ENTRY("/Statistics/Endpoints", NULL,
347 init_hostlist_notebook_cb, 0, NULL, NULL),
348 ITEM_FACTORY_ENTRY("/_Help", NULL, NULL, 0, "<Branch>", NULL),
349 ITEM_FACTORY_STOCK_ENTRY("/Help/_Contents", "F1", topic_menu_cb, HELP_CONTENT, GTK_STOCK_HELP),
350 ITEM_FACTORY_ENTRY("/Help/_Supported Protocols", NULL, supported_cb, 0, NULL, NULL),
351 #if (GLIB_MAJOR_VERSION >= 2)
352 #ifdef ETHEREAL_EUG_DIR
353 ITEM_FACTORY_ENTRY("/Help/User's Guide", NULL, url_page_menu_cb, HELP_CONTENT, NULL, NULL),
355 ITEM_FACTORY_ENTRY("/Help/Manual Pages", NULL, NULL, 0, "<Branch>", NULL),
356 ITEM_FACTORY_ENTRY("/Help/Manual Pages/Ethereal", NULL, topic_menu_cb, LOCALPAGE_MAN_ETHEREAL, NULL, NULL),
357 ITEM_FACTORY_ENTRY("/Help/Manual Pages/Ethereal Filter", NULL, topic_menu_cb, LOCALPAGE_MAN_ETHEREAL_FILTER, NULL, NULL),
358 ITEM_FACTORY_ENTRY("/Help/Manual Pages/<separator>", NULL, NULL, 0, "<Separator>", NULL),
359 ITEM_FACTORY_ENTRY("/Help/Manual Pages/Tethereal", NULL, topic_menu_cb, LOCALPAGE_MAN_TETHEREAL, NULL, NULL),
360 ITEM_FACTORY_ENTRY("/Help/Manual Pages/Mergecap", NULL, topic_menu_cb, LOCALPAGE_MAN_MERGECAP, NULL, NULL),
361 ITEM_FACTORY_ENTRY("/Help/Manual Pages/Editcap", NULL, topic_menu_cb, LOCALPAGE_MAN_EDITCAP, NULL, NULL),
362 ITEM_FACTORY_ENTRY("/Help/Manual Pages/Text2pcap", NULL, topic_menu_cb, LOCALPAGE_MAN_TEXT2PCAP, NULL, NULL),
363 ITEM_FACTORY_ENTRY("/Help/Ethereal Online", NULL, NULL, 0, "<Branch>", NULL),
364 ITEM_FACTORY_STOCK_ENTRY("/Help/Ethereal Online/Home Page", NULL, topic_menu_cb, ONLINEPAGE_HOME, GTK_STOCK_HOME),
365 ITEM_FACTORY_ENTRY("/Help/Ethereal Online/Wiki", NULL, topic_menu_cb, ONLINEPAGE_WIKI, NULL, NULL),
366 ITEM_FACTORY_ENTRY("/Help/Ethereal Online/User's Guide", NULL, topic_menu_cb, ONLINEPAGE_USERGUIDE, NULL, NULL),
367 ITEM_FACTORY_ENTRY("/Help/Ethereal Online/FAQ's", NULL, topic_menu_cb, ONLINEPAGE_FAQ, NULL, NULL),
368 ITEM_FACTORY_ENTRY("/Help/Ethereal Online/Downloads", NULL, topic_menu_cb, ONLINEPAGE_DOWNLOAD, NULL, NULL),
369 ITEM_FACTORY_ENTRY("/Help/Ethereal Online/Example Files", NULL, topic_menu_cb, ONLINEPAGE_SAMPLE_FILES, NULL, NULL),
371 ITEM_FACTORY_ENTRY("/Help/<separator>", NULL, NULL, 0, "<Separator>", NULL),
372 ITEM_FACTORY_ENTRY("/Help/_About Ethereal", NULL, about_ethereal_cb,
377 /* calculate the number of menu_items */
378 static int nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
380 /* packet list popup */
381 static GtkItemFactoryEntry packet_list_menu_items[] =
383 ITEM_FACTORY_ENTRY("/Mark Packet (toggle)", 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),
389 ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
391 ITEM_FACTORY_ENTRY("/Apply as Filter", NULL, NULL, 0, "<Branch>", NULL),
392 ITEM_FACTORY_ENTRY("/Apply as Filter/_Selected", NULL, match_selected_plist_cb,
393 MATCH_SELECTED_REPLACE|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
394 ITEM_FACTORY_ENTRY("/Apply as Filter/_Not Selected", NULL, match_selected_plist_cb,
395 MATCH_SELECTED_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
396 ITEM_FACTORY_ENTRY("/Apply as Filter/... _and Selected", NULL, match_selected_plist_cb,
397 MATCH_SELECTED_AND|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
398 ITEM_FACTORY_ENTRY("/Apply as Filter/... _or Selected", NULL, match_selected_plist_cb,
399 MATCH_SELECTED_OR|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
400 ITEM_FACTORY_ENTRY("/Apply as Filter/... a_nd not Selected", NULL, match_selected_plist_cb,
401 MATCH_SELECTED_AND_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
402 ITEM_FACTORY_ENTRY("/Apply as Filter/... o_r not Selected", NULL, match_selected_plist_cb,
403 MATCH_SELECTED_OR_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
405 ITEM_FACTORY_ENTRY("/Prepare a Filter", NULL, NULL, 0, "<Branch>", NULL),
406 ITEM_FACTORY_ENTRY("/Prepare a Filter/_Selected", NULL, match_selected_plist_cb,
407 MATCH_SELECTED_REPLACE, NULL, NULL),
408 ITEM_FACTORY_ENTRY("/Prepare a Filter/_Not Selected", NULL, match_selected_plist_cb,
409 MATCH_SELECTED_NOT, NULL, NULL),
410 ITEM_FACTORY_ENTRY("/Prepare a Filter/... _and Selected", NULL, match_selected_plist_cb,
411 MATCH_SELECTED_AND, NULL, NULL),
412 ITEM_FACTORY_ENTRY("/Prepare a Filter/... _or Selected", NULL, match_selected_plist_cb,
413 MATCH_SELECTED_OR, NULL, NULL),
414 ITEM_FACTORY_ENTRY("/Prepare a Filter/... a_nd not Selected", NULL, match_selected_plist_cb,
415 MATCH_SELECTED_AND_NOT, NULL, NULL),
416 ITEM_FACTORY_ENTRY("/Prepare a Filter/... o_r not Selected", NULL, match_selected_plist_cb,
417 MATCH_SELECTED_OR_NOT, NULL, NULL),
419 ITEM_FACTORY_ENTRY("/Follow TCP Stream", NULL, follow_stream_cb,
422 ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
424 ITEM_FACTORY_ENTRY("/Decode As...", NULL, decode_as_cb, 0, NULL, NULL),
425 ITEM_FACTORY_ENTRY("/Print...", NULL, file_print_selected_cmd_cb, 0, NULL, NULL),
426 ITEM_FACTORY_ENTRY("/Show Packet in New Window", NULL, new_window_cb,
430 static GtkItemFactoryEntry tree_view_menu_items[] =
432 ITEM_FACTORY_ENTRY("/Expand Subtrees", NULL, expand_tree_cb, 0, NULL, NULL),
433 ITEM_FACTORY_ENTRY("/Expand All", NULL, expand_all_cb, 0, NULL, NULL),
434 ITEM_FACTORY_ENTRY("/Collapse All", NULL, collapse_all_cb, 0, NULL, NULL),
436 ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
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),
466 ITEM_FACTORY_ENTRY("/Follow TCP Stream", NULL, follow_stream_cb,
469 ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
471 ITEM_FACTORY_STOCK_ENTRY("/Wiki Protocol Page", NULL, selected_ptree_info_cb,
473 ITEM_FACTORY_STOCK_ENTRY("/Filter Field Reference", NULL, selected_ptree_ref_cb,
475 ITEM_FACTORY_ENTRY("/Protocol Preferences...", NULL, properties_cb,
477 ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
478 ITEM_FACTORY_ENTRY("/Decode As...", NULL, decode_as_cb, 0, NULL, NULL),
479 ITEM_FACTORY_ENTRY("/_Resolve Name", NULL, resolve_name_cb, 0, NULL, NULL),
480 ITEM_FACTORY_ENTRY("/_Go to Corresponding Packet", NULL, goto_framenum_cb, 0, NULL, NULL),
483 static GtkItemFactoryEntry hexdump_menu_items[] =
485 ITEM_FACTORY_ENTRY("/Copy", NULL, copy_hex_cb,
487 ITEM_FACTORY_ENTRY("/Export Selected Packet Bytes...", NULL, savehex_cb,
491 static int initialize = TRUE;
492 static GtkItemFactory *main_menu_factory = NULL;
493 static GtkItemFactory *packet_list_menu_factory = NULL;
494 static GtkItemFactory *tree_view_menu_factory = NULL;
495 static GtkItemFactory *hexdump_menu_factory = NULL;
497 static GSList *popup_menu_list = NULL;
499 static GtkAccelGroup *grp;
502 main_menu_new(GtkAccelGroup ** table) {
505 grp = gtk_accel_group_new();
510 menubar = main_menu_factory->widget;
524 packet_list_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
525 popup_menu_object = gtk_menu_new();
526 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);
527 OBJECT_SET_DATA(popup_menu_object, PM_PACKET_LIST_KEY,
528 packet_list_menu_factory->widget);
529 popup_menu_list = g_slist_append((GSList *)popup_menu_list, packet_list_menu_factory);
531 tree_view_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
532 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);
533 OBJECT_SET_DATA(popup_menu_object, PM_TREE_VIEW_KEY,
534 tree_view_menu_factory->widget);
535 popup_menu_list = g_slist_append((GSList *)popup_menu_list, tree_view_menu_factory);
537 hexdump_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
538 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);
539 OBJECT_SET_DATA(popup_menu_object, PM_HEXDUMP_KEY,
540 hexdump_menu_factory->widget);
541 popup_menu_list = g_slist_append((GSList *)popup_menu_list, hexdump_menu_factory);
544 main_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", grp);
545 gtk_item_factory_create_items_ac(main_menu_factory, nmenu_items, menu_items, NULL, 2);
547 merge_all_tap_menus(tap_menu_tree_root);
549 /* Initialize enabled/disabled state of menu items */
550 set_menus_for_unsaved_capture_file(FALSE);
551 set_menus_for_capture_file(FALSE);
553 /* Un-#if this when we actually implement Cut/Copy/Paste.
554 Then make sure you enable them when they can be done. */
555 set_menu_sensitivity(main_menu_factory, "/Edit/Cut", FALSE);
556 set_menu_sensitivity(main_menu_factory, "/Edit/Copy", FALSE);
557 set_menu_sensitivity(main_menu_factory, "/Edit/Paste", FALSE);
560 set_menus_for_captured_packets(FALSE);
561 set_menus_for_selected_packet(&cfile);
562 set_menus_for_selected_tree_row(&cfile);
564 /* init with an empty recent files list */
565 clear_menu_recent_capture_file_cmd_cb(NULL, NULL);
570 gint tap_menu_item_add_compare(gconstpointer a, gconstpointer b)
573 ((const menu_item_t *) a)->name,
574 ((const menu_item_t *) b)->name);
578 /* add a menuitem below the current node */
579 GList * tap_menu_item_add(
582 GtkItemFactoryCallback callback,
583 gboolean (*selected_packet_enabled)(frame_data *, epan_dissect_t *),
584 gboolean (*selected_tree_row_enabled)(field_info *),
585 gpointer callback_data,
592 child = g_malloc(sizeof (menu_item_t));
593 child->group = group;
595 child->callback = callback;
596 child->selected_packet_enabled = selected_packet_enabled;
597 child->selected_tree_row_enabled = selected_tree_row_enabled;
598 child->callback_data = callback_data;
599 child->enabled = FALSE;
600 child->children = NULL;
602 /* insert the new child node into the parent */
603 curr = curnode->data;
604 curr->children = g_list_insert_sorted(curr->children, child, tap_menu_item_add_compare);
606 /* return the new node */
607 /* XXX: improve this */
608 return g_list_find(curr->children, child);
612 * Add a new menu item for a tap.
613 * This must be called after we've created the main menu, so it can't
614 * be called from the routine that registers taps - we have to introduce
615 * another per-tap registration routine.
617 * "callback" gets called when the menu item is selected; it should do
618 * the work of creating the tap window.
620 * "selected_packet_enabled" gets called by "set_menus_for_selected_packet()";
621 * it's passed a Boolean that's TRUE if a packet is selected and FALSE
622 * otherwise, and should return TRUE if the tap will work now (which
623 * might depend on whether a packet is selected and, if one is, on the
624 * packet) and FALSE if not.
626 * "selected_tree_row_enabled" gets called by
627 * "set_menus_for_selected_tree_row()"; it's passed a Boolean that's TRUE if
628 * a protocol tree row is selected and FALSE otherwise, and should return
629 * TRUE if the tap will work now (which might depend on whether a tree row
630 * is selected and, if one is, on the tree row) and FALSE if not.
633 register_tap_menu_item(
635 REGISTER_TAP_GROUP_E group,
636 GtkItemFactoryCallback callback,
637 gboolean (*selected_packet_enabled)(frame_data *, epan_dissect_t *),
638 gboolean (*selected_tree_row_enabled)(field_info *),
639 gpointer callback_data)
641 /*static const char toolspath[] = "/Statistics/";*/
651 * The menu path must be relative.
653 g_assert(*name != '/');
656 case(REGISTER_TAP_GROUP_GENERIC): toolspath = "/Statistics/"; break;
657 case(REGISTER_TAP_GROUP_CONVERSATION_LIST): toolspath = "/Statistics/_Conversation List/"; break;
658 case(REGISTER_TAP_GROUP_ENDPOINT_LIST): toolspath = "/Statistics/_Endpoint List/"; break;
659 case(REGISTER_TAP_GROUP_RESPONSE_TIME): toolspath = "/Statistics/Service _Response Time/"; break;
660 case(REGISTER_TAP_GROUP_NONE): toolspath = "/Statistics/"; break;
666 /* add the (empty) root node, if not already done */
667 if(tap_menu_tree_root == NULL) {
668 child = g_malloc0(sizeof (menu_item_t));
669 tap_menu_tree_root = g_list_append(NULL, child);
673 * Create any submenus required.
675 curnode = tap_menu_tree_root;
677 while ((p = strchr(p, '/')) != NULL) {
679 * OK, everything between "name" and "p" is
680 * a menu relative subtree into which the menu item
683 * Construct the absolute path name of that subtree.
685 menupathlen = strlen(toolspath) + 1 + (p - name);
686 menupath = g_malloc(menupathlen);
687 strcpy(menupath, toolspath);
688 strncat(menupath, name, p - name);
691 * Does there exist an entry with that path at this
692 * level of the Analyze menu tree?
694 child = curnode->data;
695 for (childnode = child->children; childnode != NULL; childnode = childnode->next) {
696 child = childnode->data;
697 if (strcmp(child->name, menupath) == 0)
700 if (childnode == NULL) {
702 * No. Create such an item as a subtree, and
703 * add it to the Tools menu tree.
705 childnode = tap_menu_item_add(
706 menupath, group, NULL, NULL ,NULL, NULL, curnode);
709 * Yes. We don't need this "menupath" any longer.
716 * Skip over the '/' we found.
722 * Construct the main menu path for the menu item.
724 menupathlen = strlen(toolspath) + 1 + strlen(name);
725 menupath = g_malloc(menupathlen);
726 strcpy(menupath, toolspath);
727 strcat(menupath, name);
730 * Construct an item factory entry for the item, and add it to
734 menupath, group, callback,
735 selected_packet_enabled, selected_tree_row_enabled,
736 callback_data, curnode);
740 guint merge_tap_menus_layered(GList *node, gint group) {
741 GtkItemFactoryEntry *entry;
744 menu_item_t *node_data = node->data;
747 * Is this a leaf node or an interior node?
749 if (node_data->children == NULL) {
755 * The root node doesn't correspond to a menu tree item; it
756 * has a null name pointer.
758 if (node_data->name != NULL && group == node_data->group) {
759 entry = g_malloc0(sizeof (GtkItemFactoryEntry));
760 entry->path = node_data->name;
761 entry->callback = node_data->callback;
762 gtk_item_factory_create_item(main_menu_factory, entry, node_data->callback_data, 2);
763 set_menu_sensitivity(main_menu_factory, node_data->name, FALSE); /* no capture file yet */
768 * It's an interior node; call
769 * "merge_tap_menus_layered()" on all its children
773 * The root node doesn't correspond to a menu tree item; it
774 * has a null name pointer.
776 if (node_data->name != NULL && group == node_data->group) {
777 entry = g_malloc0(sizeof (GtkItemFactoryEntry));
778 entry->path = node_data->name;
779 entry->item_type = "<Branch>";
780 gtk_item_factory_create_item(main_menu_factory, entry,
782 set_menu_sensitivity(main_menu_factory, node_data->name,
783 FALSE); /* no children yet */
787 for (child = node_data->children; child != NULL; child =
789 added += merge_tap_menus_layered(child, group);
797 void merge_all_tap_menus(GList *node) {
798 GtkItemFactoryEntry *entry;
800 entry = g_malloc0(sizeof (GtkItemFactoryEntry));
801 entry->item_type = "<Separator>";
802 entry->path = "/Statistics/";
805 * merge only the menu items of the specific group,
806 * and then append a seperator
808 if (merge_tap_menus_layered(node, REGISTER_TAP_GROUP_GENERIC)) {
809 gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);
811 if (merge_tap_menus_layered(node, REGISTER_TAP_GROUP_CONVERSATION_LIST)) {
812 /*gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);*/
814 if (merge_tap_menus_layered(node, REGISTER_TAP_GROUP_ENDPOINT_LIST)) {
815 /*gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);*/
817 if (merge_tap_menus_layered(node, REGISTER_TAP_GROUP_RESPONSE_TIME)) {
818 gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);
820 if (merge_tap_menus_layered(node, REGISTER_TAP_GROUP_NONE)) {
821 /*gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);*/
828 * Enable/disable menu sensitivity.
831 set_menu_sensitivity(GtkItemFactory *ifactory, const gchar *path, gint val)
834 GtkWidget *menu_item;
839 /* the underscore character regularly confuses things, as it will prevent finding
840 * the menu_item, so it has to be removed first */
841 dup = g_strdup(path);
852 if (ifactory == NULL) {
854 * Do it for all pop-up menus.
856 for (menu_list = popup_menu_list; menu_list != NULL;
857 menu_list = g_slist_next(menu_list))
858 set_menu_sensitivity(menu_list->data, dup, val);
861 * Do it for that particular menu.
863 if ((menu_item = gtk_item_factory_get_widget(ifactory, dup)) != NULL) {
864 if (GTK_IS_MENU(menu_item)) {
866 * "dup" refers to a submenu; "gtk_item_factory_get_widget()"
867 * gets the menu, not the item that, when selected, pops up
870 * We have to change the latter item's sensitivity, so that
871 * it shows up normally if sensitive and grayed-out if
874 menu_item = gtk_menu_get_attach_widget(GTK_MENU(menu_item));
876 gtk_widget_set_sensitive(menu_item, val);
878 /* be sure this menu item *is* existing */
879 g_assert_not_reached();
887 set_menu_object_data_meat(GtkItemFactory *ifactory, gchar *path, gchar *key, gpointer data)
889 GtkWidget *menu = NULL;
891 if ((menu = gtk_item_factory_get_widget(ifactory, path)) != NULL)
892 OBJECT_SET_DATA(menu, key, data);
896 set_menu_object_data (gchar *path, gchar *key, gpointer data) {
897 GSList *menu_list = popup_menu_list;
898 gchar *shortpath = strrchr(path, '/');
900 set_menu_object_data_meat(main_menu_factory, path, key, data);
901 while (menu_list != NULL) {
902 set_menu_object_data_meat(menu_list->data, shortpath, key, data);
903 menu_list = g_slist_next(menu_list);
908 /* Recently used capture files submenu:
909 * Submenu containing the recently used capture files.
910 * The capture filenames are always kept with the absolute path, to be independant
911 * of the current path.
912 * They are only stored inside the labels of the submenu (no separate list). */
914 #define MENU_RECENT_FILES_PATH "/File/Open Recent"
915 #define MENU_RECENT_FILES_KEY "Recent File Name"
918 update_menu_recent_capture_file1(GtkWidget *widget, gpointer cnt) {
919 gchar *widget_cf_name;
921 widget_cf_name = OBJECT_GET_DATA(widget, MENU_RECENT_FILES_KEY);
923 /* if this menu item is a file, count it */
924 if (widget_cf_name) {
930 /* update the menu */
932 update_menu_recent_capture_file(GtkWidget *submenu_recent_files) {
935 gtk_container_foreach(GTK_CONTAINER(submenu_recent_files),
936 update_menu_recent_capture_file1, &cnt);
938 /* make parent menu item sensitive only, if we have any valid files in the list */
939 set_menu_sensitivity(main_menu_factory, MENU_RECENT_FILES_PATH, cnt);
943 /* remove the capture filename from the "Recent Files" menu */
945 remove_menu_recent_capture_file(GtkWidget *widget, gpointer unused _U_) {
946 GtkWidget *submenu_recent_files;
947 gchar *widget_cf_name;
950 widget_cf_name = OBJECT_GET_DATA(widget, MENU_RECENT_FILES_KEY);
951 g_free(widget_cf_name);
953 /* get the submenu container item */
954 submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
956 /* XXX: is this all we need to do, to free the menu item and its label?
957 The reference count of widget will go to 0, so it'll be freed;
958 will that free the label? */
959 gtk_container_remove(GTK_CONTAINER(submenu_recent_files), widget);
963 /* callback, if the user pushed the <Clear File List> item */
965 clear_menu_recent_capture_file_cmd_cb(GtkWidget *w _U_, gpointer unused _U_) {
966 GtkWidget *submenu_recent_files;
969 submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
971 gtk_container_foreach(GTK_CONTAINER(submenu_recent_files),
972 remove_menu_recent_capture_file, NULL);
974 update_menu_recent_capture_file(submenu_recent_files);
978 /* callback, if the user pushed a recent file submenu item */
980 menu_open_recent_file_cmd(GtkWidget *w)
982 GtkWidget *submenu_recent_files;
983 GtkWidget *menu_item_child;
987 submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
989 /* get capture filename from the menu item label */
990 menu_item_child = (GTK_BIN(w))->child;
991 gtk_label_get(GTK_LABEL(menu_item_child), &cf_name);
993 /* open and read the capture file (this will close an existing file) */
994 if (cf_open(&cfile, cf_name, FALSE, &err) == CF_OK) {
997 /* the capture file isn't existing any longer, remove menu item */
998 /* XXX: ask user to remove item, it's maybe only a temporary problem */
999 remove_menu_recent_capture_file(w, NULL);
1002 update_menu_recent_capture_file(submenu_recent_files);
1005 static void menu_open_recent_file_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
1009 /* save file first */
1010 file_save_as_cmd(after_save_open_recent_file, data);
1014 menu_open_recent_file_cmd(data);
1016 case(ESD_BTN_CANCEL):
1019 g_assert_not_reached();
1024 menu_open_recent_file_cmd_cb(GtkWidget *widget, gpointer data _U_) {
1028 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
1029 /* user didn't saved his current file, ask him */
1030 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_YES_NO_CANCEL,
1031 PRIMARY_TEXT_START "Save capture file before opening a new one?" PRIMARY_TEXT_END "\n\n"
1032 "If you open a new capture file without saving, your current capture data will be discarded.");
1033 simple_dialog_set_cb(dialog, menu_open_recent_file_answered_cb, widget);
1035 /* unchanged file */
1036 menu_open_recent_file_cmd(widget);
1040 /* add the capture filename (with an absolute path) to the "Recent Files" menu */
1042 add_menu_recent_capture_file_absolute(gchar *cf_name) {
1043 GtkWidget *submenu_recent_files;
1044 GList *menu_item_list;
1046 gchar *widget_cf_name;
1047 gchar *normalized_cf_name;
1048 GtkWidget *menu_item;
1053 normalized_cf_name = g_strdup(cf_name);
1055 /* replace all slashes by backslashes */
1056 g_strdelimit(normalized_cf_name, "/", '\\');
1059 /* get the submenu container item */
1060 submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
1062 /* convert container to a GList */
1063 menu_item_list = gtk_container_children(GTK_CONTAINER(submenu_recent_files));
1065 /* iterate through list items of menu_item_list,
1066 * removing special items, a maybe duplicate entry and every item above count_max */
1068 for (li = g_list_first(menu_item_list); li; li = li->next, cnt++) {
1069 /* get capture filename */
1070 menu_item = GTK_WIDGET(li->data);
1071 widget_cf_name = OBJECT_GET_DATA(menu_item, MENU_RECENT_FILES_KEY);
1073 /* if this element string is one of our special items (seperator, ...) or
1074 * already in the list or
1075 * this element is above maximum count (too old), remove it */
1076 if (!widget_cf_name ||
1078 /* do a case insensitive compare on win32 */
1079 #if GLIB_MAJOR_VERSION < 2
1080 g_strncasecmp(widget_cf_name, normalized_cf_name, 1000) == 0 ||
1082 g_ascii_strncasecmp(widget_cf_name, normalized_cf_name, 1000) == 0 ||
1085 /* do a case sensitive compare on unix */
1086 strncmp(widget_cf_name, normalized_cf_name, 1000) == 0 ||
1088 cnt >= prefs.gui_recent_files_count_max) {
1089 remove_menu_recent_capture_file(li->data, NULL);
1094 g_list_free(menu_item_list);
1096 /* add new item at latest position */
1097 menu_item = gtk_menu_item_new_with_label(normalized_cf_name);
1098 OBJECT_SET_DATA(menu_item, MENU_RECENT_FILES_KEY, normalized_cf_name);
1099 gtk_menu_prepend (GTK_MENU(submenu_recent_files), menu_item);
1100 SIGNAL_CONNECT_OBJECT(GTK_OBJECT(menu_item), "activate",
1101 menu_open_recent_file_cmd_cb, (GtkObject *) menu_item);
1102 gtk_widget_show (menu_item);
1104 /* add seperator at last position */
1105 menu_item = gtk_menu_item_new();
1106 gtk_menu_append (GTK_MENU(submenu_recent_files), menu_item);
1107 gtk_widget_show (menu_item);
1109 /* add new "clear list" item at last position */
1110 #if GTK_MAJOR_VERSION < 2
1111 menu_item = gtk_menu_item_new_with_label("<Clear File List>");
1113 menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_CLEAR, NULL);
1115 gtk_menu_append (GTK_MENU(submenu_recent_files), menu_item);
1116 SIGNAL_CONNECT_OBJECT(GTK_OBJECT(menu_item), "activate",
1117 clear_menu_recent_capture_file_cmd_cb, (GtkObject *) menu_item);
1118 gtk_widget_show (menu_item);
1120 update_menu_recent_capture_file(submenu_recent_files);
1124 /* add the capture filename to the "Recent Files" menu */
1125 /* (will change nothing, if this filename is already in the menu) */
1127 add_menu_recent_capture_file(gchar *cf_name) {
1132 /* if this filename is an absolute path, we can use it directly */
1133 if (g_path_is_absolute(cf_name)) {
1134 add_menu_recent_capture_file_absolute(cf_name);
1138 /* this filename is not an absolute path, prepend the current dir */
1139 curr = g_get_current_dir();
1140 absolute = g_strdup_printf("%s%s%s", curr, G_DIR_SEPARATOR_S, cf_name);
1141 add_menu_recent_capture_file_absolute(absolute);
1147 /* write all capture filenames of the menu to the user's recent file */
1149 menu_recent_file_write_all(FILE *rf) {
1150 GtkWidget *submenu_recent_files;
1156 submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
1158 /* we have to iterate backwards through the children's list,
1159 * so we get the latest item last in the file.
1160 * (don't use gtk_container_foreach() here, it will return the wrong iteration order) */
1161 children = gtk_container_children(GTK_CONTAINER(submenu_recent_files));
1162 child = g_list_last(children);
1163 while(child != NULL) {
1164 /* get capture filename from the menu item label */
1165 cf_name = OBJECT_GET_DATA(child->data, MENU_RECENT_FILES_KEY);
1167 fprintf (rf, RECENT_KEY_CAPTURE_FILE ": %s\n", cf_name);
1170 child = g_list_previous(child);
1173 g_list_free(children);
1178 main_toolbar_show_cb(GtkWidget *w _U_, gpointer d _U_)
1181 /* save current setting in recent */
1182 recent.main_toolbar_show = GTK_CHECK_MENU_ITEM(w)->active;
1184 main_widgets_show_or_hide();
1189 filter_toolbar_show_cb(GtkWidget *w _U_, gpointer d _U_)
1192 /* save current setting in recent */
1193 recent.filter_toolbar_show = GTK_CHECK_MENU_ITEM(w)->active;
1195 main_widgets_show_or_hide();
1200 packet_list_show_cb(GtkWidget *w _U_, gpointer d _U_)
1203 /* save current setting in recent */
1204 recent.packet_list_show = GTK_CHECK_MENU_ITEM(w)->active;
1206 main_widgets_show_or_hide();
1211 tree_view_show_cb(GtkWidget *w _U_, gpointer d _U_)
1214 /* save current setting in recent */
1215 recent.tree_view_show = GTK_CHECK_MENU_ITEM(w)->active;
1217 main_widgets_show_or_hide();
1222 byte_view_show_cb(GtkWidget *w _U_, gpointer d _U_)
1225 /* save current setting in recent */
1226 recent.byte_view_show = GTK_CHECK_MENU_ITEM(w)->active;
1228 main_widgets_show_or_hide();
1233 statusbar_show_cb(GtkWidget *w _U_, gpointer d _U_)
1236 /* save current setting in recent */
1237 recent.statusbar_show = GTK_CHECK_MENU_ITEM(w)->active;
1239 main_widgets_show_or_hide();
1244 timestamp_absolute_cb(GtkWidget *w _U_, gpointer d _U_)
1246 if (recent.gui_time_format != TS_ABSOLUTE) {
1247 set_timestamp_setting(TS_ABSOLUTE);
1248 recent.gui_time_format = TS_ABSOLUTE;
1249 cf_change_time_formats(&cfile);
1254 timestamp_absolute_date_cb(GtkWidget *w _U_, gpointer d _U_)
1256 if (recent.gui_time_format != TS_ABSOLUTE_WITH_DATE) {
1257 set_timestamp_setting(TS_ABSOLUTE_WITH_DATE);
1258 recent.gui_time_format = TS_ABSOLUTE_WITH_DATE;
1259 cf_change_time_formats(&cfile);
1264 timestamp_relative_cb(GtkWidget *w _U_, gpointer d _U_)
1266 if (recent.gui_time_format != TS_RELATIVE) {
1267 set_timestamp_setting(TS_RELATIVE);
1268 recent.gui_time_format = TS_RELATIVE;
1269 cf_change_time_formats(&cfile);
1274 timestamp_delta_cb(GtkWidget *w _U_, gpointer d _U_)
1276 if (recent.gui_time_format != TS_DELTA) {
1277 set_timestamp_setting(TS_DELTA);
1278 recent.gui_time_format = TS_DELTA;
1279 cf_change_time_formats(&cfile);
1284 menu_name_resolution_changed(void)
1286 GtkWidget *menu = NULL;
1288 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Name Resolution/Enable for MAC Layer");
1289 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), g_resolv_flags & RESOLV_MAC);
1291 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Name Resolution/Enable for Network Layer");
1292 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), g_resolv_flags & RESOLV_NETWORK);
1294 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Name Resolution/Enable for Transport Layer");
1295 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), g_resolv_flags & RESOLV_TRANSPORT);
1299 name_resolution_mac_cb(GtkWidget *w _U_, gpointer d _U_)
1301 if (GTK_CHECK_MENU_ITEM(w)->active) {
1302 g_resolv_flags |= RESOLV_MAC;
1304 g_resolv_flags &= ~RESOLV_MAC;
1309 name_resolution_network_cb(GtkWidget *w _U_, gpointer d _U_)
1311 if (GTK_CHECK_MENU_ITEM(w)->active) {
1312 g_resolv_flags |= RESOLV_NETWORK;
1314 g_resolv_flags &= ~RESOLV_NETWORK;
1319 name_resolution_transport_cb(GtkWidget *w _U_, gpointer d _U_)
1321 if (GTK_CHECK_MENU_ITEM(w)->active) {
1322 g_resolv_flags |= RESOLV_TRANSPORT;
1324 g_resolv_flags &= ~RESOLV_TRANSPORT;
1330 auto_scroll_live_cb(GtkWidget *w _U_, gpointer d _U_)
1332 auto_scroll_live = GTK_CHECK_MENU_ITEM(w)->active;
1336 /* the recent file read has finished, update the menu corresponding */
1338 menu_recent_read_finished(void) {
1339 GtkWidget *menu = NULL;
1341 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Main Toolbar");
1342 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.main_toolbar_show);
1344 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Filter Toolbar");
1345 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.filter_toolbar_show);
1347 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Statusbar");
1348 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.statusbar_show);
1350 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Packet List");
1351 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.packet_list_show);
1353 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Packet Details");
1354 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.tree_view_show);
1356 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Packet Bytes");
1357 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.byte_view_show);
1359 menu_name_resolution_changed();
1362 menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Auto Scroll in Live Capture");
1363 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), auto_scroll_live);
1366 main_widgets_rearrange();
1368 /* don't change the time format, if we had a command line value */
1369 if (get_timestamp_setting() != TS_NOT_SET) {
1370 recent.gui_time_format = get_timestamp_setting();
1373 switch(recent.gui_time_format) {
1375 menu = gtk_item_factory_get_widget(main_menu_factory,
1376 "/View/Time Display Format/Time of Day");
1377 /* set_active will not trigger the callback when activating an active item! */
1378 recent.gui_time_format = -1;
1379 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), FALSE);
1380 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
1382 case(TS_ABSOLUTE_WITH_DATE):
1383 menu = gtk_item_factory_get_widget(main_menu_factory,
1384 "/View/Time Display Format/Date and Time of Day");
1385 recent.gui_time_format = -1;
1386 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
1389 menu = gtk_item_factory_get_widget(main_menu_factory,
1390 "/View/Time Display Format/Seconds Since Beginning of Capture");
1391 recent.gui_time_format = -1;
1392 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
1395 menu = gtk_item_factory_get_widget(main_menu_factory,
1396 "/View/Time Display Format/Seconds Since Previous Packet");
1397 recent.gui_time_format = -1;
1398 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
1401 g_assert_not_reached();
1407 popup_menu_handler(GtkWidget *widget, GdkEvent *event, gpointer data)
1409 GtkWidget *menu = (GtkWidget *)data;
1410 GdkEventButton *event_button = NULL;
1413 if(widget == NULL || event == NULL || data == NULL) {
1418 * If we ever want to make the menu differ based on what row
1419 * and/or column we're above, we'd use "eth_clist_get_selection_info()"
1420 * to find the row and column number for the coordinates; a CTree is,
1421 * I guess, like a CList with one column(?) and the expander widget
1424 /* Check if we are on packet_list object */
1425 if (widget == OBJECT_GET_DATA(popup_menu_object, E_MPACKET_LIST_KEY)) {
1426 if (packet_list_get_event_row_column(widget, (GdkEventButton *)event,
1428 OBJECT_SET_DATA(popup_menu_object, E_MPACKET_LIST_ROW_KEY,
1429 GINT_TO_POINTER(row));
1430 OBJECT_SET_DATA(popup_menu_object, E_MPACKET_LIST_COL_KEY,
1431 GINT_TO_POINTER(column));
1432 packet_list_set_selected_row(row);
1436 /* Check if we are on tree_view object */
1437 if (widget == tree_view) {
1438 tree_view_select(widget, (GdkEventButton *) event);
1441 /* Check if we are on byte_view object */
1442 if(widget == get_notebook_bv_ptr(byte_nb_ptr)) {
1443 byte_view_select(widget, (GdkEventButton *) event);
1446 /* context menu handler (but the byte view notebook pages have their own handler) */
1447 if(event->type == GDK_BUTTON_PRESS && widget != byte_nb_ptr) {
1448 event_button = (GdkEventButton *) event;
1450 /* To qoute the "Gdk Event Structures" doc:
1451 * "Normally button 1 is the left mouse button, 2 is the middle button, and 3 is the right button" */
1452 if(event_button->button == 3) {
1453 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
1454 event_button->button,
1455 event_button->time);
1456 SIGNAL_EMIT_STOP_BY_NAME(widget, "button_press_event");
1460 #if GTK_MAJOR_VERSION >= 2
1461 /* GDK_2BUTTON_PRESS is a doubleclick -> expand/collapse tree row */
1462 /* GTK version 1 seems to be doing this automatically */
1463 if (widget == tree_view && event->type == GDK_2BUTTON_PRESS) {
1466 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget),
1467 (gint) (((GdkEventButton *)event)->x),
1468 (gint) (((GdkEventButton *)event)->y),
1469 &path, NULL, NULL, NULL))
1471 if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(widget), path))
1472 gtk_tree_view_collapse_row(GTK_TREE_VIEW(widget), path);
1474 gtk_tree_view_expand_row(GTK_TREE_VIEW(widget), path,
1476 gtk_tree_path_free(path);
1483 /* Enable or disable menu items based on whether you have a capture file
1484 you've finished reading. */
1486 set_menus_for_capture_file(gboolean have_capture_file)
1488 set_menu_sensitivity(main_menu_factory, "/File/Open...", have_capture_file);
1489 set_menu_sensitivity(main_menu_factory, "/File/Open Recent", have_capture_file);
1490 set_menu_sensitivity(main_menu_factory, "/File/Merge...", have_capture_file);
1491 set_menu_sensitivity(main_menu_factory, "/File/Close", have_capture_file);
1492 set_menu_sensitivity(main_menu_factory, "/File/Save As...",
1494 set_menu_sensitivity(main_menu_factory, "/File/Export", have_capture_file);
1495 set_menu_sensitivity(main_menu_factory, "/View/Reload", have_capture_file);
1496 set_toolbar_for_capture_file(have_capture_file);
1497 packets_bar_update();
1500 /* Enable or disable menu items based on whether you have an unsaved
1501 capture file you've finished reading. */
1503 set_menus_for_unsaved_capture_file(gboolean have_unsaved_capture_file)
1505 set_menu_sensitivity(main_menu_factory, "/File/Save",
1506 have_unsaved_capture_file);
1507 set_toolbar_for_unsaved_capture_file(have_unsaved_capture_file);
1510 /* Enable or disable menu items based on whether there's a capture in
1513 set_menus_for_capture_in_progress(gboolean capture_in_progress)
1515 set_menu_sensitivity(main_menu_factory, "/File/Open...",
1516 !capture_in_progress);
1517 set_menu_sensitivity(main_menu_factory, "/File/Open Recent",
1518 !capture_in_progress);
1520 set_menu_sensitivity(main_menu_factory, "/Capture/Start...",
1521 !capture_in_progress);
1522 set_menu_sensitivity(main_menu_factory, "/Capture/Stop",
1523 capture_in_progress);
1524 set_toolbar_for_capture_in_progress(capture_in_progress);
1526 set_capture_if_dialog_for_capture_in_progress(capture_in_progress);
1527 #endif /* HAVE_LIBPCAP */
1530 /* Enable or disable menu items based on whether you have some captured
1533 walk_menu_tree_for_captured_packets(GList *node,
1534 gboolean have_captured_packets)
1536 gboolean is_enabled;
1538 menu_item_t *node_data = node->data;
1541 * Is this a leaf node or an interior node?
1543 if (node_data->children == NULL) {
1547 * If it has no "selected_packet_enabled()" or
1548 * "selected_tree_row_enabled()" routines, we enable
1549 * it. This allows tap windows to be popped up even
1550 * if you have no capture file; this is done to let
1551 * the user pop up multiple tap windows before reading
1552 * in a capture file, so that they can be processed in
1553 * parallel while the capture file is being read rather
1554 * than one at at time as you pop up the windows, and to
1555 * let the user pop up tap windows before starting an
1556 * "Update list of packets in real time" capture, so that
1557 * the statistics can be displayed while the capture is
1560 * If it has either of those routines, we disable it for
1561 * now - as long as, when a capture is first available,
1562 * we don't get called after a packet or tree row is
1563 * selected, that's OK.
1564 * XXX - that should be done better.
1566 if (node_data->selected_packet_enabled == NULL &&
1567 node_data->selected_tree_row_enabled == NULL)
1568 node_data->enabled = TRUE;
1570 node_data->enabled = FALSE;
1573 * It's an interior node; call
1574 * "walk_menu_tree_for_captured_packets()" on all its
1575 * children and, if any of them are enabled, enable
1576 * this node, otherwise disable it.
1578 * XXX - should we just leave all interior nodes enabled?
1579 * Which is a better UI choice?
1582 for (child = node_data->children; child != NULL; child =
1584 if (walk_menu_tree_for_captured_packets(child,
1585 have_captured_packets))
1588 node_data->enabled = is_enabled;
1592 * The root node doesn't correspond to a menu tree item; it
1593 * has a null name pointer.
1595 if (node_data->name != NULL) {
1596 set_menu_sensitivity(main_menu_factory, node_data->name,
1597 node_data->enabled);
1599 return node_data->enabled;
1603 set_menus_for_captured_packets(gboolean have_captured_packets)
1605 set_menu_sensitivity(main_menu_factory, "/File/Print...",
1606 have_captured_packets);
1607 set_menu_sensitivity(packet_list_menu_factory, "/Print...",
1608 have_captured_packets);
1609 set_menu_sensitivity(main_menu_factory, "/Edit/Find Packet...",
1610 have_captured_packets);
1611 set_menu_sensitivity(main_menu_factory, "/Edit/Find Next",
1612 have_captured_packets);
1613 set_menu_sensitivity(main_menu_factory, "/Edit/Find Previous",
1614 have_captured_packets);
1615 set_menu_sensitivity(main_menu_factory, "/View/Zoom In",
1616 have_captured_packets);
1617 set_menu_sensitivity(main_menu_factory, "/View/Zoom Out",
1618 have_captured_packets);
1619 set_menu_sensitivity(main_menu_factory, "/View/Normal Size",
1620 have_captured_packets);
1621 set_menu_sensitivity(main_menu_factory, "/Go/Go to Packet...",
1622 have_captured_packets);
1623 set_menu_sensitivity(main_menu_factory, "/Go/First Packet",
1624 have_captured_packets);
1625 set_menu_sensitivity(main_menu_factory, "/Go/Last Packet",
1626 have_captured_packets);
1627 set_menu_sensitivity(main_menu_factory, "/Statistics/Summary",
1628 have_captured_packets);
1629 set_menu_sensitivity(main_menu_factory, "/Statistics/Protocol Hierarchy",
1630 have_captured_packets);
1632 walk_menu_tree_for_captured_packets(tap_menu_tree_root,
1633 have_captured_packets);
1634 set_toolbar_for_captured_packets(have_captured_packets);
1635 packets_bar_update();
1638 /* Enable or disable menu items based on whether a packet is selected and,
1639 if so, on the properties of the packet. */
1641 walk_menu_tree_for_selected_packet(GList *node, frame_data *fd,
1642 epan_dissect_t *edt)
1644 gboolean is_enabled;
1646 menu_item_t *node_data = node->data;
1649 * Is this a leaf node or an interior node?
1651 if (node_data->children == NULL) {
1655 * If it has no "selected_packet_enabled()" routine,
1656 * leave its enabled/disabled status alone - it
1657 * doesn't depend on whether we have a packet selected
1658 * or not or on the selected packet.
1660 * If it has a "selected_packet_enabled()" routine,
1661 * call it and set the item's enabled/disabled status
1662 * based on its return value.
1664 if (node_data->selected_packet_enabled != NULL)
1665 node_data->enabled = node_data->selected_packet_enabled(fd, edt);
1668 * It's an interior node; call
1669 * "walk_menu_tree_for_selected_packet()" on all its
1670 * children and, if any of them are enabled, enable
1671 * this node, otherwise disable it.
1673 * XXX - should we just leave all interior nodes enabled?
1674 * Which is a better UI choice?
1677 for (child = node_data->children; child != NULL; child =
1679 if (walk_menu_tree_for_selected_packet(child, fd, edt))
1682 node_data->enabled = is_enabled;
1686 * The root node doesn't correspond to a menu tree item; it
1687 * has a null name pointer.
1689 if (node_data->name != NULL) {
1690 set_menu_sensitivity(main_menu_factory, node_data->name,
1691 node_data->enabled);
1693 return node_data->enabled;
1697 set_menus_for_selected_packet(capture_file *cf)
1699 set_menu_sensitivity(main_menu_factory, "/Edit/Mark Packet (toggle)",
1700 cf->current_frame != NULL);
1701 set_menu_sensitivity(packet_list_menu_factory, "/Mark Packet (toggle)",
1702 cf->current_frame != NULL);
1703 set_menu_sensitivity(main_menu_factory, "/Edit/Time Reference",
1704 cf->current_frame != NULL);
1705 set_menu_sensitivity(packet_list_menu_factory, "/Time Reference",
1706 cf->current_frame != NULL);
1707 set_menu_sensitivity(main_menu_factory, "/Edit/Mark All Packets",
1708 cf->current_frame != NULL);
1709 set_menu_sensitivity(main_menu_factory, "/Edit/Unmark All Packets",
1710 cf->current_frame != NULL);
1711 set_menu_sensitivity(main_menu_factory, "/View/Collapse All",
1712 cf->current_frame != NULL);
1713 set_menu_sensitivity(tree_view_menu_factory, "/Collapse All",
1714 cf->current_frame != NULL);
1715 set_menu_sensitivity(main_menu_factory, "/View/Expand All",
1716 cf->current_frame != NULL);
1717 set_menu_sensitivity(tree_view_menu_factory, "/Expand All",
1718 cf->current_frame != NULL);
1719 set_menu_sensitivity(main_menu_factory, "/View/Show Packet in New Window",
1720 cf->current_frame != NULL);
1721 set_menu_sensitivity(packet_list_menu_factory, "/Show Packet in New Window",
1722 cf->current_frame != NULL);
1723 set_menu_sensitivity(main_menu_factory, "/Analyze/Follow TCP Stream",
1724 cf->current_frame != NULL ? (cf->edt->pi.ipproto == IP_PROTO_TCP) : FALSE);
1725 set_menu_sensitivity(packet_list_menu_factory, "/Follow TCP Stream",
1726 cf->current_frame != NULL ? (cf->edt->pi.ipproto == IP_PROTO_TCP) : FALSE);
1727 set_menu_sensitivity(tree_view_menu_factory, "/Follow TCP Stream",
1728 cf->current_frame != NULL ? (cf->edt->pi.ipproto == IP_PROTO_TCP) : FALSE);
1729 set_menu_sensitivity(main_menu_factory, "/Analyze/Decode As...",
1730 cf->current_frame != NULL && decode_as_ok());
1731 set_menu_sensitivity(packet_list_menu_factory, "/Decode As...",
1732 cf->current_frame != NULL && decode_as_ok());
1733 set_menu_sensitivity(tree_view_menu_factory, "/Decode As...",
1734 cf->current_frame != NULL && decode_as_ok());
1735 set_menu_sensitivity(main_menu_factory, "/View/Name Resolution/Resolve Name",
1736 cf->current_frame != NULL && (g_resolv_flags & RESOLV_ALL_ADDRS) != RESOLV_ALL_ADDRS);
1737 set_menu_sensitivity(tree_view_menu_factory, "/Resolve Name",
1738 cf->current_frame != NULL && (g_resolv_flags & RESOLV_ALL_ADDRS) != RESOLV_ALL_ADDRS);
1739 set_menu_sensitivity(packet_list_menu_factory, "/Apply as Filter",
1740 cf->current_frame != NULL);
1741 set_menu_sensitivity(packet_list_menu_factory, "/Prepare a Filter",
1742 cf->current_frame != NULL);
1744 walk_menu_tree_for_selected_packet(tap_menu_tree_root, cf->current_frame,
1746 packets_bar_update();
1749 /* Enable or disable menu items based on whether a tree row is selected
1750 and, if so, on the properties of the tree row. */
1752 walk_menu_tree_for_selected_tree_row(GList *node, field_info *fi)
1754 gboolean is_enabled;
1756 menu_item_t *node_data = node->data;
1759 * Is this a leaf node or an interior node?
1761 if (node_data->children == NULL) {
1765 * If it has no "selected_tree_row_enabled()" routine,
1766 * leave its enabled/disabled status alone - it
1767 * doesn't depend on whether we have a tree row selected
1768 * or not or on the selected tree row.
1770 * If it has a "selected_tree_row_enabled()" routine,
1771 * call it and set the item's enabled/disabled status
1772 * based on its return value.
1774 if (node_data->selected_tree_row_enabled != NULL)
1775 node_data->enabled = node_data->selected_tree_row_enabled(fi);
1778 * It's an interior node; call
1779 * "walk_menu_tree_for_selected_tree_row()" on all its
1780 * children and, if any of them are enabled, enable
1781 * this node, otherwise disable it.
1783 * XXX - should we just leave all interior nodes enabled?
1784 * Which is a better UI choice?
1787 for (child = node_data->children; child != NULL; child =
1789 if (walk_menu_tree_for_selected_tree_row(child, fi))
1792 node_data->enabled = is_enabled;
1796 * The root node doesn't correspond to a menu tree item; it
1797 * has a null name pointer.
1799 if (node_data->name != NULL) {
1800 set_menu_sensitivity(main_menu_factory, node_data->name,
1801 node_data->enabled);
1803 return node_data->enabled;
1807 set_menus_for_selected_tree_row(capture_file *cf)
1809 gboolean properties;
1812 set_menu_sensitivity(main_menu_factory, "/File/Export/Selected Packet Bytes...",
1813 cf->finfo_selected != NULL);
1814 set_menu_sensitivity(hexdump_menu_factory, "/Copy",
1815 cf->finfo_selected != NULL);
1816 set_menu_sensitivity(hexdump_menu_factory, "/Export Selected Packet Bytes...",
1817 cf->finfo_selected != NULL);
1819 if (cf->finfo_selected != NULL) {
1820 header_field_info *hfinfo = cf->finfo_selected->hfinfo;
1821 if (hfinfo->parent == -1) {
1822 properties = prefs_is_registered_protocol(hfinfo->abbrev);
1824 properties = prefs_is_registered_protocol(proto_registrar_get_abbrev(hfinfo->parent));
1826 set_menu_sensitivity(main_menu_factory,
1827 "/Go/Go to Corresponding Packet", hfinfo->type == FT_FRAMENUM);
1828 set_menu_sensitivity(tree_view_menu_factory,
1829 "/Go to Corresponding Packet", hfinfo->type == FT_FRAMENUM);
1830 set_menu_sensitivity(main_menu_factory, "/Analyze/Apply as Filter",
1831 proto_can_match_selected(cf->finfo_selected, cf->edt));
1832 set_menu_sensitivity(tree_view_menu_factory, "/Apply as Filter",
1833 proto_can_match_selected(cf->finfo_selected, cf->edt));
1834 set_menu_sensitivity(main_menu_factory, "/Analyze/Prepare a Filter",
1835 proto_can_match_selected(cf->finfo_selected, cf->edt));
1836 set_menu_sensitivity(tree_view_menu_factory, "/Prepare a Filter",
1837 proto_can_match_selected(cf->finfo_selected, cf->edt));
1838 set_menu_sensitivity(tree_view_menu_factory, "/Protocol Preferences...",
1840 set_menu_sensitivity(main_menu_factory, "/View/Expand Tree", cf->finfo_selected->tree_type != -1);
1841 // set_menu_sensitivity(tree_view_menu_factory, "/Expand Tree", cf->finfo_selected->tree_type != -1);
1842 set_menu_sensitivity(tree_view_menu_factory, "/Wiki Protocol Page",
1844 set_menu_sensitivity(tree_view_menu_factory, "/Filter Field Reference",
1847 set_menu_sensitivity(main_menu_factory,
1848 "/Go/Go to Corresponding Packet", FALSE);
1849 set_menu_sensitivity(tree_view_menu_factory,
1850 "/Go to Corresponding Packet", FALSE);
1851 set_menu_sensitivity(main_menu_factory, "/Analyze/Apply as Filter", FALSE);
1852 set_menu_sensitivity(tree_view_menu_factory, "/Apply as Filter", FALSE);
1853 set_menu_sensitivity(main_menu_factory, "/Analyze/Prepare a Filter", FALSE);
1854 set_menu_sensitivity(tree_view_menu_factory, "/Prepare a Filter", FALSE);
1855 set_menu_sensitivity(tree_view_menu_factory, "/Protocol Preferences...",
1857 set_menu_sensitivity(main_menu_factory, "/View/Expand Tree", FALSE);
1858 set_menu_sensitivity(tree_view_menu_factory, "/Wiki Protocol Page",
1860 set_menu_sensitivity(tree_view_menu_factory, "/Filter Field Reference",
1864 walk_menu_tree_for_selected_tree_row(tap_menu_tree_root, cf->finfo_selected);
1867 void set_menus_for_packet_history(gboolean back_history, gboolean forward_history) {
1869 set_menu_sensitivity(main_menu_factory, "/Go/Back", back_history);
1870 set_menu_sensitivity(main_menu_factory, "/Go/Forward", forward_history);
1872 set_toolbar_for_packet_history(back_history, forward_history);