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