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