Fix problems when expanding whole tree '*' / all subtree nodes <Shift>-Right
[metze/wireshark/wip.git] / ui / gtk / packet_panes.c
1 /* packet_panes.c
2  * Routines for GTK+ packet display (packet details and hex dump panes)
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * Jeff Foster,    2001/03/12,  added support for displaying named
11  *                              data sources as tabbed hex windows
12  *
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.
17  *
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.
22  *
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.
26  */
27
28 #include "config.h"
29
30 #include <ctype.h>
31
32 #ifdef HAVE_FCNTL_H
33 #include <fcntl.h>
34 #endif
35
36 #ifdef HAVE_UNISTD_H
37 #include <unistd.h>
38 #endif
39
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
45
46 #include <string.h>
47
48 #include <epan/epan_dissect.h>
49
50 #include <epan/packet.h>
51 #include <epan/charsets.h>
52 #include <epan/prefs.h>
53 #include <epan/filesystem.h>
54
55 #include "../isprint.h"
56
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"
63
64 #include <wsutil/file_util.h>
65
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"
79
80 #ifdef _WIN32
81 #include <gdk/gdkwin32.h>
82 #include <windows.h>
83 #include "ui/win32/file_dlg_win32.h"
84 #endif
85
86
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"
99
100 /* Get the current text window for the notebook. */
101 GtkWidget *
102 get_notebook_bv_ptr(GtkWidget *nb_ptr)
103 {
104     int num;
105     GtkWidget *bv_page;
106
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;
113 }
114
115 /*
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.
118  */
119 const guint8 *
120 get_byte_view_data_and_length(GtkWidget *byte_view, guint *data_len)
121 {
122     tvbuff_t *byte_view_tvb;
123     const guint8 *data_ptr;
124
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;
128
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 "";
134 }
135
136 /*
137  * Set the current text window for the notebook to the window that
138  * refers to a particular tvbuff.
139  */
140 void
141 set_notebook_page(GtkWidget *nb_ptr, tvbuff_t *tvb)
142 {
143     int num;
144     GtkWidget *bv_page, *bv;
145     tvbuff_t *bv_tvb;
146
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;
156         }
157     }
158 }
159
160 /* Redraw a given byte view window. */
161 void
162 redraw_packet_bytes(GtkWidget *nb, frame_data *fd, field_info *finfo)
163 {
164     GtkWidget *bv;
165     const guint8 *data;
166     guint len;
167
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);
173     }
174 }
175
176 /* Redraw all byte view windows. */
177 void
178 redraw_packet_bytes_all(void)
179 {
180     if (cfile.current_frame != NULL)
181         redraw_packet_bytes( byte_nb_ptr_gbl, cfile.current_frame, cfile.finfo_selected);
182
183     redraw_packet_bytes_packet_wins();
184
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);
193     }
194 }
195
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.
199  */
200 static void
201 check_expand_trees(GtkTreeView *tree_view, GtkTreeModel *model, GtkTreePath *path,
202                    GtkTreeIter *iter, gboolean scroll_it, gboolean expand_parent)
203 {
204     /* code inspired by gtk_tree_model_foreach_helper */
205
206     field_info *fi;
207
208     do {
209         GtkTreeIter child;
210
211         if (gtk_tree_model_iter_children(model, &child, iter)) {
212             gtk_tree_model_get(model, iter, 1, &fi, -1);
213
214             if (tree_expanded(fi->tree_type)) {
215                 if (expand_parent)
216                     gtk_tree_view_expand_row(tree_view, path, FALSE);
217
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);
220
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);
225             }
226         }
227
228         gtk_tree_path_next(path);
229     } while (gtk_tree_model_iter_next(model, iter));
230 }
231
232 static void
233 expand_tree(GtkTreeView *tree_view, GtkTreeIter *iter,
234             GtkTreePath *path, gpointer user_data _U_)
235 {
236     field_info   *finfo;
237     GtkTreeModel *model;
238
239     model = gtk_tree_view_get_model(tree_view);
240     gtk_tree_model_get(model, iter, 1, &finfo, -1);
241     g_assert(finfo);
242
243     /* scroll the expanded item to reduce the need to do a manual scroll down
244      * and provide faster navigation of deeper trees */
245
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);
248
249     /*
250      * Nodes with "finfo->tree_type" of -1 have no ett_ value, and
251      * are thus presumably leaf nodes and cannot be expanded.
252      */
253     if (finfo->tree_type != -1)
254         tree_expanded_set(finfo->tree_type, TRUE);
255
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);
261     }
262 }
263
264 static void
265 collapse_tree(GtkTreeView *tree_view, GtkTreeIter *iter,
266               GtkTreePath *path _U_, gpointer user_data _U_)
267 {
268     field_info   *finfo;
269     GtkTreeModel *model;
270
271     model = gtk_tree_view_get_model(tree_view);
272     gtk_tree_model_get(model, iter, 1, &finfo, -1);
273     g_assert(finfo);
274
275     /*
276      * Nodes with "finfo->tree_type" of -1 have no ett_ value, and
277      * are thus presumably leaf nodes and cannot be collapsed.
278      */
279     if (finfo->tree_type != -1)
280         tree_expanded_set(finfo->tree_type, FALSE);
281 }
282
283 struct field_lookup_info {
284     field_info  *fi;
285     GtkTreeIter  iter;
286 };
287
288 static gboolean
289 lookup_finfo(GtkTreeModel *model, GtkTreePath *path _U_, GtkTreeIter *iter,
290              gpointer data)
291 {
292     field_info *fi;
293     struct field_lookup_info *fli = (struct field_lookup_info *)data;
294
295     gtk_tree_model_get(model, iter, 1, &fi, -1);
296     if (fi == fli->fi) {
297         fli->iter = *iter;
298         return TRUE;
299     }
300     return FALSE;
301 }
302
303 GtkTreePath
304 *tree_find_by_field_info(GtkTreeView *tree_view, field_info *finfo)
305 {
306     GtkTreeModel *model;
307     struct field_lookup_info fli;
308
309     g_assert(finfo != NULL);
310
311     model = gtk_tree_view_get_model(tree_view);
312     fli.fi = finfo;
313     gtk_tree_model_foreach(model, lookup_finfo, &fli);
314
315     return gtk_tree_model_get_path(model, &fli.iter);
316 }
317
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:
320  *
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)
325 {
326     proto_tree   *tree;
327     GtkTreeView  *tree_view;
328     int           byte = -1;
329     tvbuff_t     *tvb;
330
331     tree = (proto_tree *)g_object_get_data(G_OBJECT(widget), E_BYTE_VIEW_TREE_PTR);
332     if (tree == NULL) {
333         /*
334          * Somebody clicked on the dummy byte view; do nothing.
335          */
336         return FALSE;
337     }
338     tree_view = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(widget),
339                                               E_BYTE_VIEW_TREE_VIEW_PTR));
340
341     byte = bytes_view_byte_from_xy(BYTES_VIEW(widget), (gint) event->x, (gint) event->y);
342
343     if (byte == -1) {
344         return FALSE;
345     }
346
347     /* Get the data source tvbuff */
348     tvb = (tvbuff_t *)g_object_get_data(G_OBJECT(widget), E_BYTE_VIEW_TVBUFF_KEY);
349
350     return highlight_field(tvb, byte, tree_view, tree);
351 }
352
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)
357 {
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;
364
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;
370         }
371     } else {
372         /* Find the finfo that corresponds to our byte. */
373         finfo = proto_find_field_from_offset(tree, byte, tvb);
374     }
375
376     if (!finfo) {
377         return FALSE;
378     }
379
380     model = gtk_tree_view_get_model(tree_view);
381     fli.fi = finfo;
382     gtk_tree_model_foreach(model, lookup_finfo, &fli);
383
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);
388
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);
396     }
397
398     /* Refresh the display so that the expanded trees are visible */
399     proto_tree_draw(tree, GTK_WIDGET(tree_view));
400
401     /* select our field's row */
402     gtk_tree_selection_select_path(gtk_tree_view_get_selection(tree_view),
403                                    first_path);
404
405     /* If the last search was a string or hex search within "Packet data", the entire field might
406        not be highlighted. If the user just clicked on one of the bytes comprising that field, the
407        above call didn't trigger a 'gtk_tree_view_get_selection' event. Call redraw_packet_bytes()
408        to make the highlighting of the entire field visible. */
409     if (!cfile.search_in_progress) {
410         if (cfile.hex || (cfile.string && cfile.packet_data)) {
411             redraw_packet_bytes(byte_nb_ptr_gbl, cfile.current_frame, cfile.finfo_selected);
412         }
413     }
414
415     /* And position the window so the selection is visible.
416      * Position the selection in the middle of the viewable
417      * pane. */
418     gtk_tree_view_scroll_to_cell(tree_view, first_path, NULL, TRUE, 0.5f, 0.0f);
419
420     gtk_tree_path_free(first_path);
421
422     return TRUE;
423 }
424
425 /* Calls functions for different mouse-button presses. */
426 static gboolean
427 byte_view_button_press_cb(GtkWidget *widget, GdkEvent *event, gpointer data)
428 {
429     GdkEventButton *event_button = NULL;
430
431     if(widget == NULL || event == NULL || data == NULL) {
432         return FALSE;
433     }
434
435     if(event->type == GDK_BUTTON_PRESS) {
436         event_button = (GdkEventButton *) event;
437
438         /* To qoute the "Gdk Event Structures" doc:
439          * "Normally button 1 is the left mouse button, 2 is the middle button, and 3 is the right button" */
440         switch(event_button->button) {
441
442         case 1:
443             return byte_view_select(widget, event_button);
444         case 3:
445             return popup_menu_handler(widget, event, data);
446         default:
447             return FALSE;
448         }
449     }
450
451     return FALSE;
452 }
453
454 GtkWidget *
455 byte_view_new(void)
456 {
457     GtkWidget *byte_nb;
458
459     byte_nb = gtk_notebook_new();
460     gtk_notebook_set_tab_pos(GTK_NOTEBOOK(byte_nb), GTK_POS_BOTTOM);
461
462     /* this will only have an effect, if no tabs are shown */
463     gtk_notebook_set_show_border(GTK_NOTEBOOK(byte_nb), FALSE);
464
465     /* set the tabs scrollable, if they don't fit into the pane */
466     gtk_notebook_set_scrollable(GTK_NOTEBOOK(byte_nb), TRUE);
467
468     /* enable a popup menu containing the tab labels, will be helpful if tabs don't fit into the pane */
469     gtk_notebook_popup_enable(GTK_NOTEBOOK(byte_nb));
470
471     /* Add a placeholder byte view so that there's at least something
472        displayed in the byte view notebook. */
473     add_byte_tab(byte_nb, "", NULL, NULL, NULL);
474
475     return byte_nb;
476 }
477
478 static void
479 byte_view_realize_cb(GtkWidget *bv, gpointer data _U_)
480 {
481     const guint8 *byte_data;
482     guint byte_len;
483
484     byte_data = get_byte_view_data_and_length(bv, &byte_len);
485     if (byte_data == NULL) {
486         /* This must be the dummy byte view if no packet is selected. */
487         return;
488     }
489     packet_hex_print(bv, byte_data, cfile.current_frame, NULL, byte_len);
490 }
491
492 GtkWidget *
493 add_byte_tab(GtkWidget *byte_nb, const char *name, tvbuff_t *tvb,
494              proto_tree *tree, GtkWidget *tree_view)
495 {
496     GtkWidget *byte_view, *byte_scrollw, *label;
497
498     /* Byte view.  Create a scrolled window for the text. */
499     byte_scrollw = scrolled_window_new(NULL, NULL);
500     gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(byte_scrollw),
501                                         GTK_SHADOW_IN);
502     /* Add scrolled pane to tabbed window */
503     label = gtk_label_new(name);
504     gtk_notebook_append_page(GTK_NOTEBOOK(byte_nb), byte_scrollw, label);
505
506     gtk_widget_show(byte_scrollw);
507
508     byte_view = bytes_view_new();
509     bytes_view_set_font(BYTES_VIEW(byte_view), user_font_get_regular());
510
511     g_object_set_data(G_OBJECT(byte_view), E_BYTE_VIEW_TVBUFF_KEY, tvb);
512     gtk_container_add(GTK_CONTAINER(byte_scrollw), byte_view);
513
514     g_signal_connect(byte_view, "show", G_CALLBACK(byte_view_realize_cb), NULL);
515     g_signal_connect(byte_view, "button_press_event", G_CALLBACK(byte_view_button_press_cb),
516                      g_object_get_data(G_OBJECT(popup_menu_object), PM_BYTES_VIEW_KEY));
517
518     g_object_set_data(G_OBJECT(byte_view), E_BYTE_VIEW_TREE_PTR, tree);
519     g_object_set_data(G_OBJECT(byte_view), E_BYTE_VIEW_TREE_VIEW_PTR, tree_view);
520
521     gtk_widget_show(byte_view); /* triggers byte_view_realize_cb which calls packet_hex_print */
522
523     /* no tabs if this is the first page */
524     if (!(gtk_notebook_page_num(GTK_NOTEBOOK(byte_nb), byte_scrollw)))
525         gtk_notebook_set_show_tabs(GTK_NOTEBOOK(byte_nb), FALSE);
526     else
527         gtk_notebook_set_show_tabs(GTK_NOTEBOOK(byte_nb), TRUE);
528
529     /* set this page */
530     gtk_notebook_set_current_page(GTK_NOTEBOOK(byte_nb),
531                                   gtk_notebook_page_num(GTK_NOTEBOOK(byte_nb), byte_nb));
532
533     return byte_view;
534 }
535
536 void
537 add_byte_views(epan_dissect_t *edt, GtkWidget *tree_view,
538                GtkWidget *byte_nb_ptr)
539 {
540     GSList *src_le;
541     struct data_source *src;
542
543     /*
544      * Get rid of all the old notebook tabs.
545      */
546     while (gtk_notebook_get_nth_page(GTK_NOTEBOOK(byte_nb_ptr), 0) != NULL)
547         gtk_notebook_remove_page(GTK_NOTEBOOK(byte_nb_ptr), 0);
548
549     /*
550      * Add to the specified byte view notebook tabs for hex dumps
551      * of all the data sources for the specified frame.
552      */
553     for (src_le = edt->pi.data_src; src_le != NULL; src_le = src_le->next) {
554         src = (struct data_source *)src_le->data;
555         add_byte_tab(byte_nb_ptr, get_data_source_name(src), get_data_source_tvb(src), edt->tree,
556                      tree_view);
557     }
558
559     /*
560      * Initially select the first byte view.
561      */
562     gtk_notebook_set_current_page(GTK_NOTEBOOK(byte_nb_ptr), 0);
563 }
564
565 static void
566 copy_hex_all_info(GString* copy_buffer, const guint8* data_p, int data_len, gboolean append_text)
567 {
568     const int byte_line_length = 16; /* Print out data for 16 bytes on one line */
569     int i, j;
570     gboolean end_of_line = TRUE; /* Initial state is end of line */
571     int byte_line_part_length;
572
573     GString* hex_str;
574     GString* char_str;
575
576     /* Write hex data for a line, then ascii data, then concatenate and add to buffer */
577     hex_str = g_string_new("");
578     char_str= g_string_new("");
579
580     i = 0;
581     while (i<data_len) {
582         if(end_of_line) {
583             g_string_append_printf(hex_str,"%04x  ",i); /* Offset - note that we _append_ here */
584         }
585
586         g_string_append_printf(hex_str," %02x",*data_p);
587         if(append_text) {
588             g_string_append_printf(char_str,"%c",isprint(*data_p) ? *data_p : '.');
589         }
590
591         ++data_p;
592
593         /* Look ahead to see if this is the end of the data */
594         byte_line_part_length = (++i) % byte_line_length;
595         if(i == data_len){
596             /* End of data - need to fill in spaces in hex string and then do "end of line".
597              *
598              */
599             for(j = 0; append_text && (j < (byte_line_length - byte_line_part_length)); ++j) {
600                 g_string_append(hex_str,"   "); /* Three spaces for each missing byte */
601             }
602             end_of_line = TRUE;
603         } else {
604             end_of_line = (byte_line_part_length == 0 ? TRUE : FALSE);
605         }
606
607
608         if (end_of_line){
609             /* End of line */
610             g_string_append(copy_buffer, hex_str->str);
611             if(append_text) {
612                 /* Two spaces between hex and text */
613                 g_string_append_c(copy_buffer, ' ');
614                 g_string_append_c(copy_buffer, ' ');
615                 g_string_append(copy_buffer, char_str->str);
616             }
617             /* Setup ready for next line */
618             g_string_assign(char_str,"");
619             g_string_assign(hex_str, "\n");
620         }
621     }
622
623     g_string_free(hex_str, TRUE);
624     g_string_free(char_str, TRUE);
625 }
626
627 static int
628 copy_hex_bytes_text_only(GString* copy_buffer, const guint8* data_p, int data_len _U_)
629 {
630
631     gchar to_append;
632
633     /* Copy printable characters, newlines, and (horizontal) tabs. */
634     if(isprint(*data_p)) {
635         to_append = *data_p;
636     } else if(*data_p==0x0a) {
637         to_append = '\n';
638     } else if(*data_p==0x09) {
639         to_append = '\t';
640     } else {
641         return 1; /* Just ignore non-printable bytes */
642     }
643     g_string_append_c(copy_buffer,to_append);
644     return 1;
645 }
646
647 static
648 int copy_hex_bytes_hex(GString* copy_buffer, const guint8* data_p, int data_len _U_)
649 {
650     g_string_append_printf(copy_buffer, "%02x", *data_p);
651     return 1;
652 }
653
654 void
655 copy_hex_cb(GtkWidget * w _U_, gpointer data _U_, copy_data_type data_type)
656 {
657     GtkWidget *bv;
658
659     guint len = 0;
660     int bytes_consumed = 0;
661     int flags;
662
663     const guint8* data_p;
664
665     GString* copy_buffer = g_string_new(""); /* String to copy to clipboard */
666
667     bv = get_notebook_bv_ptr(byte_nb_ptr_gbl);
668     if (bv == NULL) {
669         /* shouldn't happen */
670         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Could not find the corresponding text window.");
671         return;
672     }
673
674     data_p = get_byte_view_data_and_length(bv, &len);
675     g_assert(data_p != NULL);
676
677     flags = data_type & CD_FLAGSMASK;
678     data_type = (copy_data_type)(data_type & CD_TYPEMASK);
679
680     if(flags & CD_FLAGS_SELECTEDONLY) {
681         int start, end;
682
683         /* Get the start and end of the highlighted bytes. */
684         start = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_START_KEY));
685         end = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_END_KEY));
686
687         if(start >= 0 && end > start && (end - start <= (int)len)) {
688             len = end - start;
689             data_p += start;
690         }
691     }
692
693     switch(data_type) {
694     case(CD_ALLINFO):
695         /* This is too different from other text formats - handle separately */
696         copy_hex_all_info(copy_buffer, data_p, len, TRUE);
697         break;
698     case(CD_HEXCOLUMNS):
699         /* This could be done incrementally, but it is easier to mingle with the code for CD_ALLINFO */
700         copy_hex_all_info(copy_buffer, data_p, len, FALSE);
701         break;
702     case(CD_BINARY):
703         /* Completely different logic to text copies - leave copy buffer alone */
704         copy_binary_to_clipboard(data_p,len);
705         break;
706     default:
707         /* Incrementally write to text buffer in various formats */
708         while (len > 0){
709             switch(data_type) {
710             case (CD_TEXTONLY):
711                 bytes_consumed = copy_hex_bytes_text_only(copy_buffer, data_p, len);
712                 break;
713             case (CD_HEX):
714                 bytes_consumed = copy_hex_bytes_hex(copy_buffer, data_p, len);
715                 break;
716             default:
717                 g_assert_not_reached();
718                 break;
719             }
720
721             g_assert(bytes_consumed>0);
722             data_p += bytes_consumed;
723             len -= bytes_consumed;
724         }
725         break;
726     }
727
728     if(copy_buffer->len > 0) {
729         copy_to_clipboard(copy_buffer);
730     }
731
732     g_string_free(copy_buffer, TRUE);
733 }
734
735 /* save the current highlighted hex data */
736 static gboolean
737 savehex_save_clicked_cb(gchar *file, int start, int end, const guint8 *data_p)
738 {
739     int fd;
740
741     fd = ws_open(file, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666);
742     if (fd == -1) {
743         open_failure_alert_box(file, errno, TRUE);
744         return FALSE;
745     }
746     if (ws_write(fd, data_p + start, end - start) < 0) {
747         write_failure_alert_box(file, errno);
748         ws_close(fd);
749         return FALSE;
750     }
751     if (ws_close(fd) < 0) {
752         write_failure_alert_box(file, errno);
753         return FALSE;
754     }
755
756     return TRUE;
757 }
758
759 /* Launch the dialog box to put up the file selection box etc */
760 #ifdef _WIN32
761 void
762 savehex_cb(GtkWidget * w _U_, gpointer data _U_)
763 {
764     win32_export_raw_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)));
765     return;
766 }
767 #else
768 static char *
769 gtk_export_raw_file(int start, int end)
770 {
771     GtkWidget *savehex_dlg;
772     gchar *label;
773     GtkWidget   *dlg_lb;
774     char *pathname;
775
776     /*
777      * Build the dialog box we need.
778      */
779     savehex_dlg = file_selection_new("Wireshark: Export Selected Packet Bytes", GTK_WINDOW(top_level), FILE_SELECTION_SAVE);
780
781     /* label */
782     label = g_strdup_printf("Will save %u %s of raw binary data to specified file.",
783                             end - start, plurality(end - start, "byte", "bytes"));
784     dlg_lb = gtk_label_new(label);
785     g_free(label);
786     file_selection_set_extra_widget(savehex_dlg, dlg_lb);
787     gtk_widget_show(dlg_lb);
788
789     pathname = file_selection_run(savehex_dlg);
790     if (pathname == NULL) {
791         /* User cancelled or closed the dialog. */
792         return NULL;
793     }
794
795     /* We've crosed the Rubicon; get rid of the dialog box. */
796     window_destroy(savehex_dlg);
797
798     return pathname;
799 }
800
801 void
802 savehex_cb(GtkWidget * w _U_, gpointer data _U_)
803 {
804     int start, end;
805     guint len;
806     const guint8 *data_p = NULL;
807     GtkWidget   *bv;
808     char *pathname;
809
810     /* don't show up the dialog, if no data has to be saved */
811     bv = get_notebook_bv_ptr(byte_nb_ptr_gbl);
812     if (bv == NULL) {
813         /* shouldn't happen */
814         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Could not find the corresponding text window.");
815         return;
816     }
817     start = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_START_KEY));
818     end = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_END_KEY));
819     data_p = get_byte_view_data_and_length(bv, &len);
820
821     if (data_p == NULL || start == -1 || start > end) {
822         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "No data selected to save.");
823         return;
824     }
825
826     /*
827      * Loop until the user either selects a file or gives up.
828      */
829     for (;;) {
830         pathname = gtk_export_raw_file(start, end);
831         if (pathname == NULL) {
832             /* User gave up. */
833             break;
834         }
835         if (savehex_save_clicked_cb(pathname, start, end, data_p)) {
836             /* We succeeded. */
837             g_free(pathname);
838             break;
839         }
840         /* Dump failed; let the user select another file or give up. */
841         g_free(pathname);
842     }
843 }
844 #endif
845
846 static void
847 packet_hex_update(GtkWidget *bv, const guint8 *pd, int len, int bstart,
848                   int bend, guint32 bmask, int bmask_le,
849                   int astart, int aend,
850                   int pstart, int pend,
851                   int encoding)
852 {
853         bytes_view_set_encoding(BYTES_VIEW(bv), encoding);
854         bytes_view_set_format(BYTES_VIEW(bv), recent.gui_bytes_view);
855         bytes_view_set_data(BYTES_VIEW(bv), pd, len);
856
857         bytes_view_set_highlight_style(BYTES_VIEW(bv), prefs.gui_hex_dump_highlight_style);
858
859         bytes_view_set_highlight(BYTES_VIEW(bv), bstart, bend, bmask, bmask_le);
860         bytes_view_set_highlight_extra(BYTES_VIEW(bv), BYTE_VIEW_HIGHLIGHT_APPENDIX, astart, aend);
861         bytes_view_set_highlight_extra(BYTES_VIEW(bv), BYTE_VIEW_HIGHLIGHT_PROTOCOL, pstart, pend);
862
863         if (bstart != -1 && bend != -1)
864                 bytes_view_scroll_to_byte(BYTES_VIEW(bv), bstart);
865         bytes_view_refresh(BYTES_VIEW(bv));
866 }
867
868 static field_info *
869 get_top_finfo(proto_node *node, field_info *finfo)
870 {
871         proto_node *child;
872         field_info *top;
873
874         if (node == NULL)
875             return NULL;
876         if (PNODE_FINFO(node) == finfo) {
877                 top = finfo;
878
879                 while (node && node->parent) {
880                         field_info *fi;
881
882                         node = node->parent;
883
884                         fi = PNODE_FINFO(node);
885                         if (fi && fi->ds_tvb == finfo->ds_tvb)
886                                 top = fi;
887                 }
888
889                 return top;
890         }
891
892         for (child = node->first_child; child; child = child->next) {
893                 top = get_top_finfo(child, finfo);
894                 if (top)
895                         return top;
896         }
897
898         return NULL;
899 }
900
901 void
902 packet_hex_print(GtkWidget *bv, const guint8 *pd, frame_data *fd,
903                  field_info *finfo, guint len)
904 {
905     /* do the initial printing and save the information needed  */
906     /* to redraw the display if preferences change.             */
907
908     int bstart = -1, bend = -1, blen = -1;
909     guint32 bmask = 0x00; int bmask_le = 0;
910     int astart = -1, aend = -1, alen = -1;
911     int pstart = -1, pend = -1, plen = -1;
912
913     if (finfo != NULL) {
914         proto_tree *tree = (proto_tree *)g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_TREE_PTR);
915         field_info *top_finfo;
916
917         if (cfile.search_in_progress && (cfile.hex || (cfile.string && cfile.packet_data))) {
918             /* In the hex view, only highlight the target bytes or string. The entire
919                field can then be displayed by clicking on any of the bytes in the field. */
920             if (cfile.hex) {
921                 char *p = cfile.sfilter;
922
923                 blen = 0;
924                 while (*p) {
925                     if (g_ascii_isxdigit(*p++))
926                         blen++;
927                 }
928                 blen = (blen + 1) / 2;
929             } else {
930                 blen = (int)strlen(cfile.sfilter);
931             }
932             bstart = cfile.search_pos - (blen-1);
933
934         } else {
935             blen = finfo->length;
936             bstart = finfo->start;
937         }
938
939         /* bmask = finfo->hfinfo->bitmask << finfo->hfinfo->bitshift; */ /* (value & mask) >> shift */
940         if (finfo->hfinfo) bmask = finfo->hfinfo->bitmask;
941         astart = finfo->appendix_start;
942         alen = finfo->appendix_length;
943
944         top_finfo = get_top_finfo(tree, finfo);
945         /* it's possible to have top_finfo == finfo, no problem right now */
946         if (top_finfo) {
947             pstart = top_finfo->start;
948             plen = top_finfo->length;
949         }
950
951         if (FI_GET_FLAG(finfo, FI_LITTLE_ENDIAN))
952             bmask_le = 1;
953         else if (FI_GET_FLAG(finfo, FI_BIG_ENDIAN))
954             bmask_le = 0;
955         else { /* unknown endianess - disable mask
956                   bmask_le = (G_BYTE_ORDER == G_LITTLE_ENDIAN);
957                */
958             bmask = 0x00;
959         }
960
961         if (bmask == 0x00) {
962             int bito = FI_GET_BITS_OFFSET(finfo);
963             int bitc = FI_GET_BITS_SIZE(finfo);
964             int bitt = bito + bitc;
965
966             /* construct mask using bito & bitc */
967             /* XXX, mask has only 32 bit, later we can store bito&bitc, and use them (which should be faster) */
968             if (bitt > 0 && bitt < 32) {
969
970                 bmask = ((1 << bitc) - 1) << ((8-bitt) & 7);
971                 bmask_le = 0; /* ? */
972             }
973         }
974     }
975
976     if (pstart >= 0 && plen > 0 && (guint)pstart < len)
977         pend = pstart + plen;
978
979     if (bstart >= 0 && blen > 0 && (guint)bstart < len)
980         bend = bstart + blen;
981
982     if (astart >= 0 && alen > 0 && (guint)astart < len)
983         aend = astart + alen;
984
985     if (bend == -1 && aend != -1) {
986         bstart = astart;
987         bmask = 0x00;
988         bend = aend;
989         astart = aend = -1;
990     }
991
992     /* don't exceed the end of available data */
993     if (aend != -1 && (guint)aend > len) aend = len;
994     if (bend != -1 && (guint)bend > len) bend = len;
995     if (pend != -1 && (guint)pend > len) pend = len;
996
997     /* save the information needed to redraw the text */
998     /* should we save the fd & finfo pointers instead ?? */
999     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_START_KEY, GINT_TO_POINTER(bstart));
1000     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_END_KEY, GINT_TO_POINTER(bend));
1001     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_MASK_KEY, GINT_TO_POINTER(bmask));
1002     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_MASKLE_KEY, GINT_TO_POINTER(bmask_le));
1003     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_APP_START_KEY, GINT_TO_POINTER(astart));
1004     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_APP_END_KEY, GINT_TO_POINTER(aend));
1005     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_PROTO_START_KEY, GINT_TO_POINTER(pstart));
1006     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_PROTO_END_KEY, GINT_TO_POINTER(pend));
1007     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_ENCODE_KEY,
1008                       GUINT_TO_POINTER((guint)fd->flags.encoding));
1009
1010     /* stig: it should be done only for bitview... */
1011     if (recent.gui_bytes_view != BYTES_BITS)
1012         bmask = 0x00;
1013     packet_hex_update(bv, pd, len, bstart, bend, bmask, bmask_le, astart, aend, pstart, pend, fd->flags.encoding);
1014 }
1015
1016 void
1017 packet_hex_editor_print(GtkWidget *bv, const guint8 *pd, frame_data *fd, int offset, int bitoffset, guint len)
1018 {
1019     /* do the initial printing and save the information needed  */
1020     /* to redraw the display if preferences change.             */
1021
1022     int bstart = offset, bend = (bstart != -1) ? offset+1 : -1;
1023     guint32 bmask=0; int bmask_le = 0;
1024     int astart = -1, aend = -1;
1025     int pstart = -1, pend = -1;
1026
1027     switch (recent.gui_bytes_view) {
1028     case BYTES_HEX:
1029         bmask = (bitoffset == 0) ? 0xf0 : (bitoffset == 4) ? 0x0f : 0xff;
1030         break;
1031
1032     case BYTES_BITS:
1033         bmask = (1 << (7-bitoffset));
1034         break;
1035
1036     default:
1037         g_assert_not_reached();
1038         break;
1039     }
1040
1041     /* save the information needed to redraw the text */
1042     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_START_KEY, GINT_TO_POINTER(bstart));
1043     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_END_KEY, GINT_TO_POINTER(bend));
1044     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_MASK_KEY, GINT_TO_POINTER(bmask));
1045     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_MASKLE_KEY, GINT_TO_POINTER(bmask_le));
1046     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_APP_START_KEY, GINT_TO_POINTER(astart));
1047     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_APP_END_KEY, GINT_TO_POINTER(aend));
1048     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_ENCODE_KEY,
1049                       GUINT_TO_POINTER((guint)fd->flags.encoding));
1050     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_PROTO_START_KEY, GINT_TO_POINTER(pstart));
1051     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_PROTO_END_KEY, GINT_TO_POINTER(pend));
1052
1053     packet_hex_update(bv, pd, len, bstart, bend, bmask, bmask_le, astart, aend, pstart, pend, fd->flags.encoding);
1054 }
1055
1056 /*
1057  * Redraw the text using the saved information; usually called if
1058  * the preferences have changed.
1059  */
1060 void
1061 packet_hex_reprint(GtkWidget *bv)
1062 {
1063     int start, end, mask, mask_le, encoding;
1064     int astart, aend;
1065     int pstart, pend;
1066     const guint8 *data;
1067     guint len = 0;
1068
1069     start = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_START_KEY));
1070     end = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_END_KEY));
1071     mask = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_MASK_KEY));
1072     mask_le = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_MASKLE_KEY));
1073     astart = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_APP_START_KEY));
1074     aend = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_APP_END_KEY));
1075     pstart = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_PROTO_START_KEY));
1076     pend = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_PROTO_END_KEY));
1077     data = get_byte_view_data_and_length(bv, &len);
1078     g_assert(data != NULL);
1079     encoding = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_ENCODE_KEY));
1080
1081     /* stig: it should be done only for bitview... */
1082     if (recent.gui_bytes_view != BYTES_BITS)
1083         mask = 0x00;
1084     packet_hex_update(bv, data, len, start, end, mask, mask_le, astart, aend, pstart, pend, encoding);
1085 }
1086
1087 /* List of all protocol tree widgets, so we can globally set the selection
1088    mode and font of all of them. */
1089 static GList *ptree_widgets;
1090
1091 /* Add a protocol tree widget to the list of protocol tree widgets. */
1092 static void forget_ptree_widget(GtkWidget *ptreew, gpointer data);
1093
1094 static void
1095 remember_ptree_widget(GtkWidget *ptreew)
1096 {
1097     ptree_widgets = g_list_append(ptree_widgets, ptreew);
1098
1099     /* Catch the "destroy" event on the widget, so that we remove it from
1100        the list when it's destroyed. */
1101     g_signal_connect(ptreew, "destroy", G_CALLBACK(forget_ptree_widget), NULL);
1102 }
1103
1104 /* Remove a protocol tree widget from the list of protocol tree widgets. */
1105 static void
1106 forget_ptree_widget(GtkWidget *ptreew, gpointer data _U_)
1107 {
1108     ptree_widgets = g_list_remove(ptree_widgets, ptreew);
1109 }
1110
1111 static void
1112 set_ptree_font_cb(gpointer data, gpointer user_data)
1113 {
1114 #if GTK_CHECK_VERSION(3,0,0)
1115     gtk_widget_override_font((GtkWidget *)data,
1116                            (PangoFontDescription *)user_data);
1117 #else
1118     gtk_widget_modify_font((GtkWidget *)data,
1119                            (PangoFontDescription *)user_data);
1120 #endif
1121 }
1122
1123 void
1124 set_ptree_font_all(PangoFontDescription *font)
1125 {
1126     g_list_foreach(ptree_widgets, set_ptree_font_cb, font);
1127 }
1128
1129
1130 /*
1131  * Each expert_color_* level below should match the light gradient
1132  * colors in image/expert_indicators.svg.
1133  */
1134 static gboolean colors_ok = FALSE;
1135
1136 GdkColor        expert_color_comment    = { 0, 0xb7b7, 0xf7f7, 0x7474 };        /* Green */
1137 GdkColor        expert_color_chat       = { 0, 0x8080, 0xb7b7, 0xf7f7 };        /* light blue */
1138 GdkColor        expert_color_note       = { 0, 0xa0a0, 0xffff, 0xffff };        /* bright turquoise */
1139 GdkColor        expert_color_warn       = { 0, 0xf7f7, 0xf2f2, 0x5353 };        /* yellow */
1140 GdkColor        expert_color_error      = { 0, 0xffff, 0x5c5c, 0x5c5c };        /* pale red */
1141 GdkColor        expert_color_foreground = { 0, 0x0000, 0x0000, 0x0000 };        /* black */
1142 GdkColor        hidden_proto_item       = { 0, 0x4444, 0x4444, 0x4444 };        /* gray */
1143
1144 gchar *expert_color_comment_str;
1145 gchar *expert_color_chat_str;
1146 gchar *expert_color_note_str;
1147 gchar *expert_color_warn_str;
1148 gchar *expert_color_error_str;
1149 gchar *expert_color_foreground_str;
1150
1151 void proto_draw_colors_init(void)
1152 {
1153     if(colors_ok) {
1154         return;
1155     }
1156 #if 0
1157     /* Allocating collor isn't necessary? */
1158     get_color(&expert_color_chat);
1159     get_color(&expert_color_note);
1160     get_color(&expert_color_warn);
1161     get_color(&expert_color_error);
1162     get_color(&expert_color_foreground);
1163 #endif
1164     expert_color_comment_str = gdk_color_to_string(&expert_color_comment);
1165     expert_color_chat_str = gdk_color_to_string(&expert_color_chat);
1166     expert_color_note_str = gdk_color_to_string(&expert_color_note);
1167     expert_color_warn_str = gdk_color_to_string(&expert_color_warn);
1168     expert_color_error_str = gdk_color_to_string(&expert_color_error);
1169     expert_color_foreground_str = gdk_color_to_string(&expert_color_foreground);
1170
1171 #if 0
1172     get_color(&hidden_proto_item);
1173 #endif
1174     colors_ok = TRUE;
1175 }
1176
1177
1178 static void
1179 tree_cell_renderer(GtkTreeViewColumn *tree_column _U_, GtkCellRenderer *cell,
1180                    GtkTreeModel *tree_model, GtkTreeIter *iter,
1181                    gpointer data _U_)
1182 {
1183     field_info   *fi;
1184
1185     gtk_tree_model_get(tree_model, iter, 1, &fi, -1);
1186
1187     if(!colors_ok) {
1188         proto_draw_colors_init();
1189     }
1190
1191     /* for the various possible attributes, see:
1192      * http://developer.gnome.org/doc/API/2.0/gtk/GtkCellRendererText.html
1193      *
1194      * color definitions can be found at:
1195      * http://cvs.gnome.org/viewcvs/gtk+/gdk-pixbuf/io-xpm.c?rev=1.42
1196      * (a good color overview: http://www.computerhope.com/htmcolor.htm)
1197      *
1198      * some experiences:
1199      * background-gdk: doesn't seem to work (probably the GdkColor must be allocated)
1200      * weight/style: doesn't take any effect
1201      */
1202
1203     /* for each field, we have to reset the renderer attributes */
1204     g_object_set (cell, "foreground-set", FALSE, NULL);
1205
1206     g_object_set (cell, "background-set", FALSE, NULL);
1207
1208     g_object_set (cell, "underline", PANGO_UNDERLINE_NONE, NULL);
1209     g_object_set (cell, "underline-set", FALSE, NULL);
1210
1211     /*g_object_set (cell, "style", PANGO_STYLE_NORMAL, NULL);
1212     g_object_set (cell, "style-set", FALSE, NULL);*/
1213
1214     /*g_object_set (cell, "weight", PANGO_WEIGHT_NORMAL, NULL);
1215     g_object_set (cell, "weight-set", FALSE, NULL);*/
1216
1217     if(FI_GET_FLAG(fi, FI_GENERATED)) {
1218         /* we use "[...]" to mark generated items, no need to change things here */
1219
1220         /* as some fonts don't support italic, don't use this */
1221         /*g_object_set (cell, "style", PANGO_STYLE_ITALIC, NULL);
1222         g_object_set (cell, "style-set", TRUE, NULL);
1223         */
1224         /*g_object_set (cell, "weight", PANGO_WEIGHT_BOLD, NULL);
1225         g_object_set (cell, "weight-set", TRUE, NULL);*/
1226     }
1227
1228     if(FI_GET_FLAG(fi, FI_HIDDEN)) {
1229         g_object_set (cell, "foreground-gdk", &hidden_proto_item, NULL);
1230         g_object_set (cell, "foreground-set", TRUE, NULL);
1231     }
1232
1233     if (fi && fi->hfinfo) {
1234         if(fi->hfinfo->type == FT_PROTOCOL) {
1235             g_object_set (cell, "background", "gray90", NULL);
1236             g_object_set (cell, "background-set", TRUE, NULL);
1237             g_object_set (cell, "foreground", "black", NULL);
1238             g_object_set (cell, "foreground-set", TRUE, NULL);
1239             /*g_object_set (cell, "weight", PANGO_WEIGHT_BOLD, NULL);
1240             g_object_set (cell, "weight-set", TRUE, NULL);*/
1241         }
1242
1243         if((fi->hfinfo->type == FT_FRAMENUM) ||
1244            (FI_GET_FLAG(fi, FI_URL) && IS_FT_STRING(fi->hfinfo->type))) {
1245             render_as_url(cell);
1246         }
1247     }
1248
1249     if(FI_GET_FLAG(fi, PI_SEVERITY_MASK)) {
1250         switch(FI_GET_FLAG(fi, PI_SEVERITY_MASK)) {
1251         case(PI_COMMENT):
1252             g_object_set (cell, "background-gdk", &expert_color_comment, NULL);
1253             g_object_set (cell, "background-set", TRUE, NULL);
1254             break;
1255         case(PI_CHAT):
1256             g_object_set (cell, "background-gdk", &expert_color_chat, NULL);
1257             g_object_set (cell, "background-set", TRUE, NULL);
1258             break;
1259         case(PI_NOTE):
1260             g_object_set (cell, "background-gdk", &expert_color_note, NULL);
1261             g_object_set (cell, "background-set", TRUE, NULL);
1262             break;
1263         case(PI_WARN):
1264             g_object_set (cell, "background-gdk", &expert_color_warn, NULL);
1265             g_object_set (cell, "background-set", TRUE, NULL);
1266             break;
1267         case(PI_ERROR):
1268             g_object_set (cell, "background-gdk", &expert_color_error, NULL);
1269             g_object_set (cell, "background-set", TRUE, NULL);
1270             break;
1271         default:
1272             g_assert_not_reached();
1273         }
1274         g_object_set (cell, "foreground", "black", NULL);
1275         g_object_set (cell, "foreground-set", TRUE, NULL);
1276     }
1277 }
1278
1279 GtkWidget *
1280 proto_tree_view_new(GtkWidget **tree_view_p)
1281 {
1282     GtkWidget *tv_scrollw, *tree_view;
1283     ProtoTreeModel *store;
1284     GtkCellRenderer *renderer;
1285     GtkTreeViewColumn *column;
1286     gint col_offset;
1287
1288     /* Tree view */
1289     tv_scrollw = scrolled_window_new(NULL, NULL);
1290     gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(tv_scrollw),
1291                                         GTK_SHADOW_IN);
1292
1293     store = proto_tree_model_new(NULL, prefs.display_hidden_proto_items);
1294     tree_view = tree_view_new(GTK_TREE_MODEL(store));
1295     g_object_unref(G_OBJECT(store));
1296     gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_view), FALSE);
1297     renderer = gtk_cell_renderer_text_new();
1298     g_object_set (renderer, "ypad", 0, NULL);
1299     col_offset = gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(tree_view),
1300                                                              -1, "Name", renderer,
1301                                                              "text", 0, NULL);
1302     column = gtk_tree_view_get_column(GTK_TREE_VIEW(tree_view),
1303                                       col_offset - 1);
1304     gtk_tree_view_column_set_cell_data_func(column, renderer, tree_cell_renderer,
1305                                             NULL, NULL);
1306
1307     gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column),
1308                                     GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1309     g_signal_connect(tree_view, "row-expanded", G_CALLBACK(expand_tree), NULL);
1310     g_signal_connect(tree_view, "row-collapsed", G_CALLBACK(collapse_tree), NULL);
1311     gtk_container_add( GTK_CONTAINER(tv_scrollw), tree_view );
1312 #if GTK_CHECK_VERSION(3,0,0)
1313     gtk_widget_override_font(tree_view, user_font_get_regular());
1314 #else
1315     gtk_widget_modify_font(tree_view, user_font_get_regular());
1316 #endif
1317     remember_ptree_widget(tree_view);
1318
1319     *tree_view_p = tree_view;
1320
1321     return tv_scrollw;
1322 }
1323
1324 void
1325 expand_all_tree(proto_tree *protocol_tree _U_, GtkWidget *tree_view)
1326 {
1327     int i;
1328
1329     for(i=0; i < num_tree_types; i++)
1330         tree_expanded_set(i, TRUE);
1331
1332     gtk_tree_view_expand_all(GTK_TREE_VIEW(tree_view));
1333 }
1334
1335 void
1336 collapse_all_tree(proto_tree *protocol_tree _U_, GtkWidget *tree_view)
1337 {
1338     int i;
1339
1340     for(i=0; i < num_tree_types; i++)
1341         tree_expanded_set(i, FALSE);
1342
1343     gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree_view));
1344 }
1345
1346 static void
1347 tree_view_follow_link(field_info   *fi)
1348 {
1349     gchar *url;
1350
1351     if(fi->hfinfo->type == FT_FRAMENUM) {
1352         cf_goto_frame(&cfile, fi->value.value.uinteger);
1353     }
1354     if(FI_GET_FLAG(fi, FI_URL) && IS_FT_STRING(fi->hfinfo->type)) {
1355         url = fvalue_to_string_repr(&fi->value, FTREPR_DISPLAY, NULL);
1356         if(url){
1357             browser_open_url(url);
1358             g_free(url);
1359         }
1360     }
1361 }
1362
1363
1364 /* If the user selected a position in the tree view, try to find
1365  * the item in the GUI proto_tree that corresponds to that byte, and
1366  * select it. */
1367 gboolean
1368 tree_view_select(GtkWidget *widget, GdkEventButton *event)
1369 {
1370     GtkTreeSelection    *sel;
1371     GtkTreePath         *path;
1372
1373     if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget),
1374                                       (gint) (((GdkEventButton *)event)->x),
1375                                       (gint) (((GdkEventButton *)event)->y),
1376                                       &path, NULL, NULL, NULL))
1377     {
1378         sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
1379
1380         /* if that's a doubleclick, try to follow the link */
1381         if(event->type == GDK_2BUTTON_PRESS) {
1382             GtkTreeModel *model;
1383             GtkTreeIter iter;
1384             field_info   *fi;
1385
1386             if(gtk_tree_selection_get_selected (sel, &model, &iter)) {
1387                 if (event->state & GDK_SHIFT_MASK) {
1388                     new_packet_window(NULL, TRUE, FALSE);
1389                 }
1390                 else {
1391                     gtk_tree_model_get(model, &iter, 1, &fi, -1);
1392                     tree_view_follow_link(fi);
1393                 }
1394             }
1395         }
1396         else if (((GdkEventButton *)event)->button != 1) {
1397             /* if button == 1 gtk_tree_selection_select_path is already (or will be) called by the widget */
1398             gtk_tree_selection_select_path(sel, path);
1399         }
1400     } else {
1401         return FALSE;
1402     }
1403     return TRUE;
1404 }
1405
1406 void
1407 proto_tree_draw_resolve(proto_tree *protocol_tree, GtkWidget *tree_view, const e_addr_resolve *resolv)
1408 {
1409     ProtoTreeModel *model;
1410     GtkTreePath *path;
1411     GtkTreeIter iter;
1412
1413     model = proto_tree_model_new(protocol_tree, prefs.display_hidden_proto_items);
1414     if (resolv)
1415         proto_tree_model_force_resolv(PROTO_TREE_MODEL(model), resolv);
1416     gtk_tree_view_set_model(GTK_TREE_VIEW(tree_view), GTK_TREE_MODEL(model));
1417
1418     g_signal_handlers_block_by_func(tree_view, expand_tree, NULL);
1419
1420     /* modified version of gtk_tree_model_foreach */
1421     path = gtk_tree_path_new_first();
1422     if (gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, path))
1423         check_expand_trees(GTK_TREE_VIEW(tree_view), GTK_TREE_MODEL(model),
1424                               path, &iter, prefs.gui_auto_scroll_on_expand, TRUE);
1425     gtk_tree_path_free(path);
1426
1427     g_signal_handlers_unblock_by_func(tree_view, expand_tree, NULL);
1428
1429     g_object_unref(G_OBJECT(model));
1430 }
1431
1432 /* fill the whole protocol tree with the string values */
1433 void
1434 proto_tree_draw(proto_tree *protocol_tree, GtkWidget *tree_view)
1435 {
1436     proto_tree_draw_resolve(protocol_tree, tree_view, NULL);
1437 }
1438
1439 void
1440 select_bytes_view (GtkWidget *w _U_, gpointer data _U_, gint view)
1441 {
1442     if (recent.gui_bytes_view != view) {
1443         recent.gui_bytes_view = view;
1444         redraw_packet_bytes_all();
1445     }
1446 }