2 * Graphic Analysis addition for Wireshark
6 * Copyright 2004, Verso Technologies Inc.
7 * By Alejandro Vaquero <alejandrovaquero@yahoo.com>
9 * based on rtp_analysis.c and io_stat
12 * Wireshark - Network traffic analyzer
13 * By Gerald Combs <gerald@wireshark.org>
14 * Copyright 1998 Gerald Combs
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.
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.
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.
43 #include <gdk/gdkkeysyms.h>
45 #include <epan/epan_dissect.h>
47 #include <epan/dissectors/packet-rtp.h>
48 #include <epan/addr_resolv.h>
49 #include "epan/filesystem.h"
53 #include "../simple_dialog.h"
54 #include "../alert_box.h"
55 #include <wsutil/file_util.h>
57 #include "gtk/gtkglobals.h"
58 #include "gtk/file_dlg.h"
59 #include "gtk/gui_utils.h"
60 #include "gtk/dlg_utils.h"
62 #include "gtk/graph_analysis.h"
63 #include "../image/voip_select.xpm"
64 #include "../image/voip_bg.xpm"
66 /****************************************************************************/
69 #define OK_TEXT "[ Ok ]"
70 #define PT_UNDEFINED -1
73 static GtkWidget *save_to_file_w = NULL;
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
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
92 /****************************************************************************/
93 /* Reset the user_data structure */
94 static void graph_analysis_reset(graph_analysis_data_t *user_data)
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;
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 */
113 /****************************************************************************/
114 /* Init the user_data structure */
115 static void graph_analysis_init_dlg(graph_analysis_data_t *user_data)
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;
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;
155 /****************************************************************************/
158 /****************************************************************************/
159 /* close the dialog window */
160 static void on_destroy(GtkWidget *win _U_, graph_analysis_data_t *user_data)
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;
170 user_data->dlg.window = NULL;
171 g_free(user_data->dlg.title);
172 user_data->dlg.title = NULL;
174 if(user_data->on_destroy_user_data){
175 user_data->on_destroy_user_data(user_data->data);
179 #define RIGHT_ARROW 1
181 #define WIDTH_ARROW 8
182 #define HEIGHT_ARROW 6
184 /****************************************************************************/
185 static void draw_arrow(GdkDrawable *pixmap, GdkGC *gc, gint x, gint y, gboolean direction)
187 GdkPoint arrow_point[3];
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;
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;;
199 if (GDK_IS_DRAWABLE(pixmap)) {
200 gdk_draw_polygon(pixmap, gc, TRUE, arrow_point, 3);
204 /****************************************************************************/
205 /* Adds trailing characters to complete the requested length. */
206 /****************************************************************************/
208 static void enlarge_string(GString *gstr, guint32 length, char pad){
212 for (i = gstr->len; i < length; i++){
213 g_string_append_c(gstr, pad);
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 /****************************************************************************/
223 static void overwrite (GString *gstr, char *text_to_insert, guint32 p1, guint32 p2){
240 if (len > strlen(text_to_insert)){
241 len = strlen(text_to_insert);
247 /* ouch this is ugly but gtk1 needs it */
248 if ((pos + len) > gstr->len)
249 g_string_truncate(gstr, pos);
251 g_string_erase(gstr, pos, len);
253 g_string_insert(gstr, pos, text_to_insert);
256 /****************************************************************************/
257 static gboolean dialog_graph_dump_to_file(graph_analysis_data_t *user_data)
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;
266 GString *label_string, *empty_line,*separator_line, *tmp_str, *tmp_str2;
268 char src_port[8],dst_port[8];
274 of = ws_fopen(user_data->dlg.save_file,"w");
276 open_failure_alert_box(user_data->dlg.save_file, errno, TRUE);
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("");
287 list = g_list_first(user_data->graph_info->list);
291 list = g_list_next(list);
298 first_conv_num = gai->conv_num;
301 else if (gai->conv_num != first_conv_num){
302 several_convs = TRUE;
306 /* if not items to display */
307 if (display_items == 0)
310 display_nodes = user_data->num_nodes;
312 first_node = user_data->dlg.first_node;
314 /* Write the conv. and time headers */
316 fprintf(of, CONV_TIME_HEADER);
317 empty_header = CONV_TIME_EMPTY_HEADER;
318 header_length = CONV_TIME_HEADER_LENGTH;
321 fprintf(of, TIME_HEADER);
322 empty_header = TIME_EMPTY_HEADER;
323 header_length = TIME_HEADER_LENGTH;
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);
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);
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)
350 enlarge_string(label_string, NODE_CHARS_WIDTH, ' ');
351 g_string_append(label_string, "| ");
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);
362 g_string_append_c(empty_line, '|');
364 enlarge_string(separator_line, (guint32) empty_line->len + header_length, '-');
370 list = g_list_first(user_data->graph_info->list);
374 list = g_list_next(list);
379 start_position = (gai->src_node-first_node)*NODE_CHARS_WIDTH+NODE_CHARS_WIDTH/2;
381 end_position = (gai->dst_node-first_node)*NODE_CHARS_WIDTH+NODE_CHARS_WIDTH/2;
383 if (start_position > end_position){
384 item_width=start_position-end_position;
386 else if (start_position < end_position){
387 item_width=end_position-start_position;
389 else{ /* same origin and destination address */
390 end_position = start_position+NODE_CHARS_WIDTH;
391 item_width = NODE_CHARS_WIDTH;
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;
400 /* write the conversation number */
402 g_string_printf(label_string, "%i", gai->conv_num);
403 enlarge_string(label_string, 5, ' ');
404 fprintf(of, "%s", label_string->str);
408 g_string_printf(label_string, "|%.3f", gai->time);
409 enlarge_string(label_string, 10, ' ');
410 fprintf(of, "%s", label_string->str);
412 /* write the frame label */
414 g_string_printf(tmp_str, "%s", empty_line->str);
415 overwrite(tmp_str,gai->frame_label,
419 fprintf(of, "%s", tmp_str->str);
421 /* write the comments */
422 fprintf(of, "%s\n", gai->comment);
424 /* write the arrow and frame label*/
425 fprintf(of, "%s", empty_header);
427 g_string_printf(tmp_str, "%s", empty_line->str);
429 g_string_truncate(tmp_str2, 0);
431 if (start_position<end_position){
432 enlarge_string(tmp_str2, item_width-2, '-');
433 g_string_append_c(tmp_str2, '>');
436 g_string_printf(tmp_str2, "<");
437 enlarge_string(tmp_str2, item_width-1, '-');
440 overwrite(tmp_str,tmp_str2->str,
445 g_snprintf(src_port,sizeof(src_port),"(%i)", gai->port_src);
446 g_snprintf(dst_port,sizeof(dst_port),"(%i)", gai->port_dst);
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);
453 overwrite(tmp_str,src_port,start_position+1,start_position+9);
454 overwrite(tmp_str,dst_port,end_position-9,end_position+1);
457 fprintf(of,"%s\n",tmp_str->str);
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);
472 /****************************************************************************/
473 static void save_to_file_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
475 /* Note that we no longer have a Save to file dialog box. */
476 save_to_file_w = NULL;
479 /****************************************************************************/
482 /* first an auxiliary function in case we need an overwrite confirmation dialog */
484 static void overwrite_existing_file_cb(gpointer dialog _U_, gint btn, gpointer user_data)
488 /* overwrite the file*/
489 dialog_graph_dump_to_file(user_data);
494 g_assert_not_reached();
498 /* and then the save in a file dialog itself */
500 static gboolean save_to_file_ok_cb(GtkWidget *ok_bt _U_, gpointer user_data)
503 graph_analysis_data_t *user_data_p = user_data;
505 user_data_p->dlg.save_file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(save_to_file_w));
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 */
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) */
523 /* As a work-around: */
524 /* We'll always destroy the window. */
526 /* check whether the file exists */
527 file_test = ws_fopen(user_data_p->dlg.save_file,"r");
528 if (file_test!=NULL){
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);
540 if (!dialog_graph_dump_to_file(user_data)) {
541 /* Couldn't open the file ? */
542 g_free(user_data_p->dlg.save_file);
546 g_free(user_data_p->dlg.save_file);
550 /****************************************************************************/
552 on_save_bt_clicked (GtkWidget *button _U_,
553 graph_analysis_data_t *user_data)
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);
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,
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);
573 gtk_widget_show(save_to_file_w);
574 window_present(save_to_file_w);
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. */
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 */
594 window_destroy(save_to_file_w);
597 /****************************************************************************/
598 static void dialog_graph_draw(graph_analysis_data_t *user_data)
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;
611 GdkGC *frame_fg_color;
612 GdkGC *frame_bg_color;
613 GdkGC *div_line_color;
614 GdkGC *column_header_gc;
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;
624 gint label_width, label_height;
625 guint32 draw_width, draw_height;
626 char label_string[MAX_COMMENT];
631 if(!user_data->dlg.needs_redraw){
634 user_data->dlg.needs_redraw=FALSE;
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));
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,
646 user_data->dlg.draw_area_time->allocation.width,
647 user_data->dlg.draw_area_time->allocation.height);
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,
654 user_data->dlg.draw_area->allocation.width,
655 user_data->dlg.draw_area->allocation.height);
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,
662 user_data->dlg.draw_area_comments->allocation.width,
663 user_data->dlg.draw_area_comments->allocation.height);
665 /* Calculate the y border */
666 top_y_border=TOP_Y_BORDER; /* to display the node address */
667 bottom_y_border=BOTTOM_Y_BORDER;
669 draw_height=user_data->dlg.draw_area->allocation.height-top_y_border-bottom_y_border;
671 first_item = user_data->dlg.first_item;
672 display_items = draw_height/ITEM_HEIGHT;
674 /* get the items to display and fill the matrix array */
675 list = g_list_first(user_data->graph_info->list);
682 if (current_item>=display_items) break; /* the item is outside the display */
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] = '.';
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;
699 first_conv_num = gai->conv_num;
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;
711 list = g_list_next(list);
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)
718 first_item = user_data->num_items - display_items;
721 /* in case there are less items than possible displayed */
722 display_items = current_item;
723 last_item = first_item+display_items-1;
725 /* if no items to display */
726 if (display_items == 0) return;
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);
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);
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);
746 pango_layout_get_pixel_size(layout, &label_width, &label_height);
748 /* resize the "time" draw area */
750 user_data->dlg.left_x_border = left_x_border;
753 draw_width=user_data->dlg.pixmap_width-right_x_border-left_x_border;
755 /* Paint time title background */
756 if ( GDK_IS_DRAWABLE(user_data->dlg.pixmap_time) )
757 gdk_draw_rectangle(user_data->dlg.pixmap_time,
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,
771 user_data->dlg.draw_area->allocation.width,
773 /* Paint main comment background */
774 if ( GDK_IS_DRAWABLE(user_data->dlg.pixmap_comments) )
775 gdk_draw_rectangle(user_data->dlg.pixmap_comments,
780 user_data->dlg.draw_area_comments->allocation.width,
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,
792 top_y_border/2-label_height/2,
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,
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];
815 frame_bg_color = user_data->dlg.bg_gc[1+user_data->dlg.items[current_item].conv_num%MAX_NUM_COL_CONV];
818 /* Paint background */
819 if (GDK_IS_DRAWABLE(user_data->dlg.pixmap_main)) {
820 gdk_draw_rectangle(user_data->dlg.pixmap_main,
824 top_y_border+current_item*ITEM_HEIGHT,
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),
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,
849 left_x_border+NODE_WIDTH/2+NODE_WIDTH*i,
850 user_data->dlg.draw_area->allocation.height-bottom_y_border);
856 for (current_item=0; current_item<display_items; current_item++){
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,
865 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT/2-label_height/2,
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,
877 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT/2-label_height/2,
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];
885 frame_fg_color = user_data->dlg.draw_area->style->black_gc;
886 div_line_color = user_data->dlg.div_line_gc[0];
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;
892 if (GDK_IS_DRAWABLE(user_data->dlg.pixmap_main) ) {
893 gdk_draw_line(user_data->dlg.pixmap_main, frame_fg_color,
895 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-7,
897 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-7);
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,
903 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-6,
905 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-6);
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);
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);
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;
924 arrow_width = start_arrow-end_arrow;
925 label_x = arrow_width/2+end_arrow;
928 if (label_width>(gint)arrow_width) arrow_width = label_width;
930 if ((int)left_x_border > ((int)label_x-(int)label_width/2))
931 label_x = left_x_border + label_width/2;
933 if (GDK_IS_DRAWABLE(user_data->dlg.pixmap_main)) {
934 gdk_draw_layout(user_data->dlg.pixmap_main,
936 label_x - label_width/2,
937 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT/2-label_height/2-3,
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;
949 src_port_x = start_arrow + 2;
951 if (GDK_IS_DRAWABLE(user_data->dlg.pixmap_main)) {
952 gdk_draw_layout(user_data->dlg.pixmap_main,
955 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-2-label_height/2-2,
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;
967 dst_port_x = end_arrow - label_width - 2;
969 if (GDK_IS_DRAWABLE(user_data->dlg.pixmap_main)) {
970 gdk_draw_layout(user_data->dlg.pixmap_main,
973 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-2-label_height/2-2,
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);
989 g_object_unref(G_OBJECT(layout));
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,
998 user_data->dlg.draw_area_time->allocation.width, user_data->dlg.draw_area_time->allocation.height);
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,
1006 user_data->dlg.draw_area->allocation.width, user_data->dlg.draw_area->allocation.height);
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,
1014 user_data->dlg.draw_area_comments->allocation.width, user_data->dlg.draw_area_comments->allocation.height);
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;
1023 gtk_adjustment_changed(user_data->dlg.v_scrollbar_adjustment);
1024 gtk_adjustment_value_changed(user_data->dlg.v_scrollbar_adjustment);
1027 /****************************************************************************/
1028 static void dialog_graph_redraw(graph_analysis_data_t *user_data)
1030 user_data->dlg.needs_redraw=TRUE;
1031 dialog_graph_draw(user_data);
1034 /****************************************************************************/
1035 static gboolean button_press_event(GtkWidget *widget _U_, GdkEventButton *event, gpointer data)
1037 graph_analysis_data_t *user_data = data;
1040 if (event->type != GDK_BUTTON_PRESS) return TRUE;
1042 if (event->y<TOP_Y_BORDER) return TRUE;
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;
1049 user_data->dlg.needs_redraw=TRUE;
1050 dialog_graph_draw(user_data);
1052 cf_goto_frame(&cfile, user_data->dlg.items[item].frame_num);
1057 /****************************************************************************/
1058 static gboolean scroll_event(GtkWidget *widget _U_, GdkEventScroll *event, gpointer data)
1060 graph_analysis_data_t *user_data = data;
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;
1069 user_data->dlg.first_item -= 3;
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;
1076 user_data->dlg.first_item += 3;
1078 case(GDK_SCROLL_LEFT):
1079 case(GDK_SCROLL_RIGHT):
1083 dialog_graph_redraw(user_data);
1088 /****************************************************************************/
1089 static gboolean key_press_event(GtkWidget *widget _U_, GdkEventKey *event, gpointer data)
1091 graph_analysis_data_t *user_data = data;
1093 /* if there is nothing selected, just return */
1094 if (user_data->dlg.selected_item == 0xFFFFFFFF) return TRUE;
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;
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--;
1113 user_data->dlg.needs_redraw=TRUE;
1114 dialog_graph_draw(user_data);
1116 cf_goto_frame(&cfile, user_data->dlg.items[user_data->dlg.selected_item-user_data->dlg.first_item].frame_num);
1121 /****************************************************************************/
1122 static gboolean expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
1124 graph_analysis_data_t *user_data = data;
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);
1137 /****************************************************************************/
1138 static gboolean expose_event_comments(GtkWidget *widget, GdkEventExpose *event, gpointer data)
1140 graph_analysis_data_t *user_data = data;
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);
1153 /****************************************************************************/
1154 static gboolean expose_event_time(GtkWidget *widget, GdkEventExpose *event, gpointer data)
1156 graph_analysis_data_t *user_data = data;
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);
1169 /****************************************************************************/
1170 static gboolean configure_event(GtkWidget *widget, GdkEventConfigure *event _U_, gpointer data)
1172 graph_analysis_data_t *user_data = data;
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}*/
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}
1197 if(user_data->dlg.pixmap_main){
1198 gdk_pixmap_unref(user_data->dlg.pixmap_main);
1199 user_data->dlg.pixmap_main=NULL;
1202 user_data->dlg.pixmap_main=gdk_pixmap_new(widget->window,
1203 widget->allocation.width,
1204 widget->allocation.height,
1207 if ( GDK_IS_DRAWABLE(user_data->dlg.pixmap_main) )
1208 gdk_draw_rectangle(user_data->dlg.pixmap_main,
1209 widget->style->white_gc,
1212 widget->allocation.width,
1213 widget->allocation.height);
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]);
1222 /* create gcs for the background items */
1223 for (i=0; i<MAX_NUM_COL_CONV+1; i++){
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);
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]);
1235 dialog_graph_redraw(user_data);
1240 /****************************************************************************/
1241 static gboolean configure_event_comments(GtkWidget *widget, GdkEventConfigure *event _U_, gpointer data)
1243 graph_analysis_data_t *user_data = data;
1245 if(user_data->dlg.pixmap_comments){
1246 gdk_pixmap_unref(user_data->dlg.pixmap_comments);
1247 user_data->dlg.pixmap_comments=NULL;
1250 user_data->dlg.pixmap_comments=gdk_pixmap_new(widget->window,
1251 widget->allocation.width,
1252 widget->allocation.height,
1255 if ( GDK_IS_DRAWABLE(user_data->dlg.pixmap_main) )
1256 gdk_draw_rectangle(user_data->dlg.pixmap_comments,
1257 widget->style->white_gc,
1260 widget->allocation.width,
1261 widget->allocation.height);
1263 dialog_graph_redraw(user_data);
1267 /****************************************************************************/
1268 static gboolean configure_event_time(GtkWidget *widget, GdkEventConfigure *event _U_, gpointer data)
1270 graph_analysis_data_t *user_data = data;
1272 if(user_data->dlg.pixmap_time){
1273 gdk_pixmap_unref(user_data->dlg.pixmap_time);
1274 user_data->dlg.pixmap_time=NULL;
1277 user_data->dlg.pixmap_time=gdk_pixmap_new(widget->window,
1278 widget->allocation.width,
1279 widget->allocation.height,
1282 if ( GDK_IS_DRAWABLE(user_data->dlg.pixmap_time) )
1283 gdk_draw_rectangle(user_data->dlg.pixmap_time,
1284 widget->style->white_gc,
1287 widget->allocation.width,
1288 widget->allocation.height);
1290 dialog_graph_redraw(user_data);
1295 /****************************************************************************/
1296 static gboolean pane_callback(GtkWidget *widget, GParamSpec *pspec _U_, gpointer data)
1298 graph_analysis_data_t *user_data = data;
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);
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,
1312 user_data->dlg.draw_area_comments->allocation.width,
1313 user_data->dlg.draw_area_comments->allocation.height);
1318 /****************************************************************************/
1319 static void v_scrollbar_changed(GtkWidget *widget _U_, gpointer data)
1321 graph_analysis_data_t *user_data = data;
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 ))
1327 if (user_data->dlg.first_item == user_data->dlg.v_scrollbar_adjustment->value)
1330 user_data->dlg.first_item = (guint32) user_data->dlg.v_scrollbar_adjustment->value;
1332 dialog_graph_redraw(user_data);
1337 /****************************************************************************/
1338 static void create_draw_area(graph_analysis_data_t *user_data, GtkWidget *box)
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;
1350 hbox=gtk_hbox_new(FALSE, 0);
1351 gtk_widget_show(hbox);
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);
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);
1366 * Set the scrollbar policy for the horizontal and vertical scrollbars
1367 * The policy determines when the scrollbar should appear
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 */
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);
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);
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;
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);
1396 gtk_widget_set_size_request(user_data->dlg.scroll_window, NODE_WIDTH*5, user_data->dlg.pixmap_height);
1398 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(user_data->dlg.scroll_window),
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);
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);
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);
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);
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);
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);
1435 gtk_widget_show(user_data->dlg.scroll_window);
1436 gtk_widget_show(scroll_window_comments);
1438 gtk_box_pack_start(GTK_BOX(hbox), frame_time, FALSE, FALSE, 3);
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);
1446 gtk_box_pack_start(GTK_BOX(hbox), user_data->dlg.hpane, TRUE, TRUE, 0);
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);
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);
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);
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);
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);
1479 /****************************************************************************/
1481 /****************************************************************************/
1484 /****************************************************************************/
1485 static void dialog_graph_create_window(graph_analysis_data_t *user_data)
1488 GtkWidget *hbuttonbox;
1489 GtkWidget *bt_close;
1491 GtkTooltips *tooltips = gtk_tooltips_new();
1492 const gchar *title_name_ptr;
1495 title_name_ptr = cf_get_display_name(&cfile);
1496 win_name = g_strdup_printf("%s - Graph Analysis", title_name_ptr);
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);
1502 vbox=gtk_vbox_new(FALSE, 0);
1503 gtk_container_add(GTK_CONTAINER(user_data->dlg.window), vbox);
1504 gtk_widget_show(vbox);
1506 create_draw_area(user_data, vbox);
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);
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);
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);
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);
1531 gtk_widget_show(user_data->dlg.window);
1532 window_present(user_data->dlg.window);
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);
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
1547 /****************************************************************************/
1548 static gint add_or_get_node(graph_analysis_data_t *user_data, address *node) {
1551 if (node->type == AT_NONE) return NODE_OVERFLOW;
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 */
1557 if (i == MAX_NUM_NODES) {
1558 return NODE_OVERFLOW;
1560 user_data->num_nodes++;
1561 COPY_ADDRESS(&(user_data->nodes[i]),node);
1566 /* Get the nodes from the list */
1567 /****************************************************************************/
1568 static void get_nodes(graph_analysis_data_t *user_data)
1571 graph_analysis_item_t *gai;
1573 /* fill the node array */
1574 list = g_list_first(user_data->graph_info->list);
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));
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));
1588 list = g_list_next(list);
1592 /****************************************************************************/
1593 graph_analysis_data_t *graph_analysis_init(void)
1595 graph_analysis_data_t *user_data;
1597 user_data = g_malloc(sizeof(graph_analysis_data_t));
1599 /* init user_data */
1600 graph_analysis_init_dlg(user_data);
1604 /****************************************************************************/
1606 /****************************************************************************/
1608 /****************************************************************************/
1609 void graph_analysis_create(graph_analysis_data_t *user_data)
1611 /* reset the data */
1612 graph_analysis_reset(user_data);
1614 /* get nodes (each node is an address) */
1615 get_nodes(user_data);
1617 /* create the graph windows */
1618 dialog_graph_create_window(user_data);
1620 /* redraw the graph */
1621 dialog_graph_redraw(user_data);
1626 /****************************************************************************/
1627 void graph_analysis_update(graph_analysis_data_t *user_data)
1629 /* reset the data */
1630 graph_analysis_reset(user_data);
1632 /* get nodes (each node is an address) */
1633 get_nodes(user_data);
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);
1640 gtk_widget_set_size_request(user_data->dlg.scroll_window, NODE_WIDTH*5, user_data->dlg.pixmap_height);
1642 /* redraw the graph */
1643 dialog_graph_redraw(user_data);
1645 window_present(user_data->dlg.window);
1650 /****************************************************************************/
1651 void graph_analysis_redraw(graph_analysis_data_t *user_data)
1653 /* get nodes (each node is an address) */
1654 get_nodes(user_data);
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);
1661 gtk_widget_set_size_request(user_data->dlg.scroll_window, NODE_WIDTH*5, user_data->dlg.pixmap_height);
1664 /* redraw the graph */
1665 dialog_graph_redraw(user_data);
1667 window_present(user_data->dlg.window);