2 * Routines for GTK+ packet display (packet details and hex dump panes)
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * Jeff Foster, 2001/03/12, added support for displaying named
11 * data sources as tabbed hex windows
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
41 #include <gdk/gdkkeysyms.h>
42 #if GTK_CHECK_VERSION(3,0,0)
43 # include <gdk/gdkkeysyms-compat.h>
48 #include <epan/epan_dissect.h>
50 #include <epan/packet.h>
51 #include <epan/charsets.h>
52 #include <epan/prefs.h>
53 #include <epan/filesystem.h>
55 #include "../isprint.h"
57 #include "ui/alert_box.h"
58 #include "ui/last_open_dir.h"
59 #include "ui/progress_dlg.h"
60 #include "ui/recent.h"
61 #include "ui/simple_dialog.h"
62 #include "ui/ui_util.h"
64 #include <wsutil/file_util.h>
66 #include "ui/gtk/keys.h"
67 #include "ui/gtk/color_utils.h"
68 #include "ui/gtk/packet_win.h"
69 #include "ui/gtk/file_dlg.h"
70 #include "ui/gtk/gui_utils.h"
71 #include "ui/gtk/gtkglobals.h"
72 #include "ui/gtk/font_utils.h"
73 #include "ui/gtk/webbrowser.h"
74 #include "ui/gtk/main.h"
75 #include "ui/gtk/menus.h"
76 #include "ui/gtk/packet_panes.h"
77 #include "ui/gtk/proto_tree_model.h"
78 #include "ui/gtk/bytes_view.h"
81 #include <gdk/gdkwin32.h>
83 #include "ui/win32/file_dlg_win32.h"
87 #define E_BYTE_VIEW_TREE_PTR "byte_view_tree_ptr"
88 #define E_BYTE_VIEW_TREE_VIEW_PTR "byte_view_tree_view_ptr"
89 #define E_BYTE_VIEW_TVBUFF_KEY "byte_view_tvbuff"
90 #define E_BYTE_VIEW_START_KEY "byte_view_start"
91 #define E_BYTE_VIEW_END_KEY "byte_view_end"
92 #define E_BYTE_VIEW_MASK_KEY "byte_view_mask"
93 #define E_BYTE_VIEW_MASKLE_KEY "byte_view_mask_le"
94 #define E_BYTE_VIEW_APP_START_KEY "byte_view_app_start"
95 #define E_BYTE_VIEW_APP_END_KEY "byte_view_app_end"
96 #define E_BYTE_VIEW_PROTO_START_KEY "byte_view_proto_start"
97 #define E_BYTE_VIEW_PROTO_END_KEY "byte_view_proto_end"
98 #define E_BYTE_VIEW_ENCODE_KEY "byte_view_encode"
100 /* Get the current text window for the notebook. */
102 get_notebook_bv_ptr(GtkWidget
*nb_ptr
)
107 num
= gtk_notebook_get_current_page(GTK_NOTEBOOK(nb_ptr
));
108 bv_page
= gtk_notebook_get_nth_page(GTK_NOTEBOOK(nb_ptr
), num
);
110 return gtk_bin_get_child(GTK_BIN(bv_page
));
116 * Get the data and length for a byte view, given the byte view page.
117 * Return the pointer, or NULL on error, and set "*data_len" to the length.
120 get_byte_view_data_and_length(GtkWidget
*byte_view
, guint
*data_len
)
122 tvbuff_t
*byte_view_tvb
;
123 const guint8
*data_ptr
;
125 byte_view_tvb
= (tvbuff_t
*)g_object_get_data(G_OBJECT(byte_view
), E_BYTE_VIEW_TVBUFF_KEY
);
126 if (byte_view_tvb
== NULL
)
129 if ((*data_len
= tvb_length(byte_view_tvb
))) {
130 data_ptr
= tvb_get_ptr(byte_view_tvb
, 0, -1);
137 * Set the current text window for the notebook to the window that
138 * refers to a particular tvbuff.
141 set_notebook_page(GtkWidget
*nb_ptr
, tvbuff_t
*tvb
)
144 GtkWidget
*bv_page
, *bv
;
148 (bv_page
= gtk_notebook_get_nth_page(GTK_NOTEBOOK(nb_ptr
), num
)) != NULL
;
150 bv
= gtk_bin_get_child(GTK_BIN(bv_page
));
151 bv_tvb
= (tvbuff_t
*)g_object_get_data(G_OBJECT(bv
), E_BYTE_VIEW_TVBUFF_KEY
);
154 gtk_notebook_set_current_page(GTK_NOTEBOOK(nb_ptr
), num
);
160 /* Redraw a given byte view window. */
162 redraw_packet_bytes(GtkWidget
*nb
, frame_data
*fd
, field_info
*finfo
)
168 bv
= get_notebook_bv_ptr(nb
);
170 data
= get_byte_view_data_and_length(bv
, &len
);
172 packet_hex_print(bv
, data
, fd
, finfo
, len
);
176 /* Redraw all byte view windows. */
178 redraw_packet_bytes_all(void)
180 if (cfile
.current_frame
!= NULL
)
181 redraw_packet_bytes( byte_nb_ptr_gbl
, cfile
.current_frame
, cfile
.finfo_selected
);
183 redraw_packet_bytes_packet_wins();
185 /* XXX - this is a hack, to workaround a bug in GTK2.x!
186 when changing the font size, even refilling of the corresponding
187 gtk_text_buffer doesn't seem to trigger an update.
188 The only workaround is to freshly select the frame, which will remove any
189 existing notebook tabs and "restart" the whole byte view again. */
190 if (cfile
.current_frame
!= NULL
) {
191 cfile
.current_row
= -1;
192 cf_goto_frame(&cfile
, cfile
.current_frame
->num
);
196 /* Expand trees (and any subtrees they may have) whose ett_ shows them as
198 * Callers should block calls to expand_tree() to avoid useless recursion.
201 check_expand_trees(GtkTreeView
*tree_view
, GtkTreeModel
*model
, GtkTreePath
*path
,
202 GtkTreeIter
*iter
, gboolean scroll_it
, gboolean expand_parent
)
204 /* code inspired by gtk_tree_model_foreach_helper */
211 if (gtk_tree_model_iter_children(model
, &child
, iter
)) {
212 gtk_tree_model_get(model
, iter
, 1, &fi
, -1);
214 if (tree_expanded(fi
->tree_type
)) {
216 gtk_tree_view_expand_row(tree_view
, path
, FALSE
);
219 gtk_tree_view_scroll_to_cell(tree_view
, path
, NULL
, TRUE
, (prefs
.gui_auto_scroll_percentage
/100.0f
), 0.0f
);
221 /* try to expand children only when parent is expanded */
222 gtk_tree_path_down(path
);
223 check_expand_trees(tree_view
, model
, path
, &child
, scroll_it
, TRUE
);
224 gtk_tree_path_up(path
);
228 gtk_tree_path_next(path
);
229 } while (gtk_tree_model_iter_next(model
, iter
));
233 expand_tree(GtkTreeView
*tree_view
, GtkTreeIter
*iter
,
234 GtkTreePath
*path
, gpointer user_data _U_
)
239 model
= gtk_tree_view_get_model(tree_view
);
240 gtk_tree_model_get(model
, iter
, 1, &finfo
, -1);
243 /* scroll the expanded item to reduce the need to do a manual scroll down
244 * and provide faster navigation of deeper trees */
246 if(prefs
.gui_auto_scroll_on_expand
)
247 gtk_tree_view_scroll_to_cell(tree_view
, path
, NULL
, TRUE
, (prefs
.gui_auto_scroll_percentage
/100.0f
), 0.0f
);
250 * Nodes with "finfo->tree_type" of -1 have no ett_ value, and
251 * are thus presumably leaf nodes and cannot be expanded.
253 if (finfo
->tree_type
!= -1)
254 tree_expanded_set(finfo
->tree_type
, TRUE
);
256 if (finfo
->tree_type
!= -1 && path
) {
257 /* Expand any subtrees that the user had left open */
258 g_signal_handlers_block_by_func(tree_view
, expand_tree
, NULL
);
259 check_expand_trees(tree_view
, model
, path
, iter
, FALSE
, FALSE
);
260 g_signal_handlers_unblock_by_func(tree_view
, expand_tree
, NULL
);
265 collapse_tree(GtkTreeView
*tree_view
, GtkTreeIter
*iter
,
266 GtkTreePath
*path _U_
, gpointer user_data _U_
)
271 model
= gtk_tree_view_get_model(tree_view
);
272 gtk_tree_model_get(model
, iter
, 1, &finfo
, -1);
276 * Nodes with "finfo->tree_type" of -1 have no ett_ value, and
277 * are thus presumably leaf nodes and cannot be collapsed.
279 if (finfo
->tree_type
!= -1)
280 tree_expanded_set(finfo
->tree_type
, FALSE
);
283 struct field_lookup_info
{
289 lookup_finfo(GtkTreeModel
*model
, GtkTreePath
*path _U_
, GtkTreeIter
*iter
,
293 struct field_lookup_info
*fli
= (struct field_lookup_info
*)data
;
295 gtk_tree_model_get(model
, iter
, 1, &fi
, -1);
304 *tree_find_by_field_info(GtkTreeView
*tree_view
, field_info
*finfo
)
307 struct field_lookup_info fli
;
309 g_assert(finfo
!= NULL
);
311 model
= gtk_tree_view_get_model(tree_view
);
313 gtk_tree_model_foreach(model
, lookup_finfo
, &fli
);
315 return gtk_tree_model_get_path(model
, &fli
.iter
);
318 /* If the user selected a certain byte in the byte view, try to find
319 * the item in the GUI proto_tree that corresponds to that byte, and:
321 * if we succeed, select it, and return TRUE;
322 * if we fail, return FALSE. */
324 byte_view_select(GtkWidget
*widget
, GdkEventButton
*event
)
327 GtkTreeView
*tree_view
;
331 tree
= (proto_tree
*)g_object_get_data(G_OBJECT(widget
), E_BYTE_VIEW_TREE_PTR
);
334 * Somebody clicked on the dummy byte view; do nothing.
338 tree_view
= GTK_TREE_VIEW(g_object_get_data(G_OBJECT(widget
),
339 E_BYTE_VIEW_TREE_VIEW_PTR
));
341 byte
= bytes_view_byte_from_xy(BYTES_VIEW(widget
), (gint
) event
->x
, (gint
) event
->y
);
347 /* Get the data source tvbuff */
348 tvb
= (tvbuff_t
*)g_object_get_data(G_OBJECT(widget
), E_BYTE_VIEW_TVBUFF_KEY
);
350 return highlight_field(tvb
, byte
, tree_view
, tree
);
353 /* This highlights the field in the proto tree that is at position byte */
355 highlight_field(tvbuff_t
*tvb
, gint byte
, GtkTreeView
*tree_view
,
358 GtkTreeModel
*model
= NULL
;
359 GtkTreePath
*first_path
= NULL
, *path
= NULL
;
361 field_info
*finfo
= NULL
;
363 struct field_lookup_info fli
;
365 if (cfile
.search_in_progress
&& cfile
.string
&& cfile
.decode_data
) {
366 /* The tree where the target string matched one of the labels was discarded in
367 match_protocol_tree() so we have to search again in the latest tree. (Uugh) */
368 if (cf_find_string_protocol_tree(&cfile
, tree
, &mdata
)) {
372 /* Find the finfo that corresponds to our byte. */
373 finfo
= proto_find_field_from_offset(tree
, byte
, tvb
);
380 model
= gtk_tree_view_get_model(tree_view
);
382 gtk_tree_model_foreach(model
, lookup_finfo
, &fli
);
384 /* Expand our field's row */
385 first_path
= gtk_tree_model_get_path(model
, &fli
.iter
);
386 gtk_tree_view_expand_row(tree_view
, first_path
, FALSE
);
387 expand_tree(tree_view
, &fli
.iter
, NULL
, NULL
);
389 /* ... and its parents */
390 while (gtk_tree_model_iter_parent(model
, &parent
, &fli
.iter
)) {
391 path
= gtk_tree_model_get_path(model
, &parent
);
392 gtk_tree_view_expand_row(tree_view
, path
, FALSE
);
393 expand_tree(tree_view
, &parent
, NULL
, NULL
);
395 gtk_tree_path_free(path
);
398 /* select our field's row */
399 gtk_tree_selection_select_path(gtk_tree_view_get_selection(tree_view
),
402 /* If the last search was a string or hex search within "Packet data", the entire field might
403 not be highlighted. If the user just clicked on one of the bytes comprising that field, the
404 above call didn't trigger a 'gtk_tree_view_get_selection' event. Call redraw_packet_bytes()
405 to make the highlighting of the entire field visible. */
406 if (!cfile
.search_in_progress
) {
407 if (cfile
.hex
|| (cfile
.string
&& cfile
.packet_data
)) {
408 redraw_packet_bytes(byte_nb_ptr_gbl
, cfile
.current_frame
, cfile
.finfo_selected
);
412 /* And position the window so the selection is visible.
413 * Position the selection in the middle of the viewable
415 gtk_tree_view_scroll_to_cell(tree_view
, first_path
, NULL
, TRUE
, 0.5f
, 0.0f
);
417 gtk_tree_path_free(first_path
);
422 /* Calls functions for different mouse-button presses. */
424 byte_view_button_press_cb(GtkWidget
*widget
, GdkEvent
*event
, gpointer data
)
426 GdkEventButton
*event_button
= NULL
;
428 if(widget
== NULL
|| event
== NULL
|| data
== NULL
) {
432 if(event
->type
== GDK_BUTTON_PRESS
) {
433 event_button
= (GdkEventButton
*) event
;
435 /* To qoute the "Gdk Event Structures" doc:
436 * "Normally button 1 is the left mouse button, 2 is the middle button, and 3 is the right button" */
437 switch(event_button
->button
) {
440 return byte_view_select(widget
, event_button
);
442 return popup_menu_handler(widget
, event
, data
);
456 byte_nb
= gtk_notebook_new();
457 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(byte_nb
), GTK_POS_BOTTOM
);
459 /* this will only have an effect, if no tabs are shown */
460 gtk_notebook_set_show_border(GTK_NOTEBOOK(byte_nb
), FALSE
);
462 /* set the tabs scrollable, if they don't fit into the pane */
463 gtk_notebook_set_scrollable(GTK_NOTEBOOK(byte_nb
), TRUE
);
465 /* enable a popup menu containing the tab labels, will be helpful if tabs don't fit into the pane */
466 gtk_notebook_popup_enable(GTK_NOTEBOOK(byte_nb
));
468 /* Add a placeholder byte view so that there's at least something
469 displayed in the byte view notebook. */
470 add_byte_tab(byte_nb
, "", NULL
, NULL
, NULL
);
476 byte_view_realize_cb(GtkWidget
*bv
, gpointer data _U_
)
478 const guint8
*byte_data
;
481 byte_data
= get_byte_view_data_and_length(bv
, &byte_len
);
482 if (byte_data
== NULL
) {
483 /* This must be the dummy byte view if no packet is selected. */
486 packet_hex_print(bv
, byte_data
, cfile
.current_frame
, NULL
, byte_len
);
490 add_byte_tab(GtkWidget
*byte_nb
, const char *name
, tvbuff_t
*tvb
,
491 proto_tree
*tree
, GtkWidget
*tree_view
)
493 GtkWidget
*byte_view
, *byte_scrollw
, *label
;
495 /* Byte view. Create a scrolled window for the text. */
496 byte_scrollw
= scrolled_window_new(NULL
, NULL
);
497 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(byte_scrollw
),
499 /* Add scrolled pane to tabbed window */
500 label
= gtk_label_new(name
);
501 gtk_notebook_append_page(GTK_NOTEBOOK(byte_nb
), byte_scrollw
, label
);
503 gtk_widget_show(byte_scrollw
);
505 byte_view
= bytes_view_new();
506 bytes_view_set_font(BYTES_VIEW(byte_view
), user_font_get_regular());
508 g_object_set_data(G_OBJECT(byte_view
), E_BYTE_VIEW_TVBUFF_KEY
, tvb
);
509 gtk_container_add(GTK_CONTAINER(byte_scrollw
), byte_view
);
511 g_signal_connect(byte_view
, "show", G_CALLBACK(byte_view_realize_cb
), NULL
);
512 g_signal_connect(byte_view
, "button_press_event", G_CALLBACK(byte_view_button_press_cb
),
513 g_object_get_data(G_OBJECT(popup_menu_object
), PM_BYTES_VIEW_KEY
));
515 g_object_set_data(G_OBJECT(byte_view
), E_BYTE_VIEW_TREE_PTR
, tree
);
516 g_object_set_data(G_OBJECT(byte_view
), E_BYTE_VIEW_TREE_VIEW_PTR
, tree_view
);
518 gtk_widget_show(byte_view
); /* triggers byte_view_realize_cb which calls packet_hex_print */
520 /* no tabs if this is the first page */
521 if (!(gtk_notebook_page_num(GTK_NOTEBOOK(byte_nb
), byte_scrollw
)))
522 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(byte_nb
), FALSE
);
524 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(byte_nb
), TRUE
);
527 gtk_notebook_set_current_page(GTK_NOTEBOOK(byte_nb
),
528 gtk_notebook_page_num(GTK_NOTEBOOK(byte_nb
), byte_nb
));
534 add_byte_views(epan_dissect_t
*edt
, GtkWidget
*tree_view
,
535 GtkWidget
*byte_nb_ptr
)
538 struct data_source
*src
;
541 * Get rid of all the old notebook tabs.
543 while (gtk_notebook_get_nth_page(GTK_NOTEBOOK(byte_nb_ptr
), 0) != NULL
)
544 gtk_notebook_remove_page(GTK_NOTEBOOK(byte_nb_ptr
), 0);
547 * Add to the specified byte view notebook tabs for hex dumps
548 * of all the data sources for the specified frame.
550 for (src_le
= edt
->pi
.data_src
; src_le
!= NULL
; src_le
= src_le
->next
) {
551 src
= (struct data_source
*)src_le
->data
;
552 add_byte_tab(byte_nb_ptr
, get_data_source_name(src
), get_data_source_tvb(src
), edt
->tree
,
557 * Initially select the first byte view.
559 gtk_notebook_set_current_page(GTK_NOTEBOOK(byte_nb_ptr
), 0);
563 copy_hex_all_info(GString
* copy_buffer
, const guint8
* data_p
, int data_len
, gboolean append_text
)
565 const int byte_line_length
= 16; /* Print out data for 16 bytes on one line */
567 gboolean end_of_line
= TRUE
; /* Initial state is end of line */
568 int byte_line_part_length
;
573 /* Write hex data for a line, then ascii data, then concatenate and add to buffer */
574 hex_str
= g_string_new("");
575 char_str
= g_string_new("");
580 g_string_append_printf(hex_str
,"%04x ",i
); /* Offset - note that we _append_ here */
583 g_string_append_printf(hex_str
," %02x",*data_p
);
585 g_string_append_printf(char_str
,"%c",isprint(*data_p
) ? *data_p
: '.');
590 /* Look ahead to see if this is the end of the data */
591 byte_line_part_length
= (++i
) % byte_line_length
;
593 /* End of data - need to fill in spaces in hex string and then do "end of line".
596 for(j
= 0; append_text
&& (j
< (byte_line_length
- byte_line_part_length
)); ++j
) {
597 g_string_append(hex_str
," "); /* Three spaces for each missing byte */
601 end_of_line
= (byte_line_part_length
== 0 ? TRUE
: FALSE
);
607 g_string_append(copy_buffer
, hex_str
->str
);
609 /* Two spaces between hex and text */
610 g_string_append_c(copy_buffer
, ' ');
611 g_string_append_c(copy_buffer
, ' ');
612 g_string_append(copy_buffer
, char_str
->str
);
614 /* Setup ready for next line */
615 g_string_assign(char_str
,"");
616 g_string_assign(hex_str
, "\n");
620 g_string_free(hex_str
, TRUE
);
621 g_string_free(char_str
, TRUE
);
625 copy_hex_bytes_text_only(GString
* copy_buffer
, const guint8
* data_p
, int data_len _U_
)
630 /* Copy printable characters, newlines, and (horizontal) tabs. */
631 if(isprint(*data_p
)) {
633 } else if(*data_p
==0x0a) {
635 } else if(*data_p
==0x09) {
638 return 1; /* Just ignore non-printable bytes */
640 g_string_append_c(copy_buffer
,to_append
);
645 int copy_hex_bytes_hex(GString
* copy_buffer
, const guint8
* data_p
, int data_len _U_
)
647 g_string_append_printf(copy_buffer
, "%02x", *data_p
);
652 copy_hex_cb(GtkWidget
* w _U_
, gpointer data _U_
, copy_data_type data_type
)
657 int bytes_consumed
= 0;
660 const guint8
* data_p
;
662 GString
* copy_buffer
= g_string_new(""); /* String to copy to clipboard */
664 bv
= get_notebook_bv_ptr(byte_nb_ptr_gbl
);
666 /* shouldn't happen */
667 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
, "Could not find the corresponding text window.");
671 data_p
= get_byte_view_data_and_length(bv
, &len
);
672 g_assert(data_p
!= NULL
);
674 flags
= data_type
& CD_FLAGSMASK
;
675 data_type
= (copy_data_type
)(data_type
& CD_TYPEMASK
);
677 if(flags
& CD_FLAGS_SELECTEDONLY
) {
680 /* Get the start and end of the highlighted bytes. */
681 start
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv
), E_BYTE_VIEW_START_KEY
));
682 end
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv
), E_BYTE_VIEW_END_KEY
));
684 if(start
>= 0 && end
> start
&& (end
- start
<= (int)len
)) {
692 /* This is too different from other text formats - handle separately */
693 copy_hex_all_info(copy_buffer
, data_p
, len
, TRUE
);
696 /* This could be done incrementally, but it is easier to mingle with the code for CD_ALLINFO */
697 copy_hex_all_info(copy_buffer
, data_p
, len
, FALSE
);
700 /* Completely different logic to text copies - leave copy buffer alone */
701 copy_binary_to_clipboard(data_p
,len
);
704 /* Incrementally write to text buffer in various formats */
708 bytes_consumed
= copy_hex_bytes_text_only(copy_buffer
, data_p
, len
);
711 bytes_consumed
= copy_hex_bytes_hex(copy_buffer
, data_p
, len
);
714 g_assert_not_reached();
718 g_assert(bytes_consumed
>0);
719 data_p
+= bytes_consumed
;
720 len
-= bytes_consumed
;
725 if(copy_buffer
->len
> 0) {
726 copy_to_clipboard(copy_buffer
);
729 g_string_free(copy_buffer
, TRUE
);
732 /* save the current highlighted hex data */
734 savehex_save_clicked_cb(gchar
*file
, int start
, int end
, const guint8
*data_p
)
738 fd
= ws_open(file
, O_WRONLY
|O_CREAT
|O_TRUNC
|O_BINARY
, 0666);
740 open_failure_alert_box(file
, errno
, TRUE
);
743 if (ws_write(fd
, data_p
+ start
, end
- start
) < 0) {
744 write_failure_alert_box(file
, errno
);
748 if (ws_close(fd
) < 0) {
749 write_failure_alert_box(file
, errno
);
756 /* Launch the dialog box to put up the file selection box etc */
759 savehex_cb(GtkWidget
* w _U_
, gpointer data _U_
)
761 win32_export_raw_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level
)), &cfile
);
766 gtk_export_raw_file(int start
, int end
)
768 GtkWidget
*savehex_dlg
;
774 * Build the dialog box we need.
776 savehex_dlg
= file_selection_new("Wireshark: Export Selected Packet Bytes", GTK_WINDOW(top_level
), FILE_SELECTION_SAVE
);
779 label
= g_strdup_printf("Will save %u %s of raw binary data to specified file.",
780 end
- start
, plurality(end
- start
, "byte", "bytes"));
781 dlg_lb
= gtk_label_new(label
);
783 file_selection_set_extra_widget(savehex_dlg
, dlg_lb
);
784 gtk_widget_show(dlg_lb
);
786 pathname
= file_selection_run(savehex_dlg
);
787 if (pathname
== NULL
) {
788 /* User cancelled or closed the dialog. */
792 /* We've crosed the Rubicon; get rid of the dialog box. */
793 window_destroy(savehex_dlg
);
799 savehex_cb(GtkWidget
* w _U_
, gpointer data _U_
)
803 const guint8
*data_p
= NULL
;
807 /* don't show up the dialog, if no data has to be saved */
808 bv
= get_notebook_bv_ptr(byte_nb_ptr_gbl
);
810 /* shouldn't happen */
811 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
, "Could not find the corresponding text window.");
814 start
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv
), E_BYTE_VIEW_START_KEY
));
815 end
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv
), E_BYTE_VIEW_END_KEY
));
816 data_p
= get_byte_view_data_and_length(bv
, &len
);
818 if (data_p
== NULL
|| start
== -1 || start
> end
) {
819 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
, "No data selected to save.");
824 * Loop until the user either selects a file or gives up.
827 pathname
= gtk_export_raw_file(start
, end
);
828 if (pathname
== NULL
) {
832 if (savehex_save_clicked_cb(pathname
, start
, end
, data_p
)) {
837 /* Dump failed; let the user select another file or give up. */
844 packet_hex_update(GtkWidget
*bv
, const guint8
*pd
, int len
, int bstart
,
845 int bend
, guint32 bmask
, int bmask_le
,
846 int astart
, int aend
,
847 int pstart
, int pend
,
850 bytes_view_set_encoding(BYTES_VIEW(bv
), encoding
);
851 bytes_view_set_format(BYTES_VIEW(bv
), recent
.gui_bytes_view
);
852 bytes_view_set_data(BYTES_VIEW(bv
), pd
, len
);
854 bytes_view_set_highlight_style(BYTES_VIEW(bv
), prefs
.gui_hex_dump_highlight_style
);
856 bytes_view_set_highlight(BYTES_VIEW(bv
), bstart
, bend
, bmask
, bmask_le
);
857 bytes_view_set_highlight_extra(BYTES_VIEW(bv
), BYTE_VIEW_HIGHLIGHT_APPENDIX
, astart
, aend
);
858 bytes_view_set_highlight_extra(BYTES_VIEW(bv
), BYTE_VIEW_HIGHLIGHT_PROTOCOL
, pstart
, pend
);
860 if (bstart
!= -1 && bend
!= -1)
861 bytes_view_scroll_to_byte(BYTES_VIEW(bv
), bstart
);
862 bytes_view_refresh(BYTES_VIEW(bv
));
866 get_top_finfo(proto_node
*node
, field_info
*finfo
)
873 if (PNODE_FINFO(node
) == finfo
) {
876 while (node
&& node
->parent
) {
881 fi
= PNODE_FINFO(node
);
882 if (fi
&& fi
->ds_tvb
== finfo
->ds_tvb
)
889 for (child
= node
->first_child
; child
; child
= child
->next
) {
890 top
= get_top_finfo(child
, finfo
);
899 packet_hex_print(GtkWidget
*bv
, const guint8
*pd
, frame_data
*fd
,
900 field_info
*finfo
, guint len
)
902 /* do the initial printing and save the information needed */
903 /* to redraw the display if preferences change. */
905 int bstart
= -1, bend
= -1, blen
= -1;
906 guint32 bmask
= 0x00; int bmask_le
= 0;
907 int astart
= -1, aend
= -1, alen
= -1;
908 int pstart
= -1, pend
= -1, plen
= -1;
911 proto_tree
*tree
= (proto_tree
*)g_object_get_data(G_OBJECT(bv
), E_BYTE_VIEW_TREE_PTR
);
912 field_info
*top_finfo
;
914 if (cfile
.search_in_progress
&& (cfile
.hex
|| (cfile
.string
&& cfile
.packet_data
))) {
915 /* In the hex view, only highlight the target bytes or string. The entire
916 field can then be displayed by clicking on any of the bytes in the field. */
918 char *p
= cfile
.sfilter
;
922 if (g_ascii_isxdigit(*p
++))
925 blen
= (blen
+ 1) / 2;
927 blen
= (int)strlen(cfile
.sfilter
);
929 bstart
= cfile
.search_pos
- (blen
-1);
932 blen
= finfo
->length
;
933 bstart
= finfo
->start
;
936 /* bmask = finfo->hfinfo->bitmask << hfinfo_bitshift(finfo->hfinfo); */ /* (value & mask) >> shift */
937 if (finfo
->hfinfo
) bmask
= finfo
->hfinfo
->bitmask
;
938 astart
= finfo
->appendix_start
;
939 alen
= finfo
->appendix_length
;
941 top_finfo
= get_top_finfo(tree
, finfo
);
942 /* it's possible to have top_finfo == finfo, no problem right now */
944 pstart
= top_finfo
->start
;
945 plen
= top_finfo
->length
;
948 if (FI_GET_FLAG(finfo
, FI_LITTLE_ENDIAN
))
950 else if (FI_GET_FLAG(finfo
, FI_BIG_ENDIAN
))
952 else { /* unknown endianess - disable mask
953 bmask_le = (G_BYTE_ORDER == G_LITTLE_ENDIAN);
959 int bito
= FI_GET_BITS_OFFSET(finfo
);
960 int bitc
= FI_GET_BITS_SIZE(finfo
);
961 int bitt
= bito
+ bitc
;
963 /* construct mask using bito & bitc */
964 /* XXX, mask has only 32 bit, later we can store bito&bitc, and use them (which should be faster) */
965 if (bitt
> 0 && bitt
< 32) {
967 bmask
= ((1 << bitc
) - 1) << ((8-bitt
) & 7);
968 bmask_le
= 0; /* ? */
973 if (pstart
>= 0 && plen
> 0 && (guint
)pstart
< len
)
974 pend
= pstart
+ plen
;
976 if (bstart
>= 0 && blen
> 0 && (guint
)bstart
< len
)
977 bend
= bstart
+ blen
;
979 if (astart
>= 0 && alen
> 0 && (guint
)astart
< len
)
980 aend
= astart
+ alen
;
982 if (bend
== -1 && aend
!= -1) {
989 /* don't exceed the end of available data */
990 if (aend
!= -1 && (guint
)aend
> len
) aend
= len
;
991 if (bend
!= -1 && (guint
)bend
> len
) bend
= len
;
992 if (pend
!= -1 && (guint
)pend
> len
) pend
= len
;
994 /* save the information needed to redraw the text */
995 /* should we save the fd & finfo pointers instead ?? */
996 g_object_set_data(G_OBJECT(bv
), E_BYTE_VIEW_START_KEY
, GINT_TO_POINTER(bstart
));
997 g_object_set_data(G_OBJECT(bv
), E_BYTE_VIEW_END_KEY
, GINT_TO_POINTER(bend
));
998 g_object_set_data(G_OBJECT(bv
), E_BYTE_VIEW_MASK_KEY
, GINT_TO_POINTER(bmask
));
999 g_object_set_data(G_OBJECT(bv
), E_BYTE_VIEW_MASKLE_KEY
, GINT_TO_POINTER(bmask_le
));
1000 g_object_set_data(G_OBJECT(bv
), E_BYTE_VIEW_APP_START_KEY
, GINT_TO_POINTER(astart
));
1001 g_object_set_data(G_OBJECT(bv
), E_BYTE_VIEW_APP_END_KEY
, GINT_TO_POINTER(aend
));
1002 g_object_set_data(G_OBJECT(bv
), E_BYTE_VIEW_PROTO_START_KEY
, GINT_TO_POINTER(pstart
));
1003 g_object_set_data(G_OBJECT(bv
), E_BYTE_VIEW_PROTO_END_KEY
, GINT_TO_POINTER(pend
));
1004 g_object_set_data(G_OBJECT(bv
), E_BYTE_VIEW_ENCODE_KEY
,
1005 GUINT_TO_POINTER((guint
)fd
->flags
.encoding
));
1007 /* stig: it should be done only for bitview... */
1008 if (recent
.gui_bytes_view
!= BYTES_BITS
)
1010 packet_hex_update(bv
, pd
, len
, bstart
, bend
, bmask
, bmask_le
, astart
, aend
, pstart
, pend
, fd
->flags
.encoding
);
1014 packet_hex_editor_print(GtkWidget
*bv
, const guint8
*pd
, frame_data
*fd
, int offset
, int bitoffset
, guint len
)
1016 /* do the initial printing and save the information needed */
1017 /* to redraw the display if preferences change. */
1019 int bstart
= offset
, bend
= (bstart
!= -1) ? offset
+1 : -1;
1020 guint32 bmask
=0; int bmask_le
= 0;
1021 int astart
= -1, aend
= -1;
1022 int pstart
= -1, pend
= -1;
1024 switch (recent
.gui_bytes_view
) {
1026 bmask
= (bitoffset
== 0) ? 0xf0 : (bitoffset
== 4) ? 0x0f : 0xff;
1030 bmask
= (1 << (7-bitoffset
));
1034 g_assert_not_reached();
1038 /* save the information needed to redraw the text */
1039 g_object_set_data(G_OBJECT(bv
), E_BYTE_VIEW_START_KEY
, GINT_TO_POINTER(bstart
));
1040 g_object_set_data(G_OBJECT(bv
), E_BYTE_VIEW_END_KEY
, GINT_TO_POINTER(bend
));
1041 g_object_set_data(G_OBJECT(bv
), E_BYTE_VIEW_MASK_KEY
, GINT_TO_POINTER(bmask
));
1042 g_object_set_data(G_OBJECT(bv
), E_BYTE_VIEW_MASKLE_KEY
, GINT_TO_POINTER(bmask_le
));
1043 g_object_set_data(G_OBJECT(bv
), E_BYTE_VIEW_APP_START_KEY
, GINT_TO_POINTER(astart
));
1044 g_object_set_data(G_OBJECT(bv
), E_BYTE_VIEW_APP_END_KEY
, GINT_TO_POINTER(aend
));
1045 g_object_set_data(G_OBJECT(bv
), E_BYTE_VIEW_ENCODE_KEY
,
1046 GUINT_TO_POINTER((guint
)fd
->flags
.encoding
));
1047 g_object_set_data(G_OBJECT(bv
), E_BYTE_VIEW_PROTO_START_KEY
, GINT_TO_POINTER(pstart
));
1048 g_object_set_data(G_OBJECT(bv
), E_BYTE_VIEW_PROTO_END_KEY
, GINT_TO_POINTER(pend
));
1050 packet_hex_update(bv
, pd
, len
, bstart
, bend
, bmask
, bmask_le
, astart
, aend
, pstart
, pend
, fd
->flags
.encoding
);
1054 * Redraw the text using the saved information; usually called if
1055 * the preferences have changed.
1058 packet_hex_reprint(GtkWidget
*bv
)
1060 int start
, end
, mask
, mask_le
, encoding
;
1066 start
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv
), E_BYTE_VIEW_START_KEY
));
1067 end
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv
), E_BYTE_VIEW_END_KEY
));
1068 mask
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv
), E_BYTE_VIEW_MASK_KEY
));
1069 mask_le
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv
), E_BYTE_VIEW_MASKLE_KEY
));
1070 astart
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv
), E_BYTE_VIEW_APP_START_KEY
));
1071 aend
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv
), E_BYTE_VIEW_APP_END_KEY
));
1072 pstart
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv
), E_BYTE_VIEW_PROTO_START_KEY
));
1073 pend
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv
), E_BYTE_VIEW_PROTO_END_KEY
));
1074 data
= get_byte_view_data_and_length(bv
, &len
);
1075 g_assert(data
!= NULL
);
1076 encoding
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv
), E_BYTE_VIEW_ENCODE_KEY
));
1078 /* stig: it should be done only for bitview... */
1079 if (recent
.gui_bytes_view
!= BYTES_BITS
)
1081 packet_hex_update(bv
, data
, len
, start
, end
, mask
, mask_le
, astart
, aend
, pstart
, pend
, encoding
);
1084 /* List of all protocol tree widgets, so we can globally set the selection
1085 mode and font of all of them. */
1086 static GList
*ptree_widgets
;
1088 /* Add a protocol tree widget to the list of protocol tree widgets. */
1089 static void forget_ptree_widget(GtkWidget
*ptreew
, gpointer data
);
1092 remember_ptree_widget(GtkWidget
*ptreew
)
1094 ptree_widgets
= g_list_append(ptree_widgets
, ptreew
);
1096 /* Catch the "destroy" event on the widget, so that we remove it from
1097 the list when it's destroyed. */
1098 g_signal_connect(ptreew
, "destroy", G_CALLBACK(forget_ptree_widget
), NULL
);
1101 /* Remove a protocol tree widget from the list of protocol tree widgets. */
1103 forget_ptree_widget(GtkWidget
*ptreew
, gpointer data _U_
)
1105 ptree_widgets
= g_list_remove(ptree_widgets
, ptreew
);
1109 set_ptree_font_cb(gpointer data
, gpointer user_data
)
1111 #if GTK_CHECK_VERSION(3,0,0)
1112 gtk_widget_override_font((GtkWidget
*)data
,
1113 (PangoFontDescription
*)user_data
);
1115 gtk_widget_modify_font((GtkWidget
*)data
,
1116 (PangoFontDescription
*)user_data
);
1121 set_ptree_font_all(PangoFontDescription
*font
)
1123 g_list_foreach(ptree_widgets
, set_ptree_font_cb
, font
);
1128 * Each expert_color_* level below should match the light gradient
1129 * colors in image/expert_indicators.svg.
1131 static gboolean colors_ok
= FALSE
;
1133 GdkColor expert_color_comment
= { 0, 0xb7b7, 0xf7f7, 0x7474 }; /* Green */
1134 GdkColor expert_color_chat
= { 0, 0x8080, 0xb7b7, 0xf7f7 }; /* light blue */
1135 GdkColor expert_color_note
= { 0, 0xa0a0, 0xffff, 0xffff }; /* bright turquoise */
1136 GdkColor expert_color_warn
= { 0, 0xf7f7, 0xf2f2, 0x5353 }; /* yellow */
1137 GdkColor expert_color_error
= { 0, 0xffff, 0x5c5c, 0x5c5c }; /* pale red */
1138 GdkColor expert_color_foreground
= { 0, 0x0000, 0x0000, 0x0000 }; /* black */
1139 GdkColor hidden_proto_item
= { 0, 0x4444, 0x4444, 0x4444 }; /* gray */
1141 gchar
*expert_color_comment_str
;
1142 gchar
*expert_color_chat_str
;
1143 gchar
*expert_color_note_str
;
1144 gchar
*expert_color_warn_str
;
1145 gchar
*expert_color_error_str
;
1146 gchar
*expert_color_foreground_str
;
1148 void proto_draw_colors_init(void)
1154 /* Allocating collor isn't necessary? */
1155 get_color(&expert_color_chat
);
1156 get_color(&expert_color_note
);
1157 get_color(&expert_color_warn
);
1158 get_color(&expert_color_error
);
1159 get_color(&expert_color_foreground
);
1161 expert_color_comment_str
= gdk_color_to_string(&expert_color_comment
);
1162 expert_color_chat_str
= gdk_color_to_string(&expert_color_chat
);
1163 expert_color_note_str
= gdk_color_to_string(&expert_color_note
);
1164 expert_color_warn_str
= gdk_color_to_string(&expert_color_warn
);
1165 expert_color_error_str
= gdk_color_to_string(&expert_color_error
);
1166 expert_color_foreground_str
= gdk_color_to_string(&expert_color_foreground
);
1169 get_color(&hidden_proto_item
);
1176 tree_cell_renderer(GtkTreeViewColumn
*tree_column _U_
, GtkCellRenderer
*cell
,
1177 GtkTreeModel
*tree_model
, GtkTreeIter
*iter
,
1182 gtk_tree_model_get(tree_model
, iter
, 1, &fi
, -1);
1185 proto_draw_colors_init();
1188 /* for the various possible attributes, see:
1189 * http://developer.gnome.org/doc/API/2.0/gtk/GtkCellRendererText.html
1191 * color definitions can be found at:
1192 * http://cvs.gnome.org/viewcvs/gtk+/gdk-pixbuf/io-xpm.c?rev=1.42
1193 * (a good color overview: http://www.computerhope.com/htmcolor.htm)
1196 * background-gdk: doesn't seem to work (probably the GdkColor must be allocated)
1197 * weight/style: doesn't take any effect
1200 /* for each field, we have to reset the renderer attributes */
1201 g_object_set (cell
, "foreground-set", FALSE
, NULL
);
1203 g_object_set (cell
, "background-set", FALSE
, NULL
);
1205 g_object_set (cell
, "underline", PANGO_UNDERLINE_NONE
, NULL
);
1206 g_object_set (cell
, "underline-set", FALSE
, NULL
);
1208 /*g_object_set (cell, "style", PANGO_STYLE_NORMAL, NULL);
1209 g_object_set (cell, "style-set", FALSE, NULL);*/
1211 /*g_object_set (cell, "weight", PANGO_WEIGHT_NORMAL, NULL);
1212 g_object_set (cell, "weight-set", FALSE, NULL);*/
1214 if(FI_GET_FLAG(fi
, FI_GENERATED
)) {
1215 /* we use "[...]" to mark generated items, no need to change things here */
1217 /* as some fonts don't support italic, don't use this */
1218 /*g_object_set (cell, "style", PANGO_STYLE_ITALIC, NULL);
1219 g_object_set (cell, "style-set", TRUE, NULL);
1221 /*g_object_set (cell, "weight", PANGO_WEIGHT_BOLD, NULL);
1222 g_object_set (cell, "weight-set", TRUE, NULL);*/
1225 if(FI_GET_FLAG(fi
, FI_HIDDEN
)) {
1226 g_object_set (cell
, "foreground-gdk", &hidden_proto_item
, NULL
);
1227 g_object_set (cell
, "foreground-set", TRUE
, NULL
);
1230 if (fi
&& fi
->hfinfo
) {
1231 if(fi
->hfinfo
->type
== FT_PROTOCOL
) {
1232 g_object_set (cell
, "background", "gray90", NULL
);
1233 g_object_set (cell
, "background-set", TRUE
, NULL
);
1234 g_object_set (cell
, "foreground", "black", NULL
);
1235 g_object_set (cell
, "foreground-set", TRUE
, NULL
);
1236 /*g_object_set (cell, "weight", PANGO_WEIGHT_BOLD, NULL);
1237 g_object_set (cell, "weight-set", TRUE, NULL);*/
1240 if((fi
->hfinfo
->type
== FT_FRAMENUM
) ||
1241 (FI_GET_FLAG(fi
, FI_URL
) && IS_FT_STRING(fi
->hfinfo
->type
))) {
1242 render_as_url(cell
);
1246 if(FI_GET_FLAG(fi
, PI_SEVERITY_MASK
)) {
1247 switch(FI_GET_FLAG(fi
, PI_SEVERITY_MASK
)) {
1249 g_object_set (cell
, "background-gdk", &expert_color_comment
, NULL
);
1250 g_object_set (cell
, "background-set", TRUE
, NULL
);
1253 g_object_set (cell
, "background-gdk", &expert_color_chat
, NULL
);
1254 g_object_set (cell
, "background-set", TRUE
, NULL
);
1257 g_object_set (cell
, "background-gdk", &expert_color_note
, NULL
);
1258 g_object_set (cell
, "background-set", TRUE
, NULL
);
1261 g_object_set (cell
, "background-gdk", &expert_color_warn
, NULL
);
1262 g_object_set (cell
, "background-set", TRUE
, NULL
);
1265 g_object_set (cell
, "background-gdk", &expert_color_error
, NULL
);
1266 g_object_set (cell
, "background-set", TRUE
, NULL
);
1269 g_assert_not_reached();
1271 g_object_set (cell
, "foreground", "black", NULL
);
1272 g_object_set (cell
, "foreground-set", TRUE
, NULL
);
1277 proto_tree_view_new(GtkWidget
**tree_view_p
)
1279 GtkWidget
*tv_scrollw
, *tree_view
;
1280 ProtoTreeModel
*store
;
1281 GtkCellRenderer
*renderer
;
1282 GtkTreeViewColumn
*column
;
1286 tv_scrollw
= scrolled_window_new(NULL
, NULL
);
1287 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(tv_scrollw
),
1290 store
= proto_tree_model_new(NULL
, prefs
.display_hidden_proto_items
);
1291 tree_view
= tree_view_new(GTK_TREE_MODEL(store
));
1292 g_object_unref(G_OBJECT(store
));
1293 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_view
), FALSE
);
1294 renderer
= gtk_cell_renderer_text_new();
1295 g_object_set (renderer
, "ypad", 0, NULL
);
1296 col_offset
= gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(tree_view
),
1297 -1, "Name", renderer
,
1299 column
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree_view
),
1301 gtk_tree_view_column_set_cell_data_func(column
, renderer
, tree_cell_renderer
,
1304 gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column
),
1305 GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
1306 g_signal_connect(tree_view
, "row-expanded", G_CALLBACK(expand_tree
), NULL
);
1307 g_signal_connect(tree_view
, "row-collapsed", G_CALLBACK(collapse_tree
), NULL
);
1308 gtk_container_add( GTK_CONTAINER(tv_scrollw
), tree_view
);
1309 #if GTK_CHECK_VERSION(3,0,0)
1310 gtk_widget_override_font(tree_view
, user_font_get_regular());
1312 gtk_widget_modify_font(tree_view
, user_font_get_regular());
1314 remember_ptree_widget(tree_view
);
1316 *tree_view_p
= tree_view
;
1322 expand_all_tree(proto_tree
*protocol_tree _U_
, GtkWidget
*tree_view
)
1326 for(i
=0; i
< num_tree_types
; i
++)
1327 tree_expanded_set(i
, TRUE
);
1329 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree_view
));
1333 collapse_all_tree(proto_tree
*protocol_tree _U_
, GtkWidget
*tree_view
)
1337 for(i
=0; i
< num_tree_types
; i
++)
1338 tree_expanded_set(i
, FALSE
);
1340 gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree_view
));
1344 tree_view_follow_link(field_info
*fi
)
1348 if(fi
->hfinfo
->type
== FT_FRAMENUM
) {
1349 cf_goto_frame(&cfile
, fi
->value
.value
.uinteger
);
1351 if(FI_GET_FLAG(fi
, FI_URL
) && IS_FT_STRING(fi
->hfinfo
->type
)) {
1352 url
= fvalue_to_string_repr(&fi
->value
, FTREPR_DISPLAY
, NULL
);
1354 browser_open_url(url
);
1361 /* If the user selected a position in the tree view, try to find
1362 * the item in the GUI proto_tree that corresponds to that byte, and
1365 tree_view_select(GtkWidget
*widget
, GdkEventButton
*event
)
1367 GtkTreeSelection
*sel
;
1370 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget
),
1371 (gint
) (((GdkEventButton
*)event
)->x
),
1372 (gint
) (((GdkEventButton
*)event
)->y
),
1373 &path
, NULL
, NULL
, NULL
))
1375 sel
= gtk_tree_view_get_selection(GTK_TREE_VIEW(widget
));
1377 /* if that's a doubleclick, try to follow the link */
1378 if(event
->type
== GDK_2BUTTON_PRESS
) {
1379 GtkTreeModel
*model
;
1383 if(gtk_tree_selection_get_selected (sel
, &model
, &iter
)) {
1384 if (event
->state
& GDK_SHIFT_MASK
) {
1385 new_packet_window(NULL
, TRUE
, FALSE
);
1388 gtk_tree_model_get(model
, &iter
, 1, &fi
, -1);
1389 tree_view_follow_link(fi
);
1393 else if (((GdkEventButton
*)event
)->button
!= 1) {
1394 /* if button == 1 gtk_tree_selection_select_path is already (or will be) called by the widget */
1395 gtk_tree_selection_select_path(sel
, path
);
1404 proto_tree_draw_resolve(proto_tree
*protocol_tree
, GtkWidget
*tree_view
, const e_addr_resolve
*resolv
)
1406 ProtoTreeModel
*model
;
1410 model
= proto_tree_model_new(protocol_tree
, prefs
.display_hidden_proto_items
);
1412 proto_tree_model_force_resolv(PROTO_TREE_MODEL(model
), resolv
);
1413 gtk_tree_view_set_model(GTK_TREE_VIEW(tree_view
), GTK_TREE_MODEL(model
));
1415 g_signal_handlers_block_by_func(tree_view
, expand_tree
, NULL
);
1417 /* modified version of gtk_tree_model_foreach */
1418 path
= gtk_tree_path_new_first();
1419 if (gtk_tree_model_get_iter(GTK_TREE_MODEL(model
), &iter
, path
))
1420 check_expand_trees(GTK_TREE_VIEW(tree_view
), GTK_TREE_MODEL(model
),
1421 path
, &iter
, prefs
.gui_auto_scroll_on_expand
, TRUE
);
1422 gtk_tree_path_free(path
);
1424 g_signal_handlers_unblock_by_func(tree_view
, expand_tree
, NULL
);
1426 g_object_unref(G_OBJECT(model
));
1429 /* fill the whole protocol tree with the string values */
1431 proto_tree_draw(proto_tree
*protocol_tree
, GtkWidget
*tree_view
)
1433 proto_tree_draw_resolve(protocol_tree
, tree_view
, NULL
);
1437 select_bytes_view (GtkWidget
*w _U_
, gpointer data _U_
, gint view
)
1439 if (recent
.gui_bytes_view
!= view
) {
1440 recent
.gui_bytes_view
= view
;
1441 redraw_packet_bytes_all();