2 * Routines for GTK+ packet display
4 * $Id: proto_draw.c,v 1.57 2002/08/28 21:03:49 jmayer Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
36 #include <gdk/gdkkeysyms.h>
41 #include <epan/epan_dissect.h>
44 #include <epan/packet.h>
51 #include "proto_draw.h"
52 #include "packet_win.h"
54 #include "gtkglobals.h"
56 #define BYTE_VIEW_WIDTH 16
57 #define BYTE_VIEW_SEP 8
59 #define E_BYTE_VIEW_TREE_PTR "byte_view_tree_ptr"
60 #define E_BYTE_VIEW_TREE_VIEW_PTR "byte_view_tree_view_ptr"
61 #define E_BYTE_VIEW_NDIGITS_KEY "byte_view_ndigits"
62 #define E_BYTE_VIEW_TVBUFF_KEY "byte_view_tvbuff"
63 #define E_BYTE_VIEW_START_KEY "byte_view_start"
64 #define E_BYTE_VIEW_END_KEY "byte_view_end"
65 #define E_BYTE_VIEW_ENCODE_KEY "byte_view_encode"
68 add_byte_tab(GtkWidget *byte_nb, const char *name, tvbuff_t *tvb,
69 proto_tree *tree, GtkWidget *tree_view);
72 proto_tree_draw_node(GNode *node, gpointer data);
74 /* Get the current text window for the notebook. */
76 get_notebook_bv_ptr(GtkWidget *nb_ptr)
81 num = gtk_notebook_get_current_page(GTK_NOTEBOOK(nb_ptr));
82 bv_page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(nb_ptr), num);
83 return GTK_BIN(bv_page)->child;
87 * Get the data and length for a byte view, given the byte view page.
88 * Return the pointer, or NULL on error, and set "*data_len" to the length.
91 get_byte_view_data_and_length(GtkWidget *byte_view, guint *data_len)
93 tvbuff_t *byte_view_tvb;
94 const guint8 *data_ptr;
96 byte_view_tvb = gtk_object_get_data(GTK_OBJECT(byte_view),
97 E_BYTE_VIEW_TVBUFF_KEY);
98 if (byte_view_tvb == NULL)
101 data_ptr = tvb_get_ptr(byte_view_tvb, 0, -1);
102 *data_len = tvb_length(byte_view_tvb);
107 * Set the current text window for the notebook to the window that
108 * refers to a particular tvbuff.
111 set_notebook_page(GtkWidget *nb_ptr, tvbuff_t *tvb)
114 GtkWidget *bv_page, *bv;
118 (bv_page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(nb_ptr), num)) != NULL;
120 bv = GTK_BIN(bv_page)->child;
121 bv_tvb = gtk_object_get_data(GTK_OBJECT(bv), E_BYTE_VIEW_TVBUFF_KEY);
124 gtk_notebook_set_page(GTK_NOTEBOOK(nb_ptr), num);
130 /* Redraw a given byte view window. */
132 redraw_hex_dump(GtkWidget *nb, frame_data *fd, field_info *finfo)
138 bv = get_notebook_bv_ptr(nb);
140 data = get_byte_view_data_and_length(bv, &len);
142 packet_hex_print(GTK_TEXT(bv), data, fd, finfo, len);
146 /* Redraw all byte view windows. */
148 redraw_hex_dump_all(void)
150 if (cfile.current_frame != NULL)
151 redraw_hex_dump( byte_nb_ptr, cfile.current_frame, finfo_selected);
153 redraw_hex_dump_packet_wins();
157 expand_tree(GtkCTree *ctree, GtkCTreeNode *node, gpointer user_data _U_)
161 finfo = gtk_ctree_node_get_row_data( ctree, node);
165 * Nodes with "finfo->tree_type" of -1 have no ett_ value, and
166 * are thus presumably leaf nodes and cannot be expanded.
168 if (finfo->tree_type != -1) {
169 g_assert(finfo->tree_type >= 0 &&
170 finfo->tree_type < num_tree_types);
171 tree_is_expanded[finfo->tree_type] = TRUE;
176 collapse_tree(GtkCTree *ctree, GtkCTreeNode *node, gpointer user_data _U_)
180 finfo = gtk_ctree_node_get_row_data( ctree, node);
184 * Nodes with "finfo->tree_type" of -1 have no ett_ value, and
185 * are thus presumably leaf nodes and cannot be collapsed.
187 if (finfo->tree_type != -1) {
188 g_assert(finfo->tree_type >= 0 &&
189 finfo->tree_type < num_tree_types);
190 tree_is_expanded[finfo->tree_type] = FALSE;
195 toggle_tree(GtkCTree *ctree, GdkEventKey *event, gpointer user_data _U_)
197 if (event->keyval != GDK_Return)
199 gtk_ctree_toggle_expansion(ctree, GTK_CTREE_NODE(ctree->clist.selection->data));
202 #define MAX_OFFSET_LEN 8 /* max length of hex offset of bytes */
203 #define BYTES_PER_LINE 16 /* max byte values in a line */
204 #define HEX_DUMP_LEN (BYTES_PER_LINE*3 + 1)
205 /* max number of characters hex dump takes -
206 2 digits plus trailing blank
207 plus separator between first and
209 #define DATA_DUMP_LEN (HEX_DUMP_LEN + 2 + BYTES_PER_LINE)
210 /* number of characters those bytes take;
211 3 characters per byte of hex dump,
212 2 blanks separating hex from ASCII,
213 1 character per byte of ASCII dump */
214 #define MAX_LINE_LEN (MAX_OFFSET_LEN + 2 + DATA_DUMP_LEN)
215 /* number of characters per line;
216 offset, 2 blanks separating offset
217 from data dump, data dump */
219 /* Which byte the offset is referring to. Associates
220 * whitespace with the preceding digits. */
222 byte_num(int offset, int start_point)
224 return (offset - start_point) / 3;
227 /* If the user selected a certain byte in the byte view, try to find
228 * the item in the GUI proto_tree that corresponds to that byte, and
231 byte_view_select(GtkWidget *widget, GdkEventButton *event)
235 GtkCTreeNode *node, *parent;
237 GtkText *bv = GTK_TEXT(widget);
252 * Get the number of digits of offset being displayed, and
253 * compute the columns of various parts of the display.
255 ndigits = GPOINTER_TO_UINT(gtk_object_get_data(GTK_OBJECT(bv),
256 E_BYTE_VIEW_NDIGITS_KEY));
259 * The column of the first hex digit in the first half.
260 * That starts after "ndigits" digits of offset and two
263 digits_start_1 = ndigits + 2;
266 * The column of the last hex digit in the first half.
267 * There are BYTES_PER_LINE/2 bytes displayed in the first
268 * half; there are 2 characters per byte, plus a separating
269 * blank after all but the last byte's characters.
271 * Then subtract 1 to get the last column of the first half
272 * rather than the first column after the first half.
274 digits_end_1 = digits_start_1 + (BYTES_PER_LINE/2)*2 +
275 (BYTES_PER_LINE/2 - 1) - 1;
278 * The column of the first hex digit in the second half.
279 * Add back the 1 to get the first column after the first
280 * half, and then add 2 for the 2 separating blanks between
283 digits_start_2 = digits_end_1 + 3;
286 * The column of the last hex digit in the second half.
287 * Add the same value we used to get "digits_end_1" from
290 digits_end_2 = digits_start_2 + (BYTES_PER_LINE/2)*2 +
291 (BYTES_PER_LINE/2 - 1) - 1;
294 * The column of the first "text dump" character in the first half.
295 * Add back the 1 to get the first column after the second
296 * half's hex dump, and then add 3 for the 3 separating blanks
297 * between the hex and text dummp.
299 text_start_1 = digits_end_2 + 4;
302 * The column of the last "text dump" character in the first half.
303 * There are BYTES_PER_LINE/2 bytes displayed in the first
304 * half; there is 1 character per byte.
306 * Then subtract 1 to get the last column of the first half
307 * rather than the first column after the first half.
309 text_end_1 = text_start_1 + BYTES_PER_LINE/2 - 1;
312 * The column of the first "text dump" character in the second half.
313 * Add back the 1 to get the first column after the first half,
314 * and then add 1 for the separating blank between the halves.
316 text_start_2 = text_end_1 + 2;
319 * The column of the last "text dump" character in second half.
320 * Add the same value we used to get "text_end_1" from
323 text_end_2 = text_start_2 + BYTES_PER_LINE/2 - 1;
325 tree = gtk_object_get_data(GTK_OBJECT(widget), E_BYTE_VIEW_TREE_PTR);
328 * Somebody clicked on the dummy byte view; do nothing.
332 ctree = GTK_CTREE(gtk_object_get_data(GTK_OBJECT(widget),
333 E_BYTE_VIEW_TREE_VIEW_PTR));
335 /* Given the mouse (x,y) and the current GtkText (h,v)
336 * adjustments, and the size of the font, figure out
337 * which text column/row the user selected. This could be off
338 * if the bold version of the font is bigger than the
339 * regular version of the font. */
340 column = (bv->hadj->value + event->x) / m_font_width;
341 row = (bv->vadj->value + event->y) / m_font_height;
343 /* Given the column and row, determine which byte offset
344 * the user clicked on. */
345 if (column >= digits_start_1 && column <= digits_end_1) {
346 byte = byte_num(column, digits_start_1);
351 else if (column >= digits_start_2 && column <= digits_end_2) {
352 byte = byte_num(column, digits_start_2);
358 else if (column >= text_start_1 && column <= text_end_1) {
359 byte = column - text_start_1;
361 else if (column >= text_start_2 && column <= text_end_2) {
362 byte = 8 + column - text_start_2;
365 /* The user didn't select a hex digit or
366 * text-dump character. */
370 /* Add the number of bytes from the previous rows. */
373 /* Get the data source tvbuff */
374 tvb = gtk_object_get_data(GTK_OBJECT(widget), E_BYTE_VIEW_TVBUFF_KEY);
376 /* Find the finfo that corresponds to our byte. */
377 finfo = proto_find_field_from_offset(tree, byte, tvb);
383 node = gtk_ctree_find_by_row_data(ctree, NULL, finfo);
386 /* Expand and select our field's row */
387 gtk_ctree_expand(ctree, node);
388 gtk_ctree_select(ctree, node);
389 expand_tree(ctree, node, NULL);
391 /* ... and its parents */
392 parent = GTK_CTREE_ROW(node)->parent;
394 gtk_ctree_expand(ctree, parent);
395 expand_tree(ctree, parent, NULL);
396 parent = GTK_CTREE_ROW(parent)->parent;
399 /* And position the window so the selection is visible.
400 * Position the selection in the middle of the viewable
402 gtk_ctree_node_moveto(ctree, node, 0, .5, 0);
407 /* Calls functions for different mouse-button presses. */
409 byte_view_button_press_cb(GtkWidget *widget, GdkEvent *event, gpointer data)
411 GdkEventButton *event_button = NULL;
413 if(widget == NULL || event == NULL || data == NULL) {
417 if(event->type == GDK_BUTTON_PRESS) {
418 event_button = (GdkEventButton *) event;
420 switch(event_button->button) {
423 return byte_view_select(widget, event_button);
425 return popup_menu_handler(widget, event, data);
435 create_byte_view(gint bv_size, GtkWidget *pane)
439 byte_nb = gtk_notebook_new();
440 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(byte_nb), GTK_POS_BOTTOM);
442 gtk_paned_pack2(GTK_PANED(pane), byte_nb, FALSE, FALSE);
443 gtk_widget_set_usize(byte_nb, -1, bv_size);
444 gtk_widget_show(byte_nb);
446 /* Add a placeholder byte view so that there's at least something
447 displayed in the byte view notebook. */
448 add_byte_tab(byte_nb, "", NULL, NULL, NULL);
454 byte_view_realize_cb(GtkWidget *bv, gpointer data _U_)
456 const guint8 *byte_data;
459 byte_data = get_byte_view_data_and_length(bv, &byte_len);
460 if (byte_data == NULL) {
461 /* This must be the dummy byte view if no packet is selected. */
464 packet_hex_print(GTK_TEXT(bv), byte_data, cfile.current_frame, NULL, byte_len);
468 add_byte_tab(GtkWidget *byte_nb, const char *name, tvbuff_t *tvb,
469 proto_tree *tree, GtkWidget *tree_view)
471 GtkWidget *byte_view, *byte_scrollw, *label;
473 /* Byte view. Create a scrolled window for the text. */
474 byte_scrollw = scrolled_window_new(NULL, NULL);
476 /* Add scrolled pane to tabbed window */
477 label = gtk_label_new(name);
478 gtk_notebook_append_page(GTK_NOTEBOOK(byte_nb), byte_scrollw, label);
480 /* The horizontal scrollbar of the scroll-window doesn't seem
481 * to affect the GtkText widget at all, even when line wrapping
482 * is turned off in the GtkText widget and there is indeed more
483 * horizontal data. */
484 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(byte_scrollw),
485 /* Horizontal */GTK_POLICY_NEVER,
486 /* Vertical*/ GTK_POLICY_ALWAYS);
487 gtk_widget_show(byte_scrollw);
489 byte_view = gtk_text_new(NULL, NULL);
490 gtk_text_set_editable(GTK_TEXT(byte_view), FALSE);
491 gtk_text_set_word_wrap(GTK_TEXT(byte_view), FALSE);
492 gtk_text_set_line_wrap(GTK_TEXT(byte_view), FALSE);
493 gtk_object_set_data(GTK_OBJECT(byte_view), E_BYTE_VIEW_TVBUFF_KEY,
495 gtk_container_add(GTK_CONTAINER(byte_scrollw), byte_view);
497 gtk_signal_connect(GTK_OBJECT(byte_view), "show",
498 GTK_SIGNAL_FUNC(byte_view_realize_cb), NULL);
499 gtk_signal_connect(GTK_OBJECT(byte_view), "button_press_event",
500 GTK_SIGNAL_FUNC(byte_view_button_press_cb),
501 gtk_object_get_data(GTK_OBJECT(popup_menu_object),
504 gtk_object_set_data(GTK_OBJECT(byte_view), E_BYTE_VIEW_TREE_PTR,
506 gtk_object_set_data(GTK_OBJECT(byte_view), E_BYTE_VIEW_TREE_VIEW_PTR,
509 gtk_widget_show(byte_view);
511 /* no tabs if this is the first page */
512 if (!(gtk_notebook_page_num(GTK_NOTEBOOK(byte_nb), byte_scrollw)))
513 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(byte_nb), FALSE);
515 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(byte_nb), TRUE);
521 add_byte_views(epan_dissect_t *edt, GtkWidget *tree_view,
522 GtkWidget *byte_nb_ptr)
528 * Get rid of all the old notebook tabs.
530 while (gtk_notebook_get_nth_page(GTK_NOTEBOOK(byte_nb_ptr), 0) != NULL)
531 gtk_notebook_remove_page(GTK_NOTEBOOK(byte_nb_ptr), 0);
534 * Add to the specified byte view notebook tabs for hex dumps
535 * of all the data sources for the specified frame.
537 for (src_le = edt->pi.data_src; src_le != NULL; src_le = src_le->next) {
539 add_byte_tab(byte_nb_ptr, src->name, src->tvb, edt->tree,
544 * Initially select the first byte view.
546 gtk_notebook_set_page(GTK_NOTEBOOK(byte_nb_ptr), 0);
550 packet_hex_print_common(GtkText *bv, const guint8 *pd, int len, int bstart,
551 int bend, int encoding)
553 int i = 0, j, k, cur;
554 guchar line[MAX_LINE_LEN + 1];
555 static guchar hexchars[16] = {
556 '0', '1', '2', '3', '4', '5', '6', '7',
557 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
559 unsigned int use_digits;
560 GdkFont *cur_font, *new_font;
562 gboolean reverse, newreverse;
564 /* Freeze the text for faster display */
567 /* Clear out the text */
568 gtk_text_set_point(bv, 0);
569 /* Keep GTK+ 1.2.3 through 1.2.6 from dumping core - see
570 http://www.ethereal.com/lists/ethereal-dev/199912/msg00312.html and
571 http://www.gnome.org/mailing-lists/archives/gtk-devel-list/1999-October/0051.shtml
572 for more information */
573 gtk_adjustment_set_value(bv->vadj, 0.0);
574 gtk_text_forward_delete(bv, gtk_text_get_length(bv));
577 * How many of the leading digits of the offset will we supply?
578 * We always supply at least 4 digits, but if the maximum offset
579 * won't fit in 4 digits, we use as many digits as will be needed.
581 if (((len - 1) & 0xF0000000) != 0)
582 use_digits = 8; /* need all 8 digits */
583 else if (((len - 1) & 0x0F000000) != 0)
584 use_digits = 7; /* need 7 digits */
585 else if (((len - 1) & 0x00F00000) != 0)
586 use_digits = 6; /* need 6 digits */
587 else if (((len - 1) & 0x000F0000) != 0)
588 use_digits = 5; /* need 5 digits */
590 use_digits = 4; /* we'll supply 4 digits */
592 /* Record the number of digits in this text view. */
593 gtk_object_set_data(GTK_OBJECT(bv), E_BYTE_VIEW_NDIGITS_KEY,
594 GUINT_TO_POINTER(use_digits));
597 /* Print the line number */
602 c = (i >> (j*4)) & 0xF;
603 line[cur++] = hexchars[c];
609 /* Display with inverse video ? */
610 if (prefs.gui_hex_dump_highlight_style) {
611 gtk_text_insert(bv, m_r_font, &BLACK, &WHITE, line, -1);
612 /* Do we start in reverse? */
613 reverse = i >= bstart && i < bend;
614 fg = reverse ? &WHITE : &BLACK;
615 bg = reverse ? &BLACK : &WHITE;
617 k = i + BYTE_VIEW_WIDTH;
619 /* Print the hex bit */
622 line[cur++] = hexchars[(pd[i] & 0xf0) >> 4];
623 line[cur++] = hexchars[pd[i] & 0x0f];
625 line[cur++] = ' '; line[cur++] = ' ';
628 newreverse = i >= bstart && i < bend;
629 /* Have we gone from reverse to plain? */
630 if (reverse && (reverse != newreverse)) {
631 gtk_text_insert(bv, m_r_font, fg, bg, line, cur);
636 /* Inter byte space if not at end of line */
639 /* insert a space every BYTE_VIEW_SEP bytes */
640 if( ( i % BYTE_VIEW_SEP ) == 0 ) {
644 /* Have we gone from plain to reversed? */
645 if (!reverse && (reverse != newreverse)) {
646 gtk_text_insert(bv, m_r_font, fg, bg, line, cur);
651 reverse = newreverse;
653 /* Print remaining part of line */
654 gtk_text_insert(bv, m_r_font, fg, bg, line, cur);
656 /* Print some space at the end of the line */
657 line[cur++] = ' '; line[cur++] = ' '; line[cur++] = ' ';
658 gtk_text_insert(bv, m_r_font, &BLACK, &WHITE, line, cur);
661 /* Print the ASCII bit */
663 /* Do we start in reverse? */
664 reverse = i >= bstart && i < bend;
665 fg = reverse ? &WHITE : &BLACK;
666 bg = reverse ? &BLACK : &WHITE;
669 if (encoding == CHAR_ASCII) {
672 else if (encoding == CHAR_EBCDIC) {
673 c = EBCDIC_to_ASCII1(pd[i]);
676 g_assert_not_reached();
678 line[cur++] = isprint(c) ? c : '.';
683 newreverse = i >= bstart && i < bend;
684 /* Have we gone from reverse to plain? */
685 if (reverse && (reverse != newreverse)) {
686 gtk_text_insert(bv, m_r_font, fg, bg, line, cur);
692 /* insert a space every BYTE_VIEW_SEP bytes */
693 if( ( i % BYTE_VIEW_SEP ) == 0 ) {
697 /* Have we gone from plain to reversed? */
698 if (!reverse && (reverse != newreverse)) {
699 gtk_text_insert(bv, m_r_font, fg, bg, line, cur);
704 reverse = newreverse;
706 /* Print remaining part of line */
707 gtk_text_insert(bv, m_r_font, fg, bg, line, cur);
711 gtk_text_insert(bv, m_r_font, &BLACK, &WHITE, line, -1);
714 gtk_text_insert(bv, m_r_font, NULL, NULL, line, -1);
715 /* Do we start in bold? */
716 cur_font = (i >= bstart && i < bend) ? m_b_font : m_r_font;
718 k = i + BYTE_VIEW_WIDTH;
720 /* Print the hex bit */
723 line[cur++] = hexchars[(pd[i] & 0xf0) >> 4];
724 line[cur++] = hexchars[pd[i] & 0x0f];
726 line[cur++] = ' '; line[cur++] = ' ';
730 /* insert a space every BYTE_VIEW_SEP bytes */
731 if( ( i % BYTE_VIEW_SEP ) == 0 ) line[cur++] = ' ';
732 /* Did we cross a bold/plain boundary? */
733 new_font = (i >= bstart && i < bend) ? m_b_font : m_r_font;
734 if (cur_font != new_font) {
735 gtk_text_insert(bv, cur_font, NULL, NULL, line, cur);
741 gtk_text_insert(bv, cur_font, NULL, NULL, line, cur);
745 /* Print the ASCII bit */
746 cur_font = (i >= bstart && i < bend) ? m_b_font : m_r_font;
749 if (encoding == CHAR_ASCII) {
752 else if (encoding == CHAR_EBCDIC) {
753 c = EBCDIC_to_ASCII1(pd[i]);
756 g_assert_not_reached();
758 line[cur++] = isprint(c) ? c : '.';
763 /* insert a space every BYTE_VIEW_SEP bytes */
764 if( ( i % BYTE_VIEW_SEP ) == 0 ) line[cur++] = ' ';
765 /* Did we cross a bold/plain boundary? */
766 new_font = (i >= bstart && i < bend) ? m_b_font : m_r_font;
767 if (cur_font != new_font) {
768 gtk_text_insert(bv, cur_font, NULL, NULL, line, cur);
775 gtk_text_insert(bv, cur_font, NULL, NULL, line, -1);
779 /* scroll text into position */
780 gtk_text_thaw(bv); /* must thaw before adjusting scroll bars */
785 linenum = bstart / BYTE_VIEW_WIDTH;
786 scrollval = MIN(linenum * m_font_height,
787 bv->vadj->upper - bv->vadj->page_size);
789 gtk_adjustment_set_value(bv->vadj, scrollval);
794 packet_hex_print(GtkText *bv, const guint8 *pd, frame_data *fd,
795 field_info *finfo, guint len)
797 /* do the initial printing and save the information needed */
798 /* to redraw the display if preferences change. */
800 int bstart, bend = -1, blen;
803 bstart = finfo->start;
804 blen = finfo->length;
809 if (bstart >= 0 && blen >= 0) {
810 bend = bstart + blen;
813 /* save the information needed to redraw the text */
814 /* should we save the fd & finfo pointers instead ?? */
815 gtk_object_set_data(GTK_OBJECT(bv), E_BYTE_VIEW_START_KEY, GINT_TO_POINTER(bend));
816 gtk_object_set_data(GTK_OBJECT(bv), E_BYTE_VIEW_END_KEY, GINT_TO_POINTER(bstart));
817 gtk_object_set_data(GTK_OBJECT(bv), E_BYTE_VIEW_ENCODE_KEY, GINT_TO_POINTER(fd->flags.encoding));
819 packet_hex_print_common(bv, pd, len, bstart, bend, fd->flags.encoding);
823 * Redraw the text using the saved information; usually called if
824 * the preferences have changed.
827 packet_hex_reprint(GtkText *bv)
829 int start, end, encoding;
833 start = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(bv),
834 E_BYTE_VIEW_START_KEY));
835 end = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(bv),
836 E_BYTE_VIEW_END_KEY));
837 data = get_byte_view_data_and_length(GTK_WIDGET(bv), &len);
838 g_assert(data != NULL);
839 encoding = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(bv),
840 E_BYTE_VIEW_ENCODE_KEY));
842 packet_hex_print_common(bv, data, len, start, end, encoding);
845 /* List of all protocol tree widgets, so we can globally set the selection
846 mode and font of all of them. */
847 static GList *ptree_widgets;
849 /* Add a protocol tree widget to the list of protocol tree widgets. */
850 static void forget_ptree_widget(GtkWidget *ptreew, gpointer data);
853 remember_ptree_widget(GtkWidget *ptreew)
855 ptree_widgets = g_list_append(ptree_widgets, ptreew);
857 /* Catch the "destroy" event on the widget, so that we remove it from
858 the list when it's destroyed. */
859 gtk_signal_connect(GTK_OBJECT(ptreew), "destroy",
860 GTK_SIGNAL_FUNC(forget_ptree_widget), NULL);
863 /* Remove a protocol tree widget from the list of protocol tree widgets. */
865 forget_ptree_widget(GtkWidget *ptreew, gpointer data _U_)
867 ptree_widgets = g_list_remove(ptree_widgets, ptreew);
870 /* Set the selection mode of a given packet tree window. */
872 set_ptree_sel_browse(GtkWidget *ptreew, gboolean val)
874 /* Yeah, GTK uses "browse" in the case where we do not, but oh well.
875 I think "browse" in Ethereal makes more sense than "SINGLE" in
878 gtk_clist_set_selection_mode(GTK_CLIST(ptreew),
879 GTK_SELECTION_SINGLE);
882 gtk_clist_set_selection_mode(GTK_CLIST(ptreew),
883 GTK_SELECTION_BROWSE);
888 set_ptree_sel_browse_cb(gpointer data, gpointer user_data)
890 set_ptree_sel_browse((GtkWidget *)data, *(gboolean *)user_data);
893 /* Set the selection mode of all packet tree windows. */
895 set_ptree_sel_browse_all(gboolean val)
897 g_list_foreach(ptree_widgets, set_ptree_sel_browse_cb, &val);
901 set_ptree_style_cb(gpointer data, gpointer user_data)
903 gtk_widget_set_style((GtkWidget *)data, (GtkStyle *)user_data);
907 set_ptree_font_all(GdkFont *font)
911 style = gtk_style_new();
912 gdk_font_unref(style->font);
916 g_list_foreach(ptree_widgets, set_ptree_style_cb, style);
918 /* Now nuke the old style and replace it with the new one. */
919 gtk_style_unref(item_style);
924 create_tree_view(gint tv_size, e_prefs *prefs, GtkWidget *pane,
925 GtkWidget **tv_scrollw_p, GtkWidget **tree_view_p)
927 GtkWidget *tv_scrollw, *tree_view;
930 tv_scrollw = scrolled_window_new(NULL, NULL);
931 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(tv_scrollw),
932 GTK_POLICY_ALWAYS, GTK_POLICY_ALWAYS);
933 gtk_paned_pack1(GTK_PANED(pane), tv_scrollw, TRUE, TRUE);
934 gtk_widget_set_usize(tv_scrollw, -1, tv_size);
935 gtk_widget_show(tv_scrollw);
937 tree_view = ctree_new(1, 0);
938 gtk_signal_connect( GTK_OBJECT(tree_view), "key-press-event",
939 (GtkSignalFunc) toggle_tree, NULL );
940 gtk_signal_connect( GTK_OBJECT(tree_view), "tree-expand",
941 (GtkSignalFunc) expand_tree, NULL );
942 gtk_signal_connect( GTK_OBJECT(tree_view), "tree-collapse",
943 (GtkSignalFunc) collapse_tree, NULL );
944 /* I need this next line to make the widget work correctly with hidden
945 * column titles and GTK_SELECTION_BROWSE */
946 gtk_clist_set_column_auto_resize( GTK_CLIST(tree_view), 0, TRUE );
947 gtk_container_add( GTK_CONTAINER(tv_scrollw), tree_view );
948 set_ptree_sel_browse(tree_view, prefs->gui_ptree_sel_browse);
949 gtk_widget_set_style(tree_view, item_style);
950 remember_ptree_widget(tree_view);
952 *tree_view_p = tree_view;
953 *tv_scrollw_p = tv_scrollw;
956 void expand_all_tree(proto_tree *protocol_tree, GtkWidget *tree_view) {
958 for(i=0; i < num_tree_types; i++) {
959 tree_is_expanded[i] = TRUE;
961 proto_tree_draw(protocol_tree, tree_view);
962 gtk_ctree_expand_recursive(GTK_CTREE(tree_view), NULL);
965 void collapse_all_tree(proto_tree *protocol_tree, GtkWidget *tree_view) {
967 for(i=0; i < num_tree_types; i++) {
968 tree_is_expanded[i] = FALSE;
970 proto_tree_draw(protocol_tree, tree_view);
974 struct proto_tree_draw_info {
976 GtkCTreeNode *ctree_node;
980 proto_tree_draw(proto_tree *protocol_tree, GtkWidget *tree_view)
982 struct proto_tree_draw_info info;
984 info.ctree = GTK_CTREE(tree_view);
985 info.ctree_node = NULL;
987 gtk_clist_freeze(GTK_CLIST(tree_view));
990 * Clear out any crud left over in the display of the protocol
991 * tree, by removing all nodes from the ctree.
992 * This is how it's done in testgtk.c in GTK+.
994 gtk_clist_clear(GTK_CLIST(tree_view));
996 g_node_children_foreach((GNode*) protocol_tree, G_TRAVERSE_ALL,
997 proto_tree_draw_node, &info);
999 gtk_clist_thaw(GTK_CLIST(tree_view));
1003 proto_tree_draw_node(GNode *node, gpointer data)
1005 struct proto_tree_draw_info info;
1006 struct proto_tree_draw_info *parent_info = (struct proto_tree_draw_info*) data;
1008 field_info *fi = PITEM_FINFO(node);
1009 gchar label_str[ITEM_LABEL_LENGTH];
1011 GtkCTreeNode *parent;
1012 gboolean is_leaf, is_expanded;
1017 /* was a free format label produced? */
1018 if (fi->representation) {
1019 label_ptr = fi->representation;
1021 else { /* no, make a generic label */
1022 label_ptr = label_str;
1023 proto_item_fill_label(fi, label_str);
1026 if (g_node_n_children(node) > 0) {
1028 g_assert(fi->tree_type >= 0 && fi->tree_type < num_tree_types);
1029 if (tree_is_expanded[fi->tree_type]) {
1033 is_expanded = FALSE;
1038 is_expanded = FALSE;
1041 info.ctree = parent_info->ctree;
1042 parent = gtk_ctree_insert_node ( info.ctree, parent_info->ctree_node, NULL,
1043 &label_ptr, 5, NULL, NULL, NULL, NULL,
1044 is_leaf, is_expanded );
1046 gtk_ctree_node_set_row_data( GTK_CTREE(info.ctree), parent, fi );
1049 info.ctree_node = parent;
1050 g_node_children_foreach(node, G_TRAVERSE_ALL,
1051 proto_tree_draw_node, &info);
1056 * Clear the hex dump and protocol tree panes.
1059 clear_tree_and_hex_views(void)
1061 /* Clear the hex dump by getting rid of all the byte views. */
1062 while (gtk_notebook_get_nth_page(GTK_NOTEBOOK(byte_nb_ptr), 0) != NULL)
1063 gtk_notebook_remove_page(GTK_NOTEBOOK(byte_nb_ptr), 0);
1065 /* Add a placeholder byte view so that there's at least something
1066 displayed in the byte view notebook. */
1067 add_byte_tab(byte_nb_ptr, "", NULL, NULL, tree_view);
1069 /* Clear the protocol tree by removing all nodes in the ctree.
1070 This is how it's done in testgtk.c in GTK+ */
1071 gtk_clist_clear(GTK_CLIST(tree_view));