2 * Graphic Analysis addition for ethereal
6 * Copyright 2004, Verso Technologies Inc.
7 * By Alejandro Vaquero <alejandrovaquero@yahoo.com>
9 * based on rtp_analysis.c and io_stat
12 * Ethereal - Network traffic analyzer
13 * By Gerald Combs <gerald@ethereal.com>
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.
35 #include "graph_analysis.h"
37 #include <epan/epan_dissect.h>
42 #include <epan/dissectors/packet-rtp.h>
43 #include <epan/addr_resolv.h>
47 #if GTK_MAJOR_VERSION >= 2
48 #include <glib-object.h>
51 #include <gdk/gdkkeysyms.h>
52 #include "gtkglobals.h"
54 #include "dlg_utils.h"
55 #include "gui_utils.h"
57 #include "compat_macros.h"
59 #include "epan/filesystem.h"
60 #include "file_util.h"
68 #include "simple_dialog.h"
72 /* GTK-1.x does not have GDK_IS_DRAWABLE so just define is as always being true
73 * so that ethereal compiles.
74 * At later stage we should implement it as a real fallback for gtk-1.x
75 * but for the time being us very few gtk-1.2 users at elast can compile.
77 #if (GTK_MAJOR_VERSION < 2)
78 #define GDK_IS_DRAWABLE(x) 1
80 /****************************************************************************/
83 #define OK_TEXT "[ Ok ]"
84 #define PT_UNDEFINED -1
87 #if GTK_MAJOR_VERSION < 2
89 GdkColormap *colormap;
92 static GtkWidget *save_to_file_w = NULL;
95 #define MAX_COMMENT 100
96 #define ITEM_HEIGHT 20
97 #define NODE_WIDTH 100
98 #define TOP_Y_BORDER 40
99 #define BOTTOM_Y_BORDER 0
100 #define COMMENT_WIDTH 400
101 #define TIME_WIDTH 50
103 #define NODE_CHARS_WIDTH 20
104 #define CONV_TIME_HEADER "Conv.| Time "
105 #define TIME_HEADER "|Time "
106 #define CONV_TIME_EMPTY_HEADER " | "
107 #define TIME_EMPTY_HEADER "| "
108 #define CONV_TIME_HEADER_LENGTH 16
109 #define TIME_HEADER_LENGTH 10
111 /****************************************************************************/
112 /* Reset the user_data structure */
113 static void graph_analysis_reset(graph_analysis_data_t* user_data)
117 user_data->num_nodes = 0;
118 user_data->num_items = 0;
119 for (i=0; i<MAX_NUM_NODES; i++){
120 user_data->nodes[i].type = AT_NONE;
121 user_data->nodes[i].len = 0;
122 g_free((void *)user_data->nodes[i].data);
123 user_data->nodes[i].data = NULL;
126 user_data->dlg.first_node=0;
127 user_data->dlg.first_item=0;
128 user_data->dlg.left_x_border=0;
129 user_data->dlg.selected_item=0xFFFFFFFF; /*not item selected */
132 /****************************************************************************/
133 /* Reset the user_data structure */
134 static void graph_analysis_init_dlg(graph_analysis_data_t* user_data)
138 user_data->num_nodes = 0;
139 user_data->num_items = 0;
140 user_data->on_destroy_user_data = NULL;
141 user_data->data = NULL;
142 for (i=0; i<MAX_NUM_NODES; i++){
143 user_data->nodes[i].type = AT_NONE;
144 user_data->nodes[i].len = 0;
145 user_data->nodes[i].data = NULL;
148 user_data->dlg.first_node=0;
149 user_data->dlg.first_item=0;
150 user_data->dlg.left_x_border=0;
151 user_data->dlg.selected_item=0xFFFFFFFF; /*not item selected */
152 /* init dialog_graph */
153 user_data->dlg.needs_redraw=TRUE;
154 user_data->dlg.draw_area_time=NULL;
155 user_data->dlg.draw_area=NULL;
156 user_data->dlg.pixmap=NULL;
157 user_data->dlg.pixmap_time=NULL;
158 user_data->dlg.draw_area_comments=NULL;
159 user_data->dlg.pixmap_comments=NULL;
160 user_data->dlg.v_scrollbar=NULL;
161 user_data->dlg.v_scrollbar_adjustment=NULL;
162 user_data->dlg.hpane=NULL;
163 user_data->dlg.pixmap_width = 350;
164 user_data->dlg.pixmap_height=400;
165 user_data->dlg.first_node=0;
166 user_data->dlg.first_item=0;
167 user_data->dlg.left_x_border=0;
168 user_data->dlg.selected_item=0xFFFFFFFF; /*not item selected */
169 user_data->dlg.window=NULL;
170 user_data->dlg.inverse = FALSE;
171 user_data->dlg.title=NULL;
174 /****************************************************************************/
177 /****************************************************************************/
178 /* close the dialog window */
179 static void on_destroy(GtkWidget *win _U_, graph_analysis_data_t *user_data _U_)
183 for (i=0; i<MAX_NUM_NODES; i++){
184 user_data->nodes[i].type = AT_NONE;
185 user_data->nodes[i].len = 0;
186 g_free((void *)user_data->nodes[i].data);
187 user_data->nodes[i].data = NULL;
189 user_data->dlg.window = NULL;
190 g_free(user_data->dlg.title);
191 user_data->dlg.title = NULL;
193 if(user_data->on_destroy_user_data){
194 user_data->on_destroy_user_data(user_data->data);
198 #define RIGHT_ARROW 1
200 #define WIDTH_ARROW 8
201 #define HEIGHT_ARROW 6
203 /****************************************************************************/
204 static void draw_arrow(GdkDrawable *pixmap, GdkGC *gc, gint x, gint y, gboolean direction)
206 GdkPoint arrow_point[3];
208 arrow_point[0].x = x;
209 arrow_point[0].y = y-HEIGHT_ARROW/2;
210 if (direction == RIGHT_ARROW)
211 arrow_point[1].x = x+WIDTH_ARROW;
213 arrow_point[1].x = x-WIDTH_ARROW;
214 arrow_point[1].y = y;
215 arrow_point[2].x = x;
216 arrow_point[2].y = y+HEIGHT_ARROW/2;;
218 if (GDK_IS_DRAWABLE(pixmap)) {
219 gdk_draw_polygon(pixmap, gc, TRUE, arrow_point, 3);
223 /****************************************************************************/
224 /* Adds trailing characters to complete the requested length. */
225 /****************************************************************************/
227 static void enlarge_string(GString *gstr, guint32 length, char pad){
231 for (i = gstr->len; i < length; i++){
232 g_string_append_c(gstr, pad);
236 /****************************************************************************/
237 /* overwrites the characters in a string, between positions p1 and p2, with */
238 /* the characters of text_to_insert */
239 /* NB: it does not check that p1 and p2 fit into string */
240 /****************************************************************************/
242 static void overwrite (GString *gstr, char *text_to_insert, guint32 p1, guint32 p2){
258 if (len > strlen(text_to_insert)){
259 len = strlen(text_to_insert);
265 if (pos + len > gstr->len)
266 g_string_truncate(gstr, pos);
268 g_string_erase(gstr, pos, len);
270 g_string_insert(gstr, pos, text_to_insert);
275 * XXX - We might want to refactor this to write the graph data directly to
276 * the file instead of loading everything into strings first.
279 /****************************************************************************/
280 static gboolean dialog_graph_dump_to_file(graph_analysis_data_t* user_data)
282 guint32 i, first_node, display_items, display_nodes;
283 guint32 start_position, end_position, item_width, header_length;
284 guint32 current_item;
285 graph_analysis_item_t *gai;
286 guint16 first_conv_num;
287 gboolean several_convs = FALSE;
288 gboolean first_packet = TRUE;
290 GString *label_string, *empty_line,*separator_line, *tmp_str, *tmp_str2;
292 char src_port[8],dst_port[8];
298 of = eth_fopen(user_data->dlg.save_file,"w");
303 label_string = g_string_new("");
304 empty_line = g_string_new("");
305 separator_line = g_string_new("");
306 tmp_str = g_string_new("");
307 tmp_str2 = g_string_new("");
309 /* get the items to display and fill the matrix array */
310 list = g_list_first(user_data->graph_info->list);
317 user_data->dlg.items[current_item].frame_num = gai->frame_num;
318 user_data->dlg.items[current_item].time = gai->time;
319 user_data->dlg.items[current_item].port_src = gai->port_src;
320 user_data->dlg.items[current_item].port_dst = gai->port_dst;
321 user_data->dlg.items[current_item].frame_label = gai->frame_label;
322 user_data->dlg.items[current_item].comment = gai->comment;
323 user_data->dlg.items[current_item].conv_num = gai->conv_num;
324 user_data->dlg.items[current_item].src_node = gai->src_node;
325 user_data->dlg.items[current_item].dst_node = gai->dst_node;
327 first_conv_num = gai->conv_num;
330 if (user_data->dlg.items[current_item].conv_num != first_conv_num){
331 several_convs = TRUE;
337 list = g_list_next(list);
339 display_items = current_item;
341 /* if not items to display */
342 if (display_items == 0) goto exit;
344 display_nodes = user_data->num_nodes;
346 first_node = user_data->dlg.first_node;
348 /* Write the conv. and time headers */
351 fprintf (of, CONV_TIME_HEADER);
352 empty_header = CONV_TIME_EMPTY_HEADER;
353 header_length = CONV_TIME_HEADER_LENGTH;
356 fprintf (of, TIME_HEADER);
357 empty_header = TIME_EMPTY_HEADER;
358 header_length = TIME_HEADER_LENGTH;
361 /* Write the node names on top */
362 for (i=0; i<display_nodes; i++){
363 /* print the node identifiers */
364 g_string_sprintf(label_string, "| %s",
365 get_addr_name(&(user_data->nodes[i+first_node])));
366 enlarge_string(label_string, NODE_CHARS_WIDTH, ' ');
367 fprintf(of, "%s", label_string->str);
368 g_string_sprintf(label_string, "| ");
369 enlarge_string(label_string, NODE_CHARS_WIDTH, ' ');
370 g_string_append(empty_line, label_string->str);
372 g_string_append_c(empty_line, '|');
374 enlarge_string(separator_line, empty_line->len + header_length, '-');
382 for (current_item=0; current_item<display_items; current_item++){
384 start_position = (user_data->dlg.items[current_item].src_node-first_node)*NODE_CHARS_WIDTH+NODE_CHARS_WIDTH/2;
386 end_position = (user_data->dlg.items[current_item].dst_node-first_node)*NODE_CHARS_WIDTH+NODE_CHARS_WIDTH/2;
388 if (start_position > end_position){
389 item_width=start_position-end_position;
391 else if (start_position < end_position){
392 item_width=end_position-start_position;
394 else{ /* same origin and destination address */
395 end_position = start_position+NODE_CHARS_WIDTH;
396 item_width = NODE_CHARS_WIDTH;
399 /* separator between conversations */
400 if (user_data->dlg.items[current_item].conv_num != first_conv_num){
401 fprintf(of, "%s\n", separator_line->str);
402 first_conv_num=user_data->dlg.items[current_item].conv_num;
405 /* write the conversation number */
407 g_string_sprintf(label_string, "%i", user_data->dlg.items[current_item].conv_num);
408 enlarge_string(label_string, 5, ' ');
409 fprintf(of, "%s", label_string->str);
413 g_string_sprintf(label_string, "|%.3f", user_data->dlg.items[current_item].time);
414 enlarge_string(label_string, 10, ' ');
415 fprintf(of, "%s", label_string->str);
417 /* write the frame label */
419 g_string_sprintf(tmp_str, empty_line->str);
420 overwrite(tmp_str,user_data->dlg.items[current_item].frame_label,
424 fprintf(of, "%s", tmp_str->str);
426 /* write the comments */
427 fprintf(of, "%s\n", user_data->dlg.items[current_item].comment);
429 /* write the arrow and frame label*/
430 fprintf(of, "%s", empty_header);
432 g_string_sprintf(tmp_str, empty_line->str);
434 g_string_truncate(tmp_str2, 0);
436 if (start_position<end_position){
437 enlarge_string(tmp_str2, item_width-2, '-');
438 g_string_append_c(tmp_str2, '>');
441 g_string_sprintf(tmp_str2, "<");
442 enlarge_string(tmp_str2, item_width-1, '-');
445 overwrite(tmp_str,tmp_str2->str,
450 g_snprintf(src_port,8,"(%i)", user_data->dlg.items[current_item].port_src);
451 g_snprintf(dst_port,8,"(%i)", user_data->dlg.items[current_item].port_dst);
453 if (start_position<end_position){
454 overwrite(tmp_str,src_port,start_position-9,start_position-1);
455 overwrite(tmp_str,dst_port,end_position+1,end_position+9);
458 overwrite(tmp_str,src_port,start_position+1,start_position+9);
459 overwrite(tmp_str,dst_port,end_position-9,end_position+1);
462 fprintf(of,"%s\n",tmp_str->str);
466 g_string_free(label_string, TRUE);
467 g_string_free(empty_line, TRUE);
468 g_string_free(separator_line, TRUE);
469 g_string_free(tmp_str, TRUE);
470 g_string_free(tmp_str2, TRUE);
477 /****************************************************************************/
478 static void save_to_file_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
480 /* Note that we no longer have a Save to file dialog box. */
481 save_to_file_w = NULL;
484 /****************************************************************************/
487 /* first an auxiliary function in case we need an overwrite confirmation dialog */
489 static void overwrite_existing_file_cb(gpointer dialog _U_, gint btn, gpointer user_data _U_)
491 graph_analysis_data_t *user_data_p;
493 user_data_p = user_data;
497 /* overwrite the file*/
498 dialog_graph_dump_to_file(user_data);
503 g_assert_not_reached();
507 /* and then the save in a file dialog itself */
509 static void save_to_file_ok_cb(GtkWidget *ok_bt _U_, gpointer user_data _U_)
513 graph_analysis_data_t *user_data_p;
515 user_data_p = user_data;
517 user_data_p->dlg.save_file = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (save_to_file_w)));
519 /* Perhaps the user specified a directory instead of a file.
520 Check whether they did. */
521 if (test_for_directory(user_data_p->dlg.save_file) == EISDIR) {
522 /* It's a directory - set the file selection box to display it. */
523 set_last_open_dir(user_data_p->dlg.save_file);
524 g_free(user_data_p->dlg.save_file);
525 file_selection_set_current_folder(save_to_file_w, get_last_open_dir());
530 /* check whether the file exists */
531 file_test = eth_fopen(user_data_p->dlg.save_file,"r");
532 if (file_test!=NULL){
534 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_YES_NO,
535 "%sFile: \"%s\" already exists!%s\n\n"
536 "Do you want to overwrite it?",
537 simple_dialog_primary_start(),user_data_p->dlg.save_file, simple_dialog_primary_end());
538 simple_dialog_set_cb(dialog, overwrite_existing_file_cb, user_data);
543 if (!dialog_graph_dump_to_file(user_data))
546 window_destroy(GTK_WIDGET(save_to_file_w));
550 /****************************************************************************/
552 on_save_bt_clicked (GtkButton *button _U_,
553 gpointer user_data _U_)
558 if (save_to_file_w != NULL) {
559 /* There's already a Save to file dialog box; reactivate it. */
560 reactivate_window(save_to_file_w);
564 save_to_file_w = gtk_file_selection_new("Ethereal: Save graph to file");
566 /* Container for each row of widgets */
567 vertb = gtk_vbox_new(FALSE, 0);
568 gtk_container_border_width(GTK_CONTAINER(vertb), 5);
569 gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(save_to_file_w)->action_area),
570 vertb, FALSE, FALSE, 0);
571 gtk_widget_show (vertb);
573 ok_bt = GTK_FILE_SELECTION(save_to_file_w)->ok_button;
574 SIGNAL_CONNECT(ok_bt, "clicked", save_to_file_ok_cb, user_data);
576 window_set_cancel_button(save_to_file_w,
577 GTK_FILE_SELECTION(save_to_file_w)->cancel_button, window_cancel_button_cb);
579 SIGNAL_CONNECT(save_to_file_w, "delete_event", window_delete_event_cb, NULL);
580 SIGNAL_CONNECT(save_to_file_w, "destroy", save_to_file_destroy_cb,
583 gtk_widget_show(save_to_file_w);
584 window_present(save_to_file_w);
589 /****************************************************************************/
590 static void dialog_graph_draw(graph_analysis_data_t* user_data)
592 guint32 i, last_item, first_item, display_items;
593 guint32 start_arrow, end_arrow, label_x, src_port_x, dst_port_x, arrow_width;
594 guint32 current_item;
595 guint32 left_x_border;
596 guint32 right_x_border;
597 guint32 top_y_border;
598 guint32 bottom_y_border;
599 graph_analysis_item_t *gai;
600 guint16 first_conv_num;
601 gboolean several_convs = FALSE;
602 gboolean first_packet = TRUE;
604 GdkGC *frame_fg_color;
605 GdkGC *frame_bg_color;
606 GdkGC *div_line_color;
608 #if GTK_MAJOR_VERSION < 2
611 FONT_TYPE *small_font;
614 PangoLayout *big_layout;
615 PangoLayout *small_layout;
617 guint32 label_width, label_height;
618 guint32 draw_width, draw_height;
619 char label_string[MAX_COMMENT];
624 #if GTK_MAJOR_VERSION <2
625 font = user_data->dlg.draw_area->style->font;
626 big_font = gdk_font_load("-adobe-helvetica-bold-r-normal--12-120-75-75-p-70-iso8859-1");
627 small_font = gdk_font_load("-adobe-helvetica-bold-r-normal--10-120-75-75-p-70-iso8859-1");
629 if(!user_data->dlg.needs_redraw){
632 user_data->dlg.needs_redraw=FALSE;
634 /* Clear out old plt */
635 if ( GDK_IS_DRAWABLE(user_data->dlg.pixmap_time) )
636 gdk_draw_rectangle(user_data->dlg.pixmap_time,
637 user_data->dlg.draw_area_time->style->white_gc,
640 user_data->dlg.draw_area_time->allocation.width,
641 user_data->dlg.draw_area_time->allocation.height);
643 if ( GDK_IS_DRAWABLE(user_data->dlg.pixmap) )
644 gdk_draw_rectangle(user_data->dlg.pixmap,
645 user_data->dlg.draw_area->style->white_gc,
648 user_data->dlg.draw_area->allocation.width,
649 user_data->dlg.draw_area->allocation.height);
651 if ( GDK_IS_DRAWABLE(user_data->dlg.pixmap_comments) )
652 gdk_draw_rectangle(user_data->dlg.pixmap_comments,
653 user_data->dlg.draw_area->style->white_gc,
656 user_data->dlg.draw_area_comments->allocation.width,
657 user_data->dlg.draw_area_comments->allocation.height);
659 /* Calculate the y border */
660 top_y_border=TOP_Y_BORDER; /* to display the node address */
663 draw_height=user_data->dlg.draw_area->allocation.height-top_y_border-bottom_y_border;
665 first_item = user_data->dlg.first_item;
666 display_items = draw_height/ITEM_HEIGHT;
667 last_item = first_item+display_items-1;
669 /* get the items to display and fill the matrix array */
670 list = g_list_first(user_data->graph_info->list);
677 if (current_item>=display_items) break; /* the item is outside the display */
679 user_data->dlg.items[current_item].frame_num = gai->frame_num;
680 user_data->dlg.items[current_item].time = gai->time;
681 user_data->dlg.items[current_item].port_src = gai->port_src;
682 user_data->dlg.items[current_item].port_dst = gai->port_dst;
683 /* Add "..." if the length is 50 characters */
684 if (strlen(gai->frame_label) > 48) {
685 gai->frame_label[48] = '.';
686 gai->frame_label[47] = '.';
687 gai->frame_label[46] = '.';
689 user_data->dlg.items[current_item].frame_label = gai->frame_label;
690 user_data->dlg.items[current_item].comment = gai->comment;
691 user_data->dlg.items[current_item].conv_num = gai->conv_num;
694 first_conv_num = gai->conv_num;
698 if (user_data->dlg.items[current_item].conv_num != first_conv_num){
699 several_convs = TRUE;
702 user_data->dlg.items[current_item].src_node = gai->src_node;
703 user_data->dlg.items[current_item].dst_node = gai->dst_node;
704 user_data->dlg.items[current_item].line_style = gai->line_style;
710 list = g_list_next(list);
712 /* in case the windows is resized so we have to move the top item */
713 if ((first_item + display_items) > user_data->num_items){
714 if (display_items>user_data->num_items)
717 first_item = user_data->num_items - display_items;
720 /* in case there are less items than possible displayed */
721 display_items = current_item;
722 last_item = first_item+display_items-1;
724 /* if not items to display */
725 if (display_items == 0) return;
728 /* Calculate the x borders */
729 /* We use time from the last display item to calcultate the x left border */
730 g_snprintf(label_string, MAX_LABEL, "%.3f", user_data->dlg.items[display_items-1].time);
731 #if GTK_MAJOR_VERSION < 2
732 label_width=gdk_string_width(font, label_string);
733 label_height=gdk_string_height(font, label_string);
735 layout = gtk_widget_create_pango_layout(user_data->dlg.draw_area_time, label_string);
736 big_layout = gtk_widget_create_pango_layout(user_data->dlg.draw_area_time, label_string);
737 small_layout = gtk_widget_create_pango_layout(user_data->dlg.draw_area_time, label_string);
739 /* XXX - to prevent messages like "Couldn't load font x, falling back to y", I've changed font
740 description from "Helvetica-Bold 8" to "Helvetica,Sans,Bold 8", this seems to be
741 conforming to the API, see http://developer.gnome.org/doc/API/2.0/pango/pango-Fonts.html */
742 pango_layout_set_font_description(big_layout, pango_font_description_from_string("Helvetica,Sans,Bold 8"));
743 pango_layout_set_font_description(small_layout, pango_font_description_from_string("Helvetica,Sans,Bold 7"));
745 pango_layout_get_pixel_size(layout, &label_width, &label_height);
748 /* resize the "time" draw area */
751 user_data->dlg.left_x_border = left_x_border;
754 draw_width=user_data->dlg.pixmap_width-right_x_border-left_x_border;
756 /* Paint time title background */
757 if ( GDK_IS_DRAWABLE(user_data->dlg.pixmap_time) )
758 gdk_draw_rectangle(user_data->dlg.pixmap_time,
759 user_data->dlg.draw_area_time->style->bg_gc[2],
763 user_data->dlg.draw_area_time->allocation.width,
765 /* Paint main title background */
766 if ( GDK_IS_DRAWABLE(user_data->dlg.pixmap) )
767 gdk_draw_rectangle(user_data->dlg.pixmap,
768 user_data->dlg.draw_area->style->bg_gc[2],
772 user_data->dlg.draw_area->allocation.width,
774 /* Paint main comment background */
775 if ( GDK_IS_DRAWABLE(user_data->dlg.pixmap_comments) )
776 gdk_draw_rectangle(user_data->dlg.pixmap_comments,
777 user_data->dlg.draw_area_comments->style->bg_gc[2],
781 user_data->dlg.draw_area_comments->allocation.width,
785 /* Draw the word "Time" on top of time column */
786 g_snprintf(label_string, label_width, "%s", "Time");
787 #if GTK_MAJOR_VERSION < 2
788 label_width=gdk_string_width(font, label_string);
789 label_height=gdk_string_height(font, label_string);
790 gdk_draw_string(user_data->dlg.pixmap_time,
792 user_data->dlg.draw_area_time->style->black_gc,
794 top_y_border/2-label_height/2,
797 pango_layout_set_text(layout, label_string, -1);
798 pango_layout_get_pixel_size(layout, &label_width, &label_height);
799 if (GDK_IS_DRAWABLE(user_data->dlg.pixmap_time)) {
800 gdk_draw_layout(user_data->dlg.pixmap_time,
801 user_data->dlg.draw_area_time->style->black_gc,
803 top_y_border/2-label_height/2,
808 /* Draw the word "Comment" on top of comment column */
809 g_snprintf(label_string, label_width, "%s", "Comment");
810 #if GTK_MAJOR_VERSION < 2
811 label_width=gdk_string_width(font, label_string);
812 label_height=gdk_string_height(font, label_string);
813 gdk_draw_string(user_data->dlg.pixmap_comments,
815 user_data->dlg.draw_area_comments->style->black_gc,
816 MAX_COMMENT/2-label_width/2,
817 top_y_border/2-label_height/2,
820 pango_layout_set_text(layout, label_string, -1);
821 pango_layout_get_pixel_size(layout, &label_width, &label_height);
822 if (GDK_IS_DRAWABLE(user_data->dlg.pixmap_comments)) {
823 gdk_draw_layout(user_data->dlg.pixmap_comments,
824 user_data->dlg.draw_area_comments->style->black_gc,
825 MAX_COMMENT/2-label_width/2,
826 top_y_border/2-label_height/2,
831 /* Paint the background items */
832 for (current_item=0; current_item<display_items; current_item++){
833 /*select the color. if it is the selected item select blue color */
834 if ( current_item+first_item == user_data->dlg.selected_item ) {
835 frame_bg_color = user_data->dlg.bg_gc[0];
837 frame_bg_color = user_data->dlg.bg_gc[1+user_data->dlg.items[current_item].conv_num%MAX_NUM_COL_CONV];
840 /* Paint background */
841 if (GDK_IS_DRAWABLE(user_data->dlg.pixmap)) {
842 gdk_draw_rectangle(user_data->dlg.pixmap,
846 top_y_border+current_item*ITEM_HEIGHT,
851 /* Draw the node names on top and the division lines */
852 for (i=0; i<user_data->num_nodes; i++){
853 /* print the node identifiers */
854 /* XXX we assign 5 pixels per character in the node identity */
855 g_snprintf(label_string, NODE_WIDTH/5, "%s",
856 get_addr_name(&(user_data->nodes[i])));
857 #if GTK_MAJOR_VERSION < 2
858 label_width=gdk_string_width(font, label_string);
859 label_height=gdk_string_height(font, label_string);
860 gdk_draw_string(user_data->dlg.pixmap,
862 user_data->dlg.draw_area->style->black_gc,
863 left_x_border+NODE_WIDTH/2-label_width/2+NODE_WIDTH*i,
864 top_y_border/2-label_height/2,
867 pango_layout_set_text(layout, label_string, -1);
868 pango_layout_get_pixel_size(layout, &label_width, &label_height);
869 if (GDK_IS_DRAWABLE(user_data->dlg.pixmap)) {
870 gdk_draw_layout(user_data->dlg.pixmap,
871 user_data->dlg.draw_area->style->black_gc,
872 left_x_border+NODE_WIDTH/2-label_width/2+NODE_WIDTH*i,
873 top_y_border/2-label_height/2,
878 /* draw the node division lines */
879 if (GDK_IS_DRAWABLE(user_data->dlg.pixmap) ) {
880 gdk_draw_line(user_data->dlg.pixmap, user_data->dlg.div_line_gc[0],
881 left_x_border+NODE_WIDTH/2+NODE_WIDTH*i,
883 left_x_border+NODE_WIDTH/2+NODE_WIDTH*i,
884 user_data->dlg.draw_area->allocation.height-bottom_y_border);
890 for (current_item=0; current_item<display_items; current_item++){
892 g_snprintf(label_string, MAX_LABEL, "%.3f", user_data->dlg.items[current_item].time);
893 #if GTK_MAJOR_VERSION < 2
894 label_width=gdk_string_width(font, label_string);
895 label_height=gdk_string_height(font, label_string);
896 gdk_draw_string(user_data->dlg.pixmap_time,
898 user_data->dlg.draw_area->style->black_gc,
900 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT/2+label_height/4,
903 pango_layout_set_text(layout, label_string, -1);
904 pango_layout_get_pixel_size(layout, &label_width, &label_height);
905 if (GDK_IS_DRAWABLE(user_data->dlg.pixmap_time)) {
906 gdk_draw_layout(user_data->dlg.pixmap_time,
907 user_data->dlg.draw_area->style->black_gc,
909 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT/2-label_height/2,
914 /*draw the comments */
915 g_snprintf(label_string, MAX_COMMENT, "%s", user_data->dlg.items[current_item].comment);
916 #if GTK_MAJOR_VERSION < 2
917 label_width=gdk_string_width(small_font, label_string);
918 label_height=gdk_string_height(small_font, label_string);
919 gdk_draw_string(user_data->dlg.pixmap_comments,
921 user_data->dlg.draw_area_comments->style->black_gc,
923 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT/2+label_height/4,
926 pango_layout_set_text(small_layout, label_string, -1);
927 pango_layout_get_pixel_size(small_layout, &label_width, &label_height);
928 if (GDK_IS_DRAWABLE(user_data->dlg.pixmap_comments)) {
929 gdk_draw_layout(user_data->dlg.pixmap_comments,
930 user_data->dlg.draw_area->style->black_gc,
932 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT/2-label_height/2,
937 if ( current_item+first_item == user_data->dlg.selected_item ){
938 frame_fg_color = user_data->dlg.draw_area->style->white_gc;
939 div_line_color = user_data->dlg.div_line_gc[1];
941 frame_fg_color = user_data->dlg.draw_area->style->black_gc;
942 div_line_color = user_data->dlg.div_line_gc[0];
944 /* draw the arrow line */
945 start_arrow = left_x_border+(user_data->dlg.items[current_item].src_node)*NODE_WIDTH+NODE_WIDTH/2;
946 end_arrow = left_x_border+(user_data->dlg.items[current_item].dst_node)*NODE_WIDTH+NODE_WIDTH/2;
948 if (GDK_IS_DRAWABLE(user_data->dlg.pixmap) ) {
949 gdk_draw_line(user_data->dlg.pixmap, frame_fg_color,
951 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-7,
953 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-7);
955 /* draw the additional line when line style is 2 pixels width */
956 if (user_data->dlg.items[current_item].line_style == 2) {
957 gdk_draw_line(user_data->dlg.pixmap, frame_fg_color,
959 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-6,
961 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-6);
966 if (start_arrow<end_arrow)
967 draw_arrow(user_data->dlg.pixmap, frame_fg_color, end_arrow-WIDTH_ARROW,top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-7, RIGHT_ARROW);
969 draw_arrow(user_data->dlg.pixmap, frame_fg_color, end_arrow+WIDTH_ARROW,top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-7, LEFT_ARROW);
971 /* draw the frame comment */
972 g_snprintf(label_string, MAX_LABEL, "%s", user_data->dlg.items[current_item].frame_label);
973 #if GTK_MAJOR_VERSION < 2
974 label_width=gdk_string_width(big_font, label_string);
975 label_height=gdk_string_height(big_font, label_string);
977 pango_layout_set_text(big_layout, label_string, -1);
978 pango_layout_get_pixel_size(big_layout, &label_width, &label_height);
980 if (start_arrow<end_arrow){
981 arrow_width = end_arrow-start_arrow;
982 label_x = arrow_width/2+start_arrow;
985 arrow_width = start_arrow-end_arrow;
986 label_x = arrow_width/2+end_arrow;
989 if (label_width>arrow_width) arrow_width = label_width;
991 if ((int)left_x_border > ((int)label_x-(int)label_width/2))
992 label_x = left_x_border + label_width/2;
994 #if GTK_MAJOR_VERSION < 2
995 gdk_draw_string(user_data->dlg.pixmap,
998 label_x - label_width/2,
999 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT/2+label_height/4-3,
1002 if (GDK_IS_DRAWABLE(user_data->dlg.pixmap)) {
1003 gdk_draw_layout(user_data->dlg.pixmap,
1005 label_x - label_width/2,
1006 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT/2-label_height/2-3,
1012 /* draw the source port number */
1013 g_snprintf(label_string, MAX_LABEL, "(%i)", user_data->dlg.items[current_item].port_src);
1014 #if GTK_MAJOR_VERSION < 2
1015 label_width=gdk_string_width(small_font, label_string);
1016 label_height=gdk_string_height(small_font, label_string);
1018 pango_layout_set_text(small_layout, label_string, -1);
1019 pango_layout_get_pixel_size(small_layout, &label_width, &label_height);
1021 if (start_arrow<end_arrow){
1022 src_port_x = start_arrow - label_width - 2;
1025 src_port_x = start_arrow + 2;
1027 #if GTK_MAJOR_VERSION < 2
1028 gdk_draw_string(user_data->dlg.pixmap,
1032 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-2+label_height/4-2,
1035 if (GDK_IS_DRAWABLE(user_data->dlg.pixmap)) {
1036 gdk_draw_layout(user_data->dlg.pixmap,
1039 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-2-label_height/2-2,
1044 /* draw the destination port number */
1045 g_snprintf(label_string, MAX_LABEL, "(%i)", user_data->dlg.items[current_item].port_dst);
1046 #if GTK_MAJOR_VERSION < 2
1047 label_width=gdk_string_width(small_font, label_string);
1048 label_height=gdk_string_height(small_font, label_string);
1050 pango_layout_set_text(small_layout, label_string, -1);
1051 pango_layout_get_pixel_size(small_layout, &label_width, &label_height);
1053 if (start_arrow<end_arrow){
1054 dst_port_x = end_arrow + 2;
1057 dst_port_x = end_arrow - label_width - 2;
1059 #if GTK_MAJOR_VERSION < 2
1060 gdk_draw_string(user_data->dlg.pixmap,
1064 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-2+label_height/4-2,
1067 if (GDK_IS_DRAWABLE(user_data->dlg.pixmap)) {
1068 gdk_draw_layout(user_data->dlg.pixmap,
1071 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-2-label_height/2-2,
1075 /* draw the div line of the selected item with soft gray*/
1076 if ( current_item+first_item == user_data->dlg.selected_item )
1077 for (i=0; i<user_data->num_nodes; i++){
1078 if (GDK_IS_DRAWABLE(user_data->dlg.pixmap) ) {
1079 gdk_draw_line(user_data->dlg.pixmap, user_data->dlg.div_line_gc[1],
1080 left_x_border+NODE_WIDTH/2+NODE_WIDTH*i,
1081 (user_data->dlg.selected_item-first_item)*ITEM_HEIGHT+TOP_Y_BORDER,
1082 left_x_border+NODE_WIDTH/2+NODE_WIDTH*i,
1083 (user_data->dlg.selected_item-first_item)*ITEM_HEIGHT+TOP_Y_BORDER+ITEM_HEIGHT);
1089 #if GTK_MAJOR_VERSION >= 2
1090 g_object_unref(G_OBJECT(layout));
1093 /* refresh the draw areas */
1094 if (GDK_IS_DRAWABLE(user_data->dlg.draw_area_time->window) )
1095 gdk_draw_pixmap(user_data->dlg.draw_area_time->window,
1096 user_data->dlg.draw_area_time->style->fg_gc[GTK_WIDGET_STATE(user_data->dlg.draw_area_time)],
1097 user_data->dlg.pixmap_time,
1100 user_data->dlg.draw_area_time->allocation.width, user_data->dlg.draw_area_time->allocation.height);
1102 if (GDK_IS_DRAWABLE(user_data->dlg.draw_area->window) )
1103 gdk_draw_pixmap(user_data->dlg.draw_area->window,
1104 user_data->dlg.draw_area->style->fg_gc[GTK_WIDGET_STATE(user_data->dlg.draw_area)],
1105 user_data->dlg.pixmap,
1108 user_data->dlg.draw_area->allocation.width, user_data->dlg.draw_area->allocation.height);
1110 if (GDK_IS_DRAWABLE(user_data->dlg.draw_area_comments->window) )
1111 gdk_draw_pixmap(user_data->dlg.draw_area_comments->window,
1112 user_data->dlg.draw_area_comments->style->fg_gc[GTK_WIDGET_STATE(user_data->dlg.draw_area_comments)],
1113 user_data->dlg.pixmap_comments,
1116 user_data->dlg.draw_area_comments->allocation.width, user_data->dlg.draw_area_comments->allocation.height);
1118 /* update the v_scrollbar */
1119 user_data->dlg.v_scrollbar_adjustment->upper=(gfloat) user_data->num_items-1;
1120 user_data->dlg.v_scrollbar_adjustment->step_increment=1;
1121 user_data->dlg.v_scrollbar_adjustment->page_increment=(gfloat) (last_item-first_item);
1122 user_data->dlg.v_scrollbar_adjustment->page_size=(gfloat) (last_item-first_item);
1123 user_data->dlg.v_scrollbar_adjustment->value=(gfloat) first_item;
1125 gtk_adjustment_changed(user_data->dlg.v_scrollbar_adjustment);
1126 gtk_adjustment_value_changed(user_data->dlg.v_scrollbar_adjustment);
1129 /****************************************************************************/
1130 static void dialog_graph_redraw(graph_analysis_data_t* user_data)
1132 user_data->dlg.needs_redraw=TRUE;
1133 dialog_graph_draw(user_data);
1136 /****************************************************************************/
1137 static gint button_press_event(GtkWidget *widget, GdkEventButton *event _U_)
1139 graph_analysis_data_t *user_data;
1142 user_data=(graph_analysis_data_t *)OBJECT_GET_DATA(widget, "graph_analysis_data_t");
1144 if (event->type != GDK_BUTTON_PRESS) return TRUE;
1146 if (event->y<TOP_Y_BORDER) return TRUE;
1148 /* get the item clicked */
1149 item = ((guint32)event->y - TOP_Y_BORDER) / ITEM_HEIGHT;
1150 user_data->dlg.selected_item = item + user_data->dlg.first_item;
1152 user_data->dlg.needs_redraw=TRUE;
1153 dialog_graph_draw(user_data);
1155 cf_goto_frame(&cfile, user_data->dlg.items[item].frame_num);
1160 #if GTK_MAJOR_VERSION >= 2
1161 /* scroll events are not available in gtk-1.2 */
1162 /****************************************************************************/
1163 static gint scroll_event(GtkWidget *widget, GdkEventScroll *event)
1165 graph_analysis_data_t *user_data;
1167 user_data=(graph_analysis_data_t *)OBJECT_GET_DATA(widget, "graph_analysis_data_t");
1170 switch(event->direction) {
1171 case(GDK_SCROLL_UP):
1172 if (user_data->dlg.first_item == 0) return TRUE;
1173 if (user_data->dlg.first_item < 3)
1174 user_data->dlg.first_item = 0;
1176 user_data->dlg.first_item -= 3;
1178 case(GDK_SCROLL_DOWN):
1179 if ((user_data->dlg.first_item+user_data->dlg.v_scrollbar_adjustment->page_size+1 == user_data->num_items)) return TRUE;
1180 if ((user_data->dlg.first_item+user_data->dlg.v_scrollbar_adjustment->page_size+1) > (user_data->num_items-3))
1181 user_data->dlg.first_item = user_data->num_items-(guint32)user_data->dlg.v_scrollbar_adjustment->page_size-1;
1183 user_data->dlg.first_item += 3;
1185 case(GDK_SCROLL_LEFT):
1186 case(GDK_SCROLL_RIGHT):
1190 dialog_graph_redraw(user_data);
1196 /****************************************************************************/
1197 static gint key_press_event(GtkWidget *widget, GdkEventKey *event _U_)
1199 graph_analysis_data_t *user_data;
1201 user_data=(graph_analysis_data_t *)OBJECT_GET_DATA(widget, "graph_analysis_data_t");
1203 /* if there is nothing selected, just return */
1204 if (user_data->dlg.selected_item == 0xFFFFFFFF) return TRUE;
1207 if (event->keyval == GDK_Up){
1208 if (user_data->dlg.selected_item == 0) return TRUE;
1209 user_data->dlg.selected_item--;
1210 if ( (user_data->dlg.selected_item<user_data->dlg.first_item) || (user_data->dlg.selected_item>user_data->dlg.first_item+user_data->dlg.v_scrollbar_adjustment->page_size) )
1211 user_data->dlg.first_item = user_data->dlg.selected_item;
1213 } else if (event->keyval == GDK_Down){
1214 if (user_data->dlg.selected_item == user_data->num_items-1) return TRUE;
1215 user_data->dlg.selected_item++;
1216 if ( (user_data->dlg.selected_item<user_data->dlg.first_item) || (user_data->dlg.selected_item>user_data->dlg.first_item+user_data->dlg.v_scrollbar_adjustment->page_size) )
1217 user_data->dlg.first_item = (guint32)user_data->dlg.selected_item-(guint32)user_data->dlg.v_scrollbar_adjustment->page_size;
1218 } else if (event->keyval == GDK_Left){
1219 if (user_data->dlg.first_node == 0) return TRUE;
1220 user_data->dlg.first_node--;
1223 user_data->dlg.needs_redraw=TRUE;
1224 dialog_graph_draw(user_data);
1226 cf_goto_frame(&cfile, user_data->dlg.items[user_data->dlg.selected_item-user_data->dlg.first_item].frame_num);
1231 /****************************************************************************/
1232 static gint expose_event(GtkWidget *widget, GdkEventExpose *event)
1234 graph_analysis_data_t *user_data;
1236 user_data=(graph_analysis_data_t *)OBJECT_GET_DATA(widget, "graph_analysis_data_t");
1241 if (GDK_IS_DRAWABLE(widget->window) )
1242 gdk_draw_pixmap(widget->window,
1243 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
1244 user_data->dlg.pixmap,
1245 event->area.x, event->area.y,
1246 event->area.x, event->area.y,
1247 event->area.width, event->area.height);
1252 /****************************************************************************/
1253 static gint expose_event_comments(GtkWidget *widget, GdkEventExpose *event)
1255 graph_analysis_data_t *user_data;
1257 user_data=(graph_analysis_data_t *)OBJECT_GET_DATA(widget, "graph_analysis_data_t");
1262 if (GDK_IS_DRAWABLE(widget->window) )
1263 gdk_draw_pixmap(widget->window,
1264 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
1265 user_data->dlg.pixmap_comments,
1266 event->area.x, event->area.y,
1267 event->area.x, event->area.y,
1268 event->area.width, event->area.height);
1273 /****************************************************************************/
1274 static gint expose_event_time(GtkWidget *widget, GdkEventExpose *event)
1276 graph_analysis_data_t *user_data;
1278 user_data=(graph_analysis_data_t *)OBJECT_GET_DATA(widget, "graph_analysis_data_t");
1283 if (GDK_IS_DRAWABLE(widget->window) )
1284 gdk_draw_pixmap(widget->window,
1285 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
1286 user_data->dlg.pixmap_time,
1287 event->area.x, event->area.y,
1288 event->area.x, event->area.y,
1289 event->area.width, event->area.height);
1294 /****************************************************************************/
1295 static gint configure_event(GtkWidget *widget, GdkEventConfigure *event _U_)
1297 graph_analysis_data_t *user_data;
1300 /* gray and soft gray colors */
1301 static GdkColor color_div_line[2] = {
1302 {0, 0x64ff, 0x64ff, 0x64ff},
1303 {0, 0x7fff, 0x7fff, 0x7fff}
1306 /* the first calor is blue to highlight the selected item */
1307 static GdkColor col[MAX_NUM_COL_CONV+1] = {
1308 {0, 0x00FF, 0x00FF, 0xFFFF},
1309 {0, 0x33FF, 0xFFFF, 0x33FF},
1310 {0, 0x00FF, 0xCCFF, 0xCCFF},
1311 {0, 0x66FF, 0xFFFF, 0xFFFF},
1312 {0, 0x99FF, 0x66FF, 0xFFFF},
1313 {0, 0xFFFF, 0xFFFF, 0x33FF},
1314 {0, 0xCCFF, 0x99FF, 0xFFFF},
1315 {0, 0xCCFF, 0xFFFF, 0x33FF},
1316 {0, 0xFFFF, 0xCCFF, 0xCCFF},
1317 {0, 0xFFFF, 0x99FF, 0x66FF},
1318 {0, 0xFFFF, 0xFFFF, 0x99FF}
1321 user_data=(graph_analysis_data_t *)OBJECT_GET_DATA(widget, "graph_analysis_data_t");
1327 if(user_data->dlg.pixmap){
1328 gdk_pixmap_unref(user_data->dlg.pixmap);
1329 user_data->dlg.pixmap=NULL;
1332 user_data->dlg.pixmap=gdk_pixmap_new(widget->window,
1333 widget->allocation.width,
1334 widget->allocation.height,
1337 if ( GDK_IS_DRAWABLE(user_data->dlg.pixmap) )
1338 gdk_draw_rectangle(user_data->dlg.pixmap,
1339 widget->style->white_gc,
1342 widget->allocation.width,
1343 widget->allocation.height);
1345 /* create gc for division lines and set the line stype to dash*/
1346 for (i=0; i<2; i++){
1347 user_data->dlg.div_line_gc[i]=gdk_gc_new(user_data->dlg.pixmap);
1348 gdk_gc_set_line_attributes(user_data->dlg.div_line_gc[i], 1, GDK_LINE_ON_OFF_DASH, 0, 0);
1349 #if GTK_MAJOR_VERSION < 2
1350 colormap = gtk_widget_get_colormap (widget);
1351 if (!gdk_color_alloc (colormap, &color_div_line[i])){
1352 g_warning ("Couldn't allocate color");
1354 gdk_gc_set_foreground(user_data->dlg.div_line_gc[i], &color_div_line[i]);
1356 gdk_gc_set_rgb_fg_color(user_data->dlg.div_line_gc[i], &color_div_line[i]);
1360 /* create gcs for the background items */
1361 for (i=0; i<MAX_NUM_COL_CONV+1; i++){
1362 user_data->dlg.bg_gc[i]=gdk_gc_new(user_data->dlg.pixmap);
1363 #if GTK_MAJOR_VERSION < 2
1364 colormap = gtk_widget_get_colormap (widget);
1365 if (!gdk_color_alloc (colormap, &col[i])){
1366 g_warning ("Couldn't allocate color");
1368 gdk_gc_set_foreground(user_data->dlg.bg_gc[i], &col[i]);
1370 gdk_gc_set_rgb_fg_color(user_data->dlg.bg_gc[i], &col[i]);
1374 dialog_graph_redraw(user_data);
1379 /****************************************************************************/
1380 static gint configure_event_comments(GtkWidget *widget, GdkEventConfigure *event _U_)
1382 graph_analysis_data_t *user_data;
1384 user_data=(graph_analysis_data_t *)OBJECT_GET_DATA(widget, "graph_analysis_data_t");
1390 if(user_data->dlg.pixmap_comments){
1391 gdk_pixmap_unref(user_data->dlg.pixmap_comments);
1392 user_data->dlg.pixmap_comments=NULL;
1395 user_data->dlg.pixmap_comments=gdk_pixmap_new(widget->window,
1396 widget->allocation.width,
1397 widget->allocation.height,
1400 if ( GDK_IS_DRAWABLE(user_data->dlg.pixmap) )
1401 gdk_draw_rectangle(user_data->dlg.pixmap_comments,
1402 widget->style->white_gc,
1405 widget->allocation.width,
1406 widget->allocation.height);
1408 dialog_graph_redraw(user_data);
1412 /****************************************************************************/
1413 static gint configure_event_time(GtkWidget *widget, GdkEventConfigure *event _U_)
1415 graph_analysis_data_t *user_data;
1417 user_data=(graph_analysis_data_t *)OBJECT_GET_DATA(widget, "graph_analysis_data_t");
1423 if(user_data->dlg.pixmap_time){
1424 gdk_pixmap_unref(user_data->dlg.pixmap_time);
1425 user_data->dlg.pixmap_time=NULL;
1428 user_data->dlg.pixmap_time=gdk_pixmap_new(widget->window,
1429 widget->allocation.width,
1430 widget->allocation.height,
1433 if ( GDK_IS_DRAWABLE(user_data->dlg.pixmap_time) )
1434 gdk_draw_rectangle(user_data->dlg.pixmap_time,
1435 widget->style->white_gc,
1438 widget->allocation.width,
1439 widget->allocation.height);
1441 dialog_graph_redraw(user_data);
1446 #if GTK_MAJOR_VERSION >= 2
1447 /****************************************************************************/
1448 static gint pane_callback(GtkWidget *widget, GParamSpec *pspec _U_, gpointer data)
1450 graph_analysis_data_t *user_data=(graph_analysis_data_t *)data;
1455 if (gtk_paned_get_position(GTK_PANED(user_data->dlg.hpane)) > user_data->dlg.pixmap_width)
1456 gtk_paned_set_position(GTK_PANED(user_data->dlg.hpane), user_data->dlg.pixmap_width);
1457 else if (gtk_paned_get_position(GTK_PANED(user_data->dlg.hpane)) < NODE_WIDTH*2)
1458 gtk_paned_set_position(GTK_PANED(user_data->dlg.hpane), NODE_WIDTH*2);
1459 /* repaint the comment area because when moving the pane position thre are times that the expose_event_comments is not called */
1460 if (GDK_IS_DRAWABLE(user_data->dlg.draw_area_comments->window) )
1461 gdk_draw_pixmap(user_data->dlg.draw_area_comments->window,
1462 user_data->dlg.draw_area_comments->style->fg_gc[GTK_WIDGET_STATE(widget)],
1463 user_data->dlg.pixmap_comments,
1466 user_data->dlg.draw_area_comments->allocation.width,
1467 user_data->dlg.draw_area_comments->allocation.height);
1472 /****************************************************************************/
1473 static gint v_scrollbar_changed(GtkWidget *widget _U_, gpointer data)
1475 graph_analysis_data_t *user_data=(graph_analysis_data_t *)data;
1476 if ((user_data->dlg.first_item+user_data->dlg.v_scrollbar_adjustment->page_size+1 == user_data->num_items)
1477 && (user_data->dlg.v_scrollbar_adjustment->value >= user_data->dlg.first_item ))
1480 if (user_data->dlg.first_item == user_data->dlg.v_scrollbar_adjustment->value)
1483 user_data->dlg.first_item = (guint32) user_data->dlg.v_scrollbar_adjustment->value;
1485 dialog_graph_redraw(user_data);
1489 /****************************************************************************/
1490 static void create_draw_area(graph_analysis_data_t* user_data, GtkWidget *box)
1494 GtkWidget *viewport;
1495 GtkWidget *scroll_window_comments;
1496 GtkWidget *viewport_comments;
1498 hbox=gtk_hbox_new(FALSE, 0);
1499 gtk_widget_show(hbox);
1501 vbox=gtk_vbox_new(FALSE, 0);
1502 gtk_widget_show(vbox);
1504 /* create "time" draw area */
1505 user_data->dlg.draw_area_time=gtk_drawing_area_new();
1506 WIDGET_SET_SIZE(user_data->dlg.draw_area_time, TIME_WIDTH, user_data->dlg.pixmap_height);
1507 OBJECT_SET_DATA(user_data->dlg.draw_area_time, "graph_analysis_data_t", user_data);
1509 /* create "comments" draw area */
1510 user_data->dlg.draw_area_comments=gtk_drawing_area_new();
1511 WIDGET_SET_SIZE(user_data->dlg.draw_area_comments, COMMENT_WIDTH, user_data->dlg.pixmap_height);
1512 scroll_window_comments=gtk_scrolled_window_new(NULL, NULL);
1513 WIDGET_SET_SIZE(scroll_window_comments, COMMENT_WIDTH/2, user_data->dlg.pixmap_height);
1514 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll_window_comments), GTK_POLICY_ALWAYS, GTK_POLICY_NEVER);
1515 viewport_comments = gtk_viewport_new(gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(scroll_window_comments)), gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scroll_window_comments)));
1516 gtk_container_add(GTK_CONTAINER(viewport_comments), user_data->dlg.draw_area_comments);
1517 gtk_container_add(GTK_CONTAINER(scroll_window_comments), viewport_comments);
1518 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport_comments), GTK_SHADOW_NONE);
1519 OBJECT_SET_DATA(user_data->dlg.draw_area_comments, "graph_analysis_data_t", user_data);
1520 gtk_widget_add_events (user_data->dlg.draw_area_comments, GDK_BUTTON_PRESS_MASK);
1522 #if GTK_MAJOR_VERSION >= 2
1523 SIGNAL_CONNECT(user_data->dlg.draw_area_comments, "scroll_event", scroll_event, user_data);
1525 /* create main Graph draw area */
1526 user_data->dlg.draw_area=gtk_drawing_area_new();
1527 if (user_data->num_nodes < 2)
1528 user_data->dlg.pixmap_width = 2 * NODE_WIDTH;
1530 user_data->dlg.pixmap_width = user_data->num_nodes * NODE_WIDTH;
1531 WIDGET_SET_SIZE(user_data->dlg.draw_area, user_data->dlg.pixmap_width, user_data->dlg.pixmap_height);
1532 user_data->dlg.scroll_window=gtk_scrolled_window_new(NULL, NULL);
1533 if ( user_data->num_nodes < 6)
1534 WIDGET_SET_SIZE(user_data->dlg.scroll_window, NODE_WIDTH*user_data->num_nodes, user_data->dlg.pixmap_height);
1536 WIDGET_SET_SIZE(user_data->dlg.scroll_window, NODE_WIDTH*5, user_data->dlg.pixmap_height);
1537 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(user_data->dlg.scroll_window), GTK_POLICY_ALWAYS, GTK_POLICY_NEVER);
1538 viewport = gtk_viewport_new(gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(user_data->dlg.scroll_window)), gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(user_data->dlg.scroll_window)));
1539 gtk_container_add(GTK_CONTAINER(viewport), user_data->dlg.draw_area);
1540 gtk_container_add(GTK_CONTAINER(user_data->dlg.scroll_window), viewport);
1541 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1542 OBJECT_SET_DATA(user_data->dlg.draw_area, "graph_analysis_data_t", user_data);
1543 GTK_WIDGET_SET_FLAGS(user_data->dlg.draw_area, GTK_CAN_FOCUS);
1544 gtk_widget_grab_focus(user_data->dlg.draw_area);
1546 /* signals needed to handle backing pixmap */
1547 SIGNAL_CONNECT(user_data->dlg.draw_area, "expose_event", expose_event, NULL);
1548 SIGNAL_CONNECT(user_data->dlg.draw_area, "configure_event", configure_event, user_data);
1550 /* signals needed to handle backing pixmap comments*/
1551 SIGNAL_CONNECT(user_data->dlg.draw_area_comments, "expose_event", expose_event_comments, NULL);
1552 SIGNAL_CONNECT(user_data->dlg.draw_area_comments, "configure_event", configure_event_comments, user_data);
1554 /* signals needed to handle backing pixmap time*/
1555 SIGNAL_CONNECT(user_data->dlg.draw_area_time, "expose_event", expose_event_time, NULL);
1556 SIGNAL_CONNECT(user_data->dlg.draw_area_time, "configure_event", configure_event_time, user_data);
1558 gtk_widget_add_events (user_data->dlg.draw_area, GDK_BUTTON_PRESS_MASK);
1559 SIGNAL_CONNECT(user_data->dlg.draw_area, "button_press_event", button_press_event, user_data);
1560 #if GTK_MAJOR_VERSION >= 2
1561 SIGNAL_CONNECT(user_data->dlg.draw_area, "scroll_event", scroll_event, user_data);
1563 SIGNAL_CONNECT(user_data->dlg.draw_area, "key_press_event", key_press_event, user_data);
1565 gtk_widget_show(user_data->dlg.draw_area_time);
1566 gtk_widget_show(user_data->dlg.draw_area);
1567 gtk_widget_show(viewport);
1568 gtk_widget_show(user_data->dlg.draw_area_comments);
1569 gtk_widget_show(viewport_comments);
1571 gtk_widget_show(user_data->dlg.scroll_window);
1572 gtk_widget_show(scroll_window_comments);
1574 gtk_box_pack_start(GTK_BOX(hbox), user_data->dlg.draw_area_time, FALSE, FALSE, 0);
1576 user_data->dlg.hpane = gtk_hpaned_new();
1577 gtk_paned_pack1(GTK_PANED (user_data->dlg.hpane), user_data->dlg.scroll_window, FALSE, TRUE);
1578 gtk_paned_pack2(GTK_PANED (user_data->dlg.hpane), scroll_window_comments, TRUE, TRUE);
1579 #if GTK_MAJOR_VERSION >= 2
1580 SIGNAL_CONNECT(user_data->dlg.hpane, "notify::position", pane_callback, user_data);
1582 gtk_widget_show(user_data->dlg.hpane);
1584 gtk_box_pack_start(GTK_BOX(hbox), user_data->dlg.hpane, TRUE, TRUE, 0);
1586 /* create the associated v_scrollbar */
1587 user_data->dlg.v_scrollbar_adjustment=(GtkAdjustment *)gtk_adjustment_new(0,0,0,0,0,0);
1588 user_data->dlg.v_scrollbar=gtk_vscrollbar_new(user_data->dlg.v_scrollbar_adjustment);
1589 gtk_widget_show(user_data->dlg.v_scrollbar);
1590 gtk_box_pack_end(GTK_BOX(hbox), user_data->dlg.v_scrollbar, FALSE, FALSE, 0);
1591 SIGNAL_CONNECT(user_data->dlg.v_scrollbar_adjustment, "value_changed", v_scrollbar_changed, user_data);
1594 gtk_box_pack_start(GTK_BOX(box), hbox, TRUE, TRUE, 0);
1596 /****************************************************************************/
1598 /****************************************************************************/
1601 /****************************************************************************/
1602 static void dialog_graph_create_window(graph_analysis_data_t* user_data)
1605 GtkWidget *hbuttonbox;
1606 GtkWidget *bt_close;
1608 GtkTooltips *tooltips = gtk_tooltips_new();
1610 /* create the main window */
1611 if (user_data->dlg.title)
1612 user_data->dlg.window=window_new(GTK_WINDOW_TOPLEVEL, user_data->dlg.title);
1614 user_data->dlg.window=window_new(GTK_WINDOW_TOPLEVEL, "Graph Analysis");
1617 vbox=gtk_vbox_new(FALSE, 0);
1618 gtk_container_add(GTK_CONTAINER(user_data->dlg.window), vbox);
1619 gtk_widget_show(vbox);
1621 create_draw_area(user_data, vbox);
1624 hbuttonbox = gtk_hbutton_box_new ();
1625 gtk_box_pack_start (GTK_BOX (vbox), hbuttonbox, FALSE, FALSE, 0);
1626 gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox), GTK_BUTTONBOX_SPREAD);
1627 gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbuttonbox), 30);
1628 gtk_widget_show(hbuttonbox);
1630 bt_save = BUTTON_NEW_FROM_STOCK(GTK_STOCK_SAVE_AS);
1631 gtk_container_add(GTK_CONTAINER(hbuttonbox), bt_save);
1632 gtk_widget_show(bt_save);
1633 SIGNAL_CONNECT(bt_save, "clicked", on_save_bt_clicked, user_data);
1634 gtk_tooltips_set_tip (tooltips, bt_save, "Save an ASCII representation of the graph to a file", NULL);
1636 bt_close = BUTTON_NEW_FROM_STOCK(GTK_STOCK_CLOSE);
1637 gtk_container_add (GTK_CONTAINER (hbuttonbox), bt_close);
1638 GTK_WIDGET_SET_FLAGS(bt_close, GTK_CAN_DEFAULT);
1639 gtk_widget_show(bt_close);
1640 gtk_tooltips_set_tip (tooltips, bt_close, "Close this dialog", NULL);
1641 window_set_cancel_button(user_data->dlg.window, bt_close, window_cancel_button_cb);
1643 SIGNAL_CONNECT(user_data->dlg.window, "delete_event", window_delete_event_cb, NULL);
1644 SIGNAL_CONNECT(user_data->dlg.window, "destroy", on_destroy, user_data);
1646 gtk_widget_show(user_data->dlg.window);
1647 window_present(user_data->dlg.window);
1650 /* Return the index array if the node is in the array. Return -1 if there is room in the array
1651 * and Return -2 if the array is full
1653 /****************************************************************************/
1654 static gint is_node_array(graph_analysis_data_t* user_data, address* node)
1657 for (i=0; i<MAX_NUM_NODES; i++){
1658 if (user_data->nodes[i].type == AT_NONE) return -1; /* it is not in the array */
1659 if (ADDRESSES_EQUAL((&user_data->nodes[i]),node)) return i; /* it is in the array */
1661 return -2; /* array full */
1665 /* Get the nodes from the list */
1666 /****************************************************************************/
1667 static void get_nodes(graph_analysis_data_t* user_data)
1670 graph_analysis_item_t *gai;
1673 /* fill the node array */
1674 list = g_list_first(user_data->graph_info->list);
1679 user_data->num_items++;
1680 if (!user_data->dlg.inverse) {
1681 /* check source node address */
1682 index = is_node_array(user_data, &(gai->src_addr));
1684 case -2: /* array full */
1685 gai->src_node = NODE_OVERFLOW;
1687 case -1: /* not in array */
1688 COPY_ADDRESS(&(user_data->nodes[user_data->num_nodes]),&(gai->src_addr));
1689 gai->src_node = user_data->num_nodes;
1690 user_data->num_nodes++;
1692 default: /* it is in the array, just update the src_node */
1693 gai->src_node = (guint16)index;
1696 /* check destination node address*/
1697 index = is_node_array(user_data, &(gai->dst_addr));
1699 case -2: /* array full */
1700 gai->dst_node = NODE_OVERFLOW;
1702 case -1: /* not in array */
1703 COPY_ADDRESS(&(user_data->nodes[user_data->num_nodes]),&(gai->dst_addr));
1704 gai->dst_node = user_data->num_nodes;
1705 user_data->num_nodes++;
1707 default: /* it is in the array, just update the dst_node */
1708 gai->dst_node = (guint16)index;
1711 /* check destination node address*/
1712 index = is_node_array(user_data, &(gai->dst_addr));
1714 case -2: /* array full */
1715 gai->dst_node = NODE_OVERFLOW;
1717 case -1: /* not in array */
1718 COPY_ADDRESS(&(user_data->nodes[user_data->num_nodes]),&(gai->dst_addr));
1719 gai->dst_node = user_data->num_nodes;
1720 user_data->num_nodes++;
1722 default: /* it is in the array, just update the dst_node */
1723 gai->dst_node = (guint16)index;
1726 /* check source node address */
1727 index = is_node_array(user_data, &(gai->src_addr));
1729 case -2: /* array full */
1730 gai->src_node = NODE_OVERFLOW;
1732 case -1: /* not in array */
1733 COPY_ADDRESS(&(user_data->nodes[user_data->num_nodes]),&(gai->src_addr));
1734 gai->src_node = user_data->num_nodes;
1735 user_data->num_nodes++;
1737 default: /* it is in the array, just update the src_node */
1738 gai->src_node = (guint16)index;
1744 list = g_list_next(list);
1748 /****************************************************************************/
1749 graph_analysis_data_t* graph_analysis_init(void)
1751 graph_analysis_data_t* user_data;
1753 user_data = g_malloc(sizeof(graph_analysis_data_t));
1755 /* init user_data */
1756 graph_analysis_init_dlg(user_data);
1760 /****************************************************************************/
1762 /****************************************************************************/
1764 /****************************************************************************/
1765 void graph_analysis_create(graph_analysis_data_t* user_data)
1767 /* reset the data */
1768 graph_analysis_reset(user_data);
1770 /* get nodes (each node is an address) */
1771 get_nodes(user_data);
1773 /* create the graph windows */
1774 dialog_graph_create_window(user_data);
1776 /* redraw the graph */
1777 dialog_graph_redraw(user_data);
1782 /****************************************************************************/
1783 void graph_analysis_update(graph_analysis_data_t* user_data)
1785 /* reset the data */
1786 graph_analysis_reset(user_data);
1788 /* get nodes (each node is an address) */
1789 get_nodes(user_data);
1791 user_data->dlg.pixmap_width = user_data->num_nodes * NODE_WIDTH;
1792 WIDGET_SET_SIZE(user_data->dlg.draw_area, user_data->dlg.pixmap_width, user_data->dlg.pixmap_height);
1793 if ( user_data->num_nodes < 6)
1794 WIDGET_SET_SIZE(user_data->dlg.scroll_window, NODE_WIDTH*user_data->num_nodes, user_data->dlg.pixmap_height);
1796 WIDGET_SET_SIZE(user_data->dlg.scroll_window, NODE_WIDTH*5, user_data->dlg.pixmap_height);
1798 /* redraw the graph */
1799 dialog_graph_redraw(user_data);
1801 window_present(user_data->dlg.window);
1806 /****************************************************************************/
1807 void graph_analysis_redraw(graph_analysis_data_t* user_data)
1809 /* get nodes (each node is an address) */
1810 get_nodes(user_data);
1812 user_data->dlg.pixmap_width = user_data->num_nodes * NODE_WIDTH;
1813 WIDGET_SET_SIZE(user_data->dlg.draw_area, user_data->dlg.pixmap_width, user_data->dlg.pixmap_height);
1814 if ( user_data->num_nodes < 6)
1815 WIDGET_SET_SIZE(user_data->dlg.scroll_window, NODE_WIDTH*user_data->num_nodes, user_data->dlg.pixmap_height);
1817 WIDGET_SET_SIZE(user_data->dlg.scroll_window, NODE_WIDTH*5, user_data->dlg.pixmap_height);
1820 /* redraw the graph */
1821 dialog_graph_redraw(user_data);
1823 window_present(user_data->dlg.window);