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