remove GTK1 code
[obnox/wireshark/wip.git] / gtk / graph_analysis.c
1 /* graph_analysis.c
2  * Graphic Analysis addition for Wireshark
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  * Wireshark - Network traffic analyzer
13  * By Gerald Combs <gerald@wireshark.org>
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 <epan/epan_dissect.h>
36
37 #include "util.h"
38 #include <epan/tap.h>
39 #include "register.h"
40 #include <epan/dissectors/packet-rtp.h>
41 #include <epan/addr_resolv.h>
42
43 /* in /gtk ... */
44 #include <gtk/gtk.h>
45 #include <glib-object.h>
46
47 #include <gdk/gdkkeysyms.h>
48 #include "gtkglobals.h"
49
50 #if 0
51 #include "dlg_utils.h"
52 #endif
53 #include "file_dlg.h"
54 #include "gui_utils.h"
55 #include "main.h"
56 #include "compat_macros.h"
57 #include "../color.h"
58 #include "epan/filesystem.h"
59 #include "file_util.h"
60
61 #include <string.h>
62
63 #ifdef HAVE_UNISTD_H
64 #include <unistd.h>
65 #endif
66
67 #include "simple_dialog.h"
68
69 #include "graph_analysis.h"
70
71
72 /****************************************************************************/
73
74
75 #define OK_TEXT "[ Ok ]"
76 #define PT_UNDEFINED -1
77
78
79 static GtkWidget *save_to_file_w = NULL;
80
81 #define MAX_LABEL 50
82 #define MAX_COMMENT 100
83 #define ITEM_HEIGHT 20
84 #define NODE_WIDTH 100
85 #define TOP_Y_BORDER 40
86 #define BOTTOM_Y_BORDER 0
87 #define COMMENT_WIDTH 400
88 #define TIME_WIDTH 50
89
90 #define NODE_CHARS_WIDTH 20
91 #define CONV_TIME_HEADER "Conv.| Time    "
92 #define TIME_HEADER "|Time     "
93 #define CONV_TIME_EMPTY_HEADER     "     |         "
94 #define TIME_EMPTY_HEADER     "|         "
95 #define CONV_TIME_HEADER_LENGTH 16
96 #define TIME_HEADER_LENGTH 10
97
98 /****************************************************************************/
99 /* Reset the user_data structure */
100 static void graph_analysis_reset(graph_analysis_data_t* user_data)
101 {
102         int i;
103
104         user_data->num_nodes = 0;
105         user_data->num_items = 0;
106         for (i=0; i<MAX_NUM_NODES; i++){
107                 user_data->nodes[i].type = AT_NONE;
108                 user_data->nodes[i].len = 0;
109                 g_free((void *)user_data->nodes[i].data);
110                 user_data->nodes[i].data = NULL;
111         }
112
113         user_data->dlg.first_node=0;
114         user_data->dlg.first_item=0;
115         user_data->dlg.left_x_border=0;
116         user_data->dlg.selected_item=0xFFFFFFFF;    /*not item selected */
117 }
118
119 /****************************************************************************/
120 /* Reset the user_data structure */
121 static void graph_analysis_init_dlg(graph_analysis_data_t* user_data)
122 {
123         int i;
124
125         user_data->num_nodes = 0;
126         user_data->num_items = 0;
127         user_data->on_destroy_user_data = NULL;
128         user_data->data = NULL;
129         for (i=0; i<MAX_NUM_NODES; i++){
130                 user_data->nodes[i].type = AT_NONE;
131                 user_data->nodes[i].len = 0;
132                 user_data->nodes[i].data = NULL;
133         }
134
135         user_data->dlg.first_node=0;
136         user_data->dlg.first_item=0;
137         user_data->dlg.left_x_border=0;
138         user_data->dlg.selected_item=0xFFFFFFFF;    /*not item selected */
139         /* init dialog_graph */
140         user_data->dlg.needs_redraw=TRUE;
141         user_data->dlg.draw_area_time=NULL;
142         user_data->dlg.draw_area=NULL;
143         user_data->dlg.pixmap=NULL;
144         user_data->dlg.pixmap_time=NULL;
145         user_data->dlg.draw_area_comments=NULL;
146         user_data->dlg.pixmap_comments=NULL;
147         user_data->dlg.v_scrollbar=NULL;
148         user_data->dlg.v_scrollbar_adjustment=NULL;
149         user_data->dlg.hpane=NULL;
150         user_data->dlg.pixmap_width = 350;
151         user_data->dlg.pixmap_height=400;
152         user_data->dlg.first_node=0;
153         user_data->dlg.first_item=0;
154         user_data->dlg.left_x_border=0;
155         user_data->dlg.selected_item=0xFFFFFFFF;    /*not item selected */
156         user_data->dlg.window=NULL;
157         user_data->dlg.parent_w=NULL;
158         user_data->dlg.inverse = FALSE;
159         user_data->dlg.title=NULL;
160 }
161
162 /****************************************************************************/
163 /* CALLBACKS */
164
165 /****************************************************************************/
166 /* close the dialog window */
167 static void on_destroy(GtkWidget *win _U_, graph_analysis_data_t *user_data _U_)
168 {
169         int i;
170
171         for (i=0; i<MAX_NUM_NODES; i++){
172                 user_data->nodes[i].type = AT_NONE;
173                 user_data->nodes[i].len = 0;
174                 g_free((void *)user_data->nodes[i].data);
175                 user_data->nodes[i].data = NULL;
176         }
177         user_data->dlg.window = NULL;
178         g_free(user_data->dlg.title);
179         user_data->dlg.title = NULL;
180
181         if(user_data->on_destroy_user_data){
182         user_data->on_destroy_user_data(user_data->data);
183         }
184 }
185
186 #define RIGHT_ARROW 1
187 #define LEFT_ARROW 0
188 #define WIDTH_ARROW 8
189 #define HEIGHT_ARROW 6
190
191 /****************************************************************************/
192 static void draw_arrow(GdkDrawable *pixmap, GdkGC *gc, gint x, gint y, gboolean direction)
193 {
194         GdkPoint arrow_point[3];
195
196         arrow_point[0].x = x;
197         arrow_point[0].y = y-HEIGHT_ARROW/2;
198         if (direction == RIGHT_ARROW)
199                 arrow_point[1].x = x+WIDTH_ARROW;
200         else
201                 arrow_point[1].x = x-WIDTH_ARROW;
202         arrow_point[1].y = y;
203         arrow_point[2].x = x;
204         arrow_point[2].y = y+HEIGHT_ARROW/2;;
205
206         if (GDK_IS_DRAWABLE(pixmap)) {
207                 gdk_draw_polygon(pixmap, gc, TRUE, arrow_point, 3);
208         }
209 }
210
211 /****************************************************************************/
212 /* Adds trailing characters to complete the requested length.               */
213 /****************************************************************************/
214
215 static void enlarge_string(GString *gstr, guint32 length, char pad){
216
217         guint32 i;
218
219         for (i = gstr->len; i < length; i++){
220                 g_string_append_c(gstr, pad);
221         }
222 }
223
224 /****************************************************************************/
225 /* overwrites the characters in a string, between positions p1 and p2, with */
226 /*   the characters of text_to_insert                                       */
227 /*   NB: it does not check that p1 and p2 fit into string                                       */
228 /****************************************************************************/
229
230 static void overwrite (GString *gstr, char *text_to_insert, guint32 p1, guint32 p2){
231
232         guint32 len;
233         gsize pos;
234
235         if (p1 == p2)
236                 return;
237
238         if (p1 > p2){
239                 pos = p2;
240                 len = p1 - p2;
241         }
242         else{
243                 pos = p1;
244                 len = p2 - p1;
245         }
246
247         if (len > strlen(text_to_insert)){
248                 len = strlen(text_to_insert);
249         }
250
251         /* ouch this is ugly but gtk1 needs it */
252         if ((guint32)pos > (guint32)gstr->len)
253                 pos = gstr->len;
254
255         /* ouch this is ugly but gtk1 needs it */
256         if ((guint32)(pos + len) > (guint32)gstr->len)
257                 g_string_truncate(gstr, pos);
258         else
259                 g_string_erase(gstr, pos, len);
260
261         g_string_insert(gstr, pos, text_to_insert);
262 }
263
264
265 /*
266  * XXX - We might want to refactor this to write the graph data directly to
267  * the file instead of loading everything into strings first.
268  */
269
270 /****************************************************************************/
271 static gboolean dialog_graph_dump_to_file(graph_analysis_data_t* user_data)
272 {
273         guint32 i, first_node, display_items, display_nodes;
274         guint32 start_position, end_position, item_width, header_length;
275         guint32 current_item;
276         graph_analysis_item_t *gai;
277         guint16 first_conv_num = 0;
278         gboolean several_convs = FALSE;
279         gboolean first_packet = TRUE;
280
281         GString *label_string, *empty_line,*separator_line, *tmp_str, *tmp_str2;
282         char *empty_header;
283         char src_port[8],dst_port[8];
284
285         GList* list;
286
287         FILE *of;
288
289         of = eth_fopen(user_data->dlg.save_file,"w");
290         if (of==NULL){
291                 return FALSE;
292         }
293
294         label_string   = g_string_new("");
295         empty_line     = g_string_new("");
296         separator_line = g_string_new("");
297         tmp_str        = g_string_new("");
298         tmp_str2       = g_string_new("");
299
300         /* get the items to display and fill the matrix array */
301         list = g_list_first(user_data->graph_info->list);
302         current_item = 0;
303         i = 0;
304         while (list && current_item < NUM_DISPLAY_ITEMS)
305         {
306                 gai = list->data;
307                 if (gai->display){
308                         user_data->dlg.items[current_item].frame_num = gai->frame_num;
309                         user_data->dlg.items[current_item].time = gai->time;
310                         user_data->dlg.items[current_item].port_src = gai->port_src;
311                         user_data->dlg.items[current_item].port_dst = gai->port_dst;
312                         user_data->dlg.items[current_item].frame_label = gai->frame_label;
313                         user_data->dlg.items[current_item].comment = gai->comment;
314                         user_data->dlg.items[current_item].conv_num = gai->conv_num;
315                         user_data->dlg.items[current_item].src_node = gai->src_node;
316                         user_data->dlg.items[current_item].dst_node = gai->dst_node;
317                         if (first_packet){
318                                 first_conv_num = gai->conv_num;
319                                 first_packet=FALSE;
320                         }
321                         if (user_data->dlg.items[current_item].conv_num != first_conv_num){
322                                 several_convs = TRUE;
323                         }
324                         current_item++;
325                         i++;
326                 }
327
328                 list = g_list_next(list);
329         }
330         display_items = current_item;
331
332         /* if not items to display */
333         if (display_items == 0) goto exit;
334
335         display_nodes = user_data->num_nodes;
336
337         first_node = user_data->dlg.first_node;
338
339         /* Write the conv. and time headers */
340
341         if (several_convs){
342                 fprintf (of, CONV_TIME_HEADER);
343                 empty_header = CONV_TIME_EMPTY_HEADER;
344                 header_length = CONV_TIME_HEADER_LENGTH;
345         }
346         else{
347                 fprintf (of, TIME_HEADER);
348                 empty_header = TIME_EMPTY_HEADER;
349                 header_length = TIME_HEADER_LENGTH;
350         }
351
352         /* Write the node names on top */
353         for (i=0; i<display_nodes; i++){
354                 /* print the node identifiers */
355                 g_string_sprintf(label_string, "| %s",
356                         get_addr_name(&(user_data->nodes[i+first_node])));
357                 enlarge_string(label_string, NODE_CHARS_WIDTH, ' ');
358                 fprintf(of, "%s", label_string->str);
359                 g_string_sprintf(label_string, "| ");
360                 enlarge_string(label_string, NODE_CHARS_WIDTH, ' ');
361                 g_string_append(empty_line, label_string->str);
362         }
363         g_string_append_c(empty_line, '|');
364
365         enlarge_string(separator_line, empty_line->len + header_length, '-');
366
367         fprintf(of, "|\n");
368
369         /*
370          * Draw the items
371          */
372
373         for (current_item=0; current_item<display_items; current_item++){
374
375                 start_position = (user_data->dlg.items[current_item].src_node-first_node)*NODE_CHARS_WIDTH+NODE_CHARS_WIDTH/2;
376
377                 end_position = (user_data->dlg.items[current_item].dst_node-first_node)*NODE_CHARS_WIDTH+NODE_CHARS_WIDTH/2;
378
379                 if (start_position > end_position){
380                         item_width=start_position-end_position;
381                 }
382                 else if (start_position < end_position){
383                         item_width=end_position-start_position;
384                 }
385                 else{ /* same origin and destination address */
386                         end_position = start_position+NODE_CHARS_WIDTH;
387                         item_width = NODE_CHARS_WIDTH;
388                 }
389
390                 /* separator between conversations */
391                 if (user_data->dlg.items[current_item].conv_num != first_conv_num){
392                         fprintf(of, "%s\n", separator_line->str);
393                         first_conv_num=user_data->dlg.items[current_item].conv_num;
394                 }
395
396                 /* write the conversation number */
397                 if (several_convs){
398                         g_string_sprintf(label_string, "%i", user_data->dlg.items[current_item].conv_num);
399                         enlarge_string(label_string, 5, ' ');
400                         fprintf(of, "%s", label_string->str);
401                 }
402
403                 /* write the time */
404                 g_string_sprintf(label_string, "|%.3f", user_data->dlg.items[current_item].time);
405                 enlarge_string(label_string, 10, ' ');
406                 fprintf(of, "%s", label_string->str);
407
408                 /* write the frame label */
409
410                 g_string_sprintf(tmp_str, empty_line->str);
411                 overwrite(tmp_str,user_data->dlg.items[current_item].frame_label,
412                         start_position,
413                         end_position
414                         );
415                 fprintf(of, "%s", tmp_str->str);
416
417                 /* write the comments */
418                 fprintf(of, "%s\n", user_data->dlg.items[current_item].comment);
419
420                 /* write the arrow and frame label*/
421                 fprintf(of, "%s", empty_header);
422
423                 g_string_sprintf(tmp_str, empty_line->str);
424
425                 g_string_truncate(tmp_str2, 0);
426
427                 if (start_position<end_position){
428                         enlarge_string(tmp_str2, item_width-2, '-');
429                         g_string_append_c(tmp_str2, '>');
430                 }
431                 else{
432                         g_string_sprintf(tmp_str2, "<");
433                         enlarge_string(tmp_str2, item_width-1, '-');
434                 }
435
436                 overwrite(tmp_str,tmp_str2->str,
437                         start_position,
438                         end_position
439                         );
440
441                 g_snprintf(src_port,8,"(%i)", user_data->dlg.items[current_item].port_src);
442                 g_snprintf(dst_port,8,"(%i)", user_data->dlg.items[current_item].port_dst);
443
444                 if (start_position<end_position){
445                         overwrite(tmp_str,src_port,start_position-9,start_position-1);
446                         overwrite(tmp_str,dst_port,end_position+1,end_position+9);
447                 }
448                 else{
449                         overwrite(tmp_str,src_port,start_position+1,start_position+9);
450                         overwrite(tmp_str,dst_port,end_position-9,end_position+1);
451                 }
452
453                 fprintf(of,"%s\n",tmp_str->str);
454         }
455
456 exit:
457         g_string_free(label_string, TRUE);
458         g_string_free(empty_line, TRUE);
459         g_string_free(separator_line, TRUE);
460         g_string_free(tmp_str, TRUE);
461         g_string_free(tmp_str2, TRUE);
462
463         fclose (of);
464         return TRUE;
465
466 }
467
468 /****************************************************************************/
469 static void save_to_file_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
470 {
471         /* Note that we no longer have a Save to file dialog box. */
472         save_to_file_w = NULL;
473 }
474
475 /****************************************************************************/
476 /* save in a file */
477
478 /* first an auxiliary function in case we need an overwrite confirmation dialog */
479
480 static void overwrite_existing_file_cb(gpointer dialog _U_, gint btn, gpointer user_data _U_)
481 {
482         graph_analysis_data_t *user_data_p;
483
484         user_data_p = user_data;
485
486         switch(btn) {
487         case(ESD_BTN_YES):
488             /* overwrite the file*/
489             dialog_graph_dump_to_file(user_data);
490             break;
491         case(ESD_BTN_NO):
492             break;
493         default:
494             g_assert_not_reached();
495         }
496 }
497
498 /* and then the save in a file dialog itself */
499
500 static void save_to_file_ok_cb(GtkWidget *ok_bt _U_, gpointer user_data _U_)
501 {
502         FILE *file_test;
503         gpointer dialog;
504         graph_analysis_data_t *user_data_p;
505
506         user_data_p = user_data;
507
508         user_data_p->dlg.save_file = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (save_to_file_w)));
509
510         /* Perhaps the user specified a directory instead of a file.
511         Check whether they did. */
512         if (test_for_directory(user_data_p->dlg.save_file) == EISDIR) {
513                 /* It's a directory - set the file selection box to display it. */
514                 set_last_open_dir(user_data_p->dlg.save_file);
515                 g_free(user_data_p->dlg.save_file);
516                 file_selection_set_current_folder(save_to_file_w, get_last_open_dir());
517                 return;
518         }
519
520
521         /* check whether the file exists */
522         file_test = eth_fopen(user_data_p->dlg.save_file,"r");
523         if (file_test!=NULL){
524
525                 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_YES_NO,
526                   "%sFile: \"%s\" already exists!%s\n\n"
527                   "Do you want to overwrite it?",
528                   simple_dialog_primary_start(),user_data_p->dlg.save_file, simple_dialog_primary_end());
529                 simple_dialog_set_cb(dialog, overwrite_existing_file_cb, user_data);
530                 fclose(file_test);
531         }
532
533         else{
534                 if (!dialog_graph_dump_to_file(user_data))
535                         return;
536         }
537         window_destroy(GTK_WIDGET(save_to_file_w));
538
539 }
540
541 /****************************************************************************/
542 static void
543 on_save_bt_clicked                    (GtkButton       *button _U_,
544                                         gpointer         user_data _U_)
545 {
546         GtkWidget *vertb;
547         GtkWidget *ok_bt;
548
549         if (save_to_file_w != NULL) {
550                 /* There's already a Save to file dialog box; reactivate it. */
551                 reactivate_window(save_to_file_w);
552                 return;
553         }
554
555         save_to_file_w = gtk_file_selection_new("Wireshark: Save graph to plain text file");
556
557         /* Container for each row of widgets */
558         vertb = gtk_vbox_new(FALSE, 0);
559         gtk_container_border_width(GTK_CONTAINER(vertb), 5);
560         gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(save_to_file_w)->action_area),
561                 vertb, FALSE, FALSE, 0);
562         gtk_widget_show (vertb);
563
564         ok_bt = GTK_FILE_SELECTION(save_to_file_w)->ok_button;
565         SIGNAL_CONNECT(ok_bt, "clicked", save_to_file_ok_cb, user_data);
566
567         window_set_cancel_button(save_to_file_w,
568         GTK_FILE_SELECTION(save_to_file_w)->cancel_button, window_cancel_button_cb);
569
570         SIGNAL_CONNECT(save_to_file_w, "delete_event", window_delete_event_cb, NULL);
571         SIGNAL_CONNECT(save_to_file_w, "destroy", save_to_file_destroy_cb,
572                        NULL);
573
574         gtk_widget_show(save_to_file_w);
575         window_present(save_to_file_w);
576
577
578 }
579
580 /****************************************************************************/
581 static void dialog_graph_draw(graph_analysis_data_t* user_data)
582 {
583         guint32 i, last_item, first_item, display_items;
584         guint32 start_arrow, end_arrow, label_x, src_port_x, dst_port_x, arrow_width;
585         guint32 current_item;
586         guint32 left_x_border;
587         guint32 right_x_border;
588         guint32 top_y_border;
589         guint32 bottom_y_border;
590         graph_analysis_item_t *gai;
591         guint16 first_conv_num;
592         gboolean several_convs = FALSE;
593         gboolean first_packet = TRUE;
594
595         GdkGC *frame_fg_color;
596         GdkGC *frame_bg_color;
597         GdkGC *div_line_color;
598
599         PangoLayout  *layout;
600         PangoLayout  *big_layout;
601         PangoLayout  *small_layout;
602         gint label_width, label_height;
603         guint32 draw_width, draw_height;
604         char label_string[MAX_COMMENT];
605         GList* list;
606
607         /* new variables */
608
609         if(!user_data->dlg.needs_redraw){
610                 return;
611         }
612         user_data->dlg.needs_redraw=FALSE;
613
614         /* Clear out old plt */
615         if ( GDK_IS_DRAWABLE(user_data->dlg.pixmap_time) )
616                 gdk_draw_rectangle(user_data->dlg.pixmap_time,
617                                                    user_data->dlg.draw_area_time->style->white_gc,
618                                                    TRUE,
619                                                    0, 0,
620                                                    user_data->dlg.draw_area_time->allocation.width,
621                                                    user_data->dlg.draw_area_time->allocation.height);
622
623         if ( GDK_IS_DRAWABLE(user_data->dlg.pixmap) )
624                 gdk_draw_rectangle(user_data->dlg.pixmap,
625                                                    user_data->dlg.draw_area->style->white_gc,
626                                                    TRUE,
627                                                    0, 0,
628                                                    user_data->dlg.draw_area->allocation.width,
629                                                    user_data->dlg.draw_area->allocation.height);
630
631         if ( GDK_IS_DRAWABLE(user_data->dlg.pixmap_comments) )
632                 gdk_draw_rectangle(user_data->dlg.pixmap_comments,
633                                                    user_data->dlg.draw_area->style->white_gc,
634                                                    TRUE,
635                                                    0, 0,
636                                                    user_data->dlg.draw_area_comments->allocation.width,
637                                                    user_data->dlg.draw_area_comments->allocation.height);
638
639         /* Calculate the y border */
640         top_y_border=TOP_Y_BORDER;      /* to display the node address */
641         bottom_y_border=2;
642
643             draw_height=user_data->dlg.draw_area->allocation.height-top_y_border-bottom_y_border;
644
645         first_item = user_data->dlg.first_item;
646         display_items = draw_height/ITEM_HEIGHT;
647         last_item = first_item+display_items-1;
648
649         /* get the items to display and fill the matrix array */
650         list = g_list_first(user_data->graph_info->list);
651         current_item = 0;
652         i = 0;
653         while (list)
654         {
655                 gai = list->data;
656                 if (gai->display){
657                         if (current_item>=display_items) break;         /* the item is outside the display */
658                         if (i>=first_item){
659                                 user_data->dlg.items[current_item].frame_num = gai->frame_num;
660                                 user_data->dlg.items[current_item].time = gai->time;
661                                 user_data->dlg.items[current_item].port_src = gai->port_src;
662                                 user_data->dlg.items[current_item].port_dst = gai->port_dst;
663                                 /* Add "..." if the length is 50 characters */
664                                 if (strlen(gai->frame_label) > 48) {
665                                         gai->frame_label[48] = '.';
666                                         gai->frame_label[47] = '.';
667                                         gai->frame_label[46] = '.';
668                                 }
669                                 user_data->dlg.items[current_item].frame_label = gai->frame_label;
670                                 user_data->dlg.items[current_item].comment = gai->comment;
671                                 user_data->dlg.items[current_item].conv_num = gai->conv_num;
672
673                                 if (first_packet){
674                                         first_conv_num = gai->conv_num;
675                                         first_packet=FALSE;
676                                 }
677
678                                 if (user_data->dlg.items[current_item].conv_num != first_conv_num){
679                                         several_convs = TRUE;
680                                 }
681
682                                 user_data->dlg.items[current_item].src_node = gai->src_node;
683                                 user_data->dlg.items[current_item].dst_node = gai->dst_node;
684                                 user_data->dlg.items[current_item].line_style = gai->line_style;
685                                 current_item++;
686                         }
687                         i++;
688                 }
689
690                 list = g_list_next(list);
691         }
692         /* in case the windows is resized so we have to move the top item */
693         if ((first_item + display_items) > user_data->num_items){
694                 if (display_items>user_data->num_items)
695                         first_item=0;
696                 else
697                         first_item = user_data->num_items - display_items;
698         }
699
700         /* in case there are less items than possible displayed */
701         display_items = current_item;
702         last_item = first_item+display_items-1;
703
704         /* if not items to display */
705         if (display_items == 0) return;
706
707
708         /* Calculate the x borders */
709         /* We use time from the last display item to calcultate the x left border */
710         g_snprintf(label_string, MAX_LABEL, "%.3f", user_data->dlg.items[display_items-1].time);
711         layout = gtk_widget_create_pango_layout(user_data->dlg.draw_area_time, label_string);
712         big_layout = gtk_widget_create_pango_layout(user_data->dlg.draw_area_time, label_string);
713         small_layout = gtk_widget_create_pango_layout(user_data->dlg.draw_area_time, label_string);
714
715         /* XXX - to prevent messages like "Couldn't load font x, falling back to y", I've changed font
716            description from "Helvetica-Bold 8" to "Helvetica,Sans,Bold 8", this seems to be
717            conforming to the API, see http://developer.gnome.org/doc/API/2.0/pango/pango-Fonts.html */
718         pango_layout_set_font_description(big_layout, pango_font_description_from_string("Helvetica,Sans,Bold 8"));
719         pango_layout_set_font_description(small_layout, pango_font_description_from_string("Helvetica,Sans,Bold 7"));
720
721         pango_layout_get_pixel_size(layout, &label_width, &label_height);
722
723                 /* resize the "time" draw area */
724
725         left_x_border=3;
726         user_data->dlg.left_x_border = left_x_border;
727
728         right_x_border=2;
729         draw_width=user_data->dlg.pixmap_width-right_x_border-left_x_border;
730
731         /* Paint time title background */
732         if ( GDK_IS_DRAWABLE(user_data->dlg.pixmap_time) )
733                 gdk_draw_rectangle(user_data->dlg.pixmap_time,
734                                                    user_data->dlg.draw_area_time->style->bg_gc[2],
735                                                    TRUE,
736                                                    0,
737                                                    0,
738                                                    user_data->dlg.draw_area_time->allocation.width,
739                                                    top_y_border);
740         /* Paint main title background */
741         if ( GDK_IS_DRAWABLE(user_data->dlg.pixmap) )
742                 gdk_draw_rectangle(user_data->dlg.pixmap,
743                                                    user_data->dlg.draw_area->style->bg_gc[2],
744                                                    TRUE,
745                                                    0,
746                                                    0,
747                                                    user_data->dlg.draw_area->allocation.width,
748                                                    top_y_border);
749         /* Paint main comment background */
750         if ( GDK_IS_DRAWABLE(user_data->dlg.pixmap_comments) )
751                 gdk_draw_rectangle(user_data->dlg.pixmap_comments,
752                                                    user_data->dlg.draw_area_comments->style->bg_gc[2],
753                                                    TRUE,
754                                                    0,
755                                                    0,
756                                                    user_data->dlg.draw_area_comments->allocation.width,
757                                                    top_y_border);
758
759
760         /* Draw the word "Time" on top of time column */
761         g_snprintf(label_string, label_width, "%s", "Time");
762         pango_layout_set_text(layout, label_string, -1);
763         pango_layout_get_pixel_size(layout, &label_width, &label_height);
764         if (GDK_IS_DRAWABLE(user_data->dlg.pixmap_time)) {
765                 gdk_draw_layout(user_data->dlg.pixmap_time,
766                                                 user_data->dlg.draw_area_time->style->black_gc,
767                                                 left_x_border,
768                                                 top_y_border/2-label_height/2,
769                                                 layout);
770         }
771
772         /* Draw the word "Comment" on top of comment column */
773         g_snprintf(label_string, label_width, "%s", "Comment");
774         pango_layout_set_text(layout, label_string, -1);
775         pango_layout_get_pixel_size(layout, &label_width, &label_height);
776         if (GDK_IS_DRAWABLE(user_data->dlg.pixmap_comments)) {
777                 gdk_draw_layout(user_data->dlg.pixmap_comments,
778                            user_data->dlg.draw_area_comments->style->black_gc,
779                            MAX_COMMENT/2-label_width/2,
780                            top_y_border/2-label_height/2,
781                            layout);
782         }
783
784         /* Paint the background items */
785         for (current_item=0; current_item<display_items; current_item++){
786                 /*select the color. if it is the selected item select blue color */
787                 if ( current_item+first_item == user_data->dlg.selected_item ) {
788                         frame_bg_color = user_data->dlg.bg_gc[0];
789                 } else {
790                         frame_bg_color = user_data->dlg.bg_gc[1+user_data->dlg.items[current_item].conv_num%MAX_NUM_COL_CONV];
791                 }
792
793                 /* Paint background */
794                 if (GDK_IS_DRAWABLE(user_data->dlg.pixmap)) {
795                         gdk_draw_rectangle(user_data->dlg.pixmap,
796                                                            frame_bg_color,
797                                                            TRUE,
798                                                            left_x_border,
799                                                            top_y_border+current_item*ITEM_HEIGHT,
800                                                            draw_width,
801                                                            ITEM_HEIGHT);
802                 }
803         }
804         /* Draw the node names on top and the division lines */
805         for (i=0; i<user_data->num_nodes; i++){
806                 /* print the node identifiers */
807                 /* XXX we assign 5 pixels per character in the node identity */
808                 g_snprintf(label_string, NODE_WIDTH/5, "%s",
809                         get_addr_name(&(user_data->nodes[i])));
810                 pango_layout_set_text(layout, label_string, -1);
811                 pango_layout_get_pixel_size(layout, &label_width, &label_height);
812                 if (GDK_IS_DRAWABLE(user_data->dlg.pixmap)) {
813                         gdk_draw_layout(user_data->dlg.pixmap,
814                                                         user_data->dlg.draw_area->style->black_gc,
815                                                         left_x_border+NODE_WIDTH/2-label_width/2+NODE_WIDTH*i,
816                                                         top_y_border/2-label_height/2,
817                                                         layout);
818                 }
819
820                 /* draw the node division lines */
821                 if (GDK_IS_DRAWABLE(user_data->dlg.pixmap) ) {
822                         gdk_draw_line(user_data->dlg.pixmap, user_data->dlg.div_line_gc[0],
823                                                   left_x_border+NODE_WIDTH/2+NODE_WIDTH*i,
824                                                   top_y_border,
825                                                   left_x_border+NODE_WIDTH/2+NODE_WIDTH*i,
826                                                   user_data->dlg.draw_area->allocation.height-bottom_y_border);
827                 }
828
829         }
830
831         /* Draw the items */
832         for (current_item=0; current_item<display_items; current_item++){
833                 /* draw the time */
834                 g_snprintf(label_string, MAX_LABEL, "%.3f", user_data->dlg.items[current_item].time);
835                 pango_layout_set_text(layout, label_string, -1);
836                 pango_layout_get_pixel_size(layout, &label_width, &label_height);
837                 if (GDK_IS_DRAWABLE(user_data->dlg.pixmap_time)) {
838                         gdk_draw_layout(user_data->dlg.pixmap_time,
839                                                         user_data->dlg.draw_area->style->black_gc,
840                                                         3,
841                                                         top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT/2-label_height/2,
842                                                         layout);
843                 }
844
845                 /*draw the comments */
846                 g_snprintf(label_string, MAX_COMMENT, "%s", user_data->dlg.items[current_item].comment);
847                 pango_layout_set_text(small_layout, label_string, -1);
848                 pango_layout_get_pixel_size(small_layout, &label_width, &label_height);
849                 if (GDK_IS_DRAWABLE(user_data->dlg.pixmap_comments)) {
850                         gdk_draw_layout(user_data->dlg.pixmap_comments,
851                                                         user_data->dlg.draw_area->style->black_gc,
852                                                         2,
853                                                         top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT/2-label_height/2,
854                                                         small_layout);
855                 }
856                 /* select colors */
857                 if ( current_item+first_item == user_data->dlg.selected_item ){
858                         frame_fg_color = user_data->dlg.draw_area->style->white_gc;
859                         div_line_color = user_data->dlg.div_line_gc[1];
860                 } else {
861                         frame_fg_color = user_data->dlg.draw_area->style->black_gc;
862                         div_line_color = user_data->dlg.div_line_gc[0];
863                 }
864                 /* draw the arrow line */
865                 start_arrow = left_x_border+(user_data->dlg.items[current_item].src_node)*NODE_WIDTH+NODE_WIDTH/2;
866                 end_arrow = left_x_border+(user_data->dlg.items[current_item].dst_node)*NODE_WIDTH+NODE_WIDTH/2;
867
868                 if (GDK_IS_DRAWABLE(user_data->dlg.pixmap) ) {
869                         gdk_draw_line(user_data->dlg.pixmap, frame_fg_color,
870                                 start_arrow,
871                                 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-7,
872                                 end_arrow,
873                                 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-7);
874
875                         /* draw the additional line when line style is 2 pixels width */
876                         if (user_data->dlg.items[current_item].line_style == 2) {
877                                 gdk_draw_line(user_data->dlg.pixmap, frame_fg_color,
878                                         start_arrow,
879                                         top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-6,
880                                         end_arrow,
881                                         top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-6);
882                         }
883                 }
884
885                 /* draw the arrow */
886                 if (start_arrow<end_arrow)
887                         draw_arrow(user_data->dlg.pixmap, frame_fg_color, end_arrow-WIDTH_ARROW,top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-7, RIGHT_ARROW);
888                 else
889                         draw_arrow(user_data->dlg.pixmap, frame_fg_color, end_arrow+WIDTH_ARROW,top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-7, LEFT_ARROW);
890
891                 /* draw the frame comment */
892                 g_snprintf(label_string, MAX_LABEL, "%s", user_data->dlg.items[current_item].frame_label);
893                 pango_layout_set_text(big_layout, label_string, -1);
894                 pango_layout_get_pixel_size(big_layout, &label_width, &label_height);
895                 if (start_arrow<end_arrow){
896                         arrow_width = end_arrow-start_arrow;
897                         label_x = arrow_width/2+start_arrow;
898                 }
899                 else {
900                         arrow_width = start_arrow-end_arrow;
901                         label_x = arrow_width/2+end_arrow;
902                 }
903
904                 if (label_width>(gint)arrow_width) arrow_width = label_width;
905
906                 if ((int)left_x_border > ((int)label_x-(int)label_width/2))
907                         label_x = left_x_border + label_width/2;
908
909                 if (GDK_IS_DRAWABLE(user_data->dlg.pixmap)) {
910                         gdk_draw_layout(user_data->dlg.pixmap,
911                                                         frame_fg_color,
912                                                         label_x - label_width/2,
913                                                         top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT/2-label_height/2-3,
914                                                         big_layout);
915                 }
916
917                 /* draw the source port number */
918                 g_snprintf(label_string, MAX_LABEL, "(%i)", user_data->dlg.items[current_item].port_src);
919                 pango_layout_set_text(small_layout, label_string, -1);
920                 pango_layout_get_pixel_size(small_layout, &label_width, &label_height);
921                 if (start_arrow<end_arrow){
922                         src_port_x = start_arrow - label_width - 2;
923                 }
924                 else {
925                         src_port_x = start_arrow + 2;
926                 }
927                 if (GDK_IS_DRAWABLE(user_data->dlg.pixmap)) {
928                         gdk_draw_layout(user_data->dlg.pixmap,
929                                                         div_line_color,
930                                                         src_port_x,
931                                                         top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-2-label_height/2-2,
932                                                         small_layout);
933                 }
934
935                 /* draw the destination port number */
936                 g_snprintf(label_string, MAX_LABEL, "(%i)", user_data->dlg.items[current_item].port_dst);
937                 pango_layout_set_text(small_layout, label_string, -1);
938                 pango_layout_get_pixel_size(small_layout, &label_width, &label_height);
939                 if (start_arrow<end_arrow){
940                         dst_port_x = end_arrow + 2;
941                 }
942                 else {
943                         dst_port_x = end_arrow - label_width - 2;
944                 }
945                 if (GDK_IS_DRAWABLE(user_data->dlg.pixmap)) {
946                         gdk_draw_layout(user_data->dlg.pixmap,
947                                                         div_line_color,
948                                                         dst_port_x,
949                                                         top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-2-label_height/2-2,
950                                                         small_layout);
951                 }
952                 /* draw the div line of the selected item with soft gray*/
953                 if ( current_item+first_item == user_data->dlg.selected_item )
954                         for (i=0; i<user_data->num_nodes; i++){
955                                 if (GDK_IS_DRAWABLE(user_data->dlg.pixmap) ) {
956                                         gdk_draw_line(user_data->dlg.pixmap, user_data->dlg.div_line_gc[1],
957                                                                   left_x_border+NODE_WIDTH/2+NODE_WIDTH*i,
958                                                                   (user_data->dlg.selected_item-first_item)*ITEM_HEIGHT+TOP_Y_BORDER,
959                                                                   left_x_border+NODE_WIDTH/2+NODE_WIDTH*i,
960                                                                   (user_data->dlg.selected_item-first_item)*ITEM_HEIGHT+TOP_Y_BORDER+ITEM_HEIGHT);
961                                 }
962                         }
963         }
964
965         g_object_unref(G_OBJECT(layout));
966
967         /* refresh the draw areas */
968         if (GDK_IS_DRAWABLE(user_data->dlg.draw_area_time->window) )
969                 gdk_draw_pixmap(user_data->dlg.draw_area_time->window,
970                                                 user_data->dlg.draw_area_time->style->fg_gc[GTK_WIDGET_STATE(user_data->dlg.draw_area_time)],
971                                                 user_data->dlg.pixmap_time,
972                                                 0, 0,
973                                                 0, 0,
974                                                 user_data->dlg.draw_area_time->allocation.width, user_data->dlg.draw_area_time->allocation.height);
975
976         if (GDK_IS_DRAWABLE(user_data->dlg.draw_area->window) )
977                 gdk_draw_pixmap(user_data->dlg.draw_area->window,
978                                                 user_data->dlg.draw_area->style->fg_gc[GTK_WIDGET_STATE(user_data->dlg.draw_area)],
979                                                 user_data->dlg.pixmap,
980                                                 0, 0,
981                                                 0, 0,
982                                                 user_data->dlg.draw_area->allocation.width, user_data->dlg.draw_area->allocation.height);
983
984         if (GDK_IS_DRAWABLE(user_data->dlg.draw_area_comments->window) )
985                 gdk_draw_pixmap(user_data->dlg.draw_area_comments->window,
986                                                 user_data->dlg.draw_area_comments->style->fg_gc[GTK_WIDGET_STATE(user_data->dlg.draw_area_comments)],
987                                                 user_data->dlg.pixmap_comments,
988                                                 0, 0,
989                                                 0, 0,
990                                                 user_data->dlg.draw_area_comments->allocation.width, user_data->dlg.draw_area_comments->allocation.height);
991
992         /* update the v_scrollbar */
993         user_data->dlg.v_scrollbar_adjustment->upper=(gfloat) user_data->num_items-1;
994         user_data->dlg.v_scrollbar_adjustment->step_increment=1;
995         user_data->dlg.v_scrollbar_adjustment->page_increment=(gfloat) (last_item-first_item);
996         user_data->dlg.v_scrollbar_adjustment->page_size=(gfloat) (last_item-first_item);
997         user_data->dlg.v_scrollbar_adjustment->value=(gfloat) first_item;
998
999         gtk_adjustment_changed(user_data->dlg.v_scrollbar_adjustment);
1000         gtk_adjustment_value_changed(user_data->dlg.v_scrollbar_adjustment);
1001 }
1002
1003 /****************************************************************************/
1004 static void dialog_graph_redraw(graph_analysis_data_t* user_data)
1005 {
1006         user_data->dlg.needs_redraw=TRUE;
1007         dialog_graph_draw(user_data);
1008 }
1009
1010 /****************************************************************************/
1011 static gint button_press_event(GtkWidget *widget, GdkEventButton *event _U_)
1012 {
1013         graph_analysis_data_t *user_data;
1014                 guint32 item;
1015
1016         user_data=(graph_analysis_data_t *)OBJECT_GET_DATA(widget, "graph_analysis_data_t");
1017
1018         if (event->type != GDK_BUTTON_PRESS) return TRUE;
1019
1020         if (event->y<TOP_Y_BORDER) return TRUE;
1021
1022         /* get the item clicked */
1023         item = ((guint32)event->y - TOP_Y_BORDER) / ITEM_HEIGHT;
1024         if (item >= user_data->num_items) return TRUE;
1025         user_data->dlg.selected_item = item + user_data->dlg.first_item;
1026
1027         user_data->dlg.needs_redraw=TRUE;
1028         dialog_graph_draw(user_data);
1029
1030         cf_goto_frame(&cfile, user_data->dlg.items[item].frame_num);
1031
1032         return TRUE;
1033 }
1034
1035 /****************************************************************************/
1036 static gint scroll_event(GtkWidget *widget, GdkEventScroll *event)
1037 {
1038         graph_analysis_data_t *user_data;
1039
1040         user_data=(graph_analysis_data_t *)OBJECT_GET_DATA(widget, "graph_analysis_data_t");
1041
1042         /* Up scroll */
1043         switch(event->direction) {
1044         case(GDK_SCROLL_UP):
1045                 if (user_data->dlg.first_item == 0) return TRUE;
1046                 if (user_data->dlg.first_item < 3)
1047                         user_data->dlg.first_item = 0;
1048                 else
1049                         user_data->dlg.first_item -= 3;
1050                 break;
1051         case(GDK_SCROLL_DOWN):
1052                 if ((user_data->dlg.first_item+user_data->dlg.v_scrollbar_adjustment->page_size+1 == user_data->num_items)) return TRUE;
1053                 if ((user_data->dlg.first_item+user_data->dlg.v_scrollbar_adjustment->page_size+1) > (user_data->num_items-3))
1054                         user_data->dlg.first_item = user_data->num_items-(guint32)user_data->dlg.v_scrollbar_adjustment->page_size-1;
1055                 else
1056                         user_data->dlg.first_item += 3;
1057             break;
1058         case(GDK_SCROLL_LEFT):
1059         case(GDK_SCROLL_RIGHT):
1060             /* nothing to do */
1061             break;
1062         }
1063         dialog_graph_redraw(user_data);
1064
1065         return TRUE;
1066 }
1067
1068 /****************************************************************************/
1069 static gint key_press_event(GtkWidget *widget, GdkEventKey *event _U_)
1070 {
1071         graph_analysis_data_t *user_data;
1072
1073         user_data=(graph_analysis_data_t *)OBJECT_GET_DATA(widget, "graph_analysis_data_t");
1074
1075         /* if there is nothing selected, just return */
1076         if (user_data->dlg.selected_item == 0xFFFFFFFF) return TRUE;
1077
1078         /* Up arrow */
1079         if (event->keyval == GDK_Up){
1080                 if (user_data->dlg.selected_item == 0) return TRUE;
1081                 user_data->dlg.selected_item--;
1082                 if ( (user_data->dlg.selected_item<user_data->dlg.first_item) || (user_data->dlg.selected_item>user_data->dlg.first_item+user_data->dlg.v_scrollbar_adjustment->page_size) )
1083                         user_data->dlg.first_item = user_data->dlg.selected_item;
1084                 /* Down arrow */
1085         } else if (event->keyval == GDK_Down){
1086                 if (user_data->dlg.selected_item == user_data->num_items-1) return TRUE;
1087                 user_data->dlg.selected_item++;
1088                 if ( (user_data->dlg.selected_item<user_data->dlg.first_item) || (user_data->dlg.selected_item>user_data->dlg.first_item+user_data->dlg.v_scrollbar_adjustment->page_size) )
1089                         user_data->dlg.first_item = (guint32)user_data->dlg.selected_item-(guint32)user_data->dlg.v_scrollbar_adjustment->page_size;
1090         } else if (event->keyval == GDK_Left){
1091                 if (user_data->dlg.first_node == 0) return TRUE;
1092                 user_data->dlg.first_node--;
1093         } else return TRUE;
1094
1095         user_data->dlg.needs_redraw=TRUE;
1096         dialog_graph_draw(user_data);
1097
1098         cf_goto_frame(&cfile, user_data->dlg.items[user_data->dlg.selected_item-user_data->dlg.first_item].frame_num);
1099
1100         return TRUE;
1101 }
1102
1103 /****************************************************************************/
1104 static gint expose_event(GtkWidget *widget, GdkEventExpose *event)
1105 {
1106         graph_analysis_data_t *user_data;
1107
1108         user_data=(graph_analysis_data_t *)OBJECT_GET_DATA(widget, "graph_analysis_data_t");
1109         if(!user_data){
1110                 exit(10);
1111         }
1112
1113         if (GDK_IS_DRAWABLE(widget->window) )
1114                 gdk_draw_pixmap(widget->window,
1115                 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
1116                 user_data->dlg.pixmap,
1117                 event->area.x, event->area.y,
1118                 event->area.x, event->area.y,
1119                 event->area.width, event->area.height);
1120
1121         return FALSE;
1122 }
1123
1124 /****************************************************************************/
1125 static gint expose_event_comments(GtkWidget *widget, GdkEventExpose *event)
1126 {
1127         graph_analysis_data_t *user_data;
1128
1129         user_data=(graph_analysis_data_t *)OBJECT_GET_DATA(widget, "graph_analysis_data_t");
1130         if(!user_data){
1131                 exit(10);
1132         }
1133
1134         if (GDK_IS_DRAWABLE(widget->window) )
1135                 gdk_draw_pixmap(widget->window,
1136                 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
1137                 user_data->dlg.pixmap_comments,
1138                 event->area.x, event->area.y,
1139                 event->area.x, event->area.y,
1140                 event->area.width, event->area.height);
1141
1142         return FALSE;
1143 }
1144
1145 /****************************************************************************/
1146 static gint expose_event_time(GtkWidget *widget, GdkEventExpose *event)
1147 {
1148         graph_analysis_data_t *user_data;
1149
1150         user_data=(graph_analysis_data_t *)OBJECT_GET_DATA(widget, "graph_analysis_data_t");
1151         if(!user_data){
1152                 exit(10);
1153         }
1154
1155         if (GDK_IS_DRAWABLE(widget->window) )
1156                 gdk_draw_pixmap(widget->window,
1157                 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
1158                 user_data->dlg.pixmap_time,
1159                 event->area.x, event->area.y,
1160                 event->area.x, event->area.y,
1161                 event->area.width, event->area.height);
1162
1163         return FALSE;
1164 }
1165
1166 /****************************************************************************/
1167 static gint configure_event(GtkWidget *widget, GdkEventConfigure *event _U_)
1168 {
1169         graph_analysis_data_t *user_data;
1170         int i;
1171
1172         /* gray and soft gray colors */
1173         static GdkColor color_div_line[2] = {
1174                 {0, 0x64ff, 0x64ff, 0x64ff},
1175                 {0, 0x7fff, 0x7fff, 0x7fff}
1176         };
1177
1178         /* the first calor is blue to highlight the selected item */
1179         static GdkColor col[MAX_NUM_COL_CONV+1] = {
1180                 {0,     0x00FF, 0x00FF, 0xFFFF},
1181         {0,     0x33FF, 0xFFFF, 0x33FF},
1182         {0,     0x00FF, 0xCCFF, 0xCCFF},
1183                 {0,     0x66FF, 0xFFFF, 0xFFFF},
1184                 {0,     0x99FF, 0x66FF, 0xFFFF},
1185                 {0,     0xFFFF, 0xFFFF, 0x33FF},
1186                 {0,     0xCCFF, 0x99FF, 0xFFFF},
1187                 {0,     0xCCFF, 0xFFFF, 0x33FF},
1188                 {0,     0xFFFF, 0xCCFF, 0xCCFF},
1189                 {0,     0xFFFF, 0x99FF, 0x66FF},
1190                 {0,     0xFFFF, 0xFFFF, 0x99FF}
1191         };
1192
1193         user_data=(graph_analysis_data_t *)OBJECT_GET_DATA(widget, "graph_analysis_data_t");
1194
1195         if(!user_data){
1196                 exit(10);
1197         }
1198
1199         if(user_data->dlg.pixmap){
1200                 gdk_pixmap_unref(user_data->dlg.pixmap);
1201                 user_data->dlg.pixmap=NULL;
1202         }
1203
1204         user_data->dlg.pixmap=gdk_pixmap_new(widget->window,
1205                         widget->allocation.width,
1206                         widget->allocation.height,
1207                         -1);
1208
1209         if ( GDK_IS_DRAWABLE(user_data->dlg.pixmap) )
1210                         gdk_draw_rectangle(user_data->dlg.pixmap,
1211                 widget->style->white_gc,
1212                 TRUE,
1213                 0, 0,
1214                 widget->allocation.width,
1215                 widget->allocation.height);
1216
1217         /* create gc for division lines and set the line stype to dash*/
1218         for (i=0; i<2; i++){
1219                 user_data->dlg.div_line_gc[i]=gdk_gc_new(user_data->dlg.pixmap);
1220                 gdk_gc_set_line_attributes(user_data->dlg.div_line_gc[i], 1, GDK_LINE_ON_OFF_DASH, 0, 0);
1221         gdk_gc_set_rgb_fg_color(user_data->dlg.div_line_gc[i], &color_div_line[i]);
1222         }
1223
1224         /* create gcs for the background items */
1225         for (i=0; i<MAX_NUM_COL_CONV+1; i++){
1226                 user_data->dlg.bg_gc[i]=gdk_gc_new(user_data->dlg.pixmap);
1227         gdk_gc_set_rgb_fg_color(user_data->dlg.bg_gc[i], &col[i]);
1228         }
1229                 
1230                 dialog_graph_redraw(user_data);
1231
1232         return TRUE;
1233 }
1234
1235 /****************************************************************************/
1236 static gint configure_event_comments(GtkWidget *widget, GdkEventConfigure *event _U_)
1237 {
1238         graph_analysis_data_t *user_data;
1239
1240         user_data=(graph_analysis_data_t *)OBJECT_GET_DATA(widget, "graph_analysis_data_t");
1241
1242         if(!user_data){
1243                 exit(10);
1244         }
1245
1246         if(user_data->dlg.pixmap_comments){
1247                 gdk_pixmap_unref(user_data->dlg.pixmap_comments);
1248                 user_data->dlg.pixmap_comments=NULL;
1249         }
1250
1251         user_data->dlg.pixmap_comments=gdk_pixmap_new(widget->window,
1252                                                 widget->allocation.width,
1253                         widget->allocation.height,
1254                         -1);
1255
1256         if ( GDK_IS_DRAWABLE(user_data->dlg.pixmap) )
1257                 gdk_draw_rectangle(user_data->dlg.pixmap_comments,
1258                                                    widget->style->white_gc,
1259                                                    TRUE,
1260                                                    0, 0,
1261                                                    widget->allocation.width,
1262                                                    widget->allocation.height);
1263
1264         dialog_graph_redraw(user_data);
1265         return TRUE;
1266 }
1267
1268 /****************************************************************************/
1269 static gint configure_event_time(GtkWidget *widget, GdkEventConfigure *event _U_)
1270 {
1271         graph_analysis_data_t *user_data;
1272
1273         user_data=(graph_analysis_data_t *)OBJECT_GET_DATA(widget, "graph_analysis_data_t");
1274
1275         if(!user_data){
1276                 exit(10);
1277         }
1278
1279         if(user_data->dlg.pixmap_time){
1280                 gdk_pixmap_unref(user_data->dlg.pixmap_time);
1281                 user_data->dlg.pixmap_time=NULL;
1282         }
1283
1284         user_data->dlg.pixmap_time=gdk_pixmap_new(widget->window,
1285                                                 widget->allocation.width,
1286                         widget->allocation.height,
1287                         -1);
1288
1289         if ( GDK_IS_DRAWABLE(user_data->dlg.pixmap_time) )
1290                 gdk_draw_rectangle(user_data->dlg.pixmap_time,
1291                                                    widget->style->white_gc,
1292                                                    TRUE,
1293                                                    0, 0,
1294                                                    widget->allocation.width,
1295                                                    widget->allocation.height);
1296
1297         dialog_graph_redraw(user_data);
1298
1299
1300         return TRUE;
1301 }
1302 /****************************************************************************/
1303 static gint pane_callback(GtkWidget *widget, GParamSpec *pspec _U_, gpointer data)
1304 {
1305         graph_analysis_data_t *user_data=(graph_analysis_data_t *)data;
1306
1307         if(!user_data){
1308                 exit(10);
1309         }
1310         if (gtk_paned_get_position(GTK_PANED(user_data->dlg.hpane)) > user_data->dlg.pixmap_width)
1311                 gtk_paned_set_position(GTK_PANED(user_data->dlg.hpane), user_data->dlg.pixmap_width);
1312         else if (gtk_paned_get_position(GTK_PANED(user_data->dlg.hpane)) < NODE_WIDTH*2)
1313                 gtk_paned_set_position(GTK_PANED(user_data->dlg.hpane), NODE_WIDTH*2);
1314         /* repaint the comment area because when moving the pane position thre are times that the expose_event_comments is not called */
1315         if (GDK_IS_DRAWABLE(user_data->dlg.draw_area_comments->window) )
1316                 gdk_draw_pixmap(user_data->dlg.draw_area_comments->window,
1317                 user_data->dlg.draw_area_comments->style->fg_gc[GTK_WIDGET_STATE(widget)],
1318                 user_data->dlg.pixmap_comments,
1319                                         0,0,
1320                                         0,0,
1321                                         user_data->dlg.draw_area_comments->allocation.width,
1322                 user_data->dlg.draw_area_comments->allocation.height);
1323         return TRUE;
1324 }
1325
1326 /****************************************************************************/
1327 static gint v_scrollbar_changed(GtkWidget *widget _U_, gpointer data)
1328 {
1329         graph_analysis_data_t *user_data=(graph_analysis_data_t *)data;
1330         if ((user_data->dlg.first_item+user_data->dlg.v_scrollbar_adjustment->page_size+1 == user_data->num_items)
1331                 && (user_data->dlg.v_scrollbar_adjustment->value >= user_data->dlg.first_item ))
1332                 return TRUE;
1333
1334         if (user_data->dlg.first_item == user_data->dlg.v_scrollbar_adjustment->value)
1335                 return TRUE;
1336
1337         user_data->dlg.first_item = (guint32) user_data->dlg.v_scrollbar_adjustment->value;
1338
1339         dialog_graph_redraw(user_data);
1340         return TRUE;
1341 }
1342
1343 /****************************************************************************/
1344 static void create_draw_area(graph_analysis_data_t* user_data, GtkWidget *box)
1345 {
1346         GtkWidget *vbox;
1347         GtkWidget *hbox;
1348         GtkWidget *viewport;
1349         GtkWidget *scroll_window_comments;
1350         GtkWidget *viewport_comments;
1351
1352         hbox=gtk_hbox_new(FALSE, 0);
1353         gtk_widget_show(hbox);
1354
1355         vbox=gtk_vbox_new(FALSE, 0);
1356         gtk_widget_show(vbox);
1357
1358         /* create "time" draw area */
1359         user_data->dlg.draw_area_time=gtk_drawing_area_new();
1360         WIDGET_SET_SIZE(user_data->dlg.draw_area_time, TIME_WIDTH, user_data->dlg.pixmap_height);
1361         OBJECT_SET_DATA(user_data->dlg.draw_area_time, "graph_analysis_data_t", user_data);
1362
1363         /* create "comments" draw area */
1364         user_data->dlg.draw_area_comments=gtk_drawing_area_new();
1365         WIDGET_SET_SIZE(user_data->dlg.draw_area_comments, COMMENT_WIDTH, user_data->dlg.pixmap_height);
1366         scroll_window_comments=gtk_scrolled_window_new(NULL, NULL);
1367         WIDGET_SET_SIZE(scroll_window_comments, COMMENT_WIDTH/2, user_data->dlg.pixmap_height);
1368         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll_window_comments), GTK_POLICY_ALWAYS, GTK_POLICY_NEVER);
1369         viewport_comments = gtk_viewport_new(gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(scroll_window_comments)), gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scroll_window_comments)));
1370         gtk_container_add(GTK_CONTAINER(viewport_comments), user_data->dlg.draw_area_comments);
1371         gtk_container_add(GTK_CONTAINER(scroll_window_comments), viewport_comments);
1372         gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport_comments), GTK_SHADOW_NONE);
1373         OBJECT_SET_DATA(user_data->dlg.draw_area_comments, "graph_analysis_data_t", user_data);
1374         gtk_widget_add_events (user_data->dlg.draw_area_comments, GDK_BUTTON_PRESS_MASK);
1375
1376         SIGNAL_CONNECT(user_data->dlg.draw_area_comments, "scroll_event",  scroll_event, user_data);
1377         /* create main Graph draw area */
1378         user_data->dlg.draw_area=gtk_drawing_area_new();
1379         if (user_data->num_nodes < 2)
1380                 user_data->dlg.pixmap_width = 2 * NODE_WIDTH;
1381         else
1382                 user_data->dlg.pixmap_width = user_data->num_nodes * NODE_WIDTH;
1383         WIDGET_SET_SIZE(user_data->dlg.draw_area, user_data->dlg.pixmap_width, user_data->dlg.pixmap_height);
1384         user_data->dlg.scroll_window=gtk_scrolled_window_new(NULL, NULL);
1385         if ( user_data->num_nodes < 6)
1386                 WIDGET_SET_SIZE(user_data->dlg.scroll_window, NODE_WIDTH*user_data->num_nodes, user_data->dlg.pixmap_height);
1387         else
1388                 WIDGET_SET_SIZE(user_data->dlg.scroll_window, NODE_WIDTH*5, user_data->dlg.pixmap_height);
1389         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(user_data->dlg.scroll_window), GTK_POLICY_ALWAYS, GTK_POLICY_NEVER);
1390         viewport = gtk_viewport_new(gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(user_data->dlg.scroll_window)), gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(user_data->dlg.scroll_window)));
1391         gtk_container_add(GTK_CONTAINER(viewport), user_data->dlg.draw_area);
1392         gtk_container_add(GTK_CONTAINER(user_data->dlg.scroll_window), viewport);
1393         gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1394         OBJECT_SET_DATA(user_data->dlg.draw_area, "graph_analysis_data_t", user_data);
1395         GTK_WIDGET_SET_FLAGS(user_data->dlg.draw_area, GTK_CAN_FOCUS);
1396         gtk_widget_grab_focus(user_data->dlg.draw_area);
1397
1398         /* signals needed to handle backing pixmap */
1399         SIGNAL_CONNECT(user_data->dlg.draw_area, "expose_event", expose_event, NULL);
1400         SIGNAL_CONNECT(user_data->dlg.draw_area, "configure_event", configure_event, user_data);
1401
1402         /* signals needed to handle backing pixmap comments*/
1403         SIGNAL_CONNECT(user_data->dlg.draw_area_comments, "expose_event", expose_event_comments, NULL);
1404         SIGNAL_CONNECT(user_data->dlg.draw_area_comments, "configure_event", configure_event_comments, user_data);
1405
1406         /* signals needed to handle backing pixmap time*/
1407         SIGNAL_CONNECT(user_data->dlg.draw_area_time, "expose_event", expose_event_time, NULL);
1408         SIGNAL_CONNECT(user_data->dlg.draw_area_time, "configure_event", configure_event_time, user_data);
1409
1410         gtk_widget_add_events (user_data->dlg.draw_area, GDK_BUTTON_PRESS_MASK);
1411         SIGNAL_CONNECT(user_data->dlg.draw_area, "button_press_event", button_press_event, user_data);
1412         SIGNAL_CONNECT(user_data->dlg.draw_area, "scroll_event",  scroll_event, user_data);
1413         SIGNAL_CONNECT(user_data->dlg.draw_area, "key_press_event",  key_press_event, user_data);
1414
1415         gtk_widget_show(user_data->dlg.draw_area_time);
1416         gtk_widget_show(user_data->dlg.draw_area);
1417         gtk_widget_show(viewport);
1418         gtk_widget_show(user_data->dlg.draw_area_comments);
1419         gtk_widget_show(viewport_comments);
1420
1421         gtk_widget_show(user_data->dlg.scroll_window);
1422         gtk_widget_show(scroll_window_comments);
1423
1424         gtk_box_pack_start(GTK_BOX(hbox), user_data->dlg.draw_area_time, FALSE, FALSE, 0);
1425
1426                 user_data->dlg.hpane = gtk_hpaned_new();
1427                 gtk_paned_pack1(GTK_PANED (user_data->dlg.hpane), user_data->dlg.scroll_window, FALSE, TRUE);
1428                 gtk_paned_pack2(GTK_PANED (user_data->dlg.hpane), scroll_window_comments, TRUE, TRUE);
1429         SIGNAL_CONNECT(user_data->dlg.hpane, "notify::position",  pane_callback, user_data);
1430         gtk_widget_show(user_data->dlg.hpane);
1431
1432         gtk_box_pack_start(GTK_BOX(hbox), user_data->dlg.hpane, TRUE, TRUE, 0);
1433
1434        /* create the associated v_scrollbar */
1435         user_data->dlg.v_scrollbar_adjustment=(GtkAdjustment *)gtk_adjustment_new(0,0,0,0,0,0);
1436         user_data->dlg.v_scrollbar=gtk_vscrollbar_new(user_data->dlg.v_scrollbar_adjustment);
1437         gtk_widget_show(user_data->dlg.v_scrollbar);
1438         gtk_box_pack_end(GTK_BOX(hbox), user_data->dlg.v_scrollbar, FALSE, FALSE, 0);
1439         SIGNAL_CONNECT(user_data->dlg.v_scrollbar_adjustment, "value_changed", v_scrollbar_changed, user_data);
1440
1441
1442         gtk_box_pack_start(GTK_BOX(box), hbox, TRUE, TRUE, 0);
1443 }
1444 /****************************************************************************/
1445 /* PUBLIC */
1446 /****************************************************************************/
1447
1448
1449 /****************************************************************************/
1450 static void dialog_graph_create_window(graph_analysis_data_t* user_data)
1451 {
1452         GtkWidget *vbox;
1453         GtkWidget *hbuttonbox;
1454         GtkWidget *bt_close;
1455         GtkWidget *bt_save;
1456         GtkTooltips *tooltips = gtk_tooltips_new();
1457         const gchar *title_name_ptr;
1458         gchar   *win_name;
1459
1460         title_name_ptr = cf_get_display_name(&cfile);
1461         win_name = g_strdup_printf("%s - Graph Analysis", title_name_ptr);
1462
1463         /* create the main window */
1464                 if (user_data->dlg.title)
1465                 user_data->dlg.window=window_new(GTK_WINDOW_TOPLEVEL, user_data->dlg.title);
1466                 else
1467                 user_data->dlg.window=window_new(GTK_WINDOW_TOPLEVEL, win_name);
1468
1469
1470         vbox=gtk_vbox_new(FALSE, 0);
1471         gtk_container_add(GTK_CONTAINER(user_data->dlg.window), vbox);
1472         gtk_widget_show(vbox);
1473
1474         create_draw_area(user_data, vbox);
1475
1476         /* button row */
1477         hbuttonbox = gtk_hbutton_box_new ();
1478         gtk_box_pack_start (GTK_BOX (vbox), hbuttonbox, FALSE, FALSE, 0);
1479         gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox), GTK_BUTTONBOX_SPREAD);
1480         gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbuttonbox), 30);
1481         gtk_widget_show(hbuttonbox);
1482
1483         bt_save = BUTTON_NEW_FROM_STOCK(GTK_STOCK_SAVE_AS);
1484         gtk_container_add(GTK_CONTAINER(hbuttonbox), bt_save);
1485         gtk_widget_show(bt_save);
1486         SIGNAL_CONNECT(bt_save, "clicked", on_save_bt_clicked, user_data);
1487         gtk_tooltips_set_tip (tooltips, bt_save, "Save an ASCII representation of the graph to a file", NULL);
1488
1489         bt_close = BUTTON_NEW_FROM_STOCK(GTK_STOCK_CLOSE);
1490         gtk_container_add (GTK_CONTAINER (hbuttonbox), bt_close);
1491         GTK_WIDGET_SET_FLAGS(bt_close, GTK_CAN_DEFAULT);
1492         gtk_widget_show(bt_close);
1493         gtk_tooltips_set_tip (tooltips, bt_close, "Close this dialog", NULL);
1494         window_set_cancel_button(user_data->dlg.window, bt_close, window_cancel_button_cb);
1495
1496         SIGNAL_CONNECT(user_data->dlg.window, "delete_event", window_delete_event_cb, NULL);
1497         SIGNAL_CONNECT(user_data->dlg.window, "destroy", on_destroy, user_data);
1498
1499         gtk_widget_show(user_data->dlg.window);
1500         window_present(user_data->dlg.window);
1501
1502         /* Destroy our graph window with our parent if the caller specified the parent */
1503         if(user_data->dlg.parent_w) {
1504                 gtk_window_set_transient_for(GTK_WINDOW(user_data->dlg.window),
1505                                              GTK_WINDOW(user_data->dlg.parent_w));
1506                 /* Destruction of this child window in GTK1 is handled by a call
1507                  * to destroy_window() in flow_graph.c. */
1508                 gtk_window_set_destroy_with_parent(GTK_WINDOW(user_data->dlg.window), TRUE);
1509         }
1510         g_free(win_name);
1511 }
1512
1513 /* Return the index array if the node is in the array. Return -1 if there is room in the array
1514  * and Return -2 if the array is full
1515  */
1516 /****************************************************************************/
1517 static gint add_or_get_node(graph_analysis_data_t* user_data, address* node) {
1518         guint i;
1519         
1520         if (node->type == AT_NONE) return NODE_OVERFLOW;
1521                 
1522         for (i=0; i<MAX_NUM_NODES && i < user_data->num_nodes ; i++){
1523                 if ( CMP_ADDRESS(&(user_data->nodes[i]), node) == 0 ) return i; /* it is in the array */
1524         }
1525         
1526         if (i == MAX_NUM_NODES) {
1527                 return  NODE_OVERFLOW;
1528         } else {
1529                 user_data->num_nodes++;
1530                 COPY_ADDRESS(&(user_data->nodes[i]),node);
1531                 return i;
1532         }
1533 }
1534
1535 /* Get the nodes from the list */
1536 /****************************************************************************/
1537 static void get_nodes(graph_analysis_data_t* user_data)
1538 {
1539         GList* list;
1540         graph_analysis_item_t *gai;
1541
1542         /* fill the node array */
1543         list = g_list_first(user_data->graph_info->list);
1544         while (list)
1545         {
1546                 gai = list->data;
1547                 if (gai->display) {
1548                         user_data->num_items++;
1549                         if (!user_data->dlg.inverse) {
1550                                 gai->src_node = (guint16)add_or_get_node(user_data, &(gai->src_addr));
1551                                 gai->dst_node = (guint16)add_or_get_node(user_data, &(gai->dst_addr));
1552                         } else {
1553                                 gai->dst_node = (guint16)add_or_get_node(user_data, &(gai->src_addr));
1554                                 gai->src_node = (guint16)add_or_get_node(user_data, &(gai->dst_addr));
1555                         }
1556                 }
1557                 list = g_list_next(list);
1558         }
1559 }
1560
1561 /****************************************************************************/
1562 graph_analysis_data_t* graph_analysis_init(void)
1563 {
1564         graph_analysis_data_t* user_data;
1565         /* init */
1566         user_data = g_malloc(sizeof(graph_analysis_data_t));
1567
1568         /* init user_data */
1569         graph_analysis_init_dlg(user_data);
1570
1571         return user_data;
1572 }
1573 /****************************************************************************/
1574 /* PUBLIC */
1575 /****************************************************************************/
1576
1577 /****************************************************************************/
1578 void graph_analysis_create(graph_analysis_data_t* user_data)
1579 {
1580         /* reset the data */
1581         graph_analysis_reset(user_data);
1582
1583         /* get nodes (each node is an address) */
1584         get_nodes(user_data);
1585
1586         /* create the graph windows */
1587         dialog_graph_create_window(user_data);
1588
1589         /* redraw the graph */
1590         dialog_graph_redraw(user_data);
1591
1592         return;
1593 }
1594
1595 /****************************************************************************/
1596 void graph_analysis_update(graph_analysis_data_t* user_data)
1597 {
1598         /* reset the data */
1599         graph_analysis_reset(user_data);
1600
1601         /* get nodes (each node is an address) */
1602         get_nodes(user_data);
1603
1604         user_data->dlg.pixmap_width = user_data->num_nodes * NODE_WIDTH;
1605         WIDGET_SET_SIZE(user_data->dlg.draw_area, user_data->dlg.pixmap_width, user_data->dlg.pixmap_height);
1606         if ( user_data->num_nodes < 6)
1607                 WIDGET_SET_SIZE(user_data->dlg.scroll_window, NODE_WIDTH*user_data->num_nodes, user_data->dlg.pixmap_height);
1608         else
1609                 WIDGET_SET_SIZE(user_data->dlg.scroll_window, NODE_WIDTH*5, user_data->dlg.pixmap_height);
1610
1611         /* redraw the graph */
1612         dialog_graph_redraw(user_data);
1613
1614         window_present(user_data->dlg.window);
1615         return;
1616 }
1617
1618
1619 /****************************************************************************/
1620 void graph_analysis_redraw(graph_analysis_data_t* user_data)
1621 {
1622         /* get nodes (each node is an address) */
1623         get_nodes(user_data);
1624
1625         user_data->dlg.pixmap_width = user_data->num_nodes * NODE_WIDTH;
1626     WIDGET_SET_SIZE(user_data->dlg.draw_area, user_data->dlg.pixmap_width, user_data->dlg.pixmap_height);
1627         if ( user_data->num_nodes < 6)  
1628                         WIDGET_SET_SIZE(user_data->dlg.scroll_window, NODE_WIDTH*user_data->num_nodes, user_data->dlg.pixmap_height);
1629                 else
1630                         WIDGET_SET_SIZE(user_data->dlg.scroll_window, NODE_WIDTH*5, user_data->dlg.pixmap_height);
1631
1632
1633         /* redraw the graph */
1634         dialog_graph_redraw(user_data); 
1635
1636     window_present(user_data->dlg.window);
1637         return;
1638 }