2 * Routines for GTK+ packet display
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.
35 #include <io.h> /* open/close on win32 */
47 #include <gdk/gdkkeysyms.h>
51 #include <epan/epan_dissect.h>
56 #include <epan/packet.h>
57 #include <epan/charsets.h>
61 #include <epan/prefs.h>
64 #include "proto_draw.h"
65 #include "packet_win.h"
66 #include "dlg_utils.h"
68 #include "gtkglobals.h"
69 #include "compat_macros.h"
70 #include "alert_box.h"
71 #include "simple_dialog.h"
72 #include "progress_dlg.h"
73 #include "font_utils.h"
76 /* Win32 needs the O_BINARY flag for open() */
81 #define BYTE_VIEW_WIDTH 16
82 #define BYTE_VIEW_SEP 8
84 #define E_BYTE_VIEW_TREE_PTR "byte_view_tree_ptr"
85 #define E_BYTE_VIEW_TREE_VIEW_PTR "byte_view_tree_view_ptr"
86 #define E_BYTE_VIEW_NDIGITS_KEY "byte_view_ndigits"
87 #define E_BYTE_VIEW_TVBUFF_KEY "byte_view_tvbuff"
88 #define E_BYTE_VIEW_START_KEY "byte_view_start"
89 #define E_BYTE_VIEW_END_KEY "byte_view_end"
90 #define E_BYTE_VIEW_ENCODE_KEY "byte_view_encode"
93 #if GTK_MAJOR_VERSION < 2
94 GtkStyle *item_style = NULL;
97 /* gtk_tree_view_expand_to_path doesn't exist in gtk+ v2.0 so we must include it
98 * when building with this version (taken from gtk+ v2.2.4) */
99 #if GTK_MAJOR_VERSION >= 2 && GTK_MINOR_VERSION == 0
101 * gtk_tree_view_expand_to_path:
102 * @tree_view: A #GtkTreeView.
103 * @path: path to a row.
105 * Expands the row at @path. This will also expand all parent rows of
106 * @path as necessary.
111 gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
118 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
119 g_return_if_fail (path != NULL);
121 depth = gtk_tree_path_get_depth (path);
122 indices = gtk_tree_path_get_indices (path);
124 tmp = gtk_tree_path_new ();
125 g_return_if_fail (tmp != NULL);
127 for (i = 0; i < depth; i++)
129 gtk_tree_path_append_index (tmp, indices[i]);
130 gtk_tree_view_expand_row (tree_view, tmp, FALSE);
133 gtk_tree_path_free (tmp);
138 add_byte_tab(GtkWidget *byte_nb, const char *name, tvbuff_t *tvb,
139 proto_tree *tree, GtkWidget *tree_view);
142 proto_tree_draw_node(proto_node *node, gpointer data);
144 /* Get the current text window for the notebook. */
146 get_notebook_bv_ptr(GtkWidget *nb_ptr)
151 num = gtk_notebook_get_current_page(GTK_NOTEBOOK(nb_ptr));
152 bv_page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(nb_ptr), num);
154 return GTK_BIN(bv_page)->child;
160 * Get the data and length for a byte view, given the byte view page.
161 * Return the pointer, or NULL on error, and set "*data_len" to the length.
164 get_byte_view_data_and_length(GtkWidget *byte_view, guint *data_len)
166 tvbuff_t *byte_view_tvb;
167 const guint8 *data_ptr;
169 byte_view_tvb = OBJECT_GET_DATA(byte_view, E_BYTE_VIEW_TVBUFF_KEY);
170 if (byte_view_tvb == NULL)
173 data_ptr = tvb_get_ptr(byte_view_tvb, 0, -1);
174 *data_len = tvb_length(byte_view_tvb);
179 * Set the current text window for the notebook to the window that
180 * refers to a particular tvbuff.
183 set_notebook_page(GtkWidget *nb_ptr, tvbuff_t *tvb)
186 GtkWidget *bv_page, *bv;
190 (bv_page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(nb_ptr), num)) != NULL;
192 bv = GTK_BIN(bv_page)->child;
193 bv_tvb = OBJECT_GET_DATA(bv, E_BYTE_VIEW_TVBUFF_KEY);
196 gtk_notebook_set_page(GTK_NOTEBOOK(nb_ptr), num);
202 /* Redraw a given byte view window. */
204 redraw_hex_dump(GtkWidget *nb, frame_data *fd, field_info *finfo)
210 bv = get_notebook_bv_ptr(nb);
212 data = get_byte_view_data_and_length(bv, &len);
214 #if GTK_MAJOR_VERSION < 2
215 packet_hex_print(GTK_TEXT(bv), data, fd, finfo, len);
217 packet_hex_print(GTK_TEXT_VIEW(bv), data, fd, finfo, len);
222 /* Redraw all byte view windows. */
224 redraw_hex_dump_all(void)
226 if (cfile.current_frame != NULL)
227 redraw_hex_dump( byte_nb_ptr, cfile.current_frame, cfile.finfo_selected);
229 redraw_hex_dump_packet_wins();
231 #if GTK_MAJOR_VERSION >= 2
232 /* XXX - this is a hack, to workaround a bug in GTK2.x!
233 when changing the font size, even refilling of the corresponding
234 gtk_text_buffer doesn't seem to trigger an update.
235 The only workaround is to freshly select the frame, which will remove any
236 existing notebook tabs and "restart" the whole byte view again. */
237 if (cfile.current_frame != NULL)
238 goto_frame(&cfile, cfile.current_frame->num);
242 #if GTK_MAJOR_VERSION < 2
244 expand_tree(GtkCTree *ctree, GtkCTreeNode *node, gpointer user_data _U_)
247 expand_tree(GtkTreeView *tree_view, GtkTreeIter *iter,
248 GtkTreePath *path _U_, gpointer user_data _U_)
252 #if GTK_MAJOR_VERSION >= 2
255 model = gtk_tree_view_get_model(tree_view);
256 gtk_tree_model_get(model, iter, 1, &finfo, -1);
258 finfo = gtk_ctree_node_get_row_data( ctree, node);
263 * Nodes with "finfo->tree_type" of -1 have no ett_ value, and
264 * are thus presumably leaf nodes and cannot be expanded.
266 if (finfo->tree_type != -1) {
267 g_assert(finfo->tree_type >= 0 &&
268 finfo->tree_type < num_tree_types);
269 tree_is_expanded[finfo->tree_type] = TRUE;
273 #if GTK_MAJOR_VERSION < 2
275 collapse_tree(GtkCTree *ctree, GtkCTreeNode *node, gpointer user_data _U_)
278 collapse_tree(GtkTreeView *tree_view, GtkTreeIter *iter,
279 GtkTreePath *path _U_, gpointer user_data _U_)
283 #if GTK_MAJOR_VERSION >= 2
286 model = gtk_tree_view_get_model(tree_view);
287 gtk_tree_model_get(model, iter, 1, &finfo, -1);
289 finfo = gtk_ctree_node_get_row_data( ctree, node);
294 * Nodes with "finfo->tree_type" of -1 have no ett_ value, and
295 * are thus presumably leaf nodes and cannot be collapsed.
297 if (finfo->tree_type != -1) {
298 g_assert(finfo->tree_type >= 0 &&
299 finfo->tree_type < num_tree_types);
300 tree_is_expanded[finfo->tree_type] = FALSE;
304 #if GTK_MAJOR_VERSION < 2
306 toggle_tree(GtkCTree *ctree, GdkEventKey *event, gpointer user_data _U_)
308 if (event->keyval != GDK_Return)
310 gtk_ctree_toggle_expansion(ctree, GTK_CTREE_NODE(ctree->clist.selection->data));
314 #define MAX_OFFSET_LEN 8 /* max length of hex offset of bytes */
315 #define BYTES_PER_LINE 16 /* max byte values in a line */
316 #define HEX_DUMP_LEN (BYTES_PER_LINE*3 + 1)
317 /* max number of characters hex dump takes -
318 2 digits plus trailing blank
319 plus separator between first and
321 #define DATA_DUMP_LEN (HEX_DUMP_LEN + 2 + BYTES_PER_LINE)
322 /* number of characters those bytes take;
323 3 characters per byte of hex dump,
324 2 blanks separating hex from ASCII,
325 1 character per byte of ASCII dump */
326 #define MAX_LINE_LEN (MAX_OFFSET_LEN + 2 + DATA_DUMP_LEN)
327 /* number of characters per line;
328 offset, 2 blanks separating offset
329 from data dump, data dump */
331 /* Which byte the offset is referring to. Associates
332 * whitespace with the preceding digits. */
334 byte_num(int offset, int start_point)
336 return (offset - start_point) / 3;
339 #if GTK_MAJOR_VERSION >= 2
340 struct field_lookup_info {
346 lookup_finfo(GtkTreeModel *model, GtkTreePath *path _U_, GtkTreeIter *iter,
350 struct field_lookup_info *fli = (struct field_lookup_info *)data;
352 gtk_tree_model_get(model, iter, 1, &fi, -1);
360 GtkTreePath *tree_find_by_field_info(GtkTreeView *tree_view, field_info *finfo) {
362 struct field_lookup_info fli;
364 model = gtk_tree_view_get_model(tree_view);
366 gtk_tree_model_foreach(model, lookup_finfo, &fli);
368 return gtk_tree_model_get_path(model, &fli.iter);
373 /* If the user selected a certain byte in the byte view, try to find
374 * the item in the GUI proto_tree that corresponds to that byte, and:
376 * if we succeed, select it, and return TRUE;
377 * if we fail, return FALSE. */
379 byte_view_select(GtkWidget *widget, GdkEventButton *event)
382 #if GTK_MAJOR_VERSION < 2
384 GtkCTreeNode *node, *parent;
385 GtkText *bv = GTK_TEXT(widget);
387 GtkTreeView *tree_view;
389 GtkTreePath *first_path, *path;
391 GtkTextView *bv = GTK_TEXT_VIEW(widget);
394 struct field_lookup_info fli;
411 * Get the number of digits of offset being displayed, and
412 * compute the columns of various parts of the display.
414 ndigits = GPOINTER_TO_UINT(OBJECT_GET_DATA(bv, E_BYTE_VIEW_NDIGITS_KEY));
417 * The column of the first hex digit in the first half.
418 * That starts after "ndigits" digits of offset and two
421 digits_start_1 = ndigits + 2;
424 * The column of the last hex digit in the first half.
425 * There are BYTES_PER_LINE/2 bytes displayed in the first
426 * half; there are 2 characters per byte, plus a separating
427 * blank after all but the last byte's characters.
429 * Then subtract 1 to get the last column of the first half
430 * rather than the first column after the first half.
432 digits_end_1 = digits_start_1 + (BYTES_PER_LINE/2)*2 +
433 (BYTES_PER_LINE/2 - 1) - 1;
436 * The column of the first hex digit in the second half.
437 * Add back the 1 to get the first column after the first
438 * half, and then add 2 for the 2 separating blanks between
441 digits_start_2 = digits_end_1 + 3;
444 * The column of the last hex digit in the second half.
445 * Add the same value we used to get "digits_end_1" from
448 digits_end_2 = digits_start_2 + (BYTES_PER_LINE/2)*2 +
449 (BYTES_PER_LINE/2 - 1) - 1;
452 * The column of the first "text dump" character in the first half.
453 * Add back the 1 to get the first column after the second
454 * half's hex dump, and then add 3 for the 3 separating blanks
455 * between the hex and text dummp.
457 text_start_1 = digits_end_2 + 4;
460 * The column of the last "text dump" character in the first half.
461 * There are BYTES_PER_LINE/2 bytes displayed in the first
462 * half; there is 1 character per byte.
464 * Then subtract 1 to get the last column of the first half
465 * rather than the first column after the first half.
467 text_end_1 = text_start_1 + BYTES_PER_LINE/2 - 1;
470 * The column of the first "text dump" character in the second half.
471 * Add back the 1 to get the first column after the first half,
472 * and then add 1 for the separating blank between the halves.
474 text_start_2 = text_end_1 + 2;
477 * The column of the last "text dump" character in second half.
478 * Add the same value we used to get "text_end_1" from
481 text_end_2 = text_start_2 + BYTES_PER_LINE/2 - 1;
483 tree = OBJECT_GET_DATA(widget, E_BYTE_VIEW_TREE_PTR);
486 * Somebody clicked on the dummy byte view; do nothing.
490 #if GTK_MAJOR_VERSION < 2
491 ctree = GTK_CTREE(OBJECT_GET_DATA(widget, E_BYTE_VIEW_TREE_VIEW_PTR));
493 tree_view = GTK_TREE_VIEW(OBJECT_GET_DATA(widget,
494 E_BYTE_VIEW_TREE_VIEW_PTR));
497 #if GTK_MAJOR_VERSION < 2
498 /* Given the mouse (x,y) and the current GtkText (h,v)
499 * adjustments, and the size of the font, figure out
500 * which text column/row the user selected. This could be off
501 * if the bold version of the font is bigger than the
502 * regular version of the font. */
503 column = (int) ((bv->hadj->value + event->x) / user_font_get_regular_width());
504 row = (int) ((bv->vadj->value + event->y) / user_font_get_regular_height());
506 /* get the row/column selected */
507 gtk_text_view_window_to_buffer_coords(bv,
508 gtk_text_view_get_window_type(bv, event->window),
509 (gint) event->x, (gint) event->y, &x, &y);
510 gtk_text_view_get_iter_at_location(bv, &iter, x, y);
511 row = gtk_text_iter_get_line(&iter);
512 column = gtk_text_iter_get_line_offset(&iter);
515 /* Given the column and row, determine which byte offset
516 * the user clicked on. */
517 if (column >= digits_start_1 && column <= digits_end_1) {
518 byte = byte_num(column, digits_start_1);
523 else if (column >= digits_start_2 && column <= digits_end_2) {
524 byte = byte_num(column, digits_start_2);
530 else if (column >= text_start_1 && column <= text_end_1) {
531 byte = column - text_start_1;
533 else if (column >= text_start_2 && column <= text_end_2) {
534 byte = 8 + column - text_start_2;
537 /* The user didn't select a hex digit or
538 * text-dump character. */
542 /* Add the number of bytes from the previous rows. */
545 /* Get the data source tvbuff */
546 tvb = OBJECT_GET_DATA(widget, E_BYTE_VIEW_TVBUFF_KEY);
548 /* Find the finfo that corresponds to our byte. */
549 finfo = proto_find_field_from_offset(tree, byte, tvb);
555 #if GTK_MAJOR_VERSION < 2
556 node = gtk_ctree_find_by_row_data(ctree, NULL, finfo);
559 /* Expand and select our field's row */
560 gtk_ctree_expand(ctree, node);
561 gtk_ctree_select(ctree, node);
562 expand_tree(ctree, node, NULL);
564 /* ... and its parents */
565 parent = GTK_CTREE_ROW(node)->parent;
567 gtk_ctree_expand(ctree, parent);
568 expand_tree(ctree, parent, NULL);
569 parent = GTK_CTREE_ROW(parent)->parent;
572 /* And position the window so the selection is visible.
573 * Position the selection in the middle of the viewable
575 gtk_ctree_node_moveto(ctree, node, 0, .5, 0);
579 model = gtk_tree_view_get_model(tree_view);
581 gtk_tree_model_foreach(model, lookup_finfo, &fli);
583 /* Expand our field's row */
584 first_path = gtk_tree_model_get_path(model, &fli.iter);
585 gtk_tree_view_expand_row(tree_view, first_path, FALSE);
586 expand_tree(tree_view, &fli.iter, NULL, NULL);
588 /* ... and its parents */
589 while (gtk_tree_model_iter_parent(model, &parent, &fli.iter)) {
590 path = gtk_tree_model_get_path(model, &parent);
591 gtk_tree_view_expand_row(tree_view, path, FALSE);
592 expand_tree(tree_view, &parent, NULL, NULL);
594 gtk_tree_path_free(path);
597 /* select our field's row */
598 gtk_tree_selection_select_path(gtk_tree_view_get_selection(tree_view),
601 /* And position the window so the selection is visible.
602 * Position the selection in the middle of the viewable
604 gtk_tree_view_scroll_to_cell(tree_view, first_path, NULL, TRUE, 0.5, 0.0);
606 gtk_tree_path_free(first_path);
612 /* Calls functions for different mouse-button presses. */
614 byte_view_button_press_cb(GtkWidget *widget, GdkEvent *event, gpointer data)
616 GdkEventButton *event_button = NULL;
618 if(widget == NULL || event == NULL || data == NULL) {
622 if(event->type == GDK_BUTTON_PRESS) {
623 event_button = (GdkEventButton *) event;
625 /* To qoute the "Gdk Event Structures" doc:
626 * "Normally button 1 is the left mouse button, 2 is the middle button, and 3 is the right button" */
627 switch(event_button->button) {
630 return byte_view_select(widget, event_button);
632 return popup_menu_handler(widget, event, data);
646 byte_nb = gtk_notebook_new();
647 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(byte_nb), GTK_POS_BOTTOM);
649 /* this will only have an effect, if no tabs are shown */
650 gtk_notebook_set_show_border(GTK_NOTEBOOK(byte_nb), FALSE);
652 /* set the tabs scrollable, if they don't fit into the pane */
653 gtk_notebook_set_scrollable(GTK_NOTEBOOK(byte_nb), TRUE);
655 /* enable a popup menu containing the tab labels, will be helpful if tabs don't fit into the pane */
656 gtk_notebook_popup_enable(GTK_NOTEBOOK(byte_nb));
658 /* Add a placeholder byte view so that there's at least something
659 displayed in the byte view notebook. */
660 add_byte_tab(byte_nb, "", NULL, NULL, NULL);
666 byte_view_realize_cb(GtkWidget *bv, gpointer data _U_)
668 const guint8 *byte_data;
671 byte_data = get_byte_view_data_and_length(bv, &byte_len);
672 if (byte_data == NULL) {
673 /* This must be the dummy byte view if no packet is selected. */
676 #if GTK_MAJOR_VERSION < 2
677 packet_hex_print(GTK_TEXT(bv), byte_data, cfile.current_frame, NULL,
680 packet_hex_print(GTK_TEXT_VIEW(bv), byte_data, cfile.current_frame, NULL,
686 add_byte_tab(GtkWidget *byte_nb, const char *name, tvbuff_t *tvb,
687 proto_tree *tree, GtkWidget *tree_view)
689 GtkWidget *byte_view, *byte_scrollw, *label;
690 #if GTK_MAJOR_VERSION >= 2
695 /* Byte view. Create a scrolled window for the text. */
696 byte_scrollw = scrolled_window_new(NULL, NULL);
697 #if GTK_MAJOR_VERSION < 2
698 /* The horizontal scrollbar of the scroll-window doesn't seem
699 * to affect the GtkText widget at all, even when line wrapping
700 * is turned off in the GtkText widget and there is indeed more
701 * horizontal data. */
702 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(byte_scrollw),
703 /* Horizontal */GTK_POLICY_NEVER,
704 /* Vertical*/ GTK_POLICY_ALWAYS);
706 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(byte_scrollw),
709 /* Add scrolled pane to tabbed window */
710 label = gtk_label_new(name);
711 gtk_notebook_append_page(GTK_NOTEBOOK(byte_nb), byte_scrollw, label);
713 gtk_widget_show(byte_scrollw);
715 #if GTK_MAJOR_VERSION < 2
716 byte_view = gtk_text_new(NULL, NULL);
717 gtk_text_set_editable(GTK_TEXT(byte_view), FALSE);
718 gtk_text_set_word_wrap(GTK_TEXT(byte_view), FALSE);
719 gtk_text_set_line_wrap(GTK_TEXT(byte_view), FALSE);
721 byte_view = gtk_text_view_new();
722 gtk_text_view_set_editable(GTK_TEXT_VIEW(byte_view), FALSE);
723 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(byte_view), FALSE);
724 buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(byte_view));
725 style = gtk_widget_get_style(GTK_WIDGET(byte_view));
726 gtk_text_buffer_create_tag(buf, "plain", "font-desc", user_font_get_regular(), NULL);
727 gtk_text_buffer_create_tag(buf, "reverse",
728 "font-desc", user_font_get_regular(),
729 "foreground-gdk", &style->text[GTK_STATE_SELECTED],
730 "background-gdk", &style->base[GTK_STATE_SELECTED],
732 gtk_text_buffer_create_tag(buf, "bold", "font-desc", user_font_get_bold(), NULL);
734 OBJECT_SET_DATA(byte_view, E_BYTE_VIEW_TVBUFF_KEY, tvb);
735 gtk_container_add(GTK_CONTAINER(byte_scrollw), byte_view);
737 SIGNAL_CONNECT(byte_view, "show", byte_view_realize_cb, NULL);
738 SIGNAL_CONNECT(byte_view, "button_press_event", byte_view_button_press_cb,
739 OBJECT_GET_DATA(popup_menu_object, PM_HEXDUMP_KEY));
741 OBJECT_SET_DATA(byte_view, E_BYTE_VIEW_TREE_PTR, tree);
742 OBJECT_SET_DATA(byte_view, E_BYTE_VIEW_TREE_VIEW_PTR, tree_view);
744 gtk_widget_show(byte_view);
746 /* no tabs if this is the first page */
747 if (!(gtk_notebook_page_num(GTK_NOTEBOOK(byte_nb), byte_scrollw)))
748 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(byte_nb), FALSE);
750 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(byte_nb), TRUE);
752 /* set this page (this will print the packet data) */
753 gtk_notebook_set_page(GTK_NOTEBOOK(byte_nb),
754 gtk_notebook_page_num(GTK_NOTEBOOK(byte_nb), byte_nb));
760 add_main_byte_views(epan_dissect_t *edt)
762 add_byte_views(edt, tree_view, byte_nb_ptr);
766 add_byte_views(epan_dissect_t *edt, GtkWidget *tree_view,
767 GtkWidget *byte_nb_ptr)
773 * Get rid of all the old notebook tabs.
775 while (gtk_notebook_get_nth_page(GTK_NOTEBOOK(byte_nb_ptr), 0) != NULL)
776 gtk_notebook_remove_page(GTK_NOTEBOOK(byte_nb_ptr), 0);
779 * Add to the specified byte view notebook tabs for hex dumps
780 * of all the data sources for the specified frame.
782 for (src_le = edt->pi.data_src; src_le != NULL; src_le = src_le->next) {
784 add_byte_tab(byte_nb_ptr, src->name, src->tvb, edt->tree,
789 * Initially select the first byte view.
791 gtk_notebook_set_page(GTK_NOTEBOOK(byte_nb_ptr), 0);
796 static GtkWidget *savehex_dlg=NULL;
799 savehex_dlg_destroy_cb(void)
805 copy_hex_cb(GtkWidget * w _U_, gpointer data _U_)
810 const guint8 *data_p = NULL;
811 GString *ASCII_representation = g_string_new("");
812 GString *byte_str = g_string_new("");
814 bv = get_notebook_bv_ptr(byte_nb_ptr);
816 /* shouldn't happen */
817 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Could not find the corresponding text window!");
821 data_p = get_byte_view_data_and_length(GTK_WIDGET(bv), &len);
823 g_string_sprintfa(byte_str,"%04x ",i); /* Offset 0000 */
824 for (i=0; i<len; i++){
825 g_string_sprintfa(ASCII_representation,"%c",isprint(*data_p) ? *data_p : '.');
826 g_string_sprintfa(byte_str," %02x",*data_p++);
827 if ((i+1)%16==0 && i!=0){
828 g_string_sprintfa(byte_str," %s\n%04x ",ASCII_representation->str,i+1);
829 g_string_assign (ASCII_representation,"");
833 if(ASCII_representation->len){
834 for (i=ASCII_representation->len; i<16; i++){
835 g_string_sprintfa(byte_str," ");
837 g_string_sprintfa(byte_str," %s\n",ASCII_representation->str);
839 /* Now that we have the byte data, copy it into the default clipboard */
840 copy_to_clipboard(byte_str);
841 g_string_free(byte_str, TRUE); /* Free the memory */
842 g_string_free(ASCII_representation, TRUE); /* Free the memory */
845 /* save the current highlighted hex data */
847 savehex_save_clicked_cb(GtkWidget * w _U_, gpointer data _U_)
850 int fd, start, end, len;
851 const guint8 *data_p = NULL;
852 const char *file = NULL;
854 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
855 file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(savehex_dlg));
857 file = gtk_file_selection_get_filename(GTK_FILE_SELECTION(savehex_dlg));
860 if (!file ||! *file) {
861 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Please enter a filename!");
865 /* Must check if file name exists first */
867 bv = get_notebook_bv_ptr(byte_nb_ptr);
869 /* shouldn't happen */
870 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Could not find the corresponding text window!");
874 * Retrieve the info we need
876 end = GPOINTER_TO_INT(OBJECT_GET_DATA(bv, E_BYTE_VIEW_START_KEY));
877 start = GPOINTER_TO_INT(OBJECT_GET_DATA(bv, E_BYTE_VIEW_END_KEY));
878 data_p = get_byte_view_data_and_length(GTK_WIDGET(bv), &len);
880 if (data_p == NULL || start == -1 || start > end) {
881 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
882 "No data selected to save!");
886 fd = open(file, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666);
888 open_failure_alert_box(file, errno, TRUE);
891 if (write(fd, data_p + start, end - start) < 0) {
892 write_failure_alert_box(file, errno);
897 write_failure_alert_box(file, errno);
901 /* Get rid of the dialog box */
902 window_destroy(GTK_WIDGET(savehex_dlg));
905 /* Launch the dialog box to put up the file selection box etc */
906 void savehex_cb(GtkWidget * w _U_, gpointer data _U_)
909 const guint8 *data_p = NULL;
916 /* don't show up the dialog, if no data has to be saved */
917 bv = get_notebook_bv_ptr(byte_nb_ptr);
919 /* shouldn't happen */
920 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Could not find the corresponding text window!");
923 end = GPOINTER_TO_INT(OBJECT_GET_DATA(bv, E_BYTE_VIEW_START_KEY));
924 start = GPOINTER_TO_INT(OBJECT_GET_DATA(bv, E_BYTE_VIEW_END_KEY));
925 data_p = get_byte_view_data_and_length(GTK_WIDGET(bv), &len);
927 if (data_p == NULL || start == -1 || start > end) {
928 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "No data selected to save!");
932 /* if the window is already open, bring it to front */
934 reactivate_window(savehex_dlg);
939 * Build the dialog box we need.
941 savehex_dlg = file_selection_new("Ethereal: Export Selected Packet Bytes", FILE_SELECTION_SAVE);
944 label = g_strdup_printf("Will save %u %s of raw binary data to specified file.",
945 end - start, plurality(end - start, "byte", "bytes"));
946 dlg_lb = gtk_label_new(label);
948 file_selection_set_extra_widget(savehex_dlg, dlg_lb);
949 gtk_widget_show(dlg_lb);
951 SIGNAL_CONNECT(savehex_dlg, "destroy", savehex_dlg_destroy_cb, NULL);
953 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
954 if (gtk_dialog_run(GTK_DIALOG(savehex_dlg)) == GTK_RESPONSE_ACCEPT) {
955 savehex_save_clicked_cb(savehex_dlg, savehex_dlg);
957 window_destroy(savehex_dlg);
960 /* Connect the ok_button to file_save_as_ok_cb function and pass along a
961 pointer to the file selection box widget */
962 SIGNAL_CONNECT(GTK_FILE_SELECTION (savehex_dlg)->ok_button, "clicked",
963 savehex_save_clicked_cb, savehex_dlg);
965 window_set_cancel_button(savehex_dlg,
966 GTK_FILE_SELECTION(savehex_dlg)->cancel_button, window_cancel_button_cb);
968 SIGNAL_CONNECT(savehex_dlg, "delete_event", window_delete_event_cb, NULL);
970 gtk_file_selection_set_filename(GTK_FILE_SELECTION(savehex_dlg), "");
972 gtk_widget_show_all(savehex_dlg);
973 window_present(savehex_dlg);
979 /* Update the progress bar this many times when reading a file. */
980 #define N_PROGBAR_UPDATES 100
984 * XXX - at least in GTK+ 2.x, this is not fast - in one capture with a
985 * 64K-or-so reassembled HTTP reply, it takes about 3 seconds to construct
986 * the hex dump pane on a 1.4 GHz G4 PowerMac on OS X 10.3.3. (That's
987 * presumably why there's a progress bar for it.)
989 * Perhaps what's needed is a custom widget (either one that lets you stuff
990 * text into it more quickly, or one that's a "virtual" widget so that the
991 * text for a row is constructed, via a callback, when the row is to be
992 * displayed). A custom widget might also let us treat the offset, hex
993 * data, and ASCII data as three columns, so you can select purely in
994 * the hex dump column.
996 #if GTK_MAJOR_VERSION < 2
998 packet_hex_print_common(GtkText *bv, const guint8 *pd, int len, int bstart,
999 int bend, int encoding)
1002 packet_hex_print_common(GtkTextView *bv, const guint8 *pd, int len, int bstart,
1003 int bend, int encoding)
1006 int i = 0, j, k, cur;
1007 guchar line[MAX_LINE_LEN + 1];
1008 static guchar hexchars[16] = {
1009 '0', '1', '2', '3', '4', '5', '6', '7',
1010 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
1012 unsigned int use_digits;
1013 gboolean reverse, newreverse;
1014 #if GTK_MAJOR_VERSION < 2
1015 GdkFont *cur_font, *new_font;
1018 GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(bv));
1023 GtkTextMark *mark = NULL;
1026 progdlg_t *progbar = NULL;
1028 gboolean progbar_stop_flag;
1029 GTimeVal progbar_start_time;
1030 gchar progbar_status_str[100];
1031 int progbar_nextstep;
1032 int progbar_quantum;
1034 #if GTK_MAJOR_VERSION < 2
1035 /* Freeze the text for faster display */
1036 gtk_text_freeze(bv);
1038 /* Clear out the text */
1039 gtk_text_set_point(bv, 0);
1040 /* Keep GTK+ 1.2.3 through 1.2.6 from dumping core - see
1041 http://www.ethereal.com/lists/ethereal-dev/199912/msg00312.html and
1042 http://www.gnome.org/mailing-lists/archives/gtk-devel-list/1999-October/0051.shtml
1043 for more information */
1044 gtk_adjustment_set_value(bv->vadj, 0.0);
1045 gtk_text_forward_delete(bv, gtk_text_get_length(bv));
1047 gtk_text_buffer_set_text(buf, "", 0);
1048 gtk_text_buffer_get_start_iter(buf, &iter);
1052 * How many of the leading digits of the offset will we supply?
1053 * We always supply at least 4 digits, but if the maximum offset
1054 * won't fit in 4 digits, we use as many digits as will be needed.
1056 if (((len - 1) & 0xF0000000) != 0)
1057 use_digits = 8; /* need all 8 digits */
1058 else if (((len - 1) & 0x0F000000) != 0)
1059 use_digits = 7; /* need 7 digits */
1060 else if (((len - 1) & 0x00F00000) != 0)
1061 use_digits = 6; /* need 6 digits */
1062 else if (((len - 1) & 0x000F0000) != 0)
1063 use_digits = 5; /* need 5 digits */
1065 use_digits = 4; /* we'll supply 4 digits */
1067 /* Record the number of digits in this text view. */
1068 OBJECT_SET_DATA(bv, E_BYTE_VIEW_NDIGITS_KEY, GUINT_TO_POINTER(use_digits));
1070 /* Update the progress bar when it gets to this value. */
1071 progbar_nextstep = 0;
1072 /* When we reach the value that triggers a progress bar update,
1073 bump that value by this amount. */
1074 progbar_quantum = len/N_PROGBAR_UPDATES;
1076 progbar_stop_flag = FALSE;
1077 g_get_current_time(&progbar_start_time);
1080 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
1081 when we update it, we have to run the GTK+ main loop to get it
1082 to repaint what's pending, and doing so may involve an "ioctl()"
1083 to see if there's any pending input from an X server, and doing
1084 that for every packet can be costly, especially on a big file. */
1085 if (i >= progbar_nextstep) {
1086 /* let's not divide by zero. I should never be started
1087 * with count == 0, so let's assert that
1090 progbar_val = (gfloat) i / len;
1092 if (progbar == NULL)
1093 /* Create the progress bar if necessary */
1094 progbar = delayed_create_progress_dlg("Processing", "Packet Details",
1096 &progbar_start_time,
1099 if (progbar != NULL) {
1100 g_snprintf(progbar_status_str, sizeof(progbar_status_str),
1101 "%4u of %u bytes", i, len);
1102 update_progress_dlg(progbar, progbar_val, progbar_status_str);
1105 progbar_nextstep += progbar_quantum;
1108 if (progbar_stop_flag) {
1109 /* Well, the user decided to abort the operation. Just stop,
1110 and arrange to return TRUE to our caller, so they know it
1111 was stopped explicitly. */
1115 /* Print the line number */
1120 c = (i >> (j*4)) & 0xF;
1121 line[cur++] = hexchars[c];
1127 /* Display with inverse video ? */
1128 #if GTK_MAJOR_VERSION < 2
1129 if (prefs.gui_hex_dump_highlight_style) {
1130 gtk_text_insert(bv, user_font_get_regular(), &BLACK, &WHITE, line, -1);
1131 /* Do we start in reverse? */
1132 reverse = i >= bstart && i < bend;
1133 fg = reverse ? &WHITE : &BLACK;
1134 bg = reverse ? &BLACK : &WHITE;
1136 k = i + BYTE_VIEW_WIDTH;
1138 /* Print the hex bit */
1141 line[cur++] = hexchars[(pd[i] & 0xf0) >> 4];
1142 line[cur++] = hexchars[pd[i] & 0x0f];
1144 line[cur++] = ' '; line[cur++] = ' ';
1147 newreverse = i >= bstart && i < bend;
1148 /* Have we gone from reverse to plain? */
1149 if (reverse && (reverse != newreverse)) {
1150 gtk_text_insert(bv, user_font_get_regular(), fg, bg, line, cur);
1155 /* Inter byte space if not at end of line */
1158 /* insert a space every BYTE_VIEW_SEP bytes */
1159 if( ( i % BYTE_VIEW_SEP ) == 0 ) {
1163 /* Have we gone from plain to reversed? */
1164 if (!reverse && (reverse != newreverse)) {
1165 gtk_text_insert(bv, user_font_get_regular(), fg, bg, line, cur);
1170 reverse = newreverse;
1172 /* Print remaining part of line */
1173 gtk_text_insert(bv, user_font_get_regular(), fg, bg, line, cur);
1175 /* Print some space at the end of the line */
1176 line[cur++] = ' '; line[cur++] = ' '; line[cur++] = ' ';
1177 gtk_text_insert(bv, user_font_get_regular(), &BLACK, &WHITE, line, cur);
1180 /* Print the ASCII bit */
1182 /* Do we start in reverse? */
1183 reverse = i >= bstart && i < bend;
1184 fg = reverse ? &WHITE : &BLACK;
1185 bg = reverse ? &BLACK : &WHITE;
1188 if (encoding == CHAR_ASCII) {
1191 else if (encoding == CHAR_EBCDIC) {
1192 c = EBCDIC_to_ASCII1(pd[i]);
1195 g_assert_not_reached();
1197 line[cur++] = isprint(c) ? c : '.';
1202 newreverse = i >= bstart && i < bend;
1203 /* Have we gone from reverse to plain? */
1204 if (reverse && (reverse != newreverse)) {
1205 gtk_text_insert(bv, user_font_get_regular(), fg, bg, line, cur);
1211 /* insert a space every BYTE_VIEW_SEP bytes */
1212 if( ( i % BYTE_VIEW_SEP ) == 0 ) {
1216 /* Have we gone from plain to reversed? */
1217 if (!reverse && (reverse != newreverse)) {
1218 gtk_text_insert(bv, user_font_get_regular(), fg, bg, line, cur);
1223 reverse = newreverse;
1225 /* Print remaining part of line */
1226 gtk_text_insert(bv, user_font_get_regular(), fg, bg, line, cur);
1230 gtk_text_insert(bv, user_font_get_regular(), &BLACK, &WHITE, line, -1);
1233 gtk_text_insert(bv, user_font_get_regular(), NULL, NULL, line, -1);
1234 /* Do we start in bold? */
1235 cur_font = (i >= bstart && i < bend) ? user_font_get_bold() : user_font_get_regular();
1237 k = i + BYTE_VIEW_WIDTH;
1239 /* Print the hex bit */
1242 line[cur++] = hexchars[(pd[i] & 0xf0) >> 4];
1243 line[cur++] = hexchars[pd[i] & 0x0f];
1245 line[cur++] = ' '; line[cur++] = ' ';
1249 /* insert a space every BYTE_VIEW_SEP bytes */
1250 if( ( i % BYTE_VIEW_SEP ) == 0 ) line[cur++] = ' ';
1251 /* Did we cross a bold/plain boundary? */
1252 new_font = (i >= bstart && i < bend) ? user_font_get_bold() : user_font_get_regular();
1253 if (cur_font != new_font) {
1254 gtk_text_insert(bv, cur_font, NULL, NULL, line, cur);
1255 cur_font = new_font;
1260 gtk_text_insert(bv, cur_font, NULL, NULL, line, cur);
1264 /* Print the ASCII bit */
1265 cur_font = (i >= bstart && i < bend) ? user_font_get_bold() : user_font_get_regular();
1268 if (encoding == CHAR_ASCII) {
1271 else if (encoding == CHAR_EBCDIC) {
1272 c = EBCDIC_to_ASCII1(pd[i]);
1275 g_assert_not_reached();
1277 line[cur++] = isprint(c) ? c : '.';
1282 /* insert a space every BYTE_VIEW_SEP bytes */
1283 if( ( i % BYTE_VIEW_SEP ) == 0 ) line[cur++] = ' ';
1284 /* Did we cross a bold/plain boundary? */
1285 new_font = (i >= bstart && i < bend) ? user_font_get_bold() : user_font_get_regular();
1286 if (cur_font != new_font) {
1287 gtk_text_insert(bv, cur_font, NULL, NULL, line, cur);
1288 cur_font = new_font;
1294 gtk_text_insert(bv, cur_font, NULL, NULL, line, -1);
1297 if (prefs.gui_hex_dump_highlight_style)
1298 revstyle = "reverse";
1302 gtk_text_buffer_insert_with_tags_by_name(buf, &iter, line, -1, "plain",
1304 /* Do we start in reverse? */
1305 reverse = i >= bstart && i < bend;
1307 k = i + BYTE_VIEW_WIDTH;
1309 /* Print the hex bit */
1312 line[cur++] = hexchars[(pd[i] & 0xf0) >> 4];
1313 line[cur++] = hexchars[pd[i] & 0x0f];
1315 line[cur++] = ' '; line[cur++] = ' ';
1318 newreverse = i >= bstart && i < bend;
1319 /* Have we gone from reverse to plain? */
1320 if (reverse && (reverse != newreverse)) {
1321 gtk_text_buffer_insert_with_tags_by_name(buf, &iter, line, cur,
1325 /* Inter byte space if not at end of line */
1328 /* insert a space every BYTE_VIEW_SEP bytes */
1329 if( ( i % BYTE_VIEW_SEP ) == 0 ) {
1333 /* Have we gone from plain to reversed? */
1334 if (!reverse && (reverse != newreverse)) {
1335 gtk_text_buffer_insert_with_tags_by_name(buf, &iter, line, cur,
1337 mark = gtk_text_buffer_create_mark(buf, NULL, &iter, TRUE);
1340 reverse = newreverse;
1342 /* Print remaining part of line */
1343 gtk_text_buffer_insert_with_tags_by_name(buf, &iter, line, cur,
1344 reverse ? revstyle : "plain",
1347 /* Print some space at the end of the line */
1348 line[cur++] = ' '; line[cur++] = ' '; line[cur++] = ' ';
1349 gtk_text_buffer_insert_with_tags_by_name(buf, &iter, line, cur,
1353 /* Print the ASCII bit */
1355 /* Do we start in reverse? */
1356 reverse = i >= bstart && i < bend;
1359 if (encoding == CHAR_ASCII) {
1362 else if (encoding == CHAR_EBCDIC) {
1363 c = EBCDIC_to_ASCII1(pd[i]);
1366 g_assert_not_reached();
1368 line[cur++] = isprint(c) ? c : '.';
1373 newreverse = i >= bstart && i < bend;
1374 /* Have we gone from reverse to plain? */
1375 if (reverse && (reverse != newreverse)) {
1376 convline = g_locale_to_utf8(line, cur, NULL, &newsize, NULL);
1377 gtk_text_buffer_insert_with_tags_by_name(buf, &iter, convline, newsize,
1383 /* insert a space every BYTE_VIEW_SEP bytes */
1384 if( ( i % BYTE_VIEW_SEP ) == 0 ) {
1388 /* Have we gone from plain to reversed? */
1389 if (!reverse && (reverse != newreverse)) {
1390 convline = g_locale_to_utf8(line, cur, NULL, &newsize, NULL);
1391 gtk_text_buffer_insert_with_tags_by_name(buf, &iter, convline, newsize,
1396 reverse = newreverse;
1398 /* Print remaining part of line */
1399 convline = g_locale_to_utf8(line, cur, NULL, &newsize, NULL);
1400 gtk_text_buffer_insert_with_tags_by_name(buf, &iter, convline, newsize,
1401 reverse ? revstyle : "plain",
1406 gtk_text_buffer_insert_with_tags_by_name(buf, &iter, line, cur,
1411 /* We're done printing the packets; destroy the progress bar if
1413 if (progbar != NULL)
1414 destroy_progress_dlg(progbar);
1416 /* scroll text into position */
1417 #if GTK_MAJOR_VERSION < 2
1418 gtk_text_thaw(bv); /* must thaw before adjusting scroll bars */
1423 linenum = bstart / BYTE_VIEW_WIDTH;
1424 scrollval = MIN(linenum * user_font_get_regular_height(),
1425 bv->vadj->upper - bv->vadj->page_size);
1427 gtk_adjustment_set_value(bv->vadj, scrollval);
1431 gtk_text_view_scroll_to_mark(bv, mark, 0.0, TRUE, 1.0, 0.0);
1432 gtk_text_buffer_delete_mark(buf, mark);
1437 #if GTK_MAJOR_VERSION < 2
1439 packet_hex_print(GtkText *bv, const guint8 *pd, frame_data *fd,
1440 field_info *finfo, guint len)
1443 packet_hex_print(GtkTextView *bv, const guint8 *pd, frame_data *fd,
1444 field_info *finfo, guint len)
1447 /* do the initial printing and save the information needed */
1448 /* to redraw the display if preferences change. */
1450 int bstart, bend = -1, blen;
1452 if (finfo != NULL) {
1453 bstart = finfo->start;
1454 blen = finfo->length;
1459 if (bstart >= 0 && blen >= 0) {
1460 bend = bstart + blen;
1463 /* save the information needed to redraw the text */
1464 /* should we save the fd & finfo pointers instead ?? */
1465 OBJECT_SET_DATA(bv, E_BYTE_VIEW_START_KEY, GINT_TO_POINTER(bend));
1466 OBJECT_SET_DATA(bv, E_BYTE_VIEW_END_KEY, GINT_TO_POINTER(bstart));
1467 OBJECT_SET_DATA(bv, E_BYTE_VIEW_ENCODE_KEY,
1468 GINT_TO_POINTER(fd->flags.encoding));
1470 packet_hex_print_common(bv, pd, len, bstart, bend, fd->flags.encoding);
1474 * Redraw the text using the saved information; usually called if
1475 * the preferences have changed.
1477 #if GTK_MAJOR_VERSION < 2
1479 packet_hex_reprint(GtkText *bv)
1482 packet_hex_reprint(GtkTextView *bv)
1485 int start, end, encoding;
1489 start = GPOINTER_TO_INT(OBJECT_GET_DATA(bv, E_BYTE_VIEW_START_KEY));
1490 end = GPOINTER_TO_INT(OBJECT_GET_DATA(bv, E_BYTE_VIEW_END_KEY));
1491 data = get_byte_view_data_and_length(GTK_WIDGET(bv), &len);
1492 g_assert(data != NULL);
1493 encoding = GPOINTER_TO_INT(OBJECT_GET_DATA(bv, E_BYTE_VIEW_ENCODE_KEY));
1495 packet_hex_print_common(bv, data, len, start, end, encoding);
1498 /* List of all protocol tree widgets, so we can globally set the selection
1499 mode and font of all of them. */
1500 static GList *ptree_widgets;
1502 /* Add a protocol tree widget to the list of protocol tree widgets. */
1503 static void forget_ptree_widget(GtkWidget *ptreew, gpointer data);
1506 remember_ptree_widget(GtkWidget *ptreew)
1508 ptree_widgets = g_list_append(ptree_widgets, ptreew);
1510 /* Catch the "destroy" event on the widget, so that we remove it from
1511 the list when it's destroyed. */
1512 SIGNAL_CONNECT(ptreew, "destroy", forget_ptree_widget, NULL);
1515 /* Remove a protocol tree widget from the list of protocol tree widgets. */
1517 forget_ptree_widget(GtkWidget *ptreew, gpointer data _U_)
1519 ptree_widgets = g_list_remove(ptree_widgets, ptreew);
1522 /* Set the selection mode of a given packet tree window. */
1524 set_ptree_sel_browse(GtkWidget *tree, gboolean val)
1526 #if GTK_MAJOR_VERSION >= 2
1527 GtkTreeSelection *selection;
1529 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
1531 /* Yeah, GTK uses "browse" in the case where we do not, but oh well.
1532 I think "browse" in Ethereal makes more sense than "SINGLE" in
1535 #if GTK_MAJOR_VERSION < 2
1536 gtk_clist_set_selection_mode(GTK_CLIST(tree),
1537 GTK_SELECTION_SINGLE);
1539 gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
1543 #if GTK_MAJOR_VERSION < 2
1544 gtk_clist_set_selection_mode(GTK_CLIST(tree),
1545 GTK_SELECTION_BROWSE);
1547 gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
1553 set_ptree_sel_browse_cb(gpointer data, gpointer user_data)
1555 set_ptree_sel_browse((GtkWidget *)data, *(gboolean *)user_data);
1558 /* Set the selection mode of all packet tree windows. */
1560 set_ptree_sel_browse_all(gboolean val)
1562 g_list_foreach(ptree_widgets, set_ptree_sel_browse_cb, &val);
1565 #if GTK_MAJOR_VERSION < 2
1567 set_ptree_style_cb(gpointer data, gpointer user_data)
1569 gtk_widget_set_style((GtkWidget *)data, (GtkStyle *)user_data);
1573 set_ptree_font_cb(gpointer data, gpointer user_data)
1575 gtk_widget_modify_font((GtkWidget *)data,
1576 (PangoFontDescription *)user_data);
1581 set_ptree_font_all(FONT_TYPE *font)
1583 #if GTK_MAJOR_VERSION < 2
1586 style = gtk_style_new();
1587 gdk_font_unref(style->font);
1591 g_list_foreach(ptree_widgets, set_ptree_style_cb, style);
1593 /* Now nuke the old style and replace it with the new one. */
1594 gtk_style_unref(item_style);
1597 g_list_foreach(ptree_widgets, set_ptree_font_cb, font);
1602 #if GTK_MAJOR_VERSION >= 2
1603 void tree_cell_renderer(GtkTreeViewColumn *tree_column _U_,
1604 GtkCellRenderer *cell,
1605 GtkTreeModel *tree_model,
1611 gtk_tree_model_get(tree_model, iter, 1, &fi, -1);
1613 /* for each field, we have to reset the renderer attributes */
1614 g_object_set (cell, "foreground-set", FALSE, NULL);
1616 g_object_set (cell, "underline", PANGO_UNDERLINE_NONE, NULL);
1617 g_object_set (cell, "underline-set", FALSE, NULL);
1619 /*g_object_set (cell, "style", PANGO_STYLE_NORMAL, NULL);
1620 g_object_set (cell, "style-set", FALSE, NULL);*/
1622 /*g_object_set (cell, "weight", PANGO_WEIGHT_NORMAL, NULL);
1623 g_object_set (cell, "weight-set", FALSE, NULL);*/
1625 if(FI_GET_FLAG(fi, FI_GENERATED)) {
1626 /* as some fonts don't support italic, don't use this */
1627 /*g_object_set (cell, "style", PANGO_STYLE_ITALIC, NULL);
1628 g_object_set (cell, "style-set", TRUE, NULL);
1630 /*g_object_set (cell, "weight", PANGO_WEIGHT_BOLD, NULL);
1631 g_object_set (cell, "weight-set", TRUE, NULL);*/
1634 if(fi->hfinfo->type == FT_FRAMENUM) {
1635 g_object_set (cell, "foreground", "blue", NULL);
1636 g_object_set (cell, "foreground-set", TRUE, NULL);
1638 g_object_set (cell, "underline", PANGO_UNDERLINE_SINGLE, NULL);
1639 g_object_set (cell, "underline-set", TRUE, NULL);
1646 main_tree_view_new(e_prefs *prefs, GtkWidget **tree_view_p)
1648 GtkWidget *tv_scrollw, *tree_view;
1649 #if GTK_MAJOR_VERSION >= 2
1650 GtkTreeStore *store;
1651 GtkCellRenderer *renderer;
1652 GtkTreeViewColumn *column;
1657 tv_scrollw = scrolled_window_new(NULL, NULL);
1658 #if GTK_MAJOR_VERSION >= 2
1659 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(tv_scrollw),
1663 #if GTK_MAJOR_VERSION < 2
1664 tree_view = ctree_new(1, 0);
1665 SIGNAL_CONNECT(tree_view, "key-press-event", toggle_tree, NULL );
1666 SIGNAL_CONNECT(tree_view, "tree-expand", expand_tree, NULL );
1667 SIGNAL_CONNECT(tree_view, "tree-collapse", collapse_tree, NULL );
1668 /* I need this next line to make the widget work correctly with hidden
1669 * column titles and GTK_SELECTION_BROWSE */
1670 gtk_clist_set_column_auto_resize( GTK_CLIST(tree_view), 0, TRUE );
1672 store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
1673 tree_view = tree_view_new(GTK_TREE_MODEL(store));
1674 g_object_unref(G_OBJECT(store));
1675 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_view), FALSE);
1676 renderer = gtk_cell_renderer_text_new();
1677 g_object_set (renderer, "ypad", 0, NULL);
1678 col_offset = gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(tree_view),
1679 -1, "Name", renderer,
1681 column = gtk_tree_view_get_column(GTK_TREE_VIEW(tree_view),
1683 gtk_tree_view_column_set_cell_data_func(column,
1689 gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column),
1690 GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1691 SIGNAL_CONNECT(tree_view, "row-expanded", expand_tree, NULL);
1692 SIGNAL_CONNECT(tree_view, "row-collapsed", collapse_tree, NULL);
1694 gtk_container_add( GTK_CONTAINER(tv_scrollw), tree_view );
1695 set_ptree_sel_browse(tree_view, prefs->gui_ptree_sel_browse);
1696 #if GTK_MAJOR_VERSION < 2
1697 if(item_style == NULL) {
1698 item_style = gtk_style_new();
1699 gdk_font_unref(item_style->font);
1700 item_style->font = user_font_get_regular();
1703 gtk_widget_set_style(tree_view, item_style);
1705 gtk_widget_modify_font(tree_view, user_font_get_regular());
1707 remember_ptree_widget(tree_view);
1709 *tree_view_p = tree_view;
1714 #if GTK_MAJOR_VERSION < 2
1715 void expand_all_tree(proto_tree *protocol_tree, GtkWidget *tree_view)
1717 void expand_all_tree(proto_tree *protocol_tree _U_, GtkWidget *tree_view)
1721 for(i=0; i < num_tree_types; i++) {
1722 tree_is_expanded[i] = TRUE;
1724 #if GTK_MAJOR_VERSION < 2
1725 proto_tree_draw(protocol_tree, tree_view);
1726 gtk_ctree_expand_recursive(GTK_CTREE(tree_view), NULL);
1728 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree_view));
1732 #if GTK_MAJOR_VERSION < 2
1733 void collapse_all_tree(proto_tree *protocol_tree, GtkWidget *tree_view)
1735 void collapse_all_tree(proto_tree *protocol_tree _U_, GtkWidget *tree_view)
1739 for(i=0; i < num_tree_types; i++) {
1740 tree_is_expanded[i] = FALSE;
1742 #if GTK_MAJOR_VERSION < 2
1743 proto_tree_draw(protocol_tree, tree_view);
1745 gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree_view));
1750 struct proto_tree_draw_info {
1751 #if GTK_MAJOR_VERSION < 2
1753 GtkCTreeNode *ctree_node;
1755 GtkTreeView *tree_view;
1761 main_proto_tree_draw(proto_tree *protocol_tree)
1763 proto_tree_draw(protocol_tree, tree_view);
1768 tree_view_follow_link(field_info *fi)
1770 if(fi->hfinfo->type == FT_FRAMENUM) {
1771 goto_frame(&cfile, fi->value.value.integer);
1776 /* If the user selected a position in the tree view, try to find
1777 * the item in the GUI proto_tree that corresponds to that byte, and
1780 tree_view_select(GtkWidget *widget, GdkEventButton *event)
1782 #if GTK_MAJOR_VERSION < 2
1790 if(gtk_clist_get_selection_info(GTK_CLIST(widget),
1791 (gint) (((GdkEventButton *)event)->x),
1792 (gint) (((GdkEventButton *)event)->y),
1795 ctree = GTK_CTREE(widget);
1797 node = gtk_ctree_node_nth(ctree, row);
1800 gtk_ctree_select(ctree, node);
1802 /* if that's a doubleclick, try to follow the link */
1803 if(event->type == GDK_2BUTTON_PRESS) {
1804 fi = gtk_ctree_node_get_row_data(ctree, node);
1805 tree_view_follow_link(fi);
1811 GtkTreeSelection *sel;
1814 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget),
1815 (gint) (((GdkEventButton *)event)->x),
1816 (gint) (((GdkEventButton *)event)->y),
1817 &path, NULL, NULL, NULL))
1819 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
1820 gtk_tree_selection_select_path(sel, path);
1822 /* if that's a doubleclick, try to follow the link */
1823 if(event->type == GDK_2BUTTON_PRESS) {
1824 GtkTreeModel *model;
1828 if(gtk_tree_selection_get_selected (sel, &model, &iter)) {
1829 gtk_tree_model_get(model, &iter, 1, &fi, -1);
1830 tree_view_follow_link(fi);
1841 proto_tree_draw(proto_tree *protocol_tree, GtkWidget *tree_view)
1843 #if GTK_MAJOR_VERSION >= 2
1844 GtkTreeStore *store;
1846 struct proto_tree_draw_info info;
1848 #if GTK_MAJOR_VERSION < 2
1849 info.ctree = GTK_CTREE(tree_view);
1850 info.ctree_node = NULL;
1852 gtk_clist_freeze(GTK_CLIST(tree_view));
1854 info.tree_view = GTK_TREE_VIEW(tree_view);
1857 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view)));
1861 * Clear out any crud left over in the display of the protocol
1862 * tree, by removing all nodes from the tree.
1863 * This is how it's done in testgtk.c in GTK+.
1865 #if GTK_MAJOR_VERSION < 2
1866 gtk_clist_clear(GTK_CLIST(tree_view));
1868 gtk_tree_store_clear(store);
1871 proto_tree_children_foreach(protocol_tree, proto_tree_draw_node, &info);
1873 #if GTK_MAJOR_VERSION < 2
1874 gtk_clist_thaw(GTK_CLIST(tree_view));
1879 proto_tree_draw_node(proto_node *node, gpointer data)
1881 struct proto_tree_draw_info info;
1882 struct proto_tree_draw_info *parent_info = (struct proto_tree_draw_info*) data;
1884 field_info *fi = PITEM_FINFO(node);
1885 gchar label_str[ITEM_LABEL_LENGTH];
1887 gboolean is_leaf, is_expanded;
1888 #if GTK_MAJOR_VERSION < 2
1889 GtkCTreeNode *parent;
1891 GtkTreeStore *store;
1896 if (PROTO_ITEM_IS_HIDDEN(node))
1899 /* was a free format label produced? */
1901 label_ptr = fi->rep->representation;
1903 else { /* no, make a generic label */
1904 label_ptr = label_str;
1905 proto_item_fill_label(fi, label_str);
1908 if (node->first_child != NULL) {
1910 g_assert(fi->tree_type >= 0 && fi->tree_type < num_tree_types);
1911 if (tree_is_expanded[fi->tree_type]) {
1915 is_expanded = FALSE;
1920 is_expanded = FALSE;
1923 if(PROTO_ITEM_IS_GENERATED(node)) {
1924 label_ptr = g_strdup_printf("[%s]", label_ptr);
1927 #if GTK_MAJOR_VERSION < 2
1928 info.ctree = parent_info->ctree;
1929 parent = gtk_ctree_insert_node ( info.ctree, parent_info->ctree_node, NULL,
1930 &label_ptr, 5, NULL, NULL, NULL, NULL,
1931 is_leaf, is_expanded );
1933 gtk_ctree_node_set_row_data( GTK_CTREE(info.ctree), parent, fi );
1935 info.tree_view = parent_info->tree_view;
1936 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(info.tree_view)));
1937 gtk_tree_store_append(store, &iter, parent_info->iter);
1938 gtk_tree_store_set(store, &iter, 0, label_ptr, 1, fi, -1);
1941 if(PROTO_ITEM_IS_GENERATED(node)) {
1946 #if GTK_MAJOR_VERSION < 2
1947 info.ctree_node = parent;
1951 proto_tree_children_foreach(node, proto_tree_draw_node, &info);
1952 #if GTK_MAJOR_VERSION >= 2
1953 path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
1955 /* #if GTK_MINOR_VERSION >= 2 */
1956 gtk_tree_view_expand_to_path(info.tree_view, path);
1958 gtk_tree_view_expand_row(info.tree_view, path, FALSE);
1961 gtk_tree_view_collapse_row(info.tree_view, path);
1962 gtk_tree_path_free(path);
1968 * Clear the hex dump and protocol tree panes.
1971 clear_tree_and_hex_views(void)
1973 /* Clear the hex dump by getting rid of all the byte views. */
1974 while (gtk_notebook_get_nth_page(GTK_NOTEBOOK(byte_nb_ptr), 0) != NULL)
1975 gtk_notebook_remove_page(GTK_NOTEBOOK(byte_nb_ptr), 0);
1977 /* Add a placeholder byte view so that there's at least something
1978 displayed in the byte view notebook. */
1979 add_byte_tab(byte_nb_ptr, "", NULL, NULL, tree_view);
1981 /* Clear the protocol tree by removing all nodes in the ctree.
1982 This is how it's done in testgtk.c in GTK+ */
1983 #if GTK_MAJOR_VERSION < 2
1984 gtk_clist_clear(GTK_CLIST(tree_view));
1986 gtk_tree_store_clear(GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view))));