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