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