2 * Routines for GTK+ packet display
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
43 #include <gdk/gdkkeysyms.h>
47 #include <epan/epan_dissect.h>
49 #include <epan/packet.h>
50 #include <epan/charsets.h>
51 #include <epan/prefs.h>
52 #include <epan/filesystem.h>
54 #include "../isprint.h"
55 #include "../alert_box.h"
56 #include "../simple_dialog.h"
57 #include "../progress_dlg.h"
58 #include "../ui_util.h"
59 #include <wsutil/file_util.h>
62 #include "gtk/color_utils.h"
63 #include "gtk/capture_file_dlg.h"
64 #include "gtk/packet_win.h"
65 #include "gtk/file_dlg.h"
66 #include "gtk/gui_utils.h"
67 #include "gtk/gtkglobals.h"
68 #include "gtk/font_utils.h"
69 #include "gtk/webbrowser.h"
71 #include "gtk/menus.h"
72 #include "gtk/main_proto_draw.h"
73 #include "gtk/recent.h"
76 #include <gdk/gdkwin32.h>
78 #include "file_dlg_win32.h"
82 #define E_BYTE_VIEW_TREE_PTR "byte_view_tree_ptr"
83 #define E_BYTE_VIEW_TREE_VIEW_PTR "byte_view_tree_view_ptr"
84 #define E_BYTE_VIEW_NDIGITS_KEY "byte_view_ndigits"
85 #define E_BYTE_VIEW_TVBUFF_KEY "byte_view_tvbuff"
86 #define E_BYTE_VIEW_START_KEY "byte_view_start"
87 #define E_BYTE_VIEW_END_KEY "byte_view_end"
88 #define E_BYTE_VIEW_APP_START_KEY "byte_view_app_start"
89 #define E_BYTE_VIEW_APP_END_KEY "byte_view_app_end"
90 #define E_BYTE_VIEW_ENCODE_KEY "byte_view_encode"
93 add_byte_tab(GtkWidget *byte_nb, const char *name, tvbuff_t *tvb,
94 proto_tree *tree, GtkWidget *tree_view);
97 proto_tree_draw_node(proto_node *node, gpointer data);
99 /* Get the current text window for the notebook. */
101 get_notebook_bv_ptr(GtkWidget *nb_ptr)
106 num = gtk_notebook_get_current_page(GTK_NOTEBOOK(nb_ptr));
107 bv_page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(nb_ptr), num);
109 return GTK_BIN(bv_page)->child;
115 * Get the data and length for a byte view, given the byte view page.
116 * Return the pointer, or NULL on error, and set "*data_len" to the length.
119 get_byte_view_data_and_length(GtkWidget *byte_view, guint *data_len)
121 tvbuff_t *byte_view_tvb;
122 const guint8 *data_ptr;
124 byte_view_tvb = g_object_get_data(G_OBJECT(byte_view), E_BYTE_VIEW_TVBUFF_KEY);
125 if (byte_view_tvb == NULL)
128 data_ptr = tvb_get_ptr(byte_view_tvb, 0, -1);
129 *data_len = tvb_length(byte_view_tvb);
134 * Set the current text window for the notebook to the window that
135 * refers to a particular tvbuff.
138 set_notebook_page(GtkWidget *nb_ptr, tvbuff_t *tvb)
141 GtkWidget *bv_page, *bv;
145 (bv_page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(nb_ptr), num)) != NULL;
147 bv = GTK_BIN(bv_page)->child;
148 bv_tvb = g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_TVBUFF_KEY);
151 gtk_notebook_set_current_page(GTK_NOTEBOOK(nb_ptr), num);
157 /* Redraw a given byte view window. */
159 redraw_packet_bytes(GtkWidget *nb, frame_data *fd, field_info *finfo)
165 bv = get_notebook_bv_ptr(nb);
167 data = get_byte_view_data_and_length(bv, &len);
169 packet_hex_print(bv, data, fd, finfo, len);
173 /* Redraw all byte view windows. */
175 redraw_packet_bytes_all(void)
177 if (cfile.current_frame != NULL)
178 redraw_packet_bytes( byte_nb_ptr, cfile.current_frame, cfile.finfo_selected);
180 redraw_packet_bytes_packet_wins();
182 /* XXX - this is a hack, to workaround a bug in GTK2.x!
183 when changing the font size, even refilling of the corresponding
184 gtk_text_buffer doesn't seem to trigger an update.
185 The only workaround is to freshly select the frame, which will remove any
186 existing notebook tabs and "restart" the whole byte view again. */
187 if (cfile.current_frame != NULL) {
188 cfile.current_row = -1;
189 cf_goto_frame(&cfile, cfile.current_frame->num);
194 expand_tree(GtkTreeView *tree_view, GtkTreeIter *iter,
195 GtkTreePath *path _U_, gpointer user_data _U_)
200 model = gtk_tree_view_get_model(tree_view);
201 gtk_tree_model_get(model, iter, 1, &finfo, -1);
205 * Nodes with "finfo->tree_type" of -1 have no ett_ value, and
206 * are thus presumably leaf nodes and cannot be expanded.
208 if (finfo->tree_type != -1) {
209 g_assert(finfo->tree_type >= 0 &&
210 finfo->tree_type < num_tree_types);
211 tree_is_expanded[finfo->tree_type] = TRUE;
216 collapse_tree(GtkTreeView *tree_view, GtkTreeIter *iter,
217 GtkTreePath *path _U_, gpointer user_data _U_)
222 model = gtk_tree_view_get_model(tree_view);
223 gtk_tree_model_get(model, iter, 1, &finfo, -1);
227 * Nodes with "finfo->tree_type" of -1 have no ett_ value, and
228 * are thus presumably leaf nodes and cannot be collapsed.
230 if (finfo->tree_type != -1) {
231 g_assert(finfo->tree_type >= 0 &&
232 finfo->tree_type < num_tree_types);
233 tree_is_expanded[finfo->tree_type] = FALSE;
237 #define MAX_OFFSET_LEN 8 /* max length of hex offset of bytes */
238 #define BYTES_PER_LINE 16 /* max byte values in a line */
239 #define BITS_PER_LINE 8 /* max bit values in a line */
240 #define BYTE_VIEW_SEP 8 /* insert a space every BYTE_VIEW_SEP bytes */
241 #define HEX_DUMP_LEN (BYTES_PER_LINE*3 + 1)
242 /* max number of characters hex dump takes -
243 2 digits plus trailing blank
244 plus separator between first and
246 #define DATA_DUMP_LEN (HEX_DUMP_LEN + 2 + BYTES_PER_LINE)
247 /* number of characters those bytes take;
248 3 characters per byte of hex dump,
249 2 blanks separating hex from ASCII,
250 1 character per byte of ASCII dump */
251 #define MAX_LINE_LEN (MAX_OFFSET_LEN + 2 + DATA_DUMP_LEN)
252 /* number of characters per line;
253 offset, 2 blanks separating offset
254 from data dump, data dump */
255 #define MAX_LINES 100
256 #define MAX_LINES_LEN (MAX_LINES*MAX_LINE_LEN)
258 /* Which byte the offset is referring to. Associates
259 * whitespace with the preceding digits. */
261 byte_num(int offset, int start_point)
263 return (offset - start_point) / 3;
266 bit_num(int offset, int start_point)
268 return (offset - start_point) / 9;
271 struct field_lookup_info {
277 lookup_finfo(GtkTreeModel *model, GtkTreePath *path _U_, GtkTreeIter *iter,
281 struct field_lookup_info *fli = (struct field_lookup_info *)data;
283 gtk_tree_model_get(model, iter, 1, &fi, -1);
291 GtkTreePath *tree_find_by_field_info(GtkTreeView *tree_view, field_info *finfo) {
293 struct field_lookup_info fli;
295 g_assert(finfo != NULL);
297 model = gtk_tree_view_get_model(tree_view);
299 gtk_tree_model_foreach(model, lookup_finfo, &fli);
301 return gtk_tree_model_get_path(model, &fli.iter);
305 hex_view_get_byte(guint ndigits, int row, int column)
318 * The column of the first hex digit in the first half.
319 * That starts after "ndigits" digits of offset and two
322 digits_start_1 = ndigits + 2;
325 * The column of the last hex digit in the first half.
326 * There are BYTES_PER_LINE/2 bytes displayed in the first
327 * half; there are 2 characters per byte, plus a separating
328 * blank after all but the last byte's characters.
330 digits_end_1 = digits_start_1 + (BYTES_PER_LINE/2)*2 +
331 (BYTES_PER_LINE/2 - 1);
334 * The column of the first hex digit in the second half.
335 * Add 2 for the 2 separating blanks between the halves.
337 digits_start_2 = digits_end_1 + 2;
340 * The column of the last hex digit in the second half.
341 * Add the same value we used to get "digits_end_1" from
344 digits_end_2 = digits_start_2 + (BYTES_PER_LINE/2)*2 +
345 (BYTES_PER_LINE/2 - 1);
348 * The column of the first "text dump" character in the first half.
349 * Add 3 for the 3 separating blanks between the hex and text dump.
351 text_start_1 = digits_end_2 + 3;
354 * The column of the last "text dump" character in the first half.
355 * There are BYTES_PER_LINE/2 bytes displayed in the first
356 * half; there is 1 character per byte.
358 * Then subtract 1 to get the last column of the first half
359 * rather than the first column after the first half.
361 text_end_1 = text_start_1 + BYTES_PER_LINE/2 - 1;
364 * The column of the first "text dump" character in the second half.
365 * Add back the 1 to get the first column after the first half,
366 * and then add 1 for the separating blank between the halves.
368 text_start_2 = text_end_1 + 2;
371 * The column of the last "text dump" character in second half.
372 * Add the same value we used to get "text_end_1" from
375 text_end_2 = text_start_2 + BYTES_PER_LINE/2 - 1;
377 /* Given the column and row, determine which byte offset
378 * the user clicked on. */
379 if (column >= digits_start_1 && column <= digits_end_1) {
380 byte = byte_num(column, digits_start_1);
385 else if (column >= digits_start_2 && column <= digits_end_2) {
386 byte = byte_num(column, digits_start_2);
392 else if (column >= text_start_1 && column <= text_end_1) {
393 byte = column - text_start_1;
395 else if (column >= text_start_2 && column <= text_end_2) {
396 byte = 8 + column - text_start_2;
399 /* The user didn't select a hex digit or
400 * text-dump character. */
404 /* Add the number of bytes from the previous rows. */
405 byte += row * BYTES_PER_LINE;
411 bit_view_get_byte(guint ndigits, int row, int column)
420 * The column of the first bit digit.
421 * That starts after "ndigits" digits of offset and two
424 digits_start = ndigits + 2;
427 * The column of the last bit digit.
428 * There are BITS_PER_LINE bytes displayed; there are
429 * 8 characters per byte, plus a separating blank
430 * after all but the last byte's characters.
432 digits_end = digits_start + (BITS_PER_LINE)*8 +
436 * The column of the first "text dump" character.
437 * Add 3 for the 3 separating blanks between the bit and text dump.
439 text_start = digits_end + 3;
442 * The column of the last "text dump" character.
443 * There are BITS_PER_LINE bytes displayed; there is 1 character per byte.
445 * Then subtract 1 to get the last column.
447 text_end = text_start + BITS_PER_LINE - 1;
449 /* Given the column and row, determine which byte offset
450 * the user clicked on. */
451 if (column >= digits_start && column <= digits_end) {
452 byte = bit_num(column, digits_start);
457 else if (column >= text_start && column <= text_end) {
458 byte = column - text_start;
461 /* The user didn't select a hex digit or
462 * text-dump character. */
466 /* Add the number of bytes from the previous rows. */
467 byte += row * BITS_PER_LINE;
472 /* If the user selected a certain byte in the byte view, try to find
473 * the item in the GUI proto_tree that corresponds to that byte, and:
475 * if we succeed, select it, and return TRUE;
476 * if we fail, return FALSE. */
478 byte_view_select(GtkWidget *widget, GdkEventButton *event)
480 GtkTextView *bv = GTK_TEXT_VIEW(widget);
482 GtkTreeView *tree_view;
490 tree = g_object_get_data(G_OBJECT(widget), E_BYTE_VIEW_TREE_PTR);
493 * Somebody clicked on the dummy byte view; do nothing.
497 tree_view = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(widget),
498 E_BYTE_VIEW_TREE_VIEW_PTR));
500 /* get the row/column selected */
501 gtk_text_view_window_to_buffer_coords(bv,
502 gtk_text_view_get_window_type(bv, event->window),
503 (gint) event->x, (gint) event->y, &x, &y);
504 gtk_text_view_get_iter_at_location(bv, &iter, x, y);
505 row = gtk_text_iter_get_line(&iter);
506 column = gtk_text_iter_get_line_offset(&iter);
509 * Get the number of digits of offset being displayed, and
510 * compute the byte position in the buffer.
512 ndigits = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_NDIGITS_KEY));
514 switch (recent.gui_bytes_view) {
516 byte = hex_view_get_byte(ndigits, row, column);
519 byte = bit_view_get_byte(ndigits, row, column);
522 g_assert_not_reached();
529 /* Get the data source tvbuff */
530 tvb = g_object_get_data(G_OBJECT(widget), E_BYTE_VIEW_TVBUFF_KEY);
532 return highlight_field(tvb, byte, tree_view, tree);
535 /* This highlights the field in the proto tree that is at position byte */
537 highlight_field(tvbuff_t *tvb, gint byte, GtkTreeView *tree_view,
541 GtkTreePath *first_path, *path;
543 struct field_lookup_info fli;
546 /* Find the finfo that corresponds to our byte. */
547 finfo = proto_find_field_from_offset(tree, byte, tvb);
553 model = gtk_tree_view_get_model(tree_view);
555 gtk_tree_model_foreach(model, lookup_finfo, &fli);
557 /* Expand our field's row */
558 first_path = gtk_tree_model_get_path(model, &fli.iter);
559 gtk_tree_view_expand_row(tree_view, first_path, FALSE);
560 expand_tree(tree_view, &fli.iter, NULL, NULL);
562 /* ... and its parents */
563 while (gtk_tree_model_iter_parent(model, &parent, &fli.iter)) {
564 path = gtk_tree_model_get_path(model, &parent);
565 gtk_tree_view_expand_row(tree_view, path, FALSE);
566 expand_tree(tree_view, &parent, NULL, NULL);
568 gtk_tree_path_free(path);
571 /* select our field's row */
572 gtk_tree_selection_select_path(gtk_tree_view_get_selection(tree_view),
575 /* And position the window so the selection is visible.
576 * Position the selection in the middle of the viewable
578 gtk_tree_view_scroll_to_cell(tree_view, first_path, NULL, TRUE, 0.5f, 0.0f);
580 gtk_tree_path_free(first_path);
585 /* Calls functions for different mouse-button presses. */
587 byte_view_button_press_cb(GtkWidget *widget, GdkEvent *event, gpointer data)
589 GdkEventButton *event_button = NULL;
591 if(widget == NULL || event == NULL || data == NULL) {
595 if(event->type == GDK_BUTTON_PRESS) {
596 event_button = (GdkEventButton *) event;
598 /* To qoute the "Gdk Event Structures" doc:
599 * "Normally button 1 is the left mouse button, 2 is the middle button, and 3 is the right button" */
600 switch(event_button->button) {
603 return byte_view_select(widget, event_button);
605 return popup_menu_handler(widget, event, data);
619 byte_nb = gtk_notebook_new();
620 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(byte_nb), GTK_POS_BOTTOM);
622 /* this will only have an effect, if no tabs are shown */
623 gtk_notebook_set_show_border(GTK_NOTEBOOK(byte_nb), FALSE);
625 /* set the tabs scrollable, if they don't fit into the pane */
626 gtk_notebook_set_scrollable(GTK_NOTEBOOK(byte_nb), TRUE);
628 /* enable a popup menu containing the tab labels, will be helpful if tabs don't fit into the pane */
629 gtk_notebook_popup_enable(GTK_NOTEBOOK(byte_nb));
631 /* Add a placeholder byte view so that there's at least something
632 displayed in the byte view notebook. */
633 add_byte_tab(byte_nb, "", NULL, NULL, NULL);
639 byte_view_realize_cb(GtkWidget *bv, gpointer data _U_)
641 const guint8 *byte_data;
644 byte_data = get_byte_view_data_and_length(bv, &byte_len);
645 if (byte_data == NULL) {
646 /* This must be the dummy byte view if no packet is selected. */
649 packet_hex_print(bv, byte_data, cfile.current_frame, NULL, byte_len);
653 add_byte_tab(GtkWidget *byte_nb, const char *name, tvbuff_t *tvb,
654 proto_tree *tree, GtkWidget *tree_view)
656 GtkWidget *byte_view, *byte_scrollw, *label;
660 /* Byte view. Create a scrolled window for the text. */
661 byte_scrollw = scrolled_window_new(NULL, NULL);
662 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(byte_scrollw),
664 /* Add scrolled pane to tabbed window */
665 label = gtk_label_new(name);
666 gtk_notebook_append_page(GTK_NOTEBOOK(byte_nb), byte_scrollw, label);
668 gtk_widget_show(byte_scrollw);
670 byte_view = gtk_text_view_new();
671 gtk_text_view_set_editable(GTK_TEXT_VIEW(byte_view), FALSE);
672 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(byte_view), FALSE);
673 buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(byte_view));
675 #ifdef NEW_PACKET_LIST
676 style = gtk_widget_get_style(GTK_WIDGET(top_level));
678 style = gtk_widget_get_style(GTK_WIDGET(packet_list));
680 gtk_text_buffer_create_tag(buf, "plain", "font-desc", user_font_get_regular(), NULL);
681 gtk_text_buffer_create_tag(buf, "reverse",
682 "font-desc", user_font_get_regular(),
683 "foreground-gdk", &style->text[GTK_STATE_SELECTED],
684 "background-gdk", &style->base[GTK_STATE_SELECTED],
687 gtk_text_buffer_create_tag(buf, "bold", "font-desc", user_font_get_bold(), NULL);
688 g_object_set_data(G_OBJECT(byte_view), E_BYTE_VIEW_TVBUFF_KEY, tvb);
689 gtk_container_add(GTK_CONTAINER(byte_scrollw), byte_view);
691 g_signal_connect(byte_view, "show", G_CALLBACK(byte_view_realize_cb), NULL);
692 g_signal_connect(byte_view, "button_press_event", G_CALLBACK(byte_view_button_press_cb),
693 g_object_get_data(G_OBJECT(popup_menu_object), PM_BYTES_VIEW_KEY));
695 g_object_set_data(G_OBJECT(byte_view), E_BYTE_VIEW_TREE_PTR, tree);
696 g_object_set_data(G_OBJECT(byte_view), E_BYTE_VIEW_TREE_VIEW_PTR, tree_view);
698 gtk_widget_show(byte_view);
700 /* no tabs if this is the first page */
701 if (!(gtk_notebook_page_num(GTK_NOTEBOOK(byte_nb), byte_scrollw)))
702 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(byte_nb), FALSE);
704 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(byte_nb), TRUE);
706 /* set this page (this will print the packet data) */
707 gtk_notebook_set_current_page(GTK_NOTEBOOK(byte_nb),
708 gtk_notebook_page_num(GTK_NOTEBOOK(byte_nb), byte_nb));
714 add_main_byte_views(epan_dissect_t *edt)
716 add_byte_views(edt, tree_view, byte_nb_ptr);
720 add_byte_views(epan_dissect_t *edt, GtkWidget *tree_view,
721 GtkWidget *byte_nb_ptr)
727 * Get rid of all the old notebook tabs.
729 while (gtk_notebook_get_nth_page(GTK_NOTEBOOK(byte_nb_ptr), 0) != NULL)
730 gtk_notebook_remove_page(GTK_NOTEBOOK(byte_nb_ptr), 0);
733 * Add to the specified byte view notebook tabs for hex dumps
734 * of all the data sources for the specified frame.
736 for (src_le = edt->pi.data_src; src_le != NULL; src_le = src_le->next) {
738 add_byte_tab(byte_nb_ptr, get_data_source_name(src), src->tvb, edt->tree,
743 * Initially select the first byte view.
745 gtk_notebook_set_current_page(GTK_NOTEBOOK(byte_nb_ptr), 0);
750 static GtkWidget *savehex_dlg=NULL;
753 savehex_dlg_destroy_cb(void)
759 static void copy_hex_all_info(GString* copy_buffer, const guint8* data_p, int data_len, gboolean append_text)
761 const int byte_line_length = 16; /* Print out data for 16 bytes on one line */
763 gboolean end_of_line = TRUE; /* Initial state is end of line */
764 int byte_line_part_length;
769 /* Write hex data for a line, then ascii data, then concatenate and add to buffer */
770 hex_str = g_string_new("");
771 char_str= g_string_new("");
776 g_string_append_printf(hex_str,"%04x ",i); /* Offset - note that we _append_ here */
779 g_string_append_printf(hex_str," %02x",*data_p);
781 g_string_append_printf(char_str,"%c",isprint(*data_p) ? *data_p : '.');
786 /* Look ahead to see if this is the end of the data */
787 byte_line_part_length = (++i) % byte_line_length;
789 /* End of data - need to fill in spaces in hex string and then do "end of line".
792 for(j = 0; append_text && (j < (byte_line_length - byte_line_part_length)); ++j) {
793 g_string_append(hex_str," "); /* Three spaces for each missing byte */
797 end_of_line = (byte_line_part_length == 0 ? TRUE : FALSE);
803 g_string_append(copy_buffer, hex_str->str);
805 /* Two spaces between hex and text */
806 g_string_append_c(copy_buffer, ' ');
807 g_string_append_c(copy_buffer, ' ');
808 g_string_append(copy_buffer, char_str->str);
810 /* Setup ready for next line */
811 g_string_assign(char_str,"");
812 g_string_assign(hex_str, "\n");
816 g_string_free(hex_str, TRUE);
817 g_string_free(char_str, TRUE);
821 int copy_hex_bytes_text_only(GString* copy_buffer, const guint8* data_p, int data_len _U_)
826 if(isprint(*data_p)) {
828 } else if(*data_p==0x0a) {
829 to_append = '\n'; /* Copied from old copy_hex_cb function; not sure why this is needed - portablity?*/
831 return 1; /* Just ignore non-printable bytes */
833 g_string_append_c(copy_buffer,to_append);
838 int copy_hex_bytes_hex(GString* copy_buffer, const guint8* data_p, int data_len _U_)
840 g_string_append_printf(copy_buffer, "%02x", *data_p);
845 copy_hex_cb(GtkWidget * w _U_, gpointer data _U_, copy_data_type data_type)
850 int bytes_consumed = 0;
853 const guint8* data_p;
855 GString* copy_buffer = g_string_new(""); /* String to copy to clipboard */
857 bv = get_notebook_bv_ptr(byte_nb_ptr);
859 /* shouldn't happen */
860 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Could not find the corresponding text window!");
864 data_p = get_byte_view_data_and_length(bv, &len);
865 g_assert(data_p != NULL);
867 flags = data_type & CD_FLAGSMASK;
868 data_type = data_type & CD_TYPEMASK;
870 if(flags & CD_FLAGS_SELECTEDONLY) {
873 /* Get the start and end of the highlighted bytes. */
874 start = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_START_KEY));
875 end = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_END_KEY));
877 if(start >= 0 && end > start && (end - start <= (int)len)) {
885 /* This is too different from other text formats - handle separately */
886 copy_hex_all_info(copy_buffer, data_p, len, TRUE);
889 /* This could be done incrementally, but it is easier to mingle with the code for CD_ALLINFO */
890 copy_hex_all_info(copy_buffer, data_p, len, FALSE);
893 /* Completely different logic to text copies - leave copy buffer alone */
894 copy_binary_to_clipboard(data_p,len);
897 /* Incrementally write to text buffer in various formats */
901 bytes_consumed = copy_hex_bytes_text_only(copy_buffer, data_p, len);
904 bytes_consumed = copy_hex_bytes_hex(copy_buffer, data_p, len);
907 g_assert_not_reached();
911 g_assert(bytes_consumed>0);
912 data_p += bytes_consumed;
913 len -= bytes_consumed;
918 if(copy_buffer->len > 0) {
919 copy_to_clipboard(copy_buffer);
922 g_string_free(copy_buffer, TRUE);
925 /* save the current highlighted hex data */
927 savehex_save_clicked_cb(GtkWidget * w _U_, gpointer data _U_)
932 const guint8 *data_p = NULL;
935 file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(savehex_dlg));
937 #if 0 /* Not req'd: GtkFileChooserWidget currently being used won't return with a Null filename */
938 if (!file ||! *file) {
939 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Please enter a filename!");
944 if (test_for_directory(file) == EISDIR) {
945 /* It's a directory - set the file selection box to display that
946 directory, and leave the selection box displayed. */
947 set_last_open_dir(file);
949 file_selection_set_current_folder(savehex_dlg, get_last_open_dir());
950 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(savehex_dlg), "");
951 return FALSE; /* do gtk_dialog_run again */
954 /* XXX: Must check if file name exists first */
956 bv = get_notebook_bv_ptr(byte_nb_ptr);
958 /* shouldn't happen */
959 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Could not find the corresponding text window!");
964 * Retrieve the info we need
966 start = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_START_KEY));
967 end = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_END_KEY));
968 data_p = get_byte_view_data_and_length(bv, &len);
970 if (data_p == NULL || start == -1 || start > end) {
971 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
972 "No data selected to save!");
977 fd = ws_open(file, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666);
979 open_failure_alert_box(file, errno, TRUE);
983 if (ws_write(fd, data_p + start, end - start) < 0) {
984 write_failure_alert_box(file, errno);
989 if (ws_close(fd) < 0) {
990 write_failure_alert_box(file, errno);
995 /* Get rid of the dialog box */
997 #if 0 /* being handled by caller (for now) */
998 window_destroy(GTK_WIDGET(savehex_dlg));
1003 /* Launch the dialog box to put up the file selection box etc */
1004 void savehex_cb(GtkWidget * w _U_, gpointer data _U_)
1008 const guint8 *data_p = NULL;
1015 win32_export_raw_file(GDK_WINDOW_HWND(top_level->window));
1019 /* don't show up the dialog, if no data has to be saved */
1020 bv = get_notebook_bv_ptr(byte_nb_ptr);
1022 /* shouldn't happen */
1023 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Could not find the corresponding text window!");
1026 start = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_START_KEY));
1027 end = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_END_KEY));
1028 data_p = get_byte_view_data_and_length(bv, &len);
1030 if (data_p == NULL || start == -1 || start > end) {
1031 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "No data selected to save!");
1035 #if 0 /* XXX: GtkFileChooserDialog/gtk_dialog_run currently being used is effectively modal so this is not req'd */
1036 /* if the window is already open, bring it to front */
1038 reactivate_window(savehex_dlg);
1043 * Build the dialog box we need.
1045 savehex_dlg = file_selection_new("Wireshark: Export Selected Packet Bytes", FILE_SELECTION_SAVE);
1046 #if GTK_CHECK_VERSION(2,8,0)
1047 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(savehex_dlg), TRUE);
1051 label = g_strdup_printf("Will save %u %s of raw binary data to specified file.",
1052 end - start, plurality(end - start, "byte", "bytes"));
1053 dlg_lb = gtk_label_new(label);
1055 file_selection_set_extra_widget(savehex_dlg, dlg_lb);
1056 gtk_widget_show(dlg_lb);
1058 g_signal_connect(savehex_dlg, "destroy", G_CALLBACK(savehex_dlg_destroy_cb), NULL);
1061 if (gtk_dialog_run(GTK_DIALOG(savehex_dlg)) == GTK_RESPONSE_ACCEPT) {
1062 savehex_save_clicked_cb(savehex_dlg, savehex_dlg);
1064 window_destroy(savehex_dlg);
1067 /* "Run" the GtkFileChooserDialog. */
1068 /* Upon exit: If "Accept" run the OK callback. */
1069 /* If the OK callback returns with a FALSE status, re-run the dialog.*/
1070 /* If not accept (ie: cancel) destroy the window. */
1071 /* XXX: If the OK callback pops up an alert box (eg: for an error) it *must* */
1072 /* return with a TRUE status so that the dialog window will be destroyed. */
1073 /* Trying to re-run the dialog after popping up an alert box will not work */
1074 /* since the user will not be able to dismiss the alert box. */
1075 /* The (somewhat unfriendly) effect: the user must re-invoke the */
1076 /* GtkFileChooserDialog whenever the OK callback pops up an alert box. */
1078 /* ToDo: use GtkFileChooserWidget in a dialog window instead of */
1079 /* GtkFileChooserDialog. */
1080 while (gtk_dialog_run(GTK_DIALOG(savehex_dlg)) == GTK_RESPONSE_ACCEPT) {
1081 if (savehex_save_clicked_cb(NULL, savehex_dlg)) {
1082 break; /* we're done */
1085 window_destroy(savehex_dlg);
1090 /* Update the progress bar this many times when reading a file. */
1091 #define N_PROGBAR_UPDATES 100
1092 /* The minimum packet length required to check if a progres bar is needed or not */
1093 #define MIN_PACKET_LENGTH 1024
1096 * XXX - at least in GTK+ 2.x, this is not fast - in one capture with a
1097 * 64K-or-so reassembled HTTP reply, it takes about 3 seconds to construct
1098 * the hex dump pane on a 1.4 GHz G4 PowerMac on OS X 10.3.3. (That's
1099 * presumably why there's a progress bar for it.)
1101 * Perhaps what's needed is a custom widget (either one that lets you stuff
1102 * text into it more quickly, or one that's a "virtual" widget so that the
1103 * text for a row is constructed, via a callback, when the row is to be
1104 * displayed). A custom widget might also let us treat the offset, hex
1105 * data, and ASCII data as three columns, so you can select purely in
1106 * the hex dump column.
1109 packet_hex_print_common(GtkWidget *bv, const guint8 *pd, int len, int bstart,
1110 int bend, int astart, int aend, int encoding)
1112 int i = 0, j, k = 0, b, cur;
1113 guchar line[MAX_LINES_LEN + 1];
1114 static guchar hexchars[16] = {
1115 '0', '1', '2', '3', '4', '5', '6', '7',
1116 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
1117 static const guint8 bitmask[8] = {
1118 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
1120 unsigned int use_digits;
1121 gboolean reverse, newreverse;
1122 GtkTextView *bv_text_view = GTK_TEXT_VIEW(bv);
1123 GtkTextBuffer *buf = gtk_text_view_get_buffer(bv_text_view);
1125 const char *revstyle;
1126 GtkTextMark *mark = NULL;
1128 progdlg_t *progbar = NULL;
1130 gboolean progbar_stop_flag;
1131 GTimeVal progbar_start_time;
1132 gchar progbar_status_str[100];
1133 int progbar_nextstep;
1134 int progbar_quantum;
1136 gtk_text_buffer_set_text(buf, "", 0);
1137 gtk_text_buffer_get_start_iter(buf, &iter);
1139 gtk_text_view_set_buffer( bv_text_view, NULL);
1142 * How many of the leading digits of the offset will we supply?
1143 * We always supply at least 4 digits, but if the maximum offset
1144 * won't fit in 4 digits, we use as many digits as will be needed.
1146 if (((len - 1) & 0xF0000000) != 0)
1147 use_digits = 8; /* need all 8 digits */
1148 else if (((len - 1) & 0x0F000000) != 0)
1149 use_digits = 7; /* need 7 digits */
1150 else if (((len - 1) & 0x00F00000) != 0)
1151 use_digits = 6; /* need 6 digits */
1152 else if (((len - 1) & 0x000F0000) != 0)
1153 use_digits = 5; /* need 5 digits */
1155 use_digits = 4; /* we'll supply 4 digits */
1157 /* Record the number of digits in this text view. */
1158 g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_NDIGITS_KEY, GUINT_TO_POINTER(use_digits));
1160 /* Update the progress bar when it gets to this value. */
1161 if (len > MIN_PACKET_LENGTH){
1162 progbar_nextstep = 0;
1164 /* If length =< MIN_PACKET_LENGTH
1165 * there is no need to calculate the progress
1167 progbar_nextstep = len+1;
1170 /* When we reach the value that triggers a progress bar update,
1171 bump that value by this amount. */
1172 progbar_quantum = len/N_PROGBAR_UPDATES;
1173 /* Progress so far. */
1176 progbar_stop_flag = FALSE;
1177 g_get_current_time(&progbar_start_time);
1181 /* Create the progress bar if necessary.
1182 We check on every iteration of the loop, so that it takes no
1183 longer than the standard time to create it (otherwise, for a
1184 large packet, we might take considerably longer than that standard
1185 time in order to get to the next progress bar step). */
1186 if ((progbar == NULL) && (len > MIN_PACKET_LENGTH))
1187 progbar = delayed_create_progress_dlg("Processing", "Packet Details",
1190 &progbar_start_time,
1193 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
1194 when we update it, we have to run the GTK+ main loop to get it
1195 to repaint what's pending, and doing so may involve an "ioctl()"
1196 to see if there's any pending input from an X server, and doing
1197 that for every packet can be costly, especially on a big file. */
1198 if (i >= progbar_nextstep) {
1200 if (progbar != NULL) {
1201 /* let's not divide by zero. I should never be started
1202 * with count == 0, so let's assert that
1205 progbar_val = (gfloat) i / len;
1206 g_snprintf(progbar_status_str, sizeof(progbar_status_str),
1207 "%4u of %u bytes", i, len);
1208 update_progress_dlg(progbar, progbar_val, progbar_status_str);
1211 progbar_nextstep += progbar_quantum;
1214 if (progbar_stop_flag) {
1215 /* Well, the user decided to abort the operation. Just stop,
1216 and arrange to return TRUE to our caller, so they know it
1217 was stopped explicitly. */
1221 /* Print the line number */
1225 c = (i >> (j*4)) & 0xF;
1226 line[cur++] = hexchars[c];
1231 /* Display with inverse video ? */
1232 if (prefs.gui_hex_dump_highlight_style)
1233 revstyle = "reverse";
1237 /* Do we start in reverse? */
1238 reverse = (i >= bstart && i < bend) || (i >= astart && i < aend);
1240 switch (recent.gui_bytes_view) {
1242 k = i + BYTES_PER_LINE;
1245 k = i + BITS_PER_LINE;
1248 g_assert_not_reached();
1251 gtk_text_buffer_insert_with_tags_by_name(buf, &iter, line, cur,
1255 /* Print the hex bit */
1258 switch (recent.gui_bytes_view) {
1260 line[cur++] = hexchars[(pd[i] & 0xf0) >> 4];
1261 line[cur++] = hexchars[pd[i] & 0x0f];
1264 for (b = 0; b < 8; b++) {
1265 line[cur++] = (pd[i] & bitmask[b]) ? '1' : '0';
1269 g_assert_not_reached();
1272 switch (recent.gui_bytes_view) {
1274 line[cur++] = ' '; line[cur++] = ' ';
1277 for (b = 0; b < 8; b++) {
1282 g_assert_not_reached();
1286 newreverse = (i >= bstart && i < bend) || (i >= astart && i < aend);
1287 /* Have we gone from reverse to plain? */
1288 if (reverse && (reverse != newreverse)) {
1289 gtk_text_buffer_insert_with_tags_by_name(buf, &iter, line, cur,
1293 /* Inter byte space if not at end of line */
1296 /* insert a space every BYTE_VIEW_SEP bytes */
1297 if( ( i % BYTE_VIEW_SEP ) == 0 ) {
1301 /* Have we gone from plain to reversed? */
1302 if (!reverse && (reverse != newreverse)) {
1303 gtk_text_buffer_insert_with_tags_by_name(buf, &iter, line, cur,
1305 /* If [astart..aend) and [bstart..bend) are disjoint, select first one as a marker */
1307 mark = gtk_text_buffer_create_mark(buf, NULL, &iter, TRUE);
1310 reverse = newreverse;
1313 /* Print remaining part of line */
1314 gtk_text_buffer_insert_with_tags_by_name(buf, &iter, line, cur,
1319 /* Print some space at the end of the line */
1320 line[cur++] = ' '; line[cur++] = ' '; line[cur++] = ' ';
1322 /* Print the ASCII bit */
1324 /* Do we start in reverse? */
1325 reverse = (i >= bstart && i < bend) || (i >= astart && i < aend);
1327 gtk_text_buffer_insert_with_tags_by_name(buf, &iter, line, cur,
1334 if (encoding == PACKET_CHAR_ENC_CHAR_ASCII) {
1337 else if (encoding == PACKET_CHAR_ENC_CHAR_EBCDIC) {
1338 c = EBCDIC_to_ASCII1(pd[i]);
1341 g_assert_not_reached();
1343 line[cur++] = isprint(c) ? c : '.';
1348 newreverse = (i >= bstart && i < bend) || (i >= astart && i < aend);
1349 /* Have we gone from reverse to plain? */
1350 if (reverse && (reverse != newreverse)) {
1351 gtk_text_buffer_insert_with_tags_by_name(buf, &iter, line, cur,
1357 /* insert a space every BYTE_VIEW_SEP bytes */
1358 if( ( i % BYTE_VIEW_SEP ) == 0 ) {
1362 /* Have we gone from plain to reversed? */
1363 if (!reverse && (reverse != newreverse)) {
1364 gtk_text_buffer_insert_with_tags_by_name(buf, &iter, line, cur,
1368 reverse = newreverse;
1370 /* Print remaining part of line */
1372 gtk_text_buffer_insert_with_tags_by_name(buf, &iter, line, cur,
1377 if (cur >= (MAX_LINES_LEN - MAX_LINE_LEN)) {
1378 gtk_text_buffer_insert_with_tags_by_name(buf, &iter, line, cur,
1384 /* We're done printing the packets; destroy the progress bar if
1386 if (progbar != NULL)
1387 destroy_progress_dlg(progbar);
1389 /* scroll text into position */
1391 gtk_text_buffer_insert_with_tags_by_name(buf, &iter, line, cur,
1394 gtk_text_view_set_buffer( bv_text_view, buf);
1397 gtk_text_view_scroll_to_mark(bv_text_view, mark, 0.0, TRUE, 1.0, 0.0);
1398 gtk_text_buffer_delete_mark(buf, mark);
1400 g_object_unref(buf);
1404 packet_hex_print(GtkWidget *bv, const guint8 *pd, frame_data *fd,
1405 field_info *finfo, guint len)
1407 /* do the initial printing and save the information needed */
1408 /* to redraw the display if preferences change. */
1410 int bstart = -1, bend = -1, blen = -1;
1411 int astart = -1, aend = -1, alen = -1;
1413 if (finfo != NULL) {
1414 bstart = finfo->start;
1415 blen = finfo->length;
1416 astart = finfo->appendix_start;
1417 alen = finfo->appendix_length;
1419 if (bstart >= 0 && blen >= 0) {
1420 bend = bstart + blen;
1422 if (astart >= 0 && alen >= 0) {
1423 aend = astart + alen;
1426 /* save the information needed to redraw the text */
1427 /* should we save the fd & finfo pointers instead ?? */
1428 g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_START_KEY, GINT_TO_POINTER(bstart));
1429 g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_END_KEY, GINT_TO_POINTER(bend));
1430 g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_APP_START_KEY, GINT_TO_POINTER(astart));
1431 g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_APP_END_KEY, GINT_TO_POINTER(aend));
1432 g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_ENCODE_KEY,
1433 GUINT_TO_POINTER((guint)fd->flags.encoding));
1435 packet_hex_print_common(bv, pd, len, bstart, bend, astart, aend, fd->flags.encoding);
1439 * Redraw the text using the saved information; usually called if
1440 * the preferences have changed.
1443 packet_hex_reprint(GtkWidget *bv)
1445 int start, end, encoding;
1450 start = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_START_KEY));
1451 end = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_END_KEY));
1452 astart = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_APP_START_KEY));
1453 aend = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_APP_END_KEY));
1454 data = get_byte_view_data_and_length(bv, &len);
1455 g_assert(data != NULL);
1456 encoding = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_ENCODE_KEY));
1458 packet_hex_print_common(bv, data, len, start, end, astart, aend, encoding);
1461 /* List of all protocol tree widgets, so we can globally set the selection
1462 mode and font of all of them. */
1463 static GList *ptree_widgets;
1465 /* Add a protocol tree widget to the list of protocol tree widgets. */
1466 static void forget_ptree_widget(GtkWidget *ptreew, gpointer data);
1469 remember_ptree_widget(GtkWidget *ptreew)
1471 ptree_widgets = g_list_append(ptree_widgets, ptreew);
1473 /* Catch the "destroy" event on the widget, so that we remove it from
1474 the list when it's destroyed. */
1475 g_signal_connect(ptreew, "destroy", G_CALLBACK(forget_ptree_widget), NULL);
1478 /* Remove a protocol tree widget from the list of protocol tree widgets. */
1480 forget_ptree_widget(GtkWidget *ptreew, gpointer data _U_)
1482 ptree_widgets = g_list_remove(ptree_widgets, ptreew);
1485 /* Set the selection mode of a given packet tree window. */
1487 set_ptree_sel_browse(GtkWidget *tree, gboolean val)
1489 GtkTreeSelection *selection;
1491 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
1492 /* Yeah, GTK uses "browse" in the case where we do not, but oh well.
1493 I think "browse" in Wireshark makes more sense than "SINGLE" in
1496 gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
1499 gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
1504 set_ptree_sel_browse_cb(gpointer data, gpointer user_data)
1506 set_ptree_sel_browse((GtkWidget *)data, *(gboolean *)user_data);
1509 /* Set the selection mode of all packet tree windows. */
1511 set_ptree_sel_browse_all(gboolean val)
1513 g_list_foreach(ptree_widgets, set_ptree_sel_browse_cb, &val);
1517 set_ptree_font_cb(gpointer data, gpointer user_data)
1519 gtk_widget_modify_font((GtkWidget *)data,
1520 (PangoFontDescription *)user_data);
1524 set_ptree_font_all(PangoFontDescription *font)
1526 g_list_foreach(ptree_widgets, set_ptree_font_cb, font);
1531 * Each expert_color_* level below should match the light gradient
1532 * colors in image/expert_indicators.svg.
1534 gboolean colors_ok = FALSE;
1535 GdkColor expert_color_chat = { 0, 0x8080, 0xb7b7, 0xf7f7 }; /* light blue */
1536 GdkColor expert_color_note = { 0, 0xa0a0, 0xffff, 0xffff }; /* bright turquoise */
1537 GdkColor expert_color_warn = { 0, 0xf7f7, 0xf2f2, 0x5353 }; /* yellow */
1538 GdkColor expert_color_error = { 0, 0xffff, 0x5c5c, 0x5c5c }; /* pale red */
1539 GdkColor expert_color_foreground = { 0, 0x0000, 0x0000, 0x0000 }; /* black */
1540 GdkColor hidden_proto_item = { 0, 0x4444, 0x4444, 0x4444 }; /* gray */
1542 gchar *expert_color_chat_str;
1543 gchar *expert_color_note_str;
1544 gchar *expert_color_warn_str;
1545 gchar *expert_color_error_str;
1546 gchar *expert_color_foreground_str;
1548 void proto_draw_colors_init(void)
1554 get_color(&expert_color_chat);
1555 get_color(&expert_color_note);
1556 get_color(&expert_color_warn);
1557 get_color(&expert_color_error);
1558 get_color(&expert_color_foreground);
1559 expert_color_chat_str = gdk_color_to_string(&expert_color_chat);
1560 expert_color_note_str = gdk_color_to_string(&expert_color_note);
1561 expert_color_warn_str = gdk_color_to_string(&expert_color_warn);
1562 expert_color_error_str = gdk_color_to_string(&expert_color_error);
1563 expert_color_foreground_str = gdk_color_to_string(&expert_color_foreground);
1565 get_color(&hidden_proto_item);
1571 static void tree_cell_renderer(GtkTreeViewColumn *tree_column _U_,
1572 GtkCellRenderer *cell,
1573 GtkTreeModel *tree_model,
1579 gtk_tree_model_get(tree_model, iter, 1, &fi, -1);
1582 proto_draw_colors_init();
1585 /* for the various possible attributes, see:
1586 * http://developer.gnome.org/doc/API/2.0/gtk/GtkCellRendererText.html
1588 * color definitions can be found at:
1589 * http://cvs.gnome.org/viewcvs/gtk+/gdk-pixbuf/io-xpm.c?rev=1.42
1590 * (a good color overview: http://www.computerhope.com/htmcolor.htm)
1593 * background-gdk: doesn't seem to work (probably the GdkColor must be allocated)
1594 * weight/style: doesn't take any effect
1597 /* for each field, we have to reset the renderer attributes */
1598 g_object_set (cell, "foreground-set", FALSE, NULL);
1600 g_object_set (cell, "background-set", FALSE, NULL);
1602 g_object_set (cell, "underline", PANGO_UNDERLINE_NONE, NULL);
1603 g_object_set (cell, "underline-set", FALSE, NULL);
1605 /*g_object_set (cell, "style", PANGO_STYLE_NORMAL, NULL);
1606 g_object_set (cell, "style-set", FALSE, NULL);*/
1608 /*g_object_set (cell, "weight", PANGO_WEIGHT_NORMAL, NULL);
1609 g_object_set (cell, "weight-set", FALSE, NULL);*/
1611 if(FI_GET_FLAG(fi, FI_GENERATED)) {
1612 /* we use "[...]" to mark generated items, no need to change things here */
1614 /* as some fonts don't support italic, don't use this */
1615 /*g_object_set (cell, "style", PANGO_STYLE_ITALIC, NULL);
1616 g_object_set (cell, "style-set", TRUE, NULL);
1618 /*g_object_set (cell, "weight", PANGO_WEIGHT_BOLD, NULL);
1619 g_object_set (cell, "weight-set", TRUE, NULL);*/
1622 if(FI_GET_FLAG(fi, FI_HIDDEN)) {
1623 g_object_set (cell, "foreground-gdk", &hidden_proto_item, NULL);
1624 g_object_set (cell, "foreground-set", TRUE, NULL);
1627 if (fi && fi->hfinfo) {
1628 if(fi->hfinfo->type == FT_PROTOCOL) {
1629 g_object_set (cell, "background", "gray90", NULL);
1630 g_object_set (cell, "background-set", TRUE, NULL);
1631 g_object_set (cell, "foreground", "black", NULL);
1632 g_object_set (cell, "foreground-set", TRUE, NULL);
1633 /*g_object_set (cell, "weight", PANGO_WEIGHT_BOLD, NULL);
1634 g_object_set (cell, "weight-set", TRUE, NULL);*/
1637 if((fi->hfinfo->type == FT_FRAMENUM) ||
1638 (FI_GET_FLAG(fi, FI_URL) && IS_FT_STRING(fi->hfinfo->type))) {
1639 render_as_url(cell);
1643 if(FI_GET_FLAG(fi, PI_SEVERITY_MASK)) {
1644 switch(FI_GET_FLAG(fi, PI_SEVERITY_MASK)) {
1646 g_object_set (cell, "background-gdk", &expert_color_chat, NULL);
1647 g_object_set (cell, "background-set", TRUE, NULL);
1650 g_object_set (cell, "background-gdk", &expert_color_note, NULL);
1651 g_object_set (cell, "background-set", TRUE, NULL);
1654 g_object_set (cell, "background-gdk", &expert_color_warn, NULL);
1655 g_object_set (cell, "background-set", TRUE, NULL);
1658 g_object_set (cell, "background-gdk", &expert_color_error, NULL);
1659 g_object_set (cell, "background-set", TRUE, NULL);
1662 g_assert_not_reached();
1664 g_object_set (cell, "foreground", "black", NULL);
1665 g_object_set (cell, "foreground-set", TRUE, NULL);
1670 main_tree_view_new(e_prefs *prefs, GtkWidget **tree_view_p)
1672 GtkWidget *tv_scrollw, *tree_view;
1673 GtkTreeStore *store;
1674 GtkCellRenderer *renderer;
1675 GtkTreeViewColumn *column;
1679 tv_scrollw = scrolled_window_new(NULL, NULL);
1680 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(tv_scrollw),
1683 store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
1684 tree_view = tree_view_new(GTK_TREE_MODEL(store));
1685 g_object_unref(G_OBJECT(store));
1686 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_view), FALSE);
1687 renderer = gtk_cell_renderer_text_new();
1688 g_object_set (renderer, "ypad", 0, NULL);
1689 col_offset = gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(tree_view),
1690 -1, "Name", renderer,
1692 column = gtk_tree_view_get_column(GTK_TREE_VIEW(tree_view),
1694 gtk_tree_view_column_set_cell_data_func(column,
1700 gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column),
1701 GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1702 g_signal_connect(tree_view, "row-expanded", G_CALLBACK(expand_tree), NULL);
1703 g_signal_connect(tree_view, "row-collapsed", G_CALLBACK(collapse_tree), NULL);
1704 gtk_container_add( GTK_CONTAINER(tv_scrollw), tree_view );
1705 set_ptree_sel_browse(tree_view, prefs->gui_ptree_sel_browse);
1706 gtk_widget_modify_font(tree_view, user_font_get_regular());
1707 remember_ptree_widget(tree_view);
1709 *tree_view_p = tree_view;
1714 void expand_all_tree(proto_tree *protocol_tree _U_, GtkWidget *tree_view)
1717 for(i=0; i < num_tree_types; i++) {
1718 tree_is_expanded[i] = TRUE;
1720 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree_view));
1723 void collapse_all_tree(proto_tree *protocol_tree _U_, GtkWidget *tree_view)
1726 for(i=0; i < num_tree_types; i++) {
1727 tree_is_expanded[i] = FALSE;
1729 gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree_view));
1733 struct proto_tree_draw_info {
1734 GtkTreeView *tree_view;
1739 main_proto_tree_draw(proto_tree *protocol_tree)
1741 proto_tree_draw(protocol_tree, tree_view);
1746 tree_view_follow_link(field_info *fi)
1750 if(fi->hfinfo->type == FT_FRAMENUM) {
1751 cf_goto_frame(&cfile, fi->value.value.uinteger);
1753 if(FI_GET_FLAG(fi, FI_URL) && IS_FT_STRING(fi->hfinfo->type)) {
1754 url = g_strndup(tvb_get_ptr(fi->ds_tvb, fi->start, fi->length), fi->length);
1755 browser_open_url(url);
1761 /* If the user selected a position in the tree view, try to find
1762 * the item in the GUI proto_tree that corresponds to that byte, and
1765 tree_view_select(GtkWidget *widget, GdkEventButton *event)
1767 GtkTreeSelection *sel;
1770 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget),
1771 (gint) (((GdkEventButton *)event)->x),
1772 (gint) (((GdkEventButton *)event)->y),
1773 &path, NULL, NULL, NULL))
1775 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
1777 /* if that's a doubleclick, try to follow the link */
1778 if(event->type == GDK_2BUTTON_PRESS) {
1779 GtkTreeModel *model;
1783 if(gtk_tree_selection_get_selected (sel, &model, &iter)) {
1784 gtk_tree_model_get(model, &iter, 1, &fi, -1);
1785 tree_view_follow_link(fi);
1788 else if (((GdkEventButton *)event)->button != 1) {
1789 /* if button == 1 gtk_tree_selection_select_path is already (or will be) called by the widget */
1790 gtk_tree_selection_select_path(sel, path);
1798 /* fill the whole protocol tree with the string values */
1800 proto_tree_draw(proto_tree *protocol_tree, GtkWidget *tree_view)
1802 GtkTreeStore *store;
1803 struct proto_tree_draw_info info;
1805 info.tree_view = GTK_TREE_VIEW(tree_view);
1808 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view)));
1811 * Clear out any crud left over in the display of the protocol
1812 * tree, by removing all nodes from the tree.
1813 * This is how it's done in testgtk.c in GTK+.
1815 gtk_tree_store_clear(store);
1817 proto_tree_children_foreach(protocol_tree, proto_tree_draw_node, &info);
1821 /* fill a single protocol tree item with the string value */
1823 proto_tree_draw_node(proto_node *node, gpointer data)
1825 struct proto_tree_draw_info info;
1826 struct proto_tree_draw_info *parent_info = (struct proto_tree_draw_info*) data;
1828 field_info *fi = PNODE_FINFO(node);
1829 gchar label_str[ITEM_LABEL_LENGTH];
1831 gboolean is_leaf, is_expanded;
1832 GtkTreeStore *store;
1836 g_assert(fi && "dissection with an invisible proto tree?");
1838 if (PROTO_ITEM_IS_HIDDEN(node) && !prefs.display_hidden_proto_items)
1841 /* was a free format label produced? */
1843 label_ptr = fi->rep->representation;
1845 else { /* no, make a generic label */
1846 label_ptr = label_str;
1847 proto_item_fill_label(fi, label_str);
1850 if (node->first_child != NULL) {
1852 g_assert(fi->tree_type >= 0 && fi->tree_type < num_tree_types);
1853 if (tree_is_expanded[fi->tree_type]) {
1857 is_expanded = FALSE;
1862 is_expanded = FALSE;
1865 if (PROTO_ITEM_IS_GENERATED(node)) {
1866 if (PROTO_ITEM_IS_HIDDEN(node)) {
1867 label_ptr = g_strdup_printf("<[%s]>", label_ptr);
1869 label_ptr = g_strdup_printf("[%s]", label_ptr);
1871 } else if (PROTO_ITEM_IS_HIDDEN(node)) {
1872 label_ptr = g_strdup_printf("<%s>", label_ptr);
1875 info.tree_view = parent_info->tree_view;
1876 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(info.tree_view)));
1877 gtk_tree_store_append(store, &iter, parent_info->iter);
1878 gtk_tree_store_set(store, &iter, 0, label_ptr, 1, fi, -1);
1880 if (PROTO_ITEM_IS_GENERATED(node) || PROTO_ITEM_IS_HIDDEN(node)) {
1886 proto_tree_children_foreach(node, proto_tree_draw_node, &info);
1887 path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
1889 gtk_tree_view_expand_to_path(info.tree_view, path);
1891 gtk_tree_view_collapse_row(info.tree_view, path);
1892 gtk_tree_path_free(path);
1897 * Clear the hex dump and protocol tree panes.
1900 clear_tree_and_hex_views(void)
1902 /* Clear the hex dump by getting rid of all the byte views. */
1903 while (gtk_notebook_get_nth_page(GTK_NOTEBOOK(byte_nb_ptr), 0) != NULL)
1904 gtk_notebook_remove_page(GTK_NOTEBOOK(byte_nb_ptr), 0);
1906 /* Add a placeholder byte view so that there's at least something
1907 displayed in the byte view notebook. */
1908 add_byte_tab(byte_nb_ptr, "", NULL, NULL, tree_view);
1910 /* Clear the protocol tree by removing all nodes in the ctree.
1911 This is how it's done in testgtk.c in GTK+ */
1912 gtk_tree_store_clear(GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view))));
1916 select_bytes_view (GtkWidget *w _U_, gpointer data _U_, gint view)
1918 if (recent.gui_bytes_view != view) {
1919 recent.gui_bytes_view = view;
1920 redraw_packet_bytes_all();