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