b9a45148cad0aad86938c321e8aa755b90661252
[obnox/wireshark/wip.git] / gtk / graph_analysis.c
1 /* graph_analysis.c
2  * Graphic Analysis addition for ethereal
3  *
4  * $Id$
5  *
6  * Copyright 2004, Verso Technologies Inc.
7  * By Alejandro Vaquero <alejandrovaquero@yahoo.com>
8  *
9  * based on rtp_analysis.c and io_stat
10  *
11  *
12  * Ethereal - Network traffic analyzer
13  * By Gerald Combs <gerald@ethereal.com>
14  * Copyright 1998 Gerald Combs
15  *
16  * This program is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License
18  * as published by the Free Software Foundation; either version 2
19  * of the License, or (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation,  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
29  */
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include "graph_analysis.h"
36
37 #include <epan/epan_dissect.h>
38
39 /* in /gtk ... */
40 #include <gtk/gtk.h>
41 #include "gtkglobals.h"
42
43 #include "dlg_utils.h"
44 #include "ui_util.h"
45 #include "main.h"
46 #include "compat_macros.h"
47 #include "../color.h"
48
49 #ifdef HAVE_UNISTD_H
50 #include <unistd.h>
51 #endif
52
53 /****************************************************************************/
54
55
56 #define OK_TEXT "[ Ok ]"
57 #define PT_UNDEFINED -1
58
59
60 #if GTK_MAJOR_VERSION < 2
61 GtkRcStyle *rc_style;
62 GdkColormap *colormap;
63 #endif
64
65 /****************************************************************************/
66 /* Reset the user_data structure */
67 static void graph_analysis_reset(graph_analysis_data_t* user_data)
68 {
69         int i;
70
71         user_data->num_nodes = 0;
72         user_data->num_items = 0;
73         for (i=0; i<MAX_NUM_NODES; i++){
74                 user_data->nodes[i] = 0;
75         }
76         
77         user_data->dlg.first_node=0;
78         user_data->dlg.first_item=0;
79         user_data->dlg.left_x_border=0;
80         user_data->dlg.selected_item=0xFFFFFFFF;    /*not item selected */
81 }
82
83 /****************************************************************************/
84 /* Reset the user_data structure */
85 static void graph_analysis_init_dlg(graph_analysis_data_t* user_data)
86 {
87     /* init dialog_graph */
88     user_data->dlg.needs_redraw=TRUE;
89     user_data->dlg.draw_area=NULL;
90     user_data->dlg.pixmap=NULL;
91     user_data->dlg.h_scrollbar=NULL;
92     user_data->dlg.h_scrollbar_adjustment=NULL;
93     user_data->dlg.v_scrollbar=NULL;
94     user_data->dlg.v_scrollbar_adjustment=NULL;
95     user_data->dlg.pixmap_width=600;
96     user_data->dlg.pixmap_height=400;
97         user_data->dlg.first_node=0;
98         user_data->dlg.first_item=0;
99         user_data->dlg.left_x_border=0;
100         user_data->dlg.selected_item=0xFFFFFFFF;    /*not item selected */
101         user_data->dlg.window=NULL;
102 }
103
104 /****************************************************************************/
105 /* CALLBACKS */
106
107
108 /****************************************************************************/
109 /* close the dialog window and remove the tap listener */
110 static void on_destroy(GtkWidget *win _U_, graph_analysis_data_t *user_data _U_)
111 {
112
113         g_free(user_data);
114 }
115
116
117 /****************************************************************************/
118 static void dialog_graph_set_title(graph_analysis_data_t* user_data)
119 {
120         char            *title;
121         if (!user_data->dlg.window){
122                 return;
123         }
124         title = g_strdup_printf("Ale");
125
126         gtk_window_set_title(GTK_WINDOW(user_data->dlg.window), title);
127         g_free(title);  
128 }
129
130 #define RIGHT_ARROW 1
131 #define LEFT_ARROW 0
132 #define WIDTH_ARROW 8
133 #define HEIGHT_ARROW 6
134
135 /****************************************************************************/
136 static void draw_arrow(GdkDrawable *pixmap, GdkGC *gc, gint x, gint y, gboolean direction)
137 {
138         GdkPoint arrow_point[3];
139
140         arrow_point[0].x = x;
141         arrow_point[0].y = y-HEIGHT_ARROW/2;
142         if (direction == RIGHT_ARROW)
143                 arrow_point[1].x = x+WIDTH_ARROW;
144         else
145                 arrow_point[1].x = x-WIDTH_ARROW;
146         arrow_point[1].y = y;
147         arrow_point[2].x = x;
148         arrow_point[2].y = y+HEIGHT_ARROW/2;;
149
150         gdk_draw_polygon(pixmap, gc, TRUE, 
151                 arrow_point, 3);
152 }
153
154 #define MAX_LABEL 50
155 #define MAX_COMMENT 60
156 #define ITEM_HEIGHT 20
157 #define NODE_WIDTH 100
158 #define TOP_Y_BORDER 40
159 #define BOTTOM_Y_BORDER 0
160 #define COMMENT_WIDTH 250
161
162 /****************************************************************************/
163 static void dialog_graph_draw(graph_analysis_data_t* user_data)
164 {
165         guint32 i, last_item, first_item, last_node, first_node, display_items, display_nodes;
166                 guint32 start_arrow, end_arrow, label_x, src_port_x, dst_port_x, arrow_width;
167         guint32 current_item;
168         guint32 left_x_border;
169         guint32 right_x_border;
170         guint32 top_y_border;
171         guint32 bottom_y_border;
172                 graph_analysis_item_t *gai;
173                 gboolean display_label;
174
175 #if GTK_MAJOR_VERSION < 2
176         GdkFont *font;
177                 FONT_TYPE *big_font;
178                 FONT_TYPE *small_font;
179 #else
180         PangoLayout  *layout;
181         PangoLayout  *big_layout;
182         PangoLayout  *small_layout;
183 #endif
184         guint32 label_width, label_height;
185         guint32 draw_width, draw_height;
186         char label_string[MAX_COMMENT];
187                 GList* list;
188
189         /* new variables */
190
191 #if GTK_MAJOR_VERSION <2
192         font = user_data->dlg.draw_area->style->font;
193                 big_font = gdk_font_load("-adobe-helvetica-bold-r-normal--12-120-75-75-p-70-iso8859-1");
194                 small_font = gdk_font_load("-adobe-helvetica-bold-r-normal--10-120-75-75-p-70-iso8859-1");
195 #endif
196         if(!user_data->dlg.needs_redraw){
197                 return;
198         }
199         user_data->dlg.needs_redraw=FALSE;
200
201         /*
202          * Clear out old plot
203          */
204         gdk_draw_rectangle(user_data->dlg.pixmap,
205                            user_data->dlg.draw_area->style->white_gc,
206                            TRUE,
207                            0, 0,
208                            user_data->dlg.draw_area->allocation.width,
209                            user_data->dlg.draw_area->allocation.height);
210
211                 /* Calculate the y border */
212         top_y_border=TOP_Y_BORDER;      /* to display the node IP address */
213         bottom_y_border=BOTTOM_Y_BORDER;
214
215         draw_height=user_data->dlg.pixmap_height-top_y_border-bottom_y_border;
216
217                 first_item = user_data->dlg.first_item;
218                 display_items = draw_height/ITEM_HEIGHT;
219                 last_item = first_item+display_items-1;
220
221                 /* get the items to display and fill the matrix array */
222                 list = g_list_first(user_data->graph_info->list);
223                 current_item = 0;
224                 i = 0;
225                 while (list)
226                 {
227                         gai = list->data;
228                         if (gai->display){
229                                 if (current_item>=display_items) break;         /* the item is outside the display */
230                                 if (i>=first_item){
231                                         user_data->dlg.items[current_item].frame_num = gai->frame_num;
232                                         user_data->dlg.items[current_item].time = gai->time;
233                                         user_data->dlg.items[current_item].port_src = gai->port_src;
234                                         user_data->dlg.items[current_item].port_dst = gai->port_dst;
235                                         /* Add "..." if the length is 50 characters */
236                                         if (strlen(gai->frame_label) > 48) {
237                                                 gai->frame_label[48] = '.';
238                                                 gai->frame_label[47] = '.';
239                                                 gai->frame_label[46] = '.';
240                                         }
241                                         user_data->dlg.items[current_item].frame_label = gai->frame_label;
242                                         user_data->dlg.items[current_item].comment = gai->comment;
243                                         user_data->dlg.items[current_item].conv_num = gai->conv_num;
244                                         user_data->dlg.items[current_item].src_node = gai->src_node;
245                                         user_data->dlg.items[current_item].dst_node = gai->dst_node;
246                                         user_data->dlg.items[current_item].line_style = gai->line_style;
247                                         current_item++;
248                                 }
249                                 i++;
250                         }
251
252                         list = g_list_next(list);
253                 }
254                 /* in case the windows is resized so we have to move the top item */
255                 if ((first_item + display_items) > user_data->num_items){
256                         if (display_items>user_data->num_items)
257                                 first_item=0;
258                         else
259                                 first_item = user_data->num_items - display_items;
260                 }
261                 
262                 /* in case there are less items than possible displayed */
263                 display_items = current_item;
264                 last_item = first_item+display_items-1;
265
266                 /* if not items to display */
267                 if (display_items == 0) return;                         
268
269
270                 /* Calculate the x borders */
271                 /* We use time from the last display item to calcultate the x left border */
272                 g_snprintf(label_string, MAX_LABEL, "%.3f", user_data->dlg.items[display_items-1].time);
273 #if GTK_MAJOR_VERSION < 2
274         label_width=gdk_string_width(font, label_string);
275         label_height=gdk_string_height(font, label_string);
276 #else
277         layout = gtk_widget_create_pango_layout(user_data->dlg.draw_area, label_string);
278         big_layout = gtk_widget_create_pango_layout(user_data->dlg.draw_area, label_string);
279         small_layout = gtk_widget_create_pango_layout(user_data->dlg.draw_area, label_string);
280
281                 pango_layout_set_font_description(big_layout, pango_font_description_from_string("Helvetica-Bold 8"));
282                 pango_layout_set_font_description(small_layout, pango_font_description_from_string("Helvetica-Bold 7"));
283
284         pango_layout_get_pixel_size(layout, &label_width, &label_height);
285 #endif
286         left_x_border=label_width+10;
287                 user_data->dlg.left_x_border = left_x_border;
288
289         right_x_border=COMMENT_WIDTH;
290
291                 /* Calculate the number of nodes to display */
292         draw_width=user_data->dlg.pixmap_width-right_x_border-left_x_border;
293                 display_nodes = draw_width/NODE_WIDTH;
294                 first_node = user_data->dlg.first_node;
295
296                 /* in case the windows is resized so we have to move the left node */
297                 if ((first_node + display_nodes) > user_data->num_nodes){
298                         if (display_nodes>user_data->num_nodes) 
299                                 first_node=0;
300                         else
301                                 first_node=user_data->num_nodes - display_nodes;
302                 }
303
304                 /* in case there are less nodes than possible displayed */
305                 if (display_nodes>user_data->num_nodes) display_nodes=user_data->num_nodes;
306
307                 last_node = first_node + display_nodes-1;
308
309                 /* Paint the background items */ 
310                 for (current_item=0; current_item<display_items; current_item++){
311                         /* Paint background */
312                 gdk_draw_rectangle(user_data->dlg.pixmap,
313                            user_data->dlg.bg_gc[user_data->dlg.items[current_item].conv_num%MAX_NUM_COL_CONV],
314                            TRUE,
315                            left_x_border, 
316                                                    top_y_border+current_item*ITEM_HEIGHT,
317                            draw_width,
318                            ITEM_HEIGHT);
319                 }
320
321
322                 /* Draw the node names on top and the division lines */
323                 for (i=0; i<display_nodes; i++){
324                         /* draw the node IPs */
325                         g_snprintf(label_string, MAX_LABEL, "%s",
326                                 ip_to_str((guint8 *)&(user_data->nodes[i+first_node])));
327 #if GTK_MAJOR_VERSION < 2
328                 label_width=gdk_string_width(font, label_string);
329                 label_height=gdk_string_height(font, label_string);
330                         gdk_draw_string(user_data->dlg.pixmap,
331                 font,
332                 user_data->dlg.draw_area->style->black_gc,
333                 left_x_border+NODE_WIDTH/2-label_width/2+NODE_WIDTH*i,
334                 top_y_border/2-label_height/2,
335                 label_string);
336 #else
337                         pango_layout_set_text(layout, label_string, -1);
338                 pango_layout_get_pixel_size(layout, &label_width, &label_height);
339                 gdk_draw_layout(user_data->dlg.pixmap,
340                 user_data->dlg.draw_area->style->black_gc,
341                 left_x_border+NODE_WIDTH/2-label_width/2+NODE_WIDTH*i,
342                 top_y_border/2-label_height/2,
343                 layout);
344 #endif          
345
346                         /* draw the node division lines */
347                         gdk_draw_line(user_data->dlg.pixmap, user_data->dlg.div_line_gc,
348                                 left_x_border+NODE_WIDTH/2+NODE_WIDTH*i,
349                                 top_y_border,
350                                 left_x_border+NODE_WIDTH/2+NODE_WIDTH*i,
351                                 user_data->dlg.pixmap_height-bottom_y_border);
352
353                 }
354
355                 /*
356                  * Draw the items 
357                  */
358
359
360                 for (current_item=0; current_item<display_items; current_item++){
361                         /* draw the time */
362                         g_snprintf(label_string, MAX_LABEL, "%.3f", user_data->dlg.items[current_item].time);
363 #if GTK_MAJOR_VERSION < 2
364                 label_width=gdk_string_width(font, label_string);
365                 label_height=gdk_string_height(font, label_string);
366                         gdk_draw_string(user_data->dlg.pixmap,
367                 font,
368                 user_data->dlg.draw_area->style->black_gc,
369                 left_x_border-label_width-4,
370                 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT/2+label_height/4,
371                 label_string);
372 #else
373                         pango_layout_set_text(layout, label_string, -1);
374                 pango_layout_get_pixel_size(layout, &label_width, &label_height);
375                 gdk_draw_layout(user_data->dlg.pixmap,
376                 user_data->dlg.draw_area->style->black_gc,
377                 left_x_border-label_width-4,
378                 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT/2-label_height/2,
379                 layout);
380 #endif
381
382                         /*draw the comments */
383                         g_snprintf(label_string, MAX_COMMENT, "%s", user_data->dlg.items[current_item].comment);
384 #if GTK_MAJOR_VERSION < 2
385                         label_width=gdk_string_width(small_font, label_string);
386                         label_height=gdk_string_height(small_font, label_string);
387                         gdk_draw_string(user_data->dlg.pixmap,
388                 small_font,
389                 user_data->dlg.draw_area->style->black_gc,
390                 user_data->dlg.pixmap_width-right_x_border+3,
391                 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT/2+label_height/4,
392                 label_string);
393 #else
394                         pango_layout_set_text(small_layout, label_string, -1);
395                         pango_layout_get_pixel_size(small_layout, &label_width, &label_height);
396                 gdk_draw_layout(user_data->dlg.pixmap,
397                 user_data->dlg.draw_area->style->black_gc,
398                 user_data->dlg.pixmap_width-right_x_border+3,
399                 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT/2-label_height/2,
400                 small_layout);
401 #endif
402                         
403                         /* draw the arrow an frame label*/
404                         display_label = FALSE;
405                         if (user_data->dlg.items[current_item].src_node>=first_node){
406                                 if (user_data->dlg.items[current_item].src_node<=last_node){
407                                         start_arrow = left_x_border+(user_data->dlg.items[current_item].src_node-first_node)*NODE_WIDTH+NODE_WIDTH/2;
408                                         display_label = TRUE;
409                                 } else {
410                                         start_arrow = user_data->dlg.pixmap_width - right_x_border;
411                                 }
412                         } else {
413                                 start_arrow = left_x_border;
414                         }
415
416                         if (user_data->dlg.items[current_item].dst_node>=first_node){
417                                 if (user_data->dlg.items[current_item].dst_node<=last_node){
418                                         end_arrow = left_x_border+(user_data->dlg.items[current_item].dst_node-first_node)*NODE_WIDTH+NODE_WIDTH/2;
419                                         display_label = TRUE;
420                                 } else {
421                                         end_arrow = user_data->dlg.pixmap_width - right_x_border;
422                                 }
423                         } else {
424                                 end_arrow = left_x_border;
425                         }
426
427                         if (start_arrow != end_arrow){
428                                 /* draw the arrow line */
429                                 gdk_draw_line(user_data->dlg.pixmap, user_data->dlg.draw_area->style->black_gc,
430                                         start_arrow,
431                                         top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-7,
432                                         end_arrow,
433                                         top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-7);
434
435                                 /* draw the additional line when line style is 2 pixels width */
436                                 if (user_data->dlg.items[current_item].line_style == 2){
437                                         gdk_draw_line(user_data->dlg.pixmap, user_data->dlg.draw_area->style->black_gc,
438                                                 start_arrow,
439                                                 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-6,
440                                                 end_arrow,
441                                                 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-6);
442                                 }                                       
443
444                                 /* draw the arrow */
445                                 if (start_arrow<end_arrow)
446                                         draw_arrow(user_data->dlg.pixmap, user_data->dlg.draw_area->style->black_gc, end_arrow-WIDTH_ARROW,top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-7, RIGHT_ARROW);
447                                 else
448                                         draw_arrow(user_data->dlg.pixmap, user_data->dlg.draw_area->style->black_gc, end_arrow+WIDTH_ARROW,top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-7, LEFT_ARROW);
449                         }
450
451                         /* draw the frame comment */
452                         if (display_label){
453                                 g_snprintf(label_string, MAX_LABEL, "%s", user_data->dlg.items[current_item].frame_label);
454 #if GTK_MAJOR_VERSION < 2
455                                 label_width=gdk_string_width(big_font, label_string);
456                                 label_height=gdk_string_height(big_font, label_string);
457 #else
458                                 pango_layout_set_text(big_layout, label_string, -1);
459                                 pango_layout_get_pixel_size(big_layout, &label_width, &label_height);
460 #endif
461
462                                 if (start_arrow<end_arrow){
463                                         arrow_width = end_arrow-start_arrow;
464                                         label_x = arrow_width/2+start_arrow;
465                                 }
466                                 else {
467                                         arrow_width = start_arrow-end_arrow;
468                                         label_x = arrow_width/2+end_arrow;
469                                 }
470
471                                 if (label_width>arrow_width) arrow_width = label_width;
472
473                                 if (left_x_border > (label_x-label_width/2)) label_x = left_x_border + label_width/2;
474
475                                 if ((user_data->dlg.pixmap_width - right_x_border) < (label_x+label_width/2)) label_x = user_data->dlg.pixmap_width - right_x_border - label_width/2;
476
477 #if GTK_MAJOR_VERSION < 2
478                                 gdk_draw_string(user_data->dlg.pixmap,
479                                         big_font,
480                                         user_data->dlg.draw_area->style->black_gc,
481                                         label_x - label_width/2,
482                                         top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT/2+label_height/4-3,
483                                         label_string);
484 #else
485                                 gdk_draw_layout(user_data->dlg.pixmap,
486                                         user_data->dlg.draw_area->style->black_gc,
487                                         label_x - label_width/2,
488                                         top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT/2-label_height/2-3,
489                                         big_layout);
490 #endif
491
492                                 /* draw the source port number */
493                                 if ((start_arrow != left_x_border) && (start_arrow != (user_data->dlg.pixmap_width - right_x_border))){ 
494                                         g_snprintf(label_string, MAX_LABEL, "(%i)", user_data->dlg.items[current_item].port_src);
495 #if GTK_MAJOR_VERSION < 2
496                                         label_width=gdk_string_width(small_font, label_string);
497                                         label_height=gdk_string_height(small_font, label_string);
498 #else
499                                         pango_layout_set_text(small_layout, label_string, -1);
500                                         pango_layout_get_pixel_size(small_layout, &label_width, &label_height);
501 #endif
502                                         if (start_arrow<end_arrow){
503                                                 src_port_x = start_arrow - label_width - 2;
504                                         }
505                                         else {
506                                                 src_port_x = start_arrow + 2;
507                                         }
508 #if GTK_MAJOR_VERSION < 2
509                                         gdk_draw_string(user_data->dlg.pixmap,
510                                                 small_font,
511                                                 user_data->dlg.div_line_gc,
512                                                 src_port_x,
513                                                 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-2+label_height/4-2,
514                                                 label_string);
515 #else
516                                         gdk_draw_layout(user_data->dlg.pixmap,
517                                                 user_data->dlg.div_line_gc,
518                                                 src_port_x,
519                                                 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-2-label_height/2-2,
520                                                 small_layout);
521 #endif
522                                 }
523
524                                 /* draw the destination port number */
525                                 if ((end_arrow != left_x_border) && (end_arrow != (user_data->dlg.pixmap_width - right_x_border))){ 
526                                         g_snprintf(label_string, MAX_LABEL, "(%i)", user_data->dlg.items[current_item].port_dst);
527 #if GTK_MAJOR_VERSION < 2
528                                         label_width=gdk_string_width(small_font, label_string);
529                                         label_height=gdk_string_height(small_font, label_string);
530 #else
531                                         pango_layout_set_text(small_layout, label_string, -1);
532                                         pango_layout_get_pixel_size(small_layout, &label_width, &label_height);
533 #endif
534                                         if (start_arrow<end_arrow){
535                                                 dst_port_x = end_arrow + 2;
536                                         }
537                                         else {
538                                                 dst_port_x = end_arrow - label_width - 2;
539                                         }
540 #if GTK_MAJOR_VERSION < 2
541                                         gdk_draw_string(user_data->dlg.pixmap,
542                                                 small_font,
543                                                 user_data->dlg.div_line_gc,
544                                                 dst_port_x,
545                                                 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-2+label_height/4-2,
546                                                 label_string);
547 #else
548                                         gdk_draw_layout(user_data->dlg.pixmap,
549                                                 user_data->dlg.div_line_gc,
550                                                 dst_port_x,
551                                                 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-2-label_height/2-2,
552                                                 small_layout);
553 #endif
554                                 }
555
556                         }
557                 }
558
559 #if GTK_MAJOR_VERSION >= 2
560         g_object_unref(G_OBJECT(layout));
561 #endif
562
563                 /* draw the border on the selected item */
564                 if ( (user_data->dlg.selected_item != 0xFFFFFFFF) && ( (user_data->dlg.selected_item>=first_item) && (user_data->dlg.selected_item<=last_item) )){
565                         gdk_draw_rectangle(user_data->dlg.pixmap, user_data->dlg.draw_area->style->black_gc,
566                                 FALSE,
567                                 left_x_border-1,
568                                 (user_data->dlg.selected_item-first_item)*ITEM_HEIGHT+TOP_Y_BORDER,
569                                 user_data->dlg.pixmap_width-COMMENT_WIDTH-left_x_border+1,
570                                 ITEM_HEIGHT);
571                 }
572
573
574
575         gdk_draw_pixmap(user_data->dlg.draw_area->window,
576                         user_data->dlg.draw_area->style->fg_gc[GTK_WIDGET_STATE(user_data->dlg.draw_area)],
577                         user_data->dlg.pixmap,
578                         0, 0,
579                         0, 0,
580                         user_data->dlg.pixmap_width, user_data->dlg.pixmap_height);
581
582
583         /* update the h_scrollbar */
584         user_data->dlg.h_scrollbar_adjustment->upper=(gfloat) user_data->num_nodes-1;
585         user_data->dlg.h_scrollbar_adjustment->step_increment=1;
586         user_data->dlg.h_scrollbar_adjustment->page_increment=(gfloat) (last_node-first_node);
587         user_data->dlg.h_scrollbar_adjustment->page_size=(gfloat) (last_node-first_node);
588         user_data->dlg.h_scrollbar_adjustment->value=(gfloat) first_node;
589
590                 gtk_adjustment_changed(user_data->dlg.h_scrollbar_adjustment);
591         gtk_adjustment_value_changed(user_data->dlg.h_scrollbar_adjustment);
592
593         /* update the v_scrollbar */
594         user_data->dlg.v_scrollbar_adjustment->upper=(gfloat) user_data->num_items-1;
595         user_data->dlg.v_scrollbar_adjustment->step_increment=1;
596         user_data->dlg.v_scrollbar_adjustment->page_increment=(gfloat) (last_item-first_item);
597         user_data->dlg.v_scrollbar_adjustment->page_size=(gfloat) (last_item-first_item);
598         user_data->dlg.v_scrollbar_adjustment->value=(gfloat) first_item;
599
600                 gtk_adjustment_changed(user_data->dlg.v_scrollbar_adjustment);
601         gtk_adjustment_value_changed(user_data->dlg.v_scrollbar_adjustment);
602
603 }
604
605 /****************************************************************************/
606 static void dialog_graph_redraw(graph_analysis_data_t* user_data)
607 {
608         user_data->dlg.needs_redraw=TRUE;
609         dialog_graph_draw(user_data); 
610 }
611
612 /****************************************************************************/
613 static gint quit(GtkWidget *widget, GdkEventExpose *event _U_)
614 {
615         graph_analysis_data_t *user_data;
616
617         user_data=(graph_analysis_data_t *)OBJECT_GET_DATA(widget, "graph_analysis_data_t");
618
619                 user_data->dlg.window = NULL;
620
621                 user_data = NULL;
622         return TRUE;
623 }
624
625 /****************************************************************************/
626 static gint button_press_event(GtkWidget *widget, GdkEventButton *event _U_)
627 {
628         graph_analysis_data_t *user_data;
629                 guint32 item;
630
631         user_data=(graph_analysis_data_t *)OBJECT_GET_DATA(widget, "graph_analysis_data_t");
632
633                 if (event->type != GDK_BUTTON_PRESS) return TRUE;
634
635                 if (event->y<TOP_Y_BORDER) return TRUE;
636
637                 /* get the item clicked */
638                 item = ((guint32)event->y - TOP_Y_BORDER) / ITEM_HEIGHT;
639                 user_data->dlg.selected_item = item + user_data->dlg.first_item;
640
641                 user_data->dlg.needs_redraw=TRUE;
642                 dialog_graph_draw(user_data);
643
644                 cf_goto_frame(&cfile, user_data->dlg.items[item].frame_num);
645
646         return TRUE;
647 }
648
649 /****************************************************************************/
650 static gint expose_event(GtkWidget *widget, GdkEventExpose *event)
651 {
652         graph_analysis_data_t *user_data;
653
654         user_data=(graph_analysis_data_t *)OBJECT_GET_DATA(widget, "graph_analysis_data_t");
655         if(!user_data){
656                 exit(10);
657         }
658
659
660         gdk_draw_pixmap(widget->window,
661                         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
662                         user_data->dlg.pixmap,
663                         event->area.x, event->area.y,
664                         event->area.x, event->area.y,
665                         event->area.width, event->area.height);
666
667         return FALSE;
668 }
669
670 static const GdkColor COLOR_GRAY = {0, 0x7fff, 0x7fff, 0x7fff};
671
672 /****************************************************************************/
673 static gint configure_event(GtkWidget *widget, GdkEventConfigure *event _U_)
674 {
675         graph_analysis_data_t *user_data;
676                 int i;
677                 GdkColor color_div_line = COLOR_GRAY;
678
679                 static GdkColor col[MAX_NUM_COL_CONV] = {
680                 {0,     0x00FF, 0xFFFF, 0x00FF},
681                 {0,     0xFFFF, 0xFFFF, 0x00FF},
682                 {0,     0xFFFF, 0x00FF, 0x00FF},
683                 {0,     0xFFFF, 0x00FF, 0xFFFF},
684                         {0,     0x00FF, 0x00FF, 0xFFFF},
685                         {0,     0x00FF, 0xFFFF, 0xFFFF},
686                         {0,     0xFFFF, 0x80FF, 0x00FF},
687                         {0,     0x80FF, 0x00FF, 0xFFFF},
688                         {0,     0x00FF, 0x80FF, 0xFFFF},
689                         {0,     0xFFFF, 0x00FF, 0x80FF}
690                 };
691
692         user_data=(graph_analysis_data_t *)OBJECT_GET_DATA(widget, "graph_analysis_data_t");
693
694         if(!user_data){
695                 exit(10);
696         }
697
698         if(user_data->dlg.pixmap){
699                 gdk_pixmap_unref(user_data->dlg.pixmap);
700                 user_data->dlg.pixmap=NULL;
701         }
702
703         user_data->dlg.pixmap=gdk_pixmap_new(widget->window,
704                         widget->allocation.width,
705                         widget->allocation.height,
706                         -1);
707         user_data->dlg.pixmap_width=widget->allocation.width;
708         user_data->dlg.pixmap_height=widget->allocation.height;
709
710         gdk_draw_rectangle(user_data->dlg.pixmap,
711                         widget->style->white_gc,
712                         TRUE,
713                         0, 0,
714                         widget->allocation.width,
715                         widget->allocation.height);
716
717                 /* create gc for division lines and set the line stype to dash*/
718                 user_data->dlg.div_line_gc=gdk_gc_new(user_data->dlg.pixmap);
719                 gdk_gc_set_line_attributes(user_data->dlg.div_line_gc, 1, GDK_LINE_ON_OFF_DASH, 0, 0);
720 #if GTK_MAJOR_VERSION < 2
721         colormap = gtk_widget_get_colormap (widget);
722         if (!gdk_color_alloc (colormap, &color_div_line)){
723                      g_warning ("Couldn't allocate color");
724         }
725         gdk_gc_set_foreground(user_data->dlg.div_line_gc, &color_div_line);
726 #else
727         gdk_gc_set_rgb_fg_color(user_data->dlg.div_line_gc, &color_div_line);
728 #endif
729         
730                 /* create gcs for the background items */
731
732                 for (i=0; i<MAX_NUM_COL_CONV; i++){
733                         user_data->dlg.bg_gc[i]=gdk_gc_new(user_data->dlg.pixmap);
734 #if GTK_MAJOR_VERSION < 2
735                         colormap = gtk_widget_get_colormap (widget);
736                         if (!gdk_color_alloc (colormap, &col[i])){
737                                                  g_warning ("Couldn't allocate color");
738                         }
739                         gdk_gc_set_foreground(user_data->dlg.bg_gc[i], &col[i]);
740 #else
741                 gdk_gc_set_rgb_fg_color(user_data->dlg.bg_gc[i], &col[i]);
742 #endif
743                 }
744
745         dialog_graph_redraw(user_data);
746         return TRUE;
747 }
748
749 /****************************************************************************/
750 static gint h_scrollbar_changed(GtkWidget *widget _U_, gpointer data)
751 {
752     graph_analysis_data_t *user_data=(graph_analysis_data_t *)data;
753
754         if ((user_data->dlg.first_node+user_data->dlg.h_scrollbar_adjustment->page_size+1 == user_data->num_nodes) 
755                 && (user_data->dlg.h_scrollbar_adjustment->value >= user_data->dlg.first_node ))
756                 return TRUE;
757
758         if (user_data->dlg.first_node == (guint16) user_data->dlg.h_scrollbar_adjustment->value)
759                 return TRUE;
760
761     user_data->dlg.first_node = (guint16) user_data->dlg.h_scrollbar_adjustment->value;
762
763         dialog_graph_redraw(user_data);
764     return TRUE;
765 }
766
767 /****************************************************************************/
768 static gint v_scrollbar_changed(GtkWidget *widget _U_, gpointer data)
769 {
770     graph_analysis_data_t *user_data=(graph_analysis_data_t *)data;
771         if ((user_data->dlg.first_item+user_data->dlg.v_scrollbar_adjustment->page_size+1 == user_data->num_items) 
772                 && (user_data->dlg.v_scrollbar_adjustment->value >= user_data->dlg.first_item ))
773                 return TRUE;
774
775         if (user_data->dlg.first_item == user_data->dlg.v_scrollbar_adjustment->value)
776                 return TRUE;
777                 
778     user_data->dlg.first_item = (guint32) user_data->dlg.v_scrollbar_adjustment->value;
779
780         dialog_graph_redraw(user_data);
781     return TRUE;
782 }
783
784 /****************************************************************************/
785 static void create_draw_area(graph_analysis_data_t* user_data, GtkWidget *box)
786 {
787             GtkWidget *vbox;
788         GtkWidget *hbox;
789
790         hbox=gtk_hbox_new(FALSE, 0);
791         gtk_widget_show(hbox);
792
793         vbox=gtk_vbox_new(FALSE, 0);
794         gtk_widget_show(vbox);
795
796
797         user_data->dlg.draw_area=gtk_drawing_area_new();
798         SIGNAL_CONNECT(user_data->dlg.draw_area, "destroy", quit, user_data);
799         OBJECT_SET_DATA(user_data->dlg.draw_area, "graph_analysis_data_t", user_data);
800
801         WIDGET_SET_SIZE(user_data->dlg.draw_area, user_data->dlg.pixmap_width, user_data->dlg.pixmap_height);
802
803         /* signals needed to handle backing pixmap */
804         SIGNAL_CONNECT(user_data->dlg.draw_area, "expose_event", expose_event, NULL);
805         SIGNAL_CONNECT(user_data->dlg.draw_area, "configure_event", configure_event, user_data);
806
807                 gtk_widget_add_events (user_data->dlg.draw_area,
808                          GDK_BUTTON_PRESS_MASK);
809                 SIGNAL_CONNECT(user_data->dlg.draw_area, "button_press_event", button_press_event, user_data);
810
811         gtk_widget_show(user_data->dlg.draw_area);
812         gtk_box_pack_start(GTK_BOX(vbox), user_data->dlg.draw_area, TRUE, TRUE, 0);
813
814         /* create the associated h_scrollbar */
815         user_data->dlg.h_scrollbar_adjustment=(GtkAdjustment *)gtk_adjustment_new(0,0,0,0,0,0);
816         user_data->dlg.h_scrollbar=gtk_hscrollbar_new(user_data->dlg.h_scrollbar_adjustment);
817         gtk_widget_show(user_data->dlg.h_scrollbar);
818         gtk_box_pack_end(GTK_BOX(vbox), user_data->dlg.h_scrollbar, FALSE, FALSE, 0);
819         SIGNAL_CONNECT(user_data->dlg.h_scrollbar_adjustment, "value_changed", h_scrollbar_changed, user_data);
820
821         gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
822
823        /* create the associated v_scrollbar */
824         user_data->dlg.v_scrollbar_adjustment=(GtkAdjustment *)gtk_adjustment_new(0,0,0,0,0,0);
825         user_data->dlg.v_scrollbar=gtk_vscrollbar_new(user_data->dlg.v_scrollbar_adjustment);
826         gtk_widget_show(user_data->dlg.v_scrollbar);
827         gtk_box_pack_end(GTK_BOX(hbox), user_data->dlg.v_scrollbar, FALSE, FALSE, 0);
828                 SIGNAL_CONNECT(user_data->dlg.v_scrollbar_adjustment, "value_changed", v_scrollbar_changed, user_data);
829
830         gtk_box_pack_start(GTK_BOX(box), hbox, TRUE, TRUE, 0);
831 }
832
833
834 /****************************************************************************/
835 static void dialog_graph_create_window(graph_analysis_data_t* user_data)
836 {
837         GtkWidget *vbox;
838         GtkWidget *hbox;
839         GtkWidget *bt_close;
840
841         /* create the main window */
842         user_data->dlg.window=window_new(GTK_WINDOW_TOPLEVEL, "Graph Analysis");
843
844
845         vbox=gtk_vbox_new(FALSE, 0);
846         gtk_container_add(GTK_CONTAINER(user_data->dlg.window), vbox);
847         gtk_widget_show(vbox);
848
849         create_draw_area(user_data, vbox);
850
851         hbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL);
852         gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
853         gtk_widget_show(hbox);
854
855         bt_close = OBJECT_GET_DATA(hbox, GTK_STOCK_CLOSE);
856         window_set_cancel_button(user_data->dlg.window, bt_close, window_cancel_button_cb);
857
858         SIGNAL_CONNECT(user_data->dlg.window, "delete_event", window_delete_event_cb, NULL);
859
860         gtk_widget_show(user_data->dlg.window);
861         window_present(user_data->dlg.window);
862 }
863
864 /* Return the index array if the node is in the array. Return -1 if there is room in the array
865  * and Return -2 if the array is full
866  */
867 /****************************************************************************/
868 gint is_node_array(graph_analysis_data_t* user_data, guint32 node)
869 {
870         int i;
871         for (i=0; i<MAX_NUM_NODES; i++){
872                 if (user_data->nodes[i] == 0)   return -1;      /* it is not in the array */
873                 if (user_data->nodes[i] == node) return i;      /* it is in the array */
874         }
875         return -2;              /* array full */
876 }
877
878
879 /* Get the nodes (IPs) from the list */
880 /****************************************************************************/
881 void get_nodes(graph_analysis_data_t* user_data)
882 {
883         GList* list;
884         graph_analysis_item_t *gai;
885         gint index;
886
887         /* fill the node array */
888         list = g_list_first(user_data->graph_info->list);
889         while (list)
890         {
891                 gai = list->data;
892                 if (gai->display){
893                         user_data->num_items++;
894                         /* check source IP node */
895                         index = is_node_array(user_data, gai->ip_src);
896                         switch(index){
897                                 case -2: /* array full */
898                                         gai->src_node = NODE_OVERFLOW;
899                                         break;
900                                 case -1: /* not in array */
901                                         user_data->nodes[user_data->num_nodes] = gai->ip_src;
902                                         gai->src_node = user_data->num_nodes;
903                                         user_data->num_nodes++;
904                                         break;
905                                 default: /* it is in the array, just update the src_node */
906                                         gai->src_node = (guint16)index;
907                         }
908
909                         /* check destination  IP node */
910                         index = is_node_array(user_data, gai->ip_dst);
911                         switch(index){
912                                 case -2: /* array full */
913                                         gai->dst_node = NODE_OVERFLOW;
914                                         break;
915                                 case -1: /* not in array */
916                                         user_data->nodes[user_data->num_nodes] = gai->ip_dst;
917                                         gai->dst_node = user_data->num_nodes;
918                                         user_data->num_nodes++;
919                                         break;
920                                 default: /* it is in the array, just update the dst_node */
921                                         gai->dst_node = (guint16)index;
922                         }
923                 }
924
925                 list = g_list_next(list);
926         }
927 }
928
929 /****************************************************************************/
930 /* XXX only handles IPv4, should add IPv6 support */
931 graph_analysis_data_t* graph_analysis_init(void)
932 {
933         graph_analysis_data_t* user_data;
934         /* init */
935         user_data = g_malloc(sizeof(graph_analysis_data_t));
936
937         /* init user_data */
938         graph_analysis_init_dlg(user_data);
939
940         return user_data;
941 }
942
943 /****************************************************************************/
944 void graph_analysis_create(graph_analysis_data_t* user_data)
945 {
946         /* reset the data */
947         graph_analysis_reset(user_data);
948
949         /* get nodes (each node is an IP address) */
950         get_nodes(user_data);
951
952         /* create the graph windows */
953         dialog_graph_create_window(user_data);
954
955         /* redraw the graph */
956         dialog_graph_redraw(user_data); 
957
958         return;
959 }
960
961 /****************************************************************************/
962 void graph_analysis_update(graph_analysis_data_t* user_data)
963 {
964         /* reset the data */
965         graph_analysis_reset(user_data);
966
967         /* get nodes (each node is an IP address) */
968         get_nodes(user_data);
969
970         /* redraw the graph */
971         dialog_graph_redraw(user_data); 
972
973     window_present(user_data->dlg.window);
974         return;
975 }