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