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