merge_all_tap_menus() has been moved to menus.c.
[obnox/wireshark/wip.git] / gtk / main_proto_draw.c
1 /* proto_draw.c
2  * Routines for GTK+ packet display
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <ctype.h>
33
34 #ifdef HAVE_FCNTL_H
35 #include <fcntl.h>
36 #endif
37
38 #ifdef HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
41
42 #include <gtk/gtk.h>
43 #include <gdk/gdkkeysyms.h>
44 #if GTK_CHECK_VERSION(3,0,0)
45 # include <gdk/gdkkeysyms-compat.h>
46 #endif
47
48 #include <string.h>
49
50 #include <epan/epan_dissect.h>
51
52 #include <epan/packet.h>
53 #include <epan/charsets.h>
54 #include <epan/prefs.h>
55 #include <epan/filesystem.h>
56
57 #include "../isprint.h"
58 #include "../alert_box.h"
59 #include "../simple_dialog.h"
60 #include "../progress_dlg.h"
61 #include "../ui_util.h"
62 #include <wsutil/file_util.h>
63
64 #include "gtk/keys.h"
65 #include "gtk/color_utils.h"
66 #include "gtk/capture_file_dlg.h"
67 #include "gtk/packet_win.h"
68 #include "gtk/file_dlg.h"
69 #include "gtk/gui_utils.h"
70 #include "gtk/gtkglobals.h"
71 #include "gtk/font_utils.h"
72 #include "gtk/webbrowser.h"
73 #include "gtk/main.h"
74 #include "gtk/menus.h"
75 #include "gtk/main_proto_draw.h"
76 #include "gtk/recent.h"
77
78 #ifdef _WIN32
79 #include <gdk/gdkwin32.h>
80 #include <windows.h>
81 #include "win32/file_dlg_win32.h"
82 #endif
83
84
85 #define E_BYTE_VIEW_TREE_PTR      "byte_view_tree_ptr"
86 #define E_BYTE_VIEW_TREE_VIEW_PTR "byte_view_tree_view_ptr"
87 #define E_BYTE_VIEW_NDIGITS_KEY   "byte_view_ndigits"
88 #define E_BYTE_VIEW_TVBUFF_KEY    "byte_view_tvbuff"
89 #define E_BYTE_VIEW_START_KEY     "byte_view_start"
90 #define E_BYTE_VIEW_END_KEY       "byte_view_end"
91 #define E_BYTE_VIEW_MASK_KEY      "byte_view_mask"
92 #define E_BYTE_VIEW_MASKLE_KEY    "byte_view_mask_le"
93 #define E_BYTE_VIEW_APP_START_KEY "byte_view_app_start"
94 #define E_BYTE_VIEW_APP_END_KEY   "byte_view_app_end"
95 #define E_BYTE_VIEW_ENCODE_KEY    "byte_view_encode"
96
97 static GtkWidget *
98 add_byte_tab(GtkWidget *byte_nb, const char *name, tvbuff_t *tvb,
99              proto_tree *tree, GtkWidget *tree_view);
100
101 static void
102 proto_tree_draw_node(proto_node *node, gpointer data);
103
104 /* Get the current text window for the notebook. */
105 GtkWidget *
106 get_notebook_bv_ptr(GtkWidget *nb_ptr)
107 {
108     int num;
109     GtkWidget *bv_page;
110
111     num = gtk_notebook_get_current_page(GTK_NOTEBOOK(nb_ptr));
112     bv_page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(nb_ptr), num);
113     if (bv_page)
114         return gtk_bin_get_child(GTK_BIN(bv_page));
115     else
116         return NULL;
117 }
118
119 /*
120  * Get the data and length for a byte view, given the byte view page.
121  * Return the pointer, or NULL on error, and set "*data_len" to the length.
122  */
123 const guint8 *
124 get_byte_view_data_and_length(GtkWidget *byte_view, guint *data_len)
125 {
126     tvbuff_t *byte_view_tvb;
127     const guint8 *data_ptr;
128
129     byte_view_tvb = g_object_get_data(G_OBJECT(byte_view), E_BYTE_VIEW_TVBUFF_KEY);
130     if (byte_view_tvb == NULL)
131         return NULL;
132
133     data_ptr = tvb_get_ptr(byte_view_tvb, 0, -1);
134     *data_len = tvb_length(byte_view_tvb);
135     return data_ptr;
136 }
137
138 /*
139  * Set the current text window for the notebook to the window that
140  * refers to a particular tvbuff.
141  */
142 void
143 set_notebook_page(GtkWidget *nb_ptr, tvbuff_t *tvb)
144 {
145     int num;
146     GtkWidget *bv_page, *bv;
147     tvbuff_t *bv_tvb;
148
149     for (num = 0;
150          (bv_page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(nb_ptr), num)) != NULL;
151          num++) {
152         bv = gtk_bin_get_child(GTK_BIN(bv_page));
153         bv_tvb = g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_TVBUFF_KEY);
154         if (bv_tvb == tvb) {
155             /* Found it. */
156             gtk_notebook_set_current_page(GTK_NOTEBOOK(nb_ptr), num);
157             break;
158         }
159     }
160 }
161
162 /* Redraw a given byte view window. */
163 void
164 redraw_packet_bytes(GtkWidget *nb, frame_data *fd, field_info *finfo)
165 {
166     GtkWidget *bv;
167     const guint8 *data;
168     guint len;
169
170     bv = get_notebook_bv_ptr(nb);
171     if (bv != NULL) {
172         data = get_byte_view_data_and_length(bv, &len);
173         if (data != NULL)
174             packet_hex_print(bv, data, fd, finfo, len);
175     }
176 }
177
178 /* Redraw all byte view windows. */
179 void
180 redraw_packet_bytes_all(void)
181 {
182     if (cfile.current_frame != NULL)
183         redraw_packet_bytes( byte_nb_ptr_gbl, cfile.current_frame, cfile.finfo_selected);
184
185     redraw_packet_bytes_packet_wins();
186
187     /* XXX - this is a hack, to workaround a bug in GTK2.x!
188        when changing the font size, even refilling of the corresponding
189        gtk_text_buffer doesn't seem to trigger an update.
190        The only workaround is to freshly select the frame, which will remove any
191        existing notebook tabs and "restart" the whole byte view again. */
192     if (cfile.current_frame != NULL) {
193         cfile.current_row = -1;
194         cf_goto_frame(&cfile, cfile.current_frame->num);
195     }
196 }
197
198 static void
199 expand_tree(GtkTreeView *tree_view, GtkTreeIter *iter,
200             GtkTreePath *path _U_, gpointer user_data _U_)
201 {
202     field_info   *finfo;
203     GtkTreeModel *model;
204
205     model = gtk_tree_view_get_model(tree_view);
206     gtk_tree_model_get(model, iter, 1, &finfo, -1);
207     g_assert(finfo);
208
209         /* scroll the expanded item to reduce the need to do a manual scroll down
210          * and provide faster navigation of deeper trees */
211
212         if(prefs.gui_auto_scroll_on_expand) 
213                 gtk_tree_view_scroll_to_cell(tree_view, path, NULL, TRUE, (prefs.gui_auto_scroll_percentage/100.0f), 0.0f);
214
215     /*
216      * Nodes with "finfo->tree_type" of -1 have no ett_ value, and
217      * are thus presumably leaf nodes and cannot be expanded.
218      */
219     if (finfo->tree_type != -1) {
220         g_assert(finfo->tree_type >= 0 &&
221                  finfo->tree_type < num_tree_types);
222         tree_is_expanded[finfo->tree_type] = TRUE;
223     }
224 }
225
226 static void
227 collapse_tree(GtkTreeView *tree_view, GtkTreeIter *iter,
228               GtkTreePath *path _U_, gpointer user_data _U_)
229 {
230     field_info   *finfo;
231     GtkTreeModel *model;
232
233     model = gtk_tree_view_get_model(tree_view);
234     gtk_tree_model_get(model, iter, 1, &finfo, -1);
235     g_assert(finfo);
236
237     /*
238      * Nodes with "finfo->tree_type" of -1 have no ett_ value, and
239      * are thus presumably leaf nodes and cannot be collapsed.
240      */
241     if (finfo->tree_type != -1) {
242         g_assert(finfo->tree_type >= 0 &&
243                  finfo->tree_type < num_tree_types);
244         tree_is_expanded[finfo->tree_type] = FALSE;
245     }
246 }
247
248 #define MAX_OFFSET_LEN   8      /* max length of hex offset of bytes */
249 #define BYTES_PER_LINE  16      /* max byte values in a line */
250 #define BITS_PER_LINE    8      /* max bit values in a line */
251 #define BYTE_VIEW_SEP    8      /* insert a space every BYTE_VIEW_SEP bytes */
252 #define HEX_DUMP_LEN    (BYTES_PER_LINE*3 + 1)
253 /* max number of characters hex dump takes -
254    2 digits plus trailing blank
255    plus separator between first and
256    second 8 digits */
257 #define DATA_DUMP_LEN   (HEX_DUMP_LEN + 2 + BYTES_PER_LINE)
258 /* number of characters those bytes take;
259    3 characters per byte of hex dump,
260    2 blanks separating hex from ASCII,
261    1 character per byte of ASCII dump */
262 #define MAX_LINE_LEN    (MAX_OFFSET_LEN + 2 + DATA_DUMP_LEN)
263 /* number of characters per line;
264    offset, 2 blanks separating offset
265    from data dump, data dump */
266 #define MAX_LINES       100
267 #define MAX_LINES_LEN   (MAX_LINES*MAX_LINE_LEN)
268
269 /* Which byte the offset is referring to. Associates
270  * whitespace with the preceding digits. */
271 static int
272 byte_num(int offset, int start_point)
273 {
274     return (offset - start_point) / 3;
275 }
276 static int
277 bit_num(int offset, int start_point)
278 {
279     return (offset - start_point) / 9;
280 }
281
282 struct field_lookup_info {
283     field_info  *fi;
284     GtkTreeIter  iter;
285 };
286
287 static gboolean
288 lookup_finfo(GtkTreeModel *model, GtkTreePath *path _U_, GtkTreeIter *iter,
289              gpointer data)
290 {
291     field_info *fi;
292     struct field_lookup_info *fli = (struct field_lookup_info *)data;
293
294     gtk_tree_model_get(model, iter, 1, &fi, -1);
295     if (fi == fli->fi) {
296         fli->iter = *iter;
297         return TRUE;
298     }
299     return FALSE;
300 }
301
302 GtkTreePath
303 *tree_find_by_field_info(GtkTreeView *tree_view, field_info *finfo)
304 {
305     GtkTreeModel *model;
306     struct field_lookup_info fli;
307
308     g_assert(finfo != NULL);
309
310     model = gtk_tree_view_get_model(tree_view);
311     fli.fi = finfo;
312     gtk_tree_model_foreach(model, lookup_finfo, &fli);
313
314     return gtk_tree_model_get_path(model, &fli.iter);
315 }
316
317 static int
318 hex_view_get_byte(guint ndigits, int row, int column)
319 {
320     int           byte;
321     int           digits_start_1;
322     int           digits_end_1;
323     int           digits_start_2;
324     int           digits_end_2;
325     int           text_start_1;
326     int           text_end_1;
327     int           text_start_2;
328     int           text_end_2;
329
330     /*
331      * The column of the first hex digit in the first half.
332      * That starts after "ndigits" digits of offset and two
333      * separating blanks.
334      */
335     digits_start_1 = ndigits + 2;
336
337     /*
338      * The column of the last hex digit in the first half.
339      * There are BYTES_PER_LINE/2 bytes displayed in the first
340      * half; there are 2 characters per byte, plus a separating
341      * blank after all but the last byte's characters.
342      */
343     digits_end_1 = digits_start_1 + (BYTES_PER_LINE/2)*2 +
344         (BYTES_PER_LINE/2 - 1);
345
346     /*
347      * The column of the first hex digit in the second half.
348      * Add 2 for the 2 separating blanks between the halves.
349      */
350     digits_start_2 = digits_end_1 + 2;
351
352     /*
353      * The column of the last hex digit in the second half.
354      * Add the same value we used to get "digits_end_1" from
355      * "digits_start_1".
356      */
357     digits_end_2 = digits_start_2 + (BYTES_PER_LINE/2)*2 +
358         (BYTES_PER_LINE/2 - 1);
359
360     /*
361      * The column of the first "text dump" character in the first half.
362      * Add 3 for the 3 separating blanks between the hex and text dump.
363      */
364     text_start_1 = digits_end_2 + 3;
365
366     /*
367      * The column of the last "text dump" character in the first half.
368      * There are BYTES_PER_LINE/2 bytes displayed in the first
369      * half; there is 1 character per byte.
370      *
371      * Then subtract 1 to get the last column of the first half
372      * rather than the first column after the first half.
373      */
374     text_end_1 = text_start_1 + BYTES_PER_LINE/2 - 1;
375
376     /*
377      * The column of the first "text dump" character in the second half.
378      * Add back the 1 to get the first column after the first half,
379      * and then add 1 for the separating blank between the halves.
380      */
381     text_start_2 = text_end_1 + 2;
382
383     /*
384      * The column of the last "text dump" character in second half.
385      * Add the same value we used to get "text_end_1" from
386      * "text_start_1".
387      */
388     text_end_2 = text_start_2 + BYTES_PER_LINE/2 - 1;
389
390     /* Given the column and row, determine which byte offset
391      * the user clicked on. */
392     if (column >= digits_start_1 && column <= digits_end_1) {
393         byte = byte_num(column, digits_start_1);
394         if (byte == -1) {
395             return byte;
396         }
397     }
398     else if (column >= digits_start_2 && column <= digits_end_2) {
399         byte = byte_num(column, digits_start_2);
400         if (byte == -1) {
401             return byte;
402         }
403         byte += 8;
404     }
405     else if (column >= text_start_1 && column <= text_end_1) {
406         byte = column - text_start_1;
407     }
408     else if (column >= text_start_2 && column <= text_end_2) {
409         byte = 8 + column - text_start_2;
410     }
411     else {
412         /* The user didn't select a hex digit or
413          * text-dump character. */
414         return -1;
415     }
416
417     /* Add the number of bytes from the previous rows. */
418     byte += row * BYTES_PER_LINE;
419
420     return byte;
421 }
422
423 static int
424 bit_view_get_byte(guint ndigits, int row, int column)
425 {
426     int           byte;
427     int           digits_start;
428     int           digits_end;
429     int           text_start;
430     int           text_end;
431
432     /*
433      * The column of the first bit digit.
434      * That starts after "ndigits" digits of offset and two
435      * separating blanks.
436      */
437     digits_start = ndigits + 2;
438
439     /*
440      * The column of the last bit digit.
441      * There are BITS_PER_LINE bytes displayed; there are
442      * 8 characters per byte, plus a separating blank
443      * after all but the last byte's characters.
444      */
445     digits_end = digits_start + (BITS_PER_LINE)*8 +
446         (BITS_PER_LINE - 1);
447
448     /*
449      * The column of the first "text dump" character.
450      * Add 3 for the 3 separating blanks between the bit and text dump.
451      */
452     text_start = digits_end + 3;
453
454     /*
455      * The column of the last "text dump" character.
456      * There are BITS_PER_LINE bytes displayed; there is 1 character per byte.
457      *
458      * Then subtract 1 to get the last column.
459      */
460     text_end = text_start + BITS_PER_LINE - 1;
461
462     /* Given the column and row, determine which byte offset
463      * the user clicked on. */
464     if (column >= digits_start && column <= digits_end) {
465         byte = bit_num(column, digits_start);
466         if (byte == -1) {
467             return byte;
468         }
469     }
470     else if (column >= text_start && column <= text_end) {
471         byte = column - text_start;
472     }
473     else {
474         /* The user didn't select a hex digit or
475          * text-dump character. */
476         return -1;
477     }
478
479     /* Add the number of bytes from the previous rows. */
480     byte += row * BITS_PER_LINE;
481
482     return byte;
483 }
484
485 /* If the user selected a certain byte in the byte view, try to find
486  * the item in the GUI proto_tree that corresponds to that byte, and:
487  *
488  *    if we succeed, select it, and return TRUE;
489  *    if we fail, return FALSE. */
490 gboolean
491 byte_view_select(GtkWidget *widget, GdkEventButton *event)
492 {
493     GtkTextView  *bv = GTK_TEXT_VIEW(widget);
494     proto_tree   *tree;
495     GtkTreeView  *tree_view;
496     GtkTextIter   iter;
497     int           row, column;
498     guint         ndigits;
499     gint          x, y;
500     int           byte = -1;
501     tvbuff_t     *tvb;
502
503     tree = g_object_get_data(G_OBJECT(widget), E_BYTE_VIEW_TREE_PTR);
504     if (tree == NULL) {
505         /*
506          * Somebody clicked on the dummy byte view; do nothing.
507          */
508         return FALSE;
509     }
510     tree_view = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(widget),
511                                               E_BYTE_VIEW_TREE_VIEW_PTR));
512
513     /* get the row/column selected */
514     gtk_text_view_window_to_buffer_coords(bv,
515                          gtk_text_view_get_window_type(bv, event->window),
516                          (gint) event->x, (gint) event->y, &x, &y);
517     gtk_text_view_get_iter_at_location(bv, &iter, x, y);
518     row = gtk_text_iter_get_line(&iter);
519     column = gtk_text_iter_get_line_offset(&iter);
520
521     /*
522      * Get the number of digits of offset being displayed, and
523      * compute the byte position in the buffer.
524      */
525     ndigits = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_NDIGITS_KEY));
526
527     switch (recent.gui_bytes_view) {
528     case BYTES_HEX:
529         byte = hex_view_get_byte(ndigits, row, column);
530         break;
531     case BYTES_BITS:
532         byte = bit_view_get_byte(ndigits, row, column);
533         break;
534     default:
535         g_assert_not_reached();
536     }
537
538     if (byte == -1) {
539         return FALSE;
540     }
541
542     /* Get the data source tvbuff */
543     tvb = g_object_get_data(G_OBJECT(widget), E_BYTE_VIEW_TVBUFF_KEY);
544
545     return highlight_field(tvb, byte, tree_view, tree);
546 }
547
548 /* This highlights the field in the proto tree that is at position byte */
549 gboolean
550 highlight_field(tvbuff_t *tvb, gint byte, GtkTreeView *tree_view,
551                 proto_tree *tree)
552 {
553     GtkTreeModel *model = NULL;
554     GtkTreePath  *first_path = NULL, *path = NULL;
555     GtkTreeIter   parent;
556     field_info   *finfo = NULL;
557     match_data    mdata;
558     struct field_lookup_info fli;
559
560     if (cfile.search_in_progress && cfile.string && cfile.decode_data) {
561         /* The tree where the target string matched one of the labels was discarded in
562            match_protocol_tree() so we have to search again in the latest tree. (Uugh) */
563         if (cf_find_string_protocol_tree(&cfile, tree, &mdata)) {
564             finfo = mdata.finfo;
565         }
566     } else {
567         /* Find the finfo that corresponds to our byte. */
568         finfo = proto_find_field_from_offset(tree, byte, tvb);
569     }
570
571     if (!finfo) {
572         return FALSE;
573     }
574
575     model = gtk_tree_view_get_model(tree_view);
576     fli.fi = finfo;
577     gtk_tree_model_foreach(model, lookup_finfo, &fli);
578
579     /* Expand our field's row */
580     first_path = gtk_tree_model_get_path(model, &fli.iter);
581     gtk_tree_view_expand_row(tree_view, first_path, FALSE);
582     expand_tree(tree_view, &fli.iter, NULL, NULL);
583
584     /* ... and its parents */
585     while (gtk_tree_model_iter_parent(model, &parent, &fli.iter)) {
586         path = gtk_tree_model_get_path(model, &parent);
587         gtk_tree_view_expand_row(tree_view, path, FALSE);
588         expand_tree(tree_view, &parent, NULL, NULL);
589         fli.iter = parent;
590         gtk_tree_path_free(path);
591     }
592
593     /* Refresh the display so that the expanded trees are visible */
594     main_proto_tree_draw(tree);
595
596     /* select our field's row */
597     gtk_tree_selection_select_path(gtk_tree_view_get_selection(tree_view),
598                                    first_path);
599
600         /* If the last search was a string or hex search within "Packet data", the entire field might
601        not be highlighted. If the user just clicked on one of the bytes comprising that field, the
602        above call didn't trigger a 'gtk_tree_view_get_selection' event. Call redraw_packet_bytes()
603        to make the highlighting of the entire field visible. */
604     if (!cfile.search_in_progress) {
605         if (cfile.hex || (cfile.string && cfile.packet_data)) {
606             redraw_packet_bytes(byte_nb_ptr_gbl, cfile.current_frame, cfile.finfo_selected);
607         }
608     }
609
610     /* And position the window so the selection is visible.
611      * Position the selection in the middle of the viewable
612      * pane. */
613     gtk_tree_view_scroll_to_cell(tree_view, first_path, NULL, TRUE, 0.5f, 0.0f);
614
615     gtk_tree_path_free(first_path);
616
617     return TRUE;
618 }
619
620 /* Calls functions for different mouse-button presses. */
621 static gboolean
622 byte_view_button_press_cb(GtkWidget *widget, GdkEvent *event, gpointer data)
623 {
624     GdkEventButton *event_button = NULL;
625
626     if(widget == NULL || event == NULL || data == NULL) {
627         return FALSE;
628     }
629
630     if(event->type == GDK_BUTTON_PRESS) {
631         event_button = (GdkEventButton *) event;
632
633         /* To qoute the "Gdk Event Structures" doc:
634          * "Normally button 1 is the left mouse button, 2 is the middle button, and 3 is the right button" */
635         switch(event_button->button) {
636
637         case 1:
638             return byte_view_select(widget, event_button);
639         case 3:
640             return popup_menu_handler(widget, event, data);
641         default:
642             return FALSE;
643         }
644     }
645
646     return FALSE;
647 }
648
649 GtkWidget *
650 byte_view_new(void)
651 {
652     GtkWidget *byte_nb;
653
654     byte_nb = gtk_notebook_new();
655     gtk_notebook_set_tab_pos(GTK_NOTEBOOK(byte_nb), GTK_POS_BOTTOM);
656
657     /* this will only have an effect, if no tabs are shown */
658     gtk_notebook_set_show_border(GTK_NOTEBOOK(byte_nb), FALSE);
659
660     /* set the tabs scrollable, if they don't fit into the pane */
661     gtk_notebook_set_scrollable(GTK_NOTEBOOK(byte_nb), TRUE);
662
663     /* enable a popup menu containing the tab labels, will be helpful if tabs don't fit into the pane */
664     gtk_notebook_popup_enable(GTK_NOTEBOOK(byte_nb));
665
666     /* Add a placeholder byte view so that there's at least something
667        displayed in the byte view notebook. */
668     add_byte_tab(byte_nb, "", NULL, NULL, NULL);
669
670     return byte_nb;
671 }
672
673 static void
674 byte_view_realize_cb(GtkWidget *bv, gpointer data _U_)
675 {
676     const guint8 *byte_data;
677     guint byte_len;
678
679     byte_data = get_byte_view_data_and_length(bv, &byte_len);
680     if (byte_data == NULL) {
681         /* This must be the dummy byte view if no packet is selected. */
682         return;
683     }
684     packet_hex_print(bv, byte_data, cfile.current_frame, NULL, byte_len);
685 }
686
687 static GtkWidget *
688 add_byte_tab(GtkWidget *byte_nb, const char *name, tvbuff_t *tvb,
689              proto_tree *tree, GtkWidget *tree_view)
690 {
691         GtkWidget *byte_view, *byte_scrollw, *label;
692         GtkTextBuffer *buf;
693 #if GTK_CHECK_VERSION(3,0,0)
694         GtkStyleContext *context;
695         GdkRGBA         *rgba_bg_color;
696         GdkRGBA         *rgba_fg_color;
697 #else
698         GtkStyle    *style;
699 #endif
700
701     /* Byte view.  Create a scrolled window for the text. */
702     byte_scrollw = scrolled_window_new(NULL, NULL);
703     gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(byte_scrollw),
704                                         GTK_SHADOW_IN);
705     /* Add scrolled pane to tabbed window */
706     label = gtk_label_new(name);
707     gtk_notebook_append_page(GTK_NOTEBOOK(byte_nb), byte_scrollw, label);
708
709     gtk_widget_show(byte_scrollw);
710
711     byte_view = gtk_text_view_new();
712     gtk_text_view_set_editable(GTK_TEXT_VIEW(byte_view), FALSE);
713     gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(byte_view), FALSE);
714     buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(byte_view));
715 #if GTK_CHECK_VERSION(3,0,0)
716     context = gtk_widget_get_style_context (GTK_WIDGET(top_level));
717     gtk_style_context_get (context, GTK_STATE_SELECTED,
718                     "background-color", &rgba_bg_color,
719                     NULL);
720     gtk_style_context_get (context, GTK_STATE_SELECTED,
721                     "color", &rgba_fg_color,
722                     NULL);
723
724     gtk_text_buffer_create_tag(buf, "plain", "font-desc", user_font_get_regular(), NULL);
725     gtk_text_buffer_create_tag(buf, "reverse",
726                                "font-desc", user_font_get_regular(),
727                                "foreground-rgba", &rgba_fg_color,
728                                "background-rgba", &rgba_bg_color,
729                                NULL);
730
731 #else
732     style = gtk_widget_get_style(GTK_WIDGET(top_level));
733     gtk_text_buffer_create_tag(buf, "plain", "font-desc", user_font_get_regular(), NULL);
734     gtk_text_buffer_create_tag(buf, "reverse",
735                                "font-desc", user_font_get_regular(),
736                                "foreground-gdk", &style->text[GTK_STATE_SELECTED],
737                                "background-gdk", &style->base[GTK_STATE_SELECTED],
738                                NULL);
739 #endif
740     gtk_text_buffer_create_tag(buf, "bold", "font-desc", user_font_get_bold(), NULL);
741     g_object_set_data(G_OBJECT(byte_view), E_BYTE_VIEW_TVBUFF_KEY, tvb);
742     gtk_container_add(GTK_CONTAINER(byte_scrollw), byte_view);
743
744     g_signal_connect(byte_view, "show", G_CALLBACK(byte_view_realize_cb), NULL);
745     g_signal_connect(byte_view, "button_press_event", G_CALLBACK(byte_view_button_press_cb),
746                      g_object_get_data(G_OBJECT(popup_menu_object), PM_BYTES_VIEW_KEY));
747
748     g_object_set_data(G_OBJECT(byte_view), E_BYTE_VIEW_TREE_PTR, tree);
749     g_object_set_data(G_OBJECT(byte_view), E_BYTE_VIEW_TREE_VIEW_PTR, tree_view);
750
751     gtk_widget_show(byte_view); /* triggers byte_view_realize_cb which calls packet_hex_print */
752
753     /* no tabs if this is the first page */
754     if (!(gtk_notebook_page_num(GTK_NOTEBOOK(byte_nb), byte_scrollw)))
755         gtk_notebook_set_show_tabs(GTK_NOTEBOOK(byte_nb), FALSE);
756     else
757         gtk_notebook_set_show_tabs(GTK_NOTEBOOK(byte_nb), TRUE);
758
759     /* set this page */
760     gtk_notebook_set_current_page(GTK_NOTEBOOK(byte_nb),
761                                   gtk_notebook_page_num(GTK_NOTEBOOK(byte_nb), byte_nb));
762
763     return byte_view;
764 }
765
766 void
767 add_main_byte_views(epan_dissect_t *edt)
768 {
769     add_byte_views(edt, tree_view_gbl, byte_nb_ptr_gbl);
770 }
771
772 void
773 add_byte_views(epan_dissect_t *edt, GtkWidget *tree_view,
774                GtkWidget *byte_nb_ptr)
775 {
776     GSList *src_le;
777     data_source *src;
778
779     /*
780      * Get rid of all the old notebook tabs.
781      */
782     while (gtk_notebook_get_nth_page(GTK_NOTEBOOK(byte_nb_ptr), 0) != NULL)
783         gtk_notebook_remove_page(GTK_NOTEBOOK(byte_nb_ptr), 0);
784
785     /*
786      * Add to the specified byte view notebook tabs for hex dumps
787      * of all the data sources for the specified frame.
788      */
789     for (src_le = edt->pi.data_src; src_le != NULL; src_le = src_le->next) {
790         src = src_le->data;
791         add_byte_tab(byte_nb_ptr, get_data_source_name(src), src->tvb, edt->tree,
792                      tree_view);
793     }
794
795     /*
796      * Initially select the first byte view.
797      */
798     gtk_notebook_set_current_page(GTK_NOTEBOOK(byte_nb_ptr), 0);
799 }
800
801
802
803 static GtkWidget *savehex_dlg=NULL;
804
805 static void
806 savehex_dlg_destroy_cb(GtkWidget *w _U_, gpointer user_data _U_)
807 {
808     savehex_dlg = NULL;
809 }
810
811
812 static void
813 copy_hex_all_info(GString* copy_buffer, const guint8* data_p, int data_len, gboolean append_text)
814 {
815     const int byte_line_length = 16; /* Print out data for 16 bytes on one line */
816     int i, j;
817     gboolean end_of_line = TRUE; /* Initial state is end of line */
818     int byte_line_part_length;
819
820     GString* hex_str;
821     GString* char_str;
822
823     /* Write hex data for a line, then ascii data, then concatenate and add to buffer */
824     hex_str = g_string_new("");
825     char_str= g_string_new("");
826
827     i = 0;
828     while (i<data_len) {
829         if(end_of_line) {
830             g_string_append_printf(hex_str,"%04x  ",i); /* Offset - note that we _append_ here */
831         }
832
833         g_string_append_printf(hex_str," %02x",*data_p);
834         if(append_text) {
835             g_string_append_printf(char_str,"%c",isprint(*data_p) ? *data_p : '.');
836         }
837
838         ++data_p;
839
840         /* Look ahead to see if this is the end of the data */
841         byte_line_part_length = (++i) % byte_line_length;
842         if(i == data_len){
843             /* End of data - need to fill in spaces in hex string and then do "end of line".
844              *
845              */
846             for(j = 0; append_text && (j < (byte_line_length - byte_line_part_length)); ++j) {
847                 g_string_append(hex_str,"   "); /* Three spaces for each missing byte */
848             }
849             end_of_line = TRUE;
850         } else {
851             end_of_line = (byte_line_part_length == 0 ? TRUE : FALSE);
852         }
853
854
855         if (end_of_line){
856             /* End of line */
857             g_string_append(copy_buffer, hex_str->str);
858             if(append_text) {
859                 /* Two spaces between hex and text */
860                 g_string_append_c(copy_buffer, ' ');
861                 g_string_append_c(copy_buffer, ' ');
862                 g_string_append(copy_buffer, char_str->str);
863             }
864             /* Setup ready for next line */
865             g_string_assign(char_str,"");
866             g_string_assign(hex_str, "\n");
867         }
868     }
869
870     g_string_free(hex_str, TRUE);
871     g_string_free(char_str, TRUE);
872 }
873
874 static int
875 copy_hex_bytes_text_only(GString* copy_buffer, const guint8* data_p, int data_len _U_)
876 {
877
878     gchar to_append;
879
880     /* Copy printable characters, newlines, and (horizontal) tabs. */
881     if(isprint(*data_p)) {
882         to_append = *data_p;
883     } else if(*data_p==0x0a) {
884         to_append = '\n';
885     } else if(*data_p==0x09) {
886         to_append = '\t';
887     } else {
888         return 1; /* Just ignore non-printable bytes */
889     }
890     g_string_append_c(copy_buffer,to_append);
891     return 1;
892 }
893
894 static
895 int copy_hex_bytes_hex(GString* copy_buffer, const guint8* data_p, int data_len _U_)
896 {
897     g_string_append_printf(copy_buffer, "%02x", *data_p);
898     return 1;
899 }
900
901 void
902 copy_hex_cb(GtkWidget * w _U_, gpointer data _U_, copy_data_type data_type)
903 {
904     GtkWidget *bv;
905
906     guint len = 0;
907     int bytes_consumed = 0;
908     int flags;
909
910     const guint8* data_p;
911
912     GString* copy_buffer = g_string_new(""); /* String to copy to clipboard */
913
914     bv = get_notebook_bv_ptr(byte_nb_ptr_gbl);
915     if (bv == NULL) {
916         /* shouldn't happen */
917         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Could not find the corresponding text window!");
918         return;
919     }
920
921     data_p = get_byte_view_data_and_length(bv, &len);
922     g_assert(data_p != NULL);
923
924     flags = data_type & CD_FLAGSMASK;
925     data_type = data_type & CD_TYPEMASK;
926
927     if(flags & CD_FLAGS_SELECTEDONLY) {
928         int start, end;
929
930         /* Get the start and end of the highlighted bytes. */
931         start = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_START_KEY));
932         end = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_END_KEY));
933
934         if(start >= 0 && end > start && (end - start <= (int)len)) {
935             len = end - start;
936             data_p += start;
937         }
938     }
939
940     switch(data_type) {
941     case(CD_ALLINFO):
942         /* This is too different from other text formats - handle separately */
943         copy_hex_all_info(copy_buffer, data_p, len, TRUE);
944         break;
945     case(CD_HEXCOLUMNS):
946         /* This could be done incrementally, but it is easier to mingle with the code for CD_ALLINFO */
947         copy_hex_all_info(copy_buffer, data_p, len, FALSE);
948         break;
949     case(CD_BINARY):
950         /* Completely different logic to text copies - leave copy buffer alone */
951         copy_binary_to_clipboard(data_p,len);
952         break;
953     default:
954         /* Incrementally write to text buffer in various formats */
955         while (len > 0){
956             switch(data_type) {
957             case (CD_TEXTONLY):
958                 bytes_consumed = copy_hex_bytes_text_only(copy_buffer, data_p, len);
959                 break;
960             case (CD_HEX):
961                 bytes_consumed = copy_hex_bytes_hex(copy_buffer, data_p, len);
962                 break;
963             default:
964                 g_assert_not_reached();
965                 break;
966             }
967
968             g_assert(bytes_consumed>0);
969             data_p += bytes_consumed;
970             len -= bytes_consumed;
971         }
972         break;
973     }
974
975     if(copy_buffer->len > 0) {
976         copy_to_clipboard(copy_buffer);
977     }
978
979     g_string_free(copy_buffer, TRUE);
980 }
981
982 /* save the current highlighted hex data */
983 static gboolean
984 savehex_save_clicked_cb(GtkWidget * w _U_, gpointer data _U_)
985 {
986     GtkWidget *bv;
987     int fd, start, end;
988     guint len;
989     const guint8 *data_p = NULL;
990     char *file;
991
992     file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(savehex_dlg));
993
994 #if 0 /* Not req'd: GtkFileChooserWidget currently being used won't return with a Null filename */
995     if (!file ||! *file) {
996         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Please enter a filename!");
997         g_free(file);
998         return TRUE;
999     }
1000 #endif
1001     if (test_for_directory(file) == EISDIR) {
1002         /* It's a directory - set the file selection box to display that
1003            directory, and leave the selection box displayed. */
1004         set_last_open_dir(file);
1005         g_free(file);
1006         file_selection_set_current_folder(savehex_dlg, get_last_open_dir());
1007         gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(savehex_dlg), "");
1008         return FALSE; /* do gtk_dialog_run again */
1009     }
1010
1011     /* XXX: Must check if file name exists first */
1012
1013     bv = get_notebook_bv_ptr(byte_nb_ptr_gbl);
1014     if (bv == NULL) {
1015         /* shouldn't happen */
1016         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Could not find the corresponding text window!");
1017         g_free(file);
1018         return TRUE;
1019     }
1020     /*
1021      * Retrieve the info we need
1022      */
1023     start = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_START_KEY));
1024     end = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_END_KEY));
1025     data_p = get_byte_view_data_and_length(bv, &len);
1026
1027     if (data_p == NULL || start == -1 || start > end) {
1028         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1029                       "No data selected to save!");
1030         g_free(file);
1031         return TRUE;
1032     }
1033
1034     fd = ws_open(file, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666);
1035     if (fd == -1) {
1036         open_failure_alert_box(file, errno, TRUE);
1037         g_free(file);
1038         return TRUE;
1039     }
1040     if (ws_write(fd, data_p + start, end - start) < 0) {
1041         write_failure_alert_box(file, errno);
1042         ws_close(fd);
1043         g_free(file);
1044         return TRUE;
1045     }
1046     if (ws_close(fd) < 0) {
1047         write_failure_alert_box(file, errno);
1048         g_free(file);
1049         return TRUE;
1050     }
1051
1052     /* Get rid of the dialog box */
1053     g_free(file);
1054 #if 0 /* being handled by caller  (for now) */
1055     window_destroy(GTK_WIDGET(savehex_dlg));
1056 #endif
1057     return TRUE;
1058 }
1059
1060 /* Launch the dialog box to put up the file selection box etc */
1061 #ifdef _WIN32
1062 void
1063 savehex_cb(GtkWidget * w _U_, gpointer data _U_)
1064 {
1065     win32_export_raw_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)));
1066     return;
1067 }
1068 #else
1069 void
1070 savehex_cb(GtkWidget * w _U_, gpointer data _U_)
1071 {
1072     int start, end;
1073     guint len;
1074     const guint8 *data_p = NULL;
1075     gchar *label;
1076     GtkWidget   *bv;
1077     GtkWidget   *dlg_lb;
1078
1079     /* don't show up the dialog, if no data has to be saved */
1080     bv = get_notebook_bv_ptr(byte_nb_ptr_gbl);
1081     if (bv == NULL) {
1082         /* shouldn't happen */
1083         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Could not find the corresponding text window!");
1084         return;
1085     }
1086     start = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_START_KEY));
1087     end = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_END_KEY));
1088     data_p = get_byte_view_data_and_length(bv, &len);
1089
1090     if (data_p == NULL || start == -1 || start > end) {
1091         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "No data selected to save!");
1092         return;
1093     }
1094
1095 #if 0  /* XXX: GtkFileChooserDialog/gtk_dialog_run currently being used is effectively modal so this is not req'd */
1096     /* if the window is already open, bring it to front */
1097     if(savehex_dlg){
1098         reactivate_window(savehex_dlg);
1099         return;
1100     }
1101 #endif
1102     /*
1103      * Build the dialog box we need.
1104      */
1105     savehex_dlg = file_selection_new("Wireshark: Export Selected Packet Bytes", FILE_SELECTION_SAVE);
1106     gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(savehex_dlg), TRUE);
1107
1108     /* label */
1109     label = g_strdup_printf("Will save %u %s of raw binary data to specified file.",
1110                             end - start, plurality(end - start, "byte", "bytes"));
1111     dlg_lb = gtk_label_new(label);
1112     g_free(label);
1113     file_selection_set_extra_widget(savehex_dlg, dlg_lb);
1114     gtk_widget_show(dlg_lb);
1115
1116     g_signal_connect(savehex_dlg, "destroy", G_CALLBACK(savehex_dlg_destroy_cb), NULL);
1117
1118 #if 0
1119     if (gtk_dialog_run(GTK_DIALOG(savehex_dlg)) == GTK_RESPONSE_ACCEPT) {
1120         savehex_save_clicked_cb(savehex_dlg, savehex_dlg);
1121     } else {
1122         window_destroy(savehex_dlg);
1123     }
1124 #endif
1125     /* "Run" the GtkFileChooserDialog.                                              */
1126     /* Upon exit: If "Accept" run the OK callback.                                  */
1127     /*            If the OK callback returns with a FALSE status, re-run the dialog.*/
1128     /*            If not accept (ie: cancel) destroy the window.                    */
1129     /* XXX: If the OK callback pops up an alert box (eg: for an error) it *must*    */
1130     /*      return with a TRUE status so that the dialog window will be destroyed.  */
1131     /*      Trying to re-run the dialog after popping up an alert box will not work */
1132     /*       since the user will not be able to dismiss the alert box.              */
1133     /*      The (somewhat unfriendly) effect: the user must re-invoke the           */
1134     /*      GtkFileChooserDialog whenever the OK callback pops up an alert box.     */
1135     /*                                                                              */
1136     /*      ToDo: use GtkFileChooserWidget in a dialog window instead of            */
1137     /*            GtkFileChooserDialog.                                             */
1138     while (gtk_dialog_run(GTK_DIALOG(savehex_dlg)) == GTK_RESPONSE_ACCEPT) {
1139         if (savehex_save_clicked_cb(NULL, savehex_dlg)) {
1140             break; /* we're done */
1141         }
1142     }
1143     window_destroy(savehex_dlg);
1144 }
1145 #endif
1146
1147 static GtkTextMark *
1148 packet_hex_apply_reverse_tag(GtkTextBuffer *buf, int bstart, int bend, guint32 mask, int mask_le, int use_digits, int create_mark)
1149 {
1150     GtkTextIter i_start, i_stop, iter;
1151
1152     GtkTextTag    *revstyle_tag;
1153     const char    *revstyle;
1154
1155     int per_line = 0;
1156     int per_one = 0;
1157     int bits_per_one = 0;
1158     int hex_offset, ascii_offset;
1159
1160     int start_line, start_line_pos;
1161     int stop_line, stop_line_pos;
1162
1163     if (bstart == -1 || bend == -1)
1164         return NULL;
1165
1166     /* Display with inverse video ? */
1167     if (prefs.gui_hex_dump_highlight_style)
1168         revstyle = "reverse";
1169     else
1170         revstyle = "bold";
1171
1172     revstyle_tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(buf), revstyle);
1173
1174     switch (recent.gui_bytes_view) {
1175     case BYTES_HEX:
1176         per_line = BYTES_PER_LINE;
1177         per_one  = 2+1;  /* "ff " */
1178         bits_per_one = 4;
1179         break;
1180     case BYTES_BITS:
1181         per_line = BITS_PER_LINE;
1182         per_one  = 8+1;  /* "10101010 " */
1183         bits_per_one = 1;
1184         break;
1185     default:
1186         g_assert_not_reached();
1187     }
1188
1189     start_line = bstart / per_line;
1190     start_line_pos = bstart % per_line;
1191
1192     stop_line = bend / per_line;
1193     stop_line_pos = bend % per_line;
1194
1195 #define hex_fix(pos)   hex_offset + (pos * per_one) + (pos / BYTE_VIEW_SEP) - (pos == per_line)
1196 #define ascii_fix(pos) ascii_offset + pos + (pos / BYTE_VIEW_SEP) - (pos == per_line)
1197
1198     hex_offset = use_digits + 2;
1199     ascii_offset = hex_fix(per_line) + 2;
1200
1201     gtk_text_buffer_get_iter_at_line_index(buf, &iter, start_line, hex_fix(start_line_pos));
1202
1203     if (mask == 0x00) {
1204         while (start_line <= stop_line) {
1205             int line_pos_end = (start_line == stop_line) ? stop_line_pos : per_line;
1206             int first_block_adjust = (recent.gui_bytes_view == BYTES_HEX) ? (line_pos_end == per_line/2) : 0;
1207
1208             if (start_line_pos == line_pos_end) break;
1209
1210             /* bits/hex */
1211             gtk_text_buffer_get_iter_at_line_index(buf, &i_start, start_line, hex_fix(start_line_pos));
1212             gtk_text_buffer_get_iter_at_line_index(buf, &i_stop, start_line, hex_fix(line_pos_end)-1-first_block_adjust);
1213             gtk_text_buffer_apply_tag(buf, revstyle_tag, &i_start, &i_stop);
1214
1215             /* ascii */
1216             gtk_text_buffer_get_iter_at_line_index(buf, &i_start, start_line, ascii_fix(start_line_pos));
1217             gtk_text_buffer_get_iter_at_line_index(buf, &i_stop, start_line, ascii_fix(line_pos_end)-first_block_adjust);
1218             gtk_text_buffer_apply_tag(buf, revstyle_tag, &i_start, &i_stop);
1219
1220             start_line_pos = 0;
1221             start_line++;
1222         }
1223
1224     } else if (mask_le) { /* LSB of mask first (little-endian) */
1225         while (start_line <= stop_line) {
1226             int line_pos_end = (start_line == stop_line) ? stop_line_pos : per_line;
1227             int line_pos = start_line_pos;
1228
1229             while (line_pos < line_pos_end) {
1230                 int lop = 8 / bits_per_one;
1231                 int mask_per_one = (1 << bits_per_one) - 1;
1232                 int ascii_on = 0;
1233
1234                 while (lop--) {
1235                     if ((mask & mask_per_one)) {
1236                         /* bits/hex */
1237                         gtk_text_buffer_get_iter_at_line_index(buf, &i_start, start_line, hex_fix(line_pos)+lop);
1238                         gtk_text_buffer_get_iter_at_line_index(buf, &i_stop, start_line, hex_fix(line_pos)+lop+1);
1239                         gtk_text_buffer_apply_tag(buf, revstyle_tag, &i_start, &i_stop);
1240
1241                         ascii_on = 1;
1242                     }
1243                     mask >>= bits_per_one;
1244                 }
1245
1246                 /* at least one bit of ascii was one -> turn ascii on */
1247                 if (ascii_on) {
1248                     /* ascii */
1249                     gtk_text_buffer_get_iter_at_line_index(buf, &i_start, start_line, ascii_fix(line_pos));
1250                     gtk_text_buffer_get_iter_at_line_index(buf, &i_stop, start_line, ascii_fix(line_pos)+1);
1251                     gtk_text_buffer_apply_tag(buf, revstyle_tag, &i_start, &i_stop);
1252                 }
1253
1254                 if (!mask)
1255                     goto xend;
1256
1257                 line_pos++;
1258             }
1259
1260             start_line_pos = 0;
1261             start_line++;
1262         }
1263     } else { /* mask starting from end (big-endian) */
1264         while (start_line <= stop_line) {
1265             int line_pos_start = (start_line == stop_line) ? start_line_pos : 0;
1266             int line_pos = stop_line_pos-1;
1267
1268             while (line_pos >= line_pos_start) {
1269                 int lop = 8 / bits_per_one;
1270                 int mask_per_one = (1 << bits_per_one) - 1;
1271                 int ascii_on = 0;
1272
1273                 while (lop--) {
1274                     if ((mask & mask_per_one)) {
1275                         /* bits/hex */
1276                         gtk_text_buffer_get_iter_at_line_index(buf, &i_start, stop_line, hex_fix(line_pos)+lop);
1277                         gtk_text_buffer_get_iter_at_line_index(buf, &i_stop, stop_line, hex_fix(line_pos)+lop+1);
1278                         gtk_text_buffer_apply_tag(buf, revstyle_tag, &i_start, &i_stop);
1279
1280                         ascii_on = 1;
1281                     }
1282                     mask >>= bits_per_one;
1283                 }
1284
1285                 /* at least one bit of ascii was one -> turn ascii on */
1286                 if (ascii_on) {
1287                     /* ascii */
1288                     gtk_text_buffer_get_iter_at_line_index(buf, &i_start, stop_line, ascii_fix(line_pos));
1289                     gtk_text_buffer_get_iter_at_line_index(buf, &i_stop, stop_line, ascii_fix(line_pos)+1);
1290                     gtk_text_buffer_apply_tag(buf, revstyle_tag, &i_start, &i_stop);
1291                 }
1292
1293                 if (!mask)
1294                     goto xend;
1295
1296                 line_pos--;
1297             }
1298
1299             stop_line_pos = per_line;
1300             stop_line--;
1301         }
1302     }
1303 xend:
1304     return (create_mark) ? gtk_text_buffer_create_mark(buf, NULL, &iter, TRUE) : NULL;
1305 #undef hex_fix
1306 #undef ascii_fix
1307 }
1308
1309 /* Update the progress bar this many times when reading a file. */
1310 #define N_PROGBAR_UPDATES        100
1311 /* The minimum packet length required to check if a progress bar is needed or not */
1312 #define MIN_PACKET_LENGTH       1024
1313
1314 /*
1315  * XXX - at least in GTK+ 2.x, this is not fast - in one capture with a
1316  * 64K-or-so reassembled HTTP reply, it takes about 3 seconds to construct
1317  * the hex dump pane on a 1.4 GHz G4 PowerMac on OS X 10.3.3.  (That's
1318  * presumably why there's a progress bar for it.)
1319  *
1320  * Perhaps what's needed is a custom widget (either one that lets you stuff
1321  * text into it more quickly, or one that's a "virtual" widget so that the
1322  * text for a row is constructed, via a callback, when the row is to be
1323  * displayed).  A custom widget might also let us treat the offset, hex
1324  * data, and ASCII data as three columns, so you can select purely in
1325  * the hex dump column.
1326  */
1327 static void
1328 packet_hex_print_common(GtkTextBuffer *buf, GtkWidget *bv, const guint8 *pd, int len, int encoding)
1329 {
1330     int            i = 0, j, k = 0, b, cur;
1331     guchar         line[MAX_LINES_LEN + 1];
1332     static guchar  hexchars[16] = {
1333         '0', '1', '2', '3', '4', '5', '6', '7',
1334         '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
1335     static const guint8 bitmask[8] = {
1336         0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
1337     guchar         c = '\0';
1338     unsigned int   use_digits;
1339     GtkTextIter    iter;
1340
1341     progdlg_t  *progbar = NULL;
1342     float       progbar_val;
1343     gboolean    progbar_stop_flag;
1344     GTimeVal    progbar_start_time;
1345     gchar       progbar_status_str[100];
1346     int         progbar_nextstep;
1347     int         progbar_quantum;
1348
1349     gtk_text_buffer_set_text(buf, "", 0);
1350     gtk_text_buffer_get_start_iter(buf, &iter);
1351
1352     /*
1353      * How many of the leading digits of the offset will we supply?
1354      * We always supply at least 4 digits, but if the maximum offset
1355      * won't fit in 4 digits, we use as many digits as will be needed.
1356      */
1357     if (((len - 1) & 0xF0000000) != 0)
1358         use_digits = 8; /* need all 8 digits */
1359     else if (((len - 1) & 0x0F000000) != 0)
1360         use_digits = 7; /* need 7 digits */
1361     else if (((len - 1) & 0x00F00000) != 0)
1362         use_digits = 6; /* need 6 digits */
1363     else if (((len - 1) & 0x000F0000) != 0)
1364         use_digits = 5; /* need 5 digits */
1365     else
1366         use_digits = 4; /* we'll supply 4 digits */
1367
1368     /* Record the number of digits in this text view. */
1369     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_NDIGITS_KEY, GUINT_TO_POINTER(use_digits));
1370
1371     /* Update the progress bar when it gets to this value. */
1372     if (len > MIN_PACKET_LENGTH){
1373         progbar_nextstep = 0;
1374     }else{
1375         /* If length =< MIN_PACKET_LENGTH
1376          * there is no need to calculate the progress
1377          */
1378         progbar_nextstep = len+1;
1379     }
1380
1381     /* When we reach the value that triggers a progress bar update,
1382        bump that value by this amount. */
1383     progbar_quantum = len/N_PROGBAR_UPDATES;
1384     /* Progress so far. */
1385     progbar_val = 0.0f;
1386
1387     progbar_stop_flag = FALSE;
1388     g_get_current_time(&progbar_start_time);
1389
1390     cur = 0;
1391     while (i < len) {
1392         /* Create the progress bar if necessary.
1393            We check on every iteration of the loop, so that it takes no
1394            longer than the standard time to create it (otherwise, for a
1395            large packet, we might take considerably longer than that standard
1396            time in order to get to the next progress bar step). */
1397         if ((progbar == NULL) && (len > MIN_PACKET_LENGTH))
1398             progbar = delayed_create_progress_dlg("Processing", "Packet Details",
1399                                                   TRUE,
1400                                                   &progbar_stop_flag,
1401                                                   &progbar_start_time,
1402                                                   progbar_val);
1403
1404         /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
1405            when we update it, we have to run the GTK+ main loop to get it
1406            to repaint what's pending, and doing so may involve an "ioctl()"
1407            to see if there's any pending input from an X server, and doing
1408            that for every packet can be costly, especially on a big file. */
1409         if (i >= progbar_nextstep) {
1410
1411             if (progbar != NULL) {
1412                 /* let's not divide by zero. I should never be started
1413                  * with count == 0, so let's assert that
1414                  */
1415                 g_assert(len > 0);
1416                 progbar_val = (gfloat) i / len;
1417                 g_snprintf(progbar_status_str, sizeof(progbar_status_str),
1418                            "%4u of %u bytes", i, len);
1419                 update_progress_dlg(progbar, progbar_val, progbar_status_str);
1420             }
1421
1422             progbar_nextstep += progbar_quantum;
1423         }
1424
1425         if (progbar_stop_flag) {
1426             /* Well, the user decided to abort the operation.  Just stop,
1427                and arrange to return TRUE to our caller, so they know it
1428                was stopped explicitly. */
1429             break;
1430         }
1431
1432         /* Print the line number */
1433         j = use_digits;
1434         do {
1435             j--;
1436             c = (i >> (j*4)) & 0xF;
1437             line[cur++] = hexchars[c];
1438         } while (j != 0);
1439         line[cur++] = ' ';
1440         line[cur++] = ' ';
1441
1442         j   = i;
1443         switch (recent.gui_bytes_view) {
1444         case BYTES_HEX:
1445             k = i + BYTES_PER_LINE;
1446             break;
1447         case BYTES_BITS:
1448             k = i + BITS_PER_LINE;
1449             break;
1450         default:
1451             g_assert_not_reached();
1452         }
1453         /* Print the hex bit */
1454         while (i < k) {
1455             if (i < len) {
1456                 switch (recent.gui_bytes_view) {
1457                 case BYTES_HEX:
1458                     line[cur++] = hexchars[(pd[i] & 0xf0) >> 4];
1459                     line[cur++] = hexchars[pd[i] & 0x0f];
1460                     break;
1461                 case BYTES_BITS:
1462                     for (b = 0; b < 8; b++) {
1463                         line[cur++] = (pd[i] & bitmask[b]) ? '1' : '0';
1464                     }
1465                     break;
1466                 default:
1467                     g_assert_not_reached();
1468                 }
1469             } else {
1470                 switch (recent.gui_bytes_view) {
1471                 case BYTES_HEX:
1472                     line[cur++] = ' '; line[cur++] = ' ';
1473                     break;
1474                 case BYTES_BITS:
1475                     for (b = 0; b < 8; b++) {
1476                         line[cur++] = ' ';
1477                     }
1478                     break;
1479                 default:
1480                     g_assert_not_reached();
1481                 }
1482             }
1483             i++;
1484             /* Inter byte space if not at end of line */
1485             if (i < k) {
1486                 line[cur++] = ' ';
1487                 /* insert a space every BYTE_VIEW_SEP bytes */
1488                 if( ( i % BYTE_VIEW_SEP ) == 0 ) {
1489                     line[cur++] = ' ';
1490                 }
1491             }
1492         }
1493
1494         /* Print some space at the end of the line */
1495         line[cur++] = ' '; line[cur++] = ' '; line[cur++] = ' ';
1496
1497         /* Print the ASCII bit */
1498         i = j;
1499
1500         while (i < k) {
1501             if (i < len) {
1502                 if (encoding == PACKET_CHAR_ENC_CHAR_ASCII) {
1503                     c = pd[i];
1504                 }
1505                 else if (encoding == PACKET_CHAR_ENC_CHAR_EBCDIC) {
1506                     c = EBCDIC_to_ASCII1(pd[i]);
1507                 }
1508                 else {
1509                     g_assert_not_reached();
1510                 }
1511                 line[cur++] = isprint(c) ? c : '.';
1512             } else {
1513                 line[cur++] = ' ';
1514             }
1515             i++;
1516             if (i < k) {
1517                 /* insert a space every BYTE_VIEW_SEP bytes */
1518                 if( ( i % BYTE_VIEW_SEP ) == 0 ) {
1519                     line[cur++] = ' ';
1520                 }
1521             }
1522         }
1523         line[cur++] = '\n';
1524         if (cur >= (MAX_LINES_LEN - MAX_LINE_LEN)) {
1525             gtk_text_buffer_insert(buf, &iter, line, cur);
1526             cur = 0;
1527         }
1528     }
1529
1530     /* We're done printing the packets; destroy the progress bar if
1531        it was created. */
1532     if (progbar != NULL)
1533         destroy_progress_dlg(progbar);
1534
1535     if (cur) {
1536         gtk_text_buffer_insert(buf, &iter, line, cur);
1537     }
1538 }
1539
1540 static void
1541 packet_hex_update(GtkWidget *bv, const guint8 *pd, int len, int bstart,
1542                   int bend, guint32 bmask, int bmask_le,
1543                   int astart, int aend, int encoding)
1544 {
1545     GtkTextView   *bv_text_view = GTK_TEXT_VIEW(bv);
1546     GtkTextBuffer *buf = gtk_text_view_get_buffer(bv_text_view);
1547     GtkTextMark   *mark;
1548     int ndigits;
1549
1550     GtkTextIter start, end;
1551
1552     g_object_ref(buf);
1553
1554 #if 0
1555     /* XXX: Setting the text_view buffer to NULL is apparently
1556      *      not a good idea; If a progress_bar is displayed below
1557      *      in delayed_create_progress_dlg() there will then be
1558      *      a crash internally in the gtk library.
1559      *      (It appears that gtk_text_view_set_buffer
1560      *       queues a callback to be run when this
1561      *       thread is next idle. Unfortunately the call to
1562      *       gtk_main_iteration() in delayed_create_progress_dlg()
1563      *       causes the internal callback to be run which then
1564      *       crashes (because the textview has no buffer ?))
1565      */
1566     gtk_text_view_set_buffer(bv_text_view, NULL);
1567 #endif
1568
1569     /* attach a dummy buffer in place of the real buffer.
1570      * (XXX: Presumably this is done so there's no attempt
1571      *       to display the real buffer until it has been
1572      *       completely generated).
1573      */
1574     gtk_text_view_set_buffer(bv_text_view, gtk_text_buffer_new(NULL));
1575
1576     packet_hex_print_common(buf, bv, pd, len, encoding);
1577
1578     /* mark everything with "plain" tag */
1579     gtk_text_buffer_get_start_iter(buf, &start);
1580     gtk_text_buffer_get_end_iter(buf, &end);
1581     gtk_text_buffer_apply_tag_by_name(buf, "plain", &start, &end);
1582
1583     ndigits = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_NDIGITS_KEY));
1584
1585     /* mark reverse tags */
1586     mark = packet_hex_apply_reverse_tag(buf, bstart, bend, bmask, bmask_le, ndigits, 1);
1587     packet_hex_apply_reverse_tag(buf, astart, aend, 0x00, 0, ndigits, 0);
1588
1589     gtk_text_view_set_buffer(bv_text_view, buf);
1590
1591     /* scroll text into position */
1592     if (mark) {
1593         gtk_text_view_scroll_to_mark(bv_text_view, mark, 0.0, TRUE, 1.0, 0.0);
1594         gtk_text_buffer_delete_mark(buf, mark);
1595     }
1596     g_object_unref(buf);
1597 }
1598
1599 void
1600 packet_hex_print(GtkWidget *bv, const guint8 *pd, frame_data *fd,
1601                  field_info *finfo, guint len)
1602 {
1603     /* do the initial printing and save the information needed  */
1604     /* to redraw the display if preferences change.             */
1605
1606     int bstart = -1, bend = -1, blen = -1;
1607     guint32 bmask = 0x00; int bmask_le = 0;
1608     int astart = -1, aend = -1, alen = -1;
1609
1610
1611     if (finfo != NULL) {
1612
1613         if (cfile.search_in_progress && (cfile.hex || (cfile.string && cfile.packet_data))) {
1614             /* In the hex view, only highlight the target bytes or string. The entire
1615                field can then be displayed by clicking on any of the bytes in the field. */
1616             if (cfile.hex) {
1617                 blen = (int)strlen(cfile.sfilter)/2;
1618             } else {
1619                 blen = (int)strlen(cfile.sfilter);
1620             }
1621             bstart = cfile.search_pos - (blen-1);
1622
1623         } else {
1624             blen = finfo->length;
1625             bstart = finfo->start;
1626         }
1627
1628         /* bmask = finfo->hfinfo->bitmask << finfo->hfinfo->bitshift; */ /* (value & mask) >> shift */
1629         if (finfo->hfinfo) bmask = finfo->hfinfo->bitmask;
1630         astart = finfo->appendix_start;
1631         alen = finfo->appendix_length;
1632
1633         if (FI_GET_FLAG(finfo, FI_LITTLE_ENDIAN))
1634             bmask_le = 1;
1635         else if (FI_GET_FLAG(finfo, FI_BIG_ENDIAN))
1636             bmask_le = 0;
1637         else { /* unknown endianess - disable mask
1638                   bmask_le = (G_BYTE_ORDER == G_LITTLE_ENDIAN);
1639                */
1640             bmask = 0x00;
1641         }
1642
1643         if (bmask == 0x00) {
1644             int bito = FI_GET_BITS_OFFSET(finfo);
1645             int bitc = FI_GET_BITS_SIZE(finfo);
1646             int bitt = bito + bitc;
1647
1648             /* construct mask using bito & bitc */
1649             /* XXX, mask has only 32 bit, later we can store bito&bitc, and use them (which should be faster) */
1650             if (bitt > 0 && bitt < 32) {
1651
1652                 bmask = ((1 << bitc) - 1) << (8-(bitt & 0x7)); /* always? */
1653                 bmask_le = 0; /* ? */
1654             }
1655         }
1656     }
1657
1658     if (bstart >= 0 && blen > 0) {
1659         bend = bstart + blen;
1660     }
1661     if (astart >= 0 && alen > 0) {
1662         aend = astart + alen;
1663     }
1664
1665     if (bend == -1 && aend != -1) {
1666         bstart = astart;
1667         bmask = 0x00;
1668         bend = aend;
1669         astart = aend = -1;
1670     }
1671
1672     /* don't exceed the end of available data */
1673     if (aend != -1 && (guint)aend > len) aend = len;
1674     if (bend != -1 && (guint)bend > len) bend = len;
1675
1676     /* save the information needed to redraw the text */
1677     /* should we save the fd & finfo pointers instead ?? */
1678     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_START_KEY, GINT_TO_POINTER(bstart));
1679     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_END_KEY, GINT_TO_POINTER(bend));
1680     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_MASK_KEY, GINT_TO_POINTER(bmask));
1681     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_MASKLE_KEY, GINT_TO_POINTER(bmask_le));
1682     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_APP_START_KEY, GINT_TO_POINTER(astart));
1683     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_APP_END_KEY, GINT_TO_POINTER(aend));
1684     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_ENCODE_KEY,
1685                       GUINT_TO_POINTER((guint)fd->flags.encoding));
1686
1687     /* stig: it should be done only for bitview... */
1688     if (recent.gui_bytes_view != BYTES_BITS)
1689         bmask = 0x00;
1690     packet_hex_update(bv, pd, len, bstart, bend, bmask, bmask_le, astart, aend, fd->flags.encoding);
1691 }
1692
1693 void
1694 packet_hex_editor_print(GtkWidget *bv, const guint8 *pd, frame_data *fd, int offset, int bitoffset, guint len)
1695 {
1696     /* do the initial printing and save the information needed  */
1697     /* to redraw the display if preferences change.             */
1698
1699     int bstart = offset, bend = (bstart != -1) ? offset+1 : -1;
1700     guint32 bmask; int bmask_le = 0;
1701     int astart = -1, aend = -1;
1702
1703     switch (recent.gui_bytes_view) {
1704     case BYTES_HEX:
1705         bmask = (bitoffset == 0) ? 0xf0 : (bitoffset == 4) ? 0x0f : 0xff;
1706         break;
1707
1708     case BYTES_BITS:
1709         bmask = (1 << (7-bitoffset));
1710         break;
1711
1712         default:
1713                 bmask = 0x00;
1714                 g_assert_not_reached();
1715                 break;
1716     }
1717
1718     /* save the information needed to redraw the text */
1719     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_START_KEY, GINT_TO_POINTER(bstart));
1720     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_END_KEY, GINT_TO_POINTER(bend));
1721     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_MASK_KEY, GINT_TO_POINTER(bmask));
1722     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_MASKLE_KEY, GINT_TO_POINTER(bmask_le));
1723     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_APP_START_KEY, GINT_TO_POINTER(astart));
1724     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_APP_END_KEY, GINT_TO_POINTER(aend));
1725     g_object_set_data(G_OBJECT(bv), E_BYTE_VIEW_ENCODE_KEY,
1726                       GUINT_TO_POINTER((guint)fd->flags.encoding));
1727
1728     packet_hex_update(bv, pd, len, bstart, bend, bmask, bmask_le, astart, aend, fd->flags.encoding);
1729 }
1730
1731 /*
1732  * Redraw the text using the saved information; usually called if
1733  * the preferences have changed.
1734  */
1735 void
1736 packet_hex_reprint(GtkWidget *bv)
1737 {
1738     int start, end, mask, mask_le, encoding;
1739     int astart, aend;
1740     const guint8 *data;
1741     guint len = 0;
1742
1743     start = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_START_KEY));
1744     end = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_END_KEY));
1745     mask = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_MASK_KEY));
1746     mask_le = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_MASKLE_KEY));
1747     astart = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_APP_START_KEY));
1748     aend = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_APP_END_KEY));
1749     data = get_byte_view_data_and_length(bv, &len);
1750     g_assert(data != NULL);
1751     encoding = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(bv), E_BYTE_VIEW_ENCODE_KEY));
1752
1753     /* stig: it should be done only for bitview... */
1754     if (recent.gui_bytes_view != BYTES_BITS)
1755         mask = 0x00;
1756     packet_hex_update(bv, data, len, start, end, mask, mask_le, astart, aend, encoding);
1757 }
1758
1759 /* List of all protocol tree widgets, so we can globally set the selection
1760    mode and font of all of them. */
1761 static GList *ptree_widgets;
1762
1763 /* Add a protocol tree widget to the list of protocol tree widgets. */
1764 static void forget_ptree_widget(GtkWidget *ptreew, gpointer data);
1765
1766 static void
1767 remember_ptree_widget(GtkWidget *ptreew)
1768 {
1769     ptree_widgets = g_list_append(ptree_widgets, ptreew);
1770
1771     /* Catch the "destroy" event on the widget, so that we remove it from
1772        the list when it's destroyed. */
1773     g_signal_connect(ptreew, "destroy", G_CALLBACK(forget_ptree_widget), NULL);
1774 }
1775
1776 /* Remove a protocol tree widget from the list of protocol tree widgets. */
1777 static void
1778 forget_ptree_widget(GtkWidget *ptreew, gpointer data _U_)
1779 {
1780     ptree_widgets = g_list_remove(ptree_widgets, ptreew);
1781 }
1782
1783 /* Set the selection mode of a given packet tree window. */
1784 static void
1785 set_ptree_sel_browse(GtkWidget *tree, gboolean val)
1786 {
1787     GtkTreeSelection *selection;
1788
1789     selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
1790     /* Yeah, GTK uses "browse" in the case where we do not, but oh well.
1791        I think "browse" in Wireshark makes more sense than "SINGLE" in
1792        GTK+ */
1793     if (val) {
1794         gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
1795     }
1796     else {
1797         gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
1798     }
1799 }
1800
1801 static void
1802 set_ptree_sel_browse_cb(gpointer data, gpointer user_data)
1803 {
1804     set_ptree_sel_browse((GtkWidget *)data, *(gboolean *)user_data);
1805 }
1806
1807 /* Set the selection mode of all packet tree windows. */
1808 void
1809 set_ptree_sel_browse_all(gboolean val)
1810 {
1811     g_list_foreach(ptree_widgets, set_ptree_sel_browse_cb, &val);
1812 }
1813
1814 static void
1815 set_ptree_font_cb(gpointer data, gpointer user_data)
1816 {
1817 #if GTK_CHECK_VERSION(3,0,0)
1818     gtk_widget_override_font((GtkWidget *)data,
1819                            (PangoFontDescription *)user_data);
1820 #else
1821     gtk_widget_modify_font((GtkWidget *)data,
1822                            (PangoFontDescription *)user_data);
1823 #endif
1824 }
1825
1826 void
1827 set_ptree_font_all(PangoFontDescription *font)
1828 {
1829     g_list_foreach(ptree_widgets, set_ptree_font_cb, font);
1830 }
1831
1832
1833 /*
1834  * Each expert_color_* level below should match the light gradient
1835  * colors in image/expert_indicators.svg.
1836  */
1837 static gboolean colors_ok = FALSE;
1838
1839 GdkColor        expert_color_chat       = { 0, 0x8080, 0xb7b7, 0xf7f7 };        /* light blue */
1840 GdkColor        expert_color_note       = { 0, 0xa0a0, 0xffff, 0xffff };        /* bright turquoise */
1841 GdkColor        expert_color_warn       = { 0, 0xf7f7, 0xf2f2, 0x5353 };        /* yellow */
1842 GdkColor        expert_color_error      = { 0, 0xffff, 0x5c5c, 0x5c5c };        /* pale red */
1843 GdkColor        expert_color_foreground = { 0, 0x0000, 0x0000, 0x0000 };        /* black */
1844 GdkColor        hidden_proto_item       = { 0, 0x4444, 0x4444, 0x4444 };        /* gray */
1845
1846 gchar *expert_color_chat_str;
1847 gchar *expert_color_note_str;
1848 gchar *expert_color_warn_str;
1849 gchar *expert_color_error_str;
1850 gchar *expert_color_foreground_str;
1851
1852 void proto_draw_colors_init(void)
1853 {
1854     if(colors_ok) {
1855         return;
1856     }
1857 #if 0
1858         /* Allocating collor isn't necessary? */
1859     get_color(&expert_color_chat);
1860     get_color(&expert_color_note);
1861     get_color(&expert_color_warn);
1862     get_color(&expert_color_error);
1863     get_color(&expert_color_foreground);
1864 #endif
1865     expert_color_chat_str = gdk_color_to_string(&expert_color_chat);
1866     expert_color_note_str = gdk_color_to_string(&expert_color_note);
1867     expert_color_warn_str = gdk_color_to_string(&expert_color_warn);
1868     expert_color_error_str = gdk_color_to_string(&expert_color_error);
1869     expert_color_foreground_str = gdk_color_to_string(&expert_color_foreground);
1870
1871 #if 0
1872         get_color(&hidden_proto_item);
1873 #endif
1874     colors_ok = TRUE;
1875 }
1876
1877
1878 static void
1879 tree_cell_renderer(GtkTreeViewColumn *tree_column _U_, GtkCellRenderer *cell,
1880                    GtkTreeModel *tree_model, GtkTreeIter *iter,
1881                    gpointer data _U_)
1882 {
1883     field_info   *fi;
1884
1885     gtk_tree_model_get(tree_model, iter, 1, &fi, -1);
1886
1887     if(!colors_ok) {
1888         proto_draw_colors_init();
1889     }
1890
1891     /* for the various possible attributes, see:
1892      * http://developer.gnome.org/doc/API/2.0/gtk/GtkCellRendererText.html
1893      *
1894      * color definitions can be found at:
1895      * http://cvs.gnome.org/viewcvs/gtk+/gdk-pixbuf/io-xpm.c?rev=1.42
1896      * (a good color overview: http://www.computerhope.com/htmcolor.htm)
1897      *
1898      * some experiences:
1899      * background-gdk: doesn't seem to work (probably the GdkColor must be allocated)
1900      * weight/style: doesn't take any effect
1901      */
1902
1903     /* for each field, we have to reset the renderer attributes */
1904     g_object_set (cell, "foreground-set", FALSE, NULL);
1905
1906     g_object_set (cell, "background-set", FALSE, NULL);
1907
1908     g_object_set (cell, "underline", PANGO_UNDERLINE_NONE, NULL);
1909     g_object_set (cell, "underline-set", FALSE, NULL);
1910
1911     /*g_object_set (cell, "style", PANGO_STYLE_NORMAL, NULL);
1912     g_object_set (cell, "style-set", FALSE, NULL);*/
1913
1914     /*g_object_set (cell, "weight", PANGO_WEIGHT_NORMAL, NULL);
1915     g_object_set (cell, "weight-set", FALSE, NULL);*/
1916
1917     if(FI_GET_FLAG(fi, FI_GENERATED)) {
1918         /* we use "[...]" to mark generated items, no need to change things here */
1919
1920         /* as some fonts don't support italic, don't use this */
1921         /*g_object_set (cell, "style", PANGO_STYLE_ITALIC, NULL);
1922         g_object_set (cell, "style-set", TRUE, NULL);
1923         */
1924         /*g_object_set (cell, "weight", PANGO_WEIGHT_BOLD, NULL);
1925         g_object_set (cell, "weight-set", TRUE, NULL);*/
1926     }
1927
1928     if(FI_GET_FLAG(fi, FI_HIDDEN)) {
1929         g_object_set (cell, "foreground-gdk", &hidden_proto_item, NULL);
1930         g_object_set (cell, "foreground-set", TRUE, NULL);
1931     }
1932
1933     if (fi && fi->hfinfo) {
1934         if(fi->hfinfo->type == FT_PROTOCOL) {
1935             g_object_set (cell, "background", "gray90", NULL);
1936             g_object_set (cell, "background-set", TRUE, NULL);
1937             g_object_set (cell, "foreground", "black", NULL);
1938             g_object_set (cell, "foreground-set", TRUE, NULL);
1939             /*g_object_set (cell, "weight", PANGO_WEIGHT_BOLD, NULL);
1940             g_object_set (cell, "weight-set", TRUE, NULL);*/
1941         }
1942
1943         if((fi->hfinfo->type == FT_FRAMENUM) ||
1944            (FI_GET_FLAG(fi, FI_URL) && IS_FT_STRING(fi->hfinfo->type))) {
1945             render_as_url(cell);
1946         }
1947     }
1948
1949     if(FI_GET_FLAG(fi, PI_SEVERITY_MASK)) {
1950         switch(FI_GET_FLAG(fi, PI_SEVERITY_MASK)) {
1951         case(PI_CHAT):
1952             g_object_set (cell, "background-gdk", &expert_color_chat, NULL);
1953             g_object_set (cell, "background-set", TRUE, NULL);
1954             break;
1955         case(PI_NOTE):
1956             g_object_set (cell, "background-gdk", &expert_color_note, NULL);
1957             g_object_set (cell, "background-set", TRUE, NULL);
1958             break;
1959         case(PI_WARN):
1960             g_object_set (cell, "background-gdk", &expert_color_warn, NULL);
1961             g_object_set (cell, "background-set", TRUE, NULL);
1962             break;
1963         case(PI_ERROR):
1964             g_object_set (cell, "background-gdk", &expert_color_error, NULL);
1965             g_object_set (cell, "background-set", TRUE, NULL);
1966             break;
1967         default:
1968             g_assert_not_reached();
1969         }
1970         g_object_set (cell, "foreground", "black", NULL);
1971         g_object_set (cell, "foreground-set", TRUE, NULL);
1972     }
1973 }
1974
1975 GtkWidget *
1976 main_tree_view_new(e_prefs *prefs_p, GtkWidget **tree_view_p)
1977 {
1978     GtkWidget *tv_scrollw, *tree_view;
1979     GtkTreeStore *store;
1980     GtkCellRenderer *renderer;
1981     GtkTreeViewColumn *column;
1982     gint col_offset;
1983
1984     /* Tree view */
1985     tv_scrollw = scrolled_window_new(NULL, NULL);
1986     gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(tv_scrollw),
1987                                         GTK_SHADOW_IN);
1988
1989     store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
1990     tree_view = tree_view_new(GTK_TREE_MODEL(store));
1991     g_object_unref(G_OBJECT(store));
1992     gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_view), FALSE);
1993     renderer = gtk_cell_renderer_text_new();
1994     g_object_set (renderer, "ypad", 0, NULL);
1995     col_offset = gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(tree_view),
1996                                                              -1, "Name", renderer,
1997                                                              "text", 0, NULL);
1998     column = gtk_tree_view_get_column(GTK_TREE_VIEW(tree_view),
1999                                       col_offset - 1);
2000     gtk_tree_view_column_set_cell_data_func(column, renderer, tree_cell_renderer,
2001                                             NULL, NULL);
2002
2003     gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column),
2004                                     GTK_TREE_VIEW_COLUMN_AUTOSIZE);
2005     g_signal_connect(tree_view, "row-expanded", G_CALLBACK(expand_tree), NULL);
2006     g_signal_connect(tree_view, "row-collapsed", G_CALLBACK(collapse_tree), NULL);
2007     gtk_container_add( GTK_CONTAINER(tv_scrollw), tree_view );
2008     set_ptree_sel_browse(tree_view, prefs_p->gui_ptree_sel_browse);
2009 #if GTK_CHECK_VERSION(3,0,0)
2010     gtk_widget_override_font(tree_view, user_font_get_regular());
2011 #else
2012         gtk_widget_modify_font(tree_view, user_font_get_regular());
2013 #endif
2014     remember_ptree_widget(tree_view);
2015
2016     *tree_view_p = tree_view;
2017
2018     return tv_scrollw;
2019 }
2020
2021 void
2022 expand_all_tree(proto_tree *protocol_tree _U_, GtkWidget *tree_view)
2023 {
2024     int i;
2025     for(i=0; i < num_tree_types; i++) {
2026         tree_is_expanded[i] = TRUE;
2027     }
2028     gtk_tree_view_expand_all(GTK_TREE_VIEW(tree_view));
2029 }
2030
2031 void
2032 collapse_all_tree(proto_tree *protocol_tree _U_, GtkWidget *tree_view)
2033 {
2034     int i;
2035     for(i=0; i < num_tree_types; i++) {
2036         tree_is_expanded[i] = FALSE;
2037     }
2038     gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree_view));
2039 }
2040
2041
2042 struct proto_tree_draw_info {
2043     GtkTreeView  *tree_view;
2044     GtkTreeIter  *iter;
2045 };
2046
2047 void
2048 main_proto_tree_draw(proto_tree *protocol_tree)
2049 {
2050     proto_tree_draw(protocol_tree, tree_view_gbl);
2051 }
2052
2053
2054 static void
2055 tree_view_follow_link(field_info   *fi)
2056 {
2057     gchar *url;
2058
2059     if(fi->hfinfo->type == FT_FRAMENUM) {
2060         cf_goto_frame(&cfile, fi->value.value.uinteger);
2061     }
2062     if(FI_GET_FLAG(fi, FI_URL) && IS_FT_STRING(fi->hfinfo->type)) {
2063         url = fvalue_to_string_repr(&fi->value, FTREPR_DISPLAY, NULL);
2064         if(url){
2065             browser_open_url(url);
2066             g_free(url);
2067         }
2068     }
2069 }
2070
2071
2072 /* If the user selected a position in the tree view, try to find
2073  * the item in the GUI proto_tree that corresponds to that byte, and
2074  * select it. */
2075 gboolean
2076 tree_view_select(GtkWidget *widget, GdkEventButton *event)
2077 {
2078     GtkTreeSelection    *sel;
2079     GtkTreePath         *path;
2080
2081     if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget),
2082                                       (gint) (((GdkEventButton *)event)->x),
2083                                       (gint) (((GdkEventButton *)event)->y),
2084                                       &path, NULL, NULL, NULL))
2085     {
2086         sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
2087
2088         /* if that's a doubleclick, try to follow the link */
2089         if(event->type == GDK_2BUTTON_PRESS) {
2090             GtkTreeModel *model;
2091             GtkTreeIter iter;
2092             field_info   *fi;
2093
2094             if(gtk_tree_selection_get_selected (sel, &model, &iter)) {
2095                 gtk_tree_model_get(model, &iter, 1, &fi, -1);
2096                 tree_view_follow_link(fi);
2097             }
2098         }
2099         else if (((GdkEventButton *)event)->button != 1) {
2100             /* if button == 1 gtk_tree_selection_select_path is already (or will be) called by the widget */
2101             gtk_tree_selection_select_path(sel, path);
2102         }
2103     } else {
2104         return FALSE;
2105     }
2106     return TRUE;
2107 }
2108
2109 /* fill the whole protocol tree with the string values */
2110 void
2111 proto_tree_draw(proto_tree *protocol_tree, GtkWidget *tree_view)
2112 {
2113     GtkTreeStore *store;
2114     struct proto_tree_draw_info info;
2115
2116     info.tree_view = GTK_TREE_VIEW(tree_view);
2117     info.iter = NULL;
2118
2119     store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view)));
2120
2121     /*
2122      * Clear out any crud left over in the display of the protocol
2123      * tree, by removing all nodes from the tree.
2124      * This is how it's done in testgtk.c in GTK+.
2125      */
2126     gtk_tree_store_clear(store);
2127
2128     proto_tree_children_foreach(protocol_tree, proto_tree_draw_node, &info);
2129 }
2130
2131
2132 /* fill a single protocol tree item with the string value */
2133 static void
2134 proto_tree_draw_node(proto_node *node, gpointer data)
2135 {
2136     struct proto_tree_draw_info  info;
2137     struct proto_tree_draw_info *parent_info = (struct proto_tree_draw_info*) data;
2138
2139     field_info   *fi = PNODE_FINFO(node);
2140     gchar         label_str[ITEM_LABEL_LENGTH];
2141     gchar        *label_ptr;
2142     gboolean      is_leaf, is_expanded;
2143     GtkTreeStore *store;
2144     GtkTreeIter   iter;
2145     GtkTreePath  *path;
2146
2147     g_assert(fi && "dissection with an invisible proto tree?");
2148
2149     if (PROTO_ITEM_IS_HIDDEN(node) && !prefs.display_hidden_proto_items)
2150         return;
2151
2152     /* was a free format label produced? */
2153     if (fi->rep) {
2154         label_ptr = fi->rep->representation;
2155     }
2156     else { /* no, make a generic label */
2157         label_ptr = label_str;
2158         proto_item_fill_label(fi, label_str);
2159     }
2160
2161     if (node->first_child != NULL) {
2162         is_leaf = FALSE;
2163         g_assert(fi->tree_type >= 0 && fi->tree_type < num_tree_types);
2164         if (tree_is_expanded[fi->tree_type]) {
2165             is_expanded = TRUE;
2166         }
2167         else {
2168             is_expanded = FALSE;
2169         }
2170     }
2171     else {
2172         is_leaf = TRUE;
2173         is_expanded = FALSE;
2174     }
2175
2176     if (PROTO_ITEM_IS_GENERATED(node)) {
2177         if (PROTO_ITEM_IS_HIDDEN(node)) {
2178             label_ptr = g_strdup_printf("<[%s]>", label_ptr);
2179         } else {
2180             label_ptr = g_strdup_printf("[%s]", label_ptr);
2181         }
2182     } else if (PROTO_ITEM_IS_HIDDEN(node)) {
2183         label_ptr = g_strdup_printf("<%s>", label_ptr);
2184     }
2185
2186     info.tree_view = parent_info->tree_view;
2187     store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(info.tree_view)));
2188     gtk_tree_store_append(store, &iter, parent_info->iter);
2189     gtk_tree_store_set(store, &iter, 0, label_ptr, 1, fi, -1);
2190
2191     if (PROTO_ITEM_IS_GENERATED(node) || PROTO_ITEM_IS_HIDDEN(node)) {
2192         g_free(label_ptr);
2193     }
2194
2195     if (!is_leaf) {
2196         info.iter = &iter;
2197         proto_tree_children_foreach(node, proto_tree_draw_node, &info);
2198         path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
2199         if (is_expanded)
2200             gtk_tree_view_expand_to_path(info.tree_view, path);
2201         else
2202             gtk_tree_view_collapse_row(info.tree_view, path);
2203         gtk_tree_path_free(path);
2204     }
2205 }
2206
2207 /*
2208  * Clear the hex dump and protocol tree panes.
2209  */
2210 void
2211 clear_tree_and_hex_views(void)
2212 {
2213     /* Clear the hex dump by getting rid of all the byte views. */
2214     while (gtk_notebook_get_nth_page(GTK_NOTEBOOK(byte_nb_ptr_gbl), 0) != NULL)
2215         gtk_notebook_remove_page(GTK_NOTEBOOK(byte_nb_ptr_gbl), 0);
2216
2217     /* Add a placeholder byte view so that there's at least something
2218        displayed in the byte view notebook. */
2219     add_byte_tab(byte_nb_ptr_gbl, "", NULL, NULL, tree_view_gbl);
2220
2221     /* Clear the protocol tree by removing all nodes in the ctree.
2222        This is how it's done in testgtk.c in GTK+ */
2223     gtk_tree_store_clear(GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view_gbl))));
2224 }
2225
2226 void
2227 select_bytes_view (GtkWidget *w _U_, gpointer data _U_, gint view)
2228 {
2229     if (recent.gui_bytes_view != view) {
2230         recent.gui_bytes_view = view;
2231         redraw_packet_bytes_all();
2232     }
2233 }