First check for the new GTK+/OS X integration functions, then the old
[obnox/wireshark/wip.git] / gtk / packet_win.c
1 /* packet_win.c
2  * Routines for popping a window to display current packet
3  *
4  * Copyright 2000, Jeffrey C. Foster <jfoste@woodward.com>
5  *
6  * $Id$
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  *
26  * To do:
27  * - Add close button to bottom.
28  * - improve the window Title and allow user to config it
29  * - Add print support ? ( could be a mess)
30  * - Add button to have main window jump to this packet ?
31  */
32
33
34 #ifdef HAVE_CONFIG_H
35 # include "config.h"
36 #endif
37
38 #ifdef HAVE_SYS_TYPES_H
39 #include <sys/types.h>
40 #endif
41
42 #include <gtk/gtk.h>
43
44 #include <string.h>
45
46 #include <epan/epan.h>
47 #include <epan/timestamp.h>
48 #include <epan/packet.h>
49 #include <epan/prefs.h>
50 #include <epan/column.h>
51 #include <epan/addr_resolv.h>
52 #include <epan/plugins.h>
53 #include <epan/epan_dissect.h>
54 #include <epan/strutil.h>
55
56 #include "../file.h"
57 #include "../print.h"
58 #include "../simple_dialog.h"
59 #include "../ui_util.h"
60 #include "../summary.h"
61
62 #include "gtk/main.h"
63 #include "gtk/packet_win.h"
64 #include "gtk/main_proto_draw.h"
65 #include "gtk/keys.h"
66 #include "gtk/gtkglobals.h"
67 #include "gtk/gui_utils.h"
68
69
70 /* Data structure holding information about a packet-detail window. */
71 struct PacketWinData {
72         frame_data *frame;         /* The frame being displayed */
73         union wtap_pseudo_header pseudo_header; /* Pseudo-header for packet */
74         guint8     *pd;            /* Data for packet */
75         GtkWidget  *main;
76         GtkWidget  *tv_scrollw;
77         GtkWidget  *tree_view;
78         GtkWidget  *bv_nb_ptr;
79         field_info *finfo_selected;
80         epan_dissect_t  *edt;
81 };
82
83 /* List of all the packet-detail windows popped up. */
84 static GList *detail_windows;
85
86 static void new_tree_view_selection_changed_cb(GtkTreeSelection *sel,
87                                                gpointer user_data);
88
89
90 static void destroy_new_window(GtkObject *object, gpointer user_data);
91
92 static gint
93 button_press_handler(GtkWidget *widget, GdkEvent *event, gpointer data _U_)
94 {
95   if (widget == NULL || event == NULL) {
96     return FALSE;
97   }
98
99   tree_view_select(widget, (GdkEventButton *) event);
100
101   /* GDK_2BUTTON_PRESS is a doubleclick -> expand/collapse tree row */
102   if (event->type == GDK_2BUTTON_PRESS) {
103     GtkTreePath      *path;
104
105     if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget),
106                                       (gint) (((GdkEventButton *)event)->x),
107                                       (gint) (((GdkEventButton *)event)->y),
108                                       &path, NULL, NULL, NULL))
109     {
110       if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(widget), path)) {
111         gtk_tree_view_collapse_row(GTK_TREE_VIEW(widget), path);
112       } else {
113         gtk_tree_view_expand_row(GTK_TREE_VIEW(widget), path, FALSE);
114       }
115       gtk_tree_path_free(path);
116     }
117   }
118
119   return FALSE;
120 }
121
122 void new_window_cb(GtkWidget *w _U_)
123 {
124 #define NewWinTitleLen 1000
125   char Title[NewWinTitleLen] = "";
126   const char *TextPtr;
127   gint tv_size = 95, bv_size = 75;
128   GtkWidget *main_w, *main_vbox, *pane,
129                       *tree_view, *tv_scrollw,
130                       *bv_nb_ptr;
131   struct PacketWinData *DataPtr;
132   int i;
133
134 #ifdef NEW_PACKET_LIST
135   int err;
136   gchar *err_info;
137 #endif /* NEW_PACKET_LIST */
138
139   if (!cfile.current_frame) {
140     /* nothing has been captured so far */
141     return;
142   }
143
144 #ifdef NEW_PACKET_LIST
145
146   /* With the new packetlists "lazy columns" it's neccesary to reread the frame */
147   if (!cf_read_frame(&cfile, cfile.current_frame, &err, &err_info)) {
148             simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
149             cf_read_error_message(err, err_info), cfile.filename);
150             return;
151   }
152 #endif
153
154   /* Allocate data structure to represent this window. */
155   DataPtr = (struct PacketWinData *) g_malloc(sizeof(struct PacketWinData));
156
157   DataPtr->frame = cfile.current_frame;
158   memcpy(&DataPtr->pseudo_header, &cfile.pseudo_header, sizeof DataPtr->pseudo_header);
159   DataPtr->pd = g_malloc(DataPtr->frame->cap_len);
160   memcpy(DataPtr->pd, cfile.pd, DataPtr->frame->cap_len);
161   DataPtr->edt = epan_dissect_new(TRUE, TRUE);
162   epan_dissect_run(DataPtr->edt, &DataPtr->pseudo_header, DataPtr->pd,
163           DataPtr->frame, &cfile.cinfo);
164   epan_dissect_fill_in_columns(DataPtr->edt, FALSE, TRUE);
165
166   /*
167    * Build title of window by getting column data constructed when the
168    * frame was dissected.
169    */
170   for (i = 0; i < cfile.cinfo.num_cols; ++i) {
171     TextPtr = cfile.cinfo.col_data[i];
172     if ((strlen(Title) + strlen(TextPtr)) < NewWinTitleLen - 1) {
173       g_strlcat(Title, TextPtr, NewWinTitleLen);
174       g_strlcat(Title, " ", NewWinTitleLen);
175     }
176   }
177
178   main_w = window_new(GTK_WINDOW_TOPLEVEL, Title);
179   gtk_window_set_default_size(GTK_WINDOW(main_w), DEF_WIDTH, -1);
180
181   /* Container for paned windows  */
182   main_vbox = gtk_vbox_new(FALSE, 1);
183   gtk_container_set_border_width(GTK_CONTAINER(main_vbox), 1);
184   gtk_container_add(GTK_CONTAINER(main_w), main_vbox);
185   gtk_widget_show(main_vbox);
186
187   /* Panes for the tree and byte view */
188   pane = gtk_vpaned_new();
189   gtk_container_add(GTK_CONTAINER(main_vbox), pane);
190   gtk_widget_show(pane);
191
192   /* Tree view */
193   tv_scrollw = main_tree_view_new(&prefs, &tree_view);
194   gtk_paned_pack1(GTK_PANED(pane), tv_scrollw, TRUE, TRUE);
195   gtk_widget_set_size_request(tv_scrollw, -1, tv_size);
196   gtk_widget_show(tv_scrollw);
197   gtk_widget_show(tree_view);
198
199   /* Byte view */
200   bv_nb_ptr = byte_view_new();
201   gtk_paned_pack2(GTK_PANED(pane), bv_nb_ptr, FALSE, FALSE);
202   gtk_widget_set_size_request(bv_nb_ptr, -1, bv_size);
203   gtk_widget_show(bv_nb_ptr);
204
205   DataPtr->main = main_w;
206   DataPtr->tv_scrollw = tv_scrollw;
207   DataPtr->tree_view = tree_view;
208   DataPtr->bv_nb_ptr = bv_nb_ptr;
209   detail_windows = g_list_append(detail_windows, DataPtr);
210
211   /* load callback handlers */
212   g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)),
213                  "changed", G_CALLBACK(new_tree_view_selection_changed_cb), DataPtr);
214   g_signal_connect(tree_view, "button_press_event", G_CALLBACK(button_press_handler), NULL);
215   g_signal_connect(main_w, "destroy", G_CALLBACK(destroy_new_window), DataPtr);
216
217   /* draw the protocol tree & print hex data */
218   add_byte_views(DataPtr->edt, tree_view, DataPtr->bv_nb_ptr);
219   proto_tree_draw(DataPtr->edt->tree, tree_view);
220
221   DataPtr->finfo_selected = NULL;
222   gtk_widget_show(main_w);
223 }
224
225 static void
226 destroy_new_window(GtkObject *object _U_, gpointer user_data)
227 {
228   struct PacketWinData *DataPtr = user_data;
229
230   detail_windows = g_list_remove(detail_windows, DataPtr);
231   epan_dissect_free(DataPtr->edt);
232   g_free(DataPtr->pd);
233   g_free(DataPtr);
234 }
235
236 /* called when a tree row is (un)selected in the popup packet window */
237 static void
238 new_tree_view_selection_changed_cb(GtkTreeSelection *sel, gpointer user_data)
239 {
240     field_info   *finfo;
241     GtkWidget    *byte_view;
242     const guint8 *data;
243     guint         len;
244     GtkTreeModel *model;
245     GtkTreeIter   iter;
246
247     struct PacketWinData *DataPtr = (struct PacketWinData*)user_data;
248
249     /* if something is selected */
250     if (gtk_tree_selection_get_selected(sel, &model, &iter))
251     {
252         gtk_tree_model_get(model, &iter, 1, &finfo, -1);
253         if (!finfo) return;
254
255         set_notebook_page(DataPtr->bv_nb_ptr, finfo->ds_tvb);
256         byte_view = get_notebook_bv_ptr(DataPtr->bv_nb_ptr);
257         if (!byte_view) /* exit if no hex window to write in */
258             return;
259
260         data = get_byte_view_data_and_length(byte_view, &len);
261         if (data == NULL) {
262             data = DataPtr->pd;
263             len =  DataPtr->frame->cap_len;
264         }
265
266         DataPtr->finfo_selected = finfo;
267         packet_hex_print(byte_view, data, DataPtr->frame, finfo, len);
268     }
269     else
270     {
271         DataPtr->finfo_selected = NULL;
272
273         byte_view = get_notebook_bv_ptr(DataPtr->bv_nb_ptr);
274         if (!byte_view) /* exit if no hex window to write in */
275             return;
276
277         data = get_byte_view_data_and_length(byte_view, &len);
278         g_assert(data != NULL);
279         packet_hex_reprint(byte_view);
280     }
281 }
282
283 /* Functions called from elsewhere to act on all popup packet windows. */
284
285 /* Destroy all popup packet windows. */
286 void
287 destroy_packet_wins(void)
288 {
289         struct PacketWinData *DataPtr;
290
291         /* Destroying a packet window causes it to be removed from
292            the list of packet windows, so we can't do a "g_list_foreach()"
293            to go through the list of all packet windows and destroy them
294            as we find them; instead, as long as the list is non-empty,
295            we destroy the first window on the list. */
296         while (detail_windows != NULL) {
297                 DataPtr = (struct PacketWinData *)(detail_windows->data);
298                 window_destroy(DataPtr->main);
299         }
300 }
301
302 static void
303 redraw_packet_bytes_cb(gpointer data, gpointer user_data _U_)
304 {
305         struct PacketWinData *DataPtr = (struct PacketWinData *)data;
306
307         redraw_packet_bytes(DataPtr->bv_nb_ptr, DataPtr->frame, DataPtr->finfo_selected);
308 }
309
310 /* Redraw the packet bytes part of all the popup packet windows. */
311 void
312 redraw_packet_bytes_packet_wins(void)
313 {
314         g_list_foreach(detail_windows, redraw_packet_bytes_cb, NULL);
315 }