2 * TCP graph drawing code
3 * By Pavel Mores <pvl@uh.cz>
4 * Win32 port: rwh@unifiedtech.com
6 * $Id: tcp_graph.c,v 1.8 2001/12/10 23:27:25 guy Exp $
8 * Ethereal - Network traffic analyzer
9 * By Gerald Combs <gerald@ethereal.com>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 #include <gdk/gdkkeysyms.h>
34 #include <math.h> /* rint() */
36 #include <sys/types.h> /* freebsd requires this */
39 # include <netinet/in.h> /* ntohs(), IPPROTO_TCP */
40 # include <arpa/inet.h> /* inet_ntoa() */
45 #include "globals.h" /* cfile */
46 #include "packet.h" /* frame_data */
47 #include "prefs_dlg.h" /* prefs */
48 #include "gtkglobals.h" /* set_scrollbar_placement_srollw() and
49 * remember_scrolled_window() */
50 #include "simple_dialog.h"
51 #include "tcp_graph.h"
53 /* from <net/ethernet.h> */
55 guint8 ether_dhost[6]; /* destination eth addr */
56 guint8 ether_shost[6]; /* source ether addr */
57 guint16 ether_type; /* packet type ID field */
59 #define ETHERTYPE_IP 0x0800
62 /* reverse engineered from capture file, not too difficult :) */
64 guint8 ppp_type; /* Protocol on PPP connection */
66 #define PPPTYPE_IP 0x21
69 /* from <netinet/ip.h> */
83 #define IPHDR_IHL_SHIFT 0
84 #define IPHDR_IHL_MASK (0xf << IPHDR_IHL_SHIFT)
85 #define IHL(iphdrptr) ( ((iphdrptr)->version_ihl & IPHDR_IHL_MASK) >> IPHDR_IHL_SHIFT )
87 /* from <netinet/tcp.h> */
105 #define TCP_SYN(tcphdr) ( ntohs ((tcphdr).flags) & TH_SYN )
106 #define TCP_ACK(tcphdr) ( ntohs ((tcphdr).flags) & TH_ACK )
107 #define TCP_DOFF_SHIFT 12
108 #define TCP_DOFF_MASK (0xf << TCP_DOFF_SHIFT)
109 #define DOFF(tcphdr) ( ( ntohs ((tcphdr).flags) & TCP_DOFF_MASK) >> TCP_DOFF_SHIFT )
111 #define TXT_WIDTH 850
112 #define TXT_HEIGHT 550
114 /* for compare_headers() */
115 /* segment went the same direction as the currently selected one */
116 #define COMPARE_CURR_DIR 0
117 #define COMPARE_ANY_DIR 1
119 /* initalize_axis() */
120 #define AXIS_HORIZONTAL 0
121 #define AXIS_VERTICAL 1
124 struct segment *next;
131 struct tcphdr tcphdr;
132 int data; /* amount of data in this segment */
136 double x, y, width, height;
140 double x1, y1, x2, y2;
144 int x, y, width, height;
176 struct segment *parent;
178 struct arc_params arc;
179 struct rect_params rect;
180 struct line_params line;
184 struct element_list {
185 struct element_list *next;
186 struct element *elements;
190 struct graph *g; /* which graph we belong to */
191 GtkWidget *drawing_area;
192 GdkPixmap *pixmap[2];
194 #define AXIS_ORIENTATION 1 << 0
196 /* dim and orig (relative to origin of window) of axis' pixmap */
198 /* dim and orig (relative to origin of axis' pixmap) of scale itself */
201 gdouble major, minor; /* major and minor ticks */
205 #define HAXIS_INIT_HEIGHT 70
206 #define VAXIS_INIT_WIDTH 100
207 #define TITLEBAR_HEIGHT 50
208 #define RMARGIN_WIDTH 30
210 struct style_tseq_tcptrace {
216 struct style_tseq_stevens {
234 #define SEQ_ORIGIN 0x1
235 /* show absolute sequence numbers (not differences from isn) */
236 #define SEQ_ORIGIN_ZERO 0x1
237 #define SEQ_ORIGIN_ISN 0x0
238 #define TIME_ORIGIN 0x10
239 /* show time from beginning of capture as opposed to time from beginning
240 * of the connection */
241 #define TIME_ORIGIN_CAP 0x10
242 #define TIME_ORIGIN_CONN 0x0
244 /* this is used by rtt module only */
253 int draw; /* indicates whether we should draw cross at all */
255 GtkToggleButton *on_toggle;
256 GtkToggleButton *off_toggle;
260 double x0, y0, width, height;
269 double step_x, step_y;
271 #define ZOOM_OUT (1 << 0)
272 #define ZOOM_HLOCK (1 << 1)
273 #define ZOOM_VLOCK (1 << 2)
274 #define ZOOM_STEPS_SAME (1 << 3)
275 #define ZOOM_STEPS_KEEP_RATIO (1 << 4)
277 /* unfortunately, we need them both because gtk_toggle_button_set_active ()
278 * with second argument FALSE doesn't do anything, somehow */
280 GtkToggleButton *in_toggle;
281 GtkToggleButton *out_toggle;
284 GtkSpinButton *h_step;
285 GtkSpinButton *v_step;
297 struct ipoint offset;
301 #define MAGZOOMS_SAME (1 << 0)
302 #define MAGZOOMS_SAME_RATIO (1 << 1)
303 #define MAGZOOMS_IGNORE (1 << 31)
306 GtkSpinButton *h_zoom, *v_zoom;
312 #define GRAPH_TSEQ_STEVENS 0
313 #define GRAPH_TSEQ_TCPTRACE 1
314 #define GRAPH_THROUGHPUT 2
317 #define GRAPH_DESTROYED (1 << 0)
318 #define GRAPH_INIT_ON_TYPE_CHANGE (1 << 1)
320 GtkWidget *toplevel; /* keypress handler needs this */
321 GtkWidget *drawing_area;
322 GtkWidget *text; /* text widget for seg list - probably temporary */
323 GdkFont *font; /* font used for annotations etc. */
326 GdkPixmap *title_pixmap;
327 GdkPixmap *pixmap[2];
328 int displayed; /* which of both pixmaps is on screen right now */
330 GtkWidget *control_panel;
331 /* this belongs to style structs of graph types that make use of it */
332 GtkToggleButton *time_orig_conn, *seq_orig_isn;
335 /* Next 4 attribs describe the graph in natural units, before any scaling.
336 * For example, if we want to display graph of TCP conversation that
337 * started 112.309845 s after beginning of the capture and ran until
338 * 479.093582 s, 237019 B went through the connection (in one direction)
339 * starting with isn 31934022, then (bounds.x0, bounds.y0)=(112.309845,
340 * 31934022) and (bounds.width, bounds.height)=(366.783737, 237019). */
341 struct bounds bounds;
342 /* dimensions and position of the graph, both expressed already in pixels.
343 * x and y give the position of upper left corner of the graph relative
344 * to origin of the graph window, size is basically bounds*zoom */
346 /* viewport (=graph window area which is reserved for graph itself), its
347 * size and position relative to origin of the graph window */
350 /* If we need to display 237019 sequence numbers (=bytes) onto say 500
351 * pixels, we have to scale the graph down by factor of 0.002109. This
352 * number would be zoom.y. Obviously, both directions have separate zooms.*/
355 struct magnify magnify;
356 struct axis *x_axis, *y_axis;
357 struct segment *segments;
358 struct segment *current;
359 struct element_list *elists; /* element lists */
361 struct style_tseq_stevens tseq_stevens;
362 struct style_tseq_tcptrace tseq_tcptrace;
363 struct style_tput tput;
364 struct style_rtt rtt;
368 static struct graph *graphs = NULL;
369 static GdkGC *xor_gc = NULL;
372 #define debug(section) if (debugging & section)
373 /* print function entry points */
374 #define DBS_FENTRY (1 << 0)
375 #define DBS_AXES_TICKS (1 << 1)
376 #define DBS_AXES_DRAWING (1 << 2)
377 #define DBS_GRAPH_DRAWING (1 << 3)
378 #define DBS_TPUT_ELMTS (1 << 4)
379 /*int debugging = DBS_FENTRY;*/
381 /*int debugging = DBS_AXES_TICKS;*/
382 /*int debugging = DBS_AXES_DRAWING;*/
383 /*int debugging = DBS_GRAPH_DRAWING;*/
384 /*int debugging = DBS_TPUT_ELMTS;*/
386 static void create_gui (struct graph * );
387 static void create_text_widget (struct graph * );
388 static void display_text (struct graph * );
389 static void create_drawing_area (struct graph * );
390 static void control_panel_create (struct graph * );
391 static GtkWidget *control_panel_create_zoom_group (struct graph * );
392 static GtkWidget *control_panel_create_magnify_group (struct graph * );
393 static GtkWidget *control_panel_create_cross_group (struct graph * );
394 static GtkWidget *control_panel_create_zoomlock_group (struct graph * );
395 static GtkWidget *control_panel_create_graph_type_group (struct graph * );
396 static void control_panel_add_zoom_page (struct graph * , GtkWidget * );
397 static void control_panel_add_magnify_page (struct graph * , GtkWidget * );
398 static void control_panel_add_origin_page (struct graph * , GtkWidget * );
399 static void control_panel_add_cross_page (struct graph * , GtkWidget * );
400 static void control_panel_add_graph_type_page (struct graph * , GtkWidget * );
401 static void callback_toplevel_destroy (GtkWidget * , gpointer );
402 static void callback_close (GtkWidget * , gpointer );
403 static void callback_time_origin (GtkWidget * , gpointer );
404 static void callback_seq_origin (GtkWidget * , gpointer );
405 static void callback_zoomlock_h (GtkWidget * , gpointer );
406 static void callback_zoomlock_v (GtkWidget * , gpointer );
407 static void callback_zoom_inout (GtkWidget * , gpointer );
408 static void callback_zoom_step (GtkWidget * , gpointer );
409 static void callback_zoom_flags (GtkWidget * , gpointer );
410 static void callback_cross_on_off (GtkWidget * , gpointer );
411 static void callback_mag_width (GtkWidget * , gpointer );
412 static void callback_mag_height (GtkWidget * , gpointer );
413 static void callback_mag_x (GtkWidget * , gpointer );
414 static void callback_mag_y (GtkWidget * , gpointer );
415 static void callback_mag_zoom (GtkWidget * , gpointer );
416 static void callback_mag_flags (GtkWidget * , gpointer );
417 static void callback_graph_type (GtkWidget * , gpointer );
418 static void callback_graph_init_on_typechg (GtkWidget * , gpointer );
419 static void callback_create_help (GtkWidget * , gpointer );
420 static void callback_close_help (GtkWidget * , gpointer );
421 static void update_zoom_spins (struct graph * );
422 static int get_headers (frame_data *, char * , struct segment * );
423 static int compare_headers (struct segment * , struct segment * , int );
424 static int get_num_dsegs (struct graph * );
425 static int get_num_acks (struct graph * );
426 static void graph_type_dependent_initialize (struct graph * );
427 static void graph_put (struct graph * );
428 static struct graph *graph_new (void);
429 static void graph_destroy (struct graph * );
430 static void graph_initialize_values (struct graph * );
431 static void graph_init_sequence (struct graph * );
432 static void draw_element_line (struct graph * , struct element * );
433 static void draw_element_arc (struct graph * , struct element * );
434 static void graph_display (struct graph * );
435 static void graph_pixmaps_create (struct graph * );
436 static void graph_pixmaps_switch (struct graph * );
437 static void graph_pixmap_draw (struct graph * );
438 static void graph_pixmap_display (struct graph * );
439 static void graph_element_lists_make (struct graph * );
440 static void graph_element_lists_free (struct graph * );
441 static void graph_element_lists_initialize (struct graph * );
442 static void graph_title_pixmap_create (struct graph * );
443 static void graph_title_pixmap_draw (struct graph * );
444 static void graph_title_pixmap_display (struct graph * );
445 static void graph_segment_list_get (struct graph * );
446 static void graph_segment_list_free (struct graph * );
447 static void graph_select_segment (struct graph * , int , int );
448 static int line_detect_collision (struct element * , int , int );
449 static int arc_detect_collision (struct element * , int , int );
450 static void update_packet_list (int );
451 static void axis_pixmaps_create (struct axis * );
452 static void axis_pixmaps_switch (struct axis * );
453 static void axis_display (struct axis * );
454 static void v_axis_pixmap_draw (struct axis * );
455 static void h_axis_pixmap_draw (struct axis * );
456 static void axis_pixmap_display (struct axis * );
457 static void axis_compute_ticks (struct axis * , double , double , int );
458 static double axis_zoom_get (struct axis * , int );
459 static void axis_ticks_up (int * , int * );
460 static void axis_ticks_down (int * , int * );
461 static void axis_destroy (struct axis * );
462 static int get_label_dim (struct axis * , int , double );
463 static void toggle_time_origin (struct graph * );
464 static void toggle_seq_origin (struct graph * );
465 static void cross_xor (struct graph * , int , int );
466 static void cross_draw (struct graph * , int , int );
467 static void cross_erase (struct graph * );
468 static void magnify_create (struct graph * , int , int );
469 static void magnify_move (struct graph * , int , int );
470 static void magnify_destroy (struct graph * );
471 static void magnify_draw (struct graph * );
472 static void magnify_get_geom (struct graph * , int , int );
473 static gint configure_event (GtkWidget * , GdkEventConfigure * );
474 static gint expose_event (GtkWidget * , GdkEventExpose * );
475 static gint button_press_event (GtkWidget * , GdkEventButton * );
476 static gint button_release_event (GtkWidget * , GdkEventButton * );
477 static gint motion_notify_event (GtkWidget * , GdkEventMotion * );
478 static gint key_press_event (GtkWidget * , GdkEventKey * );
479 static gint key_release_event (GtkWidget * , GdkEventKey * );
480 static gint leave_notify_event (GtkWidget * , GdkEventCrossing * );
481 static gint enter_notify_event (GtkWidget * , GdkEventCrossing * );
482 static void tseq_stevens_initialize (struct graph * );
483 static void tseq_stevens_get_bounds (struct graph * );
484 static void tseq_stevens_read_config (struct graph * );
485 static void tseq_stevens_make_elmtlist (struct graph * );
486 static void tseq_stevens_toggle_seq_origin (struct graph * );
487 static void tseq_stevens_toggle_time_origin (struct graph * );
488 static void tseq_tcptrace_read_config (struct graph * );
489 static void tseq_tcptrace_make_elmtlist (struct graph * );
490 static void tseq_tcptrace_toggle_seq_origin (struct graph * );
491 static void tseq_tcptrace_toggle_time_origin (struct graph * );
492 static void tput_initialize (struct graph * );
493 static void tput_read_config (struct graph * );
494 static void tput_make_elmtlist (struct graph * );
495 static void tput_toggle_time_origin (struct graph * );
496 static void rtt_read_config (struct graph * );
497 static void rtt_initialize (struct graph * );
498 static int rtt_is_retrans (struct unack * , unsigned int );
499 static struct unack *rtt_get_new_unack (double , unsigned int );
500 static void rtt_put_unack_on_list (struct unack ** , struct unack * );
501 static void rtt_delete_unack_from_list (struct unack ** , struct unack * );
502 static void rtt_make_elmtlist (struct graph * );
503 static void rtt_toggle_seq_origin (struct graph * );
505 static int rint (double ); /* compiler template for Windows */
508 static char helptext[] =
510 "Here's what you can do:\n
511 - Left Mouse Button selects segment in ethereal's packet list\n\
512 - Middle Mouse Button zooms in\n\
513 - <shift>-Middle Button zooms out\n\
514 - Right Mouse Button moves the graph (if zoomed in)\n\
515 - <ctrl>-Right Mouse Button displays a portion of graph magnified\n\
516 - Space toggles crosshairs\n\
517 - 's' toggles relative/absolute sequence numbers\n\
518 - 't' toggles time origin\n
521 "Here's what you can do:\n\
522 - <ctrl>-Left Mouse Button selects segment in ethereal's packet list\n\
523 - Left Mouse Button zooms in\n\
524 - <shift>-Left Mouse Button zooms out\n\
525 - Right Mouse Button moves the graph (if zoomed in)\n\
526 - <ctrl>-Right Mouse Button displays a portion of graph magnified\n\
528 - Space bar toggles crosshairs\n\
529 - 's' - Toggles relative/absolute sequence numbers\n\
530 - 't' - Toggles time origin\n\
534 void tcp_graph_cb (GtkWidget *w, gpointer data, guint graph_type)
536 struct segment current;
539 debug(DBS_FENTRY) puts ("tcp_graph_cb()");
541 if (! (g = graph_new()))
545 graph_initialize_values (g);
548 g->type = graph_type;
549 if (!get_headers (cfile.current_frame, cfile.pd, ¤t)) {
550 /* currently selected packet is neither TCP over IP over Ethernet II/PPP
551 * nor TCP over IP alone - should display some
552 * kind of warning dialog */
553 simple_dialog(ESD_TYPE_WARN, NULL,
554 "Selected packet is not a TCP segment");
558 graph_segment_list_get(g);
560 /* display_text(g); */
561 graph_init_sequence(g);
564 static void create_gui (struct graph *g)
566 debug(DBS_FENTRY) puts ("create_gui()");
567 /* create_text_widget(g); */
568 control_panel_create (g);
569 create_drawing_area(g);
572 static void create_text_widget (struct graph *g)
574 GtkWidget *streamwindow, *txt_scrollw, *box;
576 debug(DBS_FENTRY) puts ("create_text_widget()");
577 streamwindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);
578 gtk_widget_set_name (streamwindow, "Packet chain");
579 gtk_widget_set_usize (GTK_WIDGET (streamwindow), TXT_WIDTH, TXT_HEIGHT);
580 gtk_container_border_width (GTK_CONTAINER(streamwindow), 2);
582 box = gtk_vbox_new (FALSE, 0);
583 gtk_container_add (GTK_CONTAINER (streamwindow), box);
584 gtk_widget_show (box);
586 txt_scrollw = gtk_scrolled_window_new (NULL, NULL);
587 gtk_box_pack_start (GTK_BOX (box), txt_scrollw, TRUE, TRUE, 0);
588 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (txt_scrollw),
589 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
590 set_scrollbar_placement_scrollw (txt_scrollw, prefs.gui_scrollbar_on_right);
591 remember_scrolled_window (txt_scrollw);
592 gtk_widget_show (txt_scrollw);
594 g->text = gtk_text_new (NULL, NULL);
595 gtk_text_set_editable (GTK_TEXT (g->text), FALSE);
596 gtk_container_add (GTK_CONTAINER (txt_scrollw), g->text);
597 gtk_widget_show (g->text);
598 gtk_widget_show (streamwindow);
601 static void display_text (struct graph *g)
605 double first_time, prev_time;
606 unsigned int isn_this=0, isn_opposite=0, seq_this_prev, seq_opposite_prev;
609 debug(DBS_FENTRY) puts ("display_text()");
610 gdk_color_parse ("SlateGray", &color);
611 gtk_text_freeze (GTK_TEXT (g->text));
612 snprintf ((char * )line, 256, "%10s%15s%15s%15s%15s%15s%15s%10s\n",
613 "pkt num", "time", "delta first", "delta prev",
614 "seqno", "delta first", "delta prev", "data (B)");
615 gtk_text_insert (GTK_TEXT (g->text), g->font, NULL, NULL,
616 (const char *)line, -1);
618 first_time = g->segments->rel_secs + g->segments->rel_usecs/1000000.0;
619 prev_time = first_time;
620 /* we have to find Initial Sequence Number for both ends of connection */
621 for (ptr=g->segments; ptr; ptr=ptr->next) {
622 if (compare_headers (g->current, ptr, COMPARE_CURR_DIR)) {
623 isn_this = ntohl (ptr->tcphdr.seq);
627 for (ptr=g->segments; ptr; ptr=ptr->next) {
628 if (!compare_headers (g->current, ptr, COMPARE_CURR_DIR)) {
629 isn_opposite = ntohl (ptr->tcphdr.seq);
633 seq_this_prev = isn_this;
634 seq_opposite_prev = isn_opposite;
635 for (ptr=g->segments; ptr; ptr=ptr->next) {
636 double time=ptr->rel_secs + ptr->rel_usecs/1000000.0;
637 unsigned int seq = ntohl (ptr->tcphdr.seq);
638 int seq_delta_isn, seq_delta_prev;
640 if (compare_headers (g->current, ptr, COMPARE_CURR_DIR)) {
641 seq_delta_isn = seq - isn_this;
642 seq_delta_prev = seq - seq_this_prev;
646 seq_delta_isn = seq - isn_opposite;
647 seq_delta_prev = seq - seq_opposite_prev;
648 seq_opposite_prev = seq;
651 snprintf ((char *)line, 256, "%10d%15.6f%15.6f%15.6f%15u%15d%15d%10u\n",
652 ptr->num, time, time-first_time, time-prev_time,
653 seq, seq_delta_isn, seq_delta_prev,
654 ntohs (ptr->iphdr.tot_len) - 4*IHL(&(ptr->iphdr)) -
655 4*DOFF(ptr->tcphdr));
656 gtk_text_insert (GTK_TEXT (g->text), g->font, c, NULL,
657 (const char * )line, -1);
660 gtk_text_thaw (GTK_TEXT (g->text));
663 static void create_drawing_area (struct graph *g)
665 GdkColormap *colormap;
667 GtkWidget *frame, *box;
668 #define WINDOW_TITLE_LENGTH 64
669 char window_title[WINDOW_TITLE_LENGTH];
671 debug(DBS_FENTRY) puts ("create_drawing_area()");
673 g->font = gdk_font_load ("-sony-fixed-medium-r-normal--16-150-75-75"
675 g->font = gdk_font_load ("-biznet-fotinostypewriter-medium-r-normal-*-*-120"
676 "-*-*-m-*-iso8859-2");
678 g->toplevel = gtk_window_new (GTK_WINDOW_TOPLEVEL);
679 gtk_widget_set_name (g->toplevel, "Test Graph");
681 /* Create the drawing area */
682 g->drawing_area = gtk_drawing_area_new ();
683 g->x_axis->drawing_area = g->y_axis->drawing_area = g->drawing_area;
684 gtk_drawing_area_size (GTK_DRAWING_AREA (g->drawing_area),
685 g->wp.width + g->wp.x + RMARGIN_WIDTH,
686 g->wp.height + g->wp.y + g->x_axis->s.height);
687 gtk_widget_show (g->drawing_area);
689 gtk_signal_connect (GTK_OBJECT (g->drawing_area), "expose_event",
690 (GtkSignalFunc )expose_event, NULL);
691 /* this has to be done later, after the widget has been shown */
693 gtk_signal_connect (GTK_OBJECT(g->drawing_area),"configure_event",
694 (GtkSignalFunc )configure_event, NULL);
696 gtk_signal_connect (GTK_OBJECT (g->drawing_area), "motion_notify_event",
697 (GtkSignalFunc )motion_notify_event, NULL);
698 gtk_signal_connect (GTK_OBJECT (g->drawing_area), "button_press_event",
699 (GtkSignalFunc )button_press_event, NULL);
700 gtk_signal_connect (GTK_OBJECT (g->drawing_area), "button_release_event",
701 (GtkSignalFunc )button_release_event, NULL);
702 gtk_signal_connect (GTK_OBJECT (g->drawing_area), "leave_notify_event",
703 (GtkSignalFunc )leave_notify_event, NULL);
704 gtk_signal_connect (GTK_OBJECT (g->drawing_area), "enter_notify_event",
705 (GtkSignalFunc )enter_notify_event, NULL);
706 gtk_signal_connect (GTK_OBJECT (g->toplevel), "destroy",
707 (GtkSignalFunc )callback_toplevel_destroy, g);
708 /* why doesn't drawing area send key_press_signals? */
709 gtk_signal_connect (GTK_OBJECT (g->toplevel), "key_press_event",
710 (GtkSignalFunc )key_press_event, NULL);
711 gtk_signal_connect (GTK_OBJECT (g->toplevel), "key_release_event",
712 (GtkSignalFunc )key_release_event, NULL);
713 gtk_widget_set_events (g->toplevel,GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK);
715 gtk_widget_set_events (g->drawing_area, GDK_EXPOSURE_MASK
716 | GDK_LEAVE_NOTIFY_MASK
717 | GDK_ENTER_NOTIFY_MASK
718 | GDK_BUTTON_PRESS_MASK
719 | GDK_BUTTON_RELEASE_MASK
720 | GDK_POINTER_MOTION_MASK
721 | GDK_POINTER_MOTION_HINT_MASK);
724 frame = gtk_frame_new (NULL);
725 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
726 gtk_container_add (GTK_CONTAINER (frame), g->drawing_area);
728 box = gtk_hbox_new (FALSE, 0);
729 gtk_box_pack_start (GTK_BOX (box), g->gui.control_panel, FALSE, FALSE, 0);
730 gtk_box_pack_start (GTK_BOX (box), frame, TRUE, TRUE, 0);
731 gtk_container_add (GTK_CONTAINER (g->toplevel), box);
732 gtk_container_set_border_width (GTK_CONTAINER (g->toplevel), 5);
733 gtk_widget_show (frame);
734 gtk_widget_show (box);
737 gtk_container_add (GTK_CONTAINER (g->toplevel), g->drawing_area);
738 gtk_widget_show (g->toplevel);
739 snprintf (window_title, WINDOW_TITLE_LENGTH, "TCP Graph %d - Ethereal",
741 gtk_window_set_title (GTK_WINDOW (g->toplevel), window_title);
743 /* in case we didn't get what we asked for */
744 g->wp.width = GTK_WIDGET (g->drawing_area)->allocation.width -
745 g->wp.x - RMARGIN_WIDTH;
746 g->wp.height = GTK_WIDGET (g->drawing_area)->allocation.height -
747 g->wp.y - g->x_axis->s.height;
749 g->font = g->drawing_area->style->font;
750 gdk_font_ref (g->font);
752 colormap = gdk_window_get_colormap (g->drawing_area->window);
754 xor_gc = gdk_gc_new (g->drawing_area->window);
755 gdk_gc_set_function (xor_gc, GDK_XOR);
756 gdk_color_parse ("gray15", &color);
757 gdk_colormap_alloc_color (colormap, &color, FALSE, TRUE);
758 gdk_gc_set_foreground (xor_gc, &color);
760 g->fg_gc = gdk_gc_new (g->drawing_area->window);
761 g->bg_gc = gdk_gc_new (g->drawing_area->window);
762 gdk_color_parse ("white", &color);
763 gdk_colormap_alloc_color (colormap, &color, FALSE, TRUE);
764 gdk_gc_set_foreground (g->bg_gc, &color);
766 /* this is probably quite an ugly way to get rid of the first configure
768 * immediatelly after gtk_widget_show (window) drawing_area gets a configure
769 * event which is handled during the next return to gtk_main which is
770 * probably the gdk_gc_new() call. configure handler calls
771 * graph_element_lists_make() which is not good because the graph struct is
772 * not fully set up yet - namely we're not sure about actual geometry
773 * and we don't have the GC's at all. so we just postpone installation
774 * of configure handler until we're ready to deal with it.
776 * !!! NEMÌLO BY TO BÝT NA KONCI graph_init_sequence()? !!!
779 gtk_signal_connect (GTK_OBJECT(g->drawing_area),"configure_event",
780 (GtkSignalFunc )configure_event, NULL);
782 /* puts ("exiting create_drawing_area()"); */
785 static void callback_toplevel_destroy (GtkWidget *widget, gpointer data)
787 struct graph *g = (struct graph * )data;
789 if (!(g->flags & GRAPH_DESTROYED)) {
790 g->flags |= GRAPH_DESTROYED;
791 graph_destroy ((struct graph * )data);
795 static void control_panel_create (struct graph *g)
797 GtkWidget *toplevel, *notebook;
799 GtkWidget *help, *close, *button_box;
800 #define WINDOW_TITLE_LENGTH 64
801 char window_title[WINDOW_TITLE_LENGTH];
803 debug(DBS_FENTRY) puts ("control_panel_create()");
805 notebook = gtk_notebook_new ();
806 control_panel_add_zoom_page (g, notebook);
807 control_panel_add_magnify_page (g, notebook);
808 control_panel_add_origin_page (g, notebook);
809 control_panel_add_cross_page (g, notebook);
810 control_panel_add_graph_type_page (g, notebook);
812 /* bottom buttons group */
813 help = gtk_button_new_with_label ("Help");
814 close = gtk_button_new_with_label ("Close");
815 button_box = gtk_hbox_new (TRUE, 0);
816 gtk_box_pack_start (GTK_BOX (button_box), help, TRUE, TRUE, 0);
817 gtk_box_pack_start (GTK_BOX (button_box), close, TRUE, TRUE, 0);
819 toplevel = gtk_window_new (GTK_WINDOW_TOPLEVEL);
821 table = gtk_table_new (2, 1, FALSE);
822 gtk_container_add (GTK_CONTAINER (toplevel), table);
824 gtk_table_attach (GTK_TABLE (table), notebook, 0, 1, 0, 1,
825 GTK_FILL|GTK_EXPAND, GTK_FILL, 5, 5);
826 gtk_table_attach (GTK_TABLE (table), button_box, 0, 1, 1, 2,
827 GTK_FILL|GTK_EXPAND, GTK_FILL, 5, 5);
829 gtk_signal_connect (GTK_OBJECT (close), "clicked",
830 (GtkSignalFunc )callback_close, g);
831 gtk_signal_connect (GTK_OBJECT (help), "clicked",
832 (GtkSignalFunc )callback_create_help, g);
834 /* gtk_widget_show_all (table); */
835 /* g->gui.control_panel = table; */
836 gtk_widget_show_all (toplevel);
837 snprintf (window_title, WINDOW_TITLE_LENGTH,
838 "Graph %d - Control - Ethereal", refnum);
839 gtk_window_set_title (GTK_WINDOW (toplevel), window_title);
840 g->gui.control_panel = toplevel;
843 static void control_panel_add_zoom_page (struct graph *g, GtkWidget *n)
845 GtkWidget *zoom_frame;
846 GtkWidget *zoom_lock_frame;
850 zoom_frame = control_panel_create_zoom_group (g);
851 gtk_container_set_border_width (GTK_CONTAINER (zoom_frame), 5);
852 zoom_lock_frame = control_panel_create_zoomlock_group (g);
853 gtk_container_set_border_width (GTK_CONTAINER (zoom_lock_frame), 5);
854 box = gtk_vbox_new (FALSE, 0);
855 gtk_box_pack_start (GTK_BOX (box), zoom_frame, TRUE, TRUE, 0);
856 gtk_box_pack_start (GTK_BOX (box), zoom_lock_frame, TRUE, TRUE, 0);
857 gtk_widget_show (box);
858 label = gtk_label_new ("Zoom");
859 gtk_notebook_append_page (GTK_NOTEBOOK (n), box, label);
862 static void control_panel_add_magnify_page (struct graph *g, GtkWidget *n)
864 GtkWidget *mag_frame, *label;
866 mag_frame = control_panel_create_magnify_group (g);
867 gtk_container_set_border_width (GTK_CONTAINER (mag_frame), 5);
868 label = gtk_label_new ("Magnify");
869 gtk_notebook_append_page (GTK_NOTEBOOK (n), mag_frame, label);
872 static void control_panel_add_origin_page (struct graph *g, GtkWidget *n)
874 GtkWidget *time_orig_cap, *time_orig_conn, *time_orig_box, *time_orig_frame;
875 GtkWidget *seq_orig_isn, *seq_orig_zero, *seq_orig_box, *seq_orig_frame;
876 GtkWidget *box, *label;
878 /* time origin box */
880 gtk_radio_button_new_with_label (NULL, "beginning of capture");
881 time_orig_conn = gtk_radio_button_new_with_label (
882 gtk_radio_button_group (GTK_RADIO_BUTTON (time_orig_cap)),
883 "beginning of this TCP connection");
884 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (time_orig_conn), TRUE);
885 time_orig_box = gtk_vbox_new (TRUE, 0);
886 gtk_box_pack_start (GTK_BOX (time_orig_box), time_orig_conn, TRUE, TRUE, 0);
887 gtk_box_pack_start (GTK_BOX (time_orig_box), time_orig_cap, TRUE, TRUE, 0);
888 time_orig_frame = gtk_frame_new ("Time origin");
889 gtk_container_set_border_width (GTK_CONTAINER (time_orig_frame), 5);
890 gtk_container_add (GTK_CONTAINER (time_orig_frame), time_orig_box);
892 /* sequence number origin group */
894 gtk_radio_button_new_with_label (NULL, "initial sequence number");
895 seq_orig_zero = gtk_radio_button_new_with_label (gtk_radio_button_group (
896 GTK_RADIO_BUTTON (seq_orig_isn)), "0 (=absolute)");
897 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (seq_orig_isn), TRUE);
898 seq_orig_box = gtk_vbox_new (TRUE, 0);
899 gtk_box_pack_start (GTK_BOX (seq_orig_box), seq_orig_isn, TRUE, TRUE, 0);
900 gtk_box_pack_start (GTK_BOX (seq_orig_box), seq_orig_zero, TRUE, TRUE, 0);
901 seq_orig_frame = gtk_frame_new ("Sequence number origin");
902 gtk_container_set_border_width (GTK_CONTAINER (seq_orig_frame), 5);
903 gtk_container_add (GTK_CONTAINER (seq_orig_frame), seq_orig_box);
905 g->gui.time_orig_conn = (GtkToggleButton * )time_orig_conn;
906 g->gui.seq_orig_isn = (GtkToggleButton * )seq_orig_isn;
908 gtk_signal_connect (GTK_OBJECT (time_orig_conn), "toggled",
909 (GtkSignalFunc )callback_time_origin, g);
910 gtk_signal_connect (GTK_OBJECT (seq_orig_isn), "toggled",
911 (GtkSignalFunc )callback_seq_origin, g);
913 box = gtk_vbox_new (FALSE, 0);
914 gtk_container_set_border_width (GTK_CONTAINER (box), 5);
915 gtk_box_pack_start (GTK_BOX (box), time_orig_frame, TRUE, TRUE, 0);
916 gtk_box_pack_start (GTK_BOX (box), seq_orig_frame, TRUE, TRUE, 0);
917 gtk_widget_show (box);
918 label = gtk_label_new ("Origin");
919 gtk_notebook_append_page (GTK_NOTEBOOK (n), box, label);
922 static void control_panel_add_cross_page (struct graph *g, GtkWidget *n)
924 GtkWidget *cross_frame, *label;
926 cross_frame = control_panel_create_cross_group (g);
927 gtk_container_set_border_width (GTK_CONTAINER (cross_frame), 5);
928 label = gtk_label_new ("Cross");
929 gtk_notebook_append_page (GTK_NOTEBOOK (n), cross_frame, label);
932 static void control_panel_add_graph_type_page (struct graph *g, GtkWidget *n)
934 GtkWidget *frame, *label;
936 frame = control_panel_create_graph_type_group (g);
937 gtk_container_set_border_width (GTK_CONTAINER (frame), 5);
938 label = gtk_label_new ("Graph type");
939 gtk_notebook_append_page (GTK_NOTEBOOK (n), frame, label);
942 static void callback_close (GtkWidget *widget, gpointer data)
944 struct graph *g = (struct graph * )data;
946 if (!(g->flags & GRAPH_DESTROYED)) {
947 g->flags |= GRAPH_DESTROYED;
948 graph_destroy ((struct graph * )data);
952 static void callback_create_help (GtkWidget *widget, gpointer data)
954 struct graph *g = (struct graph * )data;
955 GtkWidget *toplevel, *box, *text, *scroll, *close;
957 toplevel = gtk_window_new (GTK_WINDOW_TOPLEVEL);
958 gtk_window_set_title(GTK_WINDOW(toplevel), "Help for TCP graphing");
959 gtk_widget_set_usize (toplevel, 500, 400);
960 box = gtk_vbox_new (FALSE, 0);
961 gtk_container_add (GTK_CONTAINER (toplevel), box);
962 scroll = gtk_scrolled_window_new (NULL, NULL);
963 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll),
964 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
965 gtk_box_pack_start (GTK_BOX (box), scroll, TRUE, TRUE, 0);
966 text = gtk_text_new (NULL, NULL);
967 gtk_text_set_editable (GTK_TEXT (text), FALSE);
968 gtk_text_set_line_wrap (GTK_TEXT (text), FALSE);
969 gtk_text_set_word_wrap (GTK_TEXT (text), FALSE);
970 gtk_text_insert (GTK_TEXT (text), g->font, NULL, NULL, helptext, -1);
971 gtk_container_add (GTK_CONTAINER (scroll), text);
972 close = gtk_button_new_with_label ("Close");
973 gtk_box_pack_start (GTK_BOX (box), close, FALSE, FALSE, 0);
974 gtk_signal_connect (GTK_OBJECT (close), "clicked",
975 (GtkSignalFunc )callback_close_help, toplevel);
977 gtk_widget_show_all (toplevel);
980 static void callback_close_help (GtkWidget *widget, gpointer data)
982 gtk_widget_destroy ((GtkWidget * )data);
985 static void callback_time_origin (GtkWidget *toggle, gpointer data)
987 toggle_time_origin ((struct graph * )data);
990 static void callback_seq_origin (GtkWidget *toggle, gpointer data)
992 toggle_seq_origin ((struct graph * )data);
995 static GtkWidget *control_panel_create_zoom_group (struct graph *g)
997 GtkWidget *zoom_in, *zoom_out, *zoom_box, *zoom_frame;
998 GtkAdjustment *zoom_h_adj, *zoom_v_adj;
999 GtkWidget *zoom_inout_box, *zoom_h_step_label, *zoom_h_step;
1000 GtkWidget *zoom_v_step_label, *zoom_v_step;
1001 GtkWidget *zoom_separator1, *zoom_separator2, *zoom_step_table, *zoom_table;
1002 GtkWidget *zoom_ratio_toggle, *zoom_same_toggle;
1003 GtkWidget *zoom_h_entry, *zoom_v_entry;
1004 GtkWidget *zoom_h_label, *zoom_v_label;
1006 zoom_in = gtk_radio_button_new_with_label (NULL, "in");
1007 zoom_out = gtk_radio_button_new_with_label (
1008 gtk_radio_button_group (GTK_RADIO_BUTTON (zoom_in)), "out");
1009 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (zoom_in), TRUE);
1010 zoom_inout_box = gtk_hbox_new (FALSE, 0);
1011 gtk_box_pack_start (GTK_BOX (zoom_inout_box), zoom_in, FALSE, FALSE, 10);
1012 gtk_box_pack_start (GTK_BOX (zoom_inout_box), zoom_out, FALSE, FALSE, 0);
1014 zoom_separator1 = gtk_hseparator_new ();
1016 zoom_h_entry = gtk_entry_new ();
1017 gtk_entry_set_text (GTK_ENTRY (zoom_h_entry), "1.000");
1018 gtk_editable_set_editable (GTK_EDITABLE (zoom_h_entry), FALSE);
1019 zoom_h_label = gtk_label_new ("Horizontal:");
1021 zoom_v_entry = gtk_entry_new ();
1022 gtk_entry_set_text (GTK_ENTRY (zoom_v_entry), "1.000");
1023 gtk_editable_set_editable (GTK_EDITABLE (zoom_v_entry), FALSE);
1024 zoom_v_label = gtk_label_new ("Vertical:");
1026 g->zoom.widget.h_zoom = (GtkEntry * )zoom_h_entry;
1027 g->zoom.widget.v_zoom = (GtkEntry * )zoom_v_entry;
1029 zoom_table = gtk_table_new (2, 2, FALSE);
1030 gtk_table_attach (GTK_TABLE (zoom_table), zoom_h_label, 0,1,0,1,
1031 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1032 gtk_table_attach (GTK_TABLE (zoom_table), zoom_h_entry, 1, 2, 0, 1,
1033 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1034 gtk_table_attach (GTK_TABLE (zoom_table), zoom_v_label, 0,1,1,2,
1035 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1036 gtk_table_attach (GTK_TABLE (zoom_table), zoom_v_entry, 1, 2, 1, 2,
1037 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1039 zoom_separator2 = gtk_hseparator_new ();
1041 zoom_h_adj = (GtkAdjustment * )gtk_adjustment_new (1.2, 1.0, 5, 0.1, 1, 0);
1042 zoom_h_step = gtk_spin_button_new (zoom_h_adj, 0, 1);
1043 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (zoom_h_step), TRUE);
1044 zoom_h_step_label = gtk_label_new ("Horizontal step:");
1046 zoom_v_adj = (GtkAdjustment * )gtk_adjustment_new (1.2, 1.0, 5, 0.1, 1, 0);
1047 zoom_v_step = gtk_spin_button_new (zoom_v_adj, 0, 1);
1048 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (zoom_v_step), TRUE);
1049 zoom_v_step_label = gtk_label_new ("Vertical step:");
1051 g->zoom.widget.h_step = (GtkSpinButton * )zoom_h_step;
1052 g->zoom.widget.v_step = (GtkSpinButton * )zoom_v_step;
1054 zoom_same_toggle = gtk_check_button_new_with_label ("Keep them the same");
1055 zoom_ratio_toggle = gtk_check_button_new_with_label("Preserve their ratio");
1056 gtk_object_set_data (GTK_OBJECT (zoom_same_toggle), "flag",
1057 (gpointer )ZOOM_STEPS_SAME);
1058 gtk_object_set_data (GTK_OBJECT (zoom_ratio_toggle), "flag",
1059 (gpointer )ZOOM_STEPS_KEEP_RATIO);
1060 gtk_signal_connect (GTK_OBJECT (zoom_same_toggle), "clicked",
1061 (GtkSignalFunc )callback_zoom_flags, g);
1062 gtk_signal_connect (GTK_OBJECT (zoom_ratio_toggle), "clicked",
1063 (GtkSignalFunc )callback_zoom_flags, g);
1065 zoom_step_table = gtk_table_new (4, 2, FALSE);
1066 gtk_table_attach (GTK_TABLE (zoom_step_table), zoom_h_step_label, 0,1,0,1,
1067 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1068 gtk_table_attach (GTK_TABLE (zoom_step_table), zoom_h_step, 1, 2, 0, 1,
1069 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1070 gtk_table_attach (GTK_TABLE (zoom_step_table), zoom_v_step_label, 0,1,1,2,
1071 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1072 gtk_table_attach (GTK_TABLE (zoom_step_table), zoom_v_step, 1, 2, 1, 2,
1073 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1074 gtk_table_attach (GTK_TABLE (zoom_step_table), zoom_same_toggle, 0,2,2,3,
1075 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1076 gtk_table_attach (GTK_TABLE (zoom_step_table), zoom_ratio_toggle, 0,2,3,4,
1077 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1079 zoom_box = gtk_vbox_new (FALSE, 0);
1080 gtk_box_pack_start (GTK_BOX (zoom_box), zoom_inout_box, TRUE, TRUE, 0);
1081 gtk_box_pack_start (GTK_BOX (zoom_box), zoom_separator1, TRUE, TRUE, 0);
1082 gtk_box_pack_start (GTK_BOX (zoom_box), zoom_table, TRUE, TRUE, 0);
1083 gtk_box_pack_start (GTK_BOX (zoom_box), zoom_separator2, TRUE, TRUE, 0);
1084 gtk_box_pack_start (GTK_BOX (zoom_box), zoom_step_table, TRUE, TRUE, 0);
1085 zoom_frame = gtk_frame_new ("Zoom");
1086 gtk_container_add (GTK_CONTAINER (zoom_frame), zoom_box);
1088 gtk_object_set_data (GTK_OBJECT (zoom_h_step), "direction", (gpointer )0);
1089 gtk_object_set_data (GTK_OBJECT (zoom_v_step), "direction", (gpointer )1);
1091 gtk_signal_connect (GTK_OBJECT (zoom_in), "toggled",
1092 (GtkSignalFunc )callback_zoom_inout, g);
1093 gtk_signal_connect (GTK_OBJECT (zoom_h_step), "changed",
1094 (GtkSignalFunc )callback_zoom_step, g);
1095 gtk_signal_connect (GTK_OBJECT (zoom_v_step), "changed",
1096 (GtkSignalFunc )callback_zoom_step, g);
1098 g->zoom.widget.in_toggle = (GtkToggleButton * )zoom_in;
1099 g->zoom.widget.out_toggle = (GtkToggleButton * )zoom_out;
1103 static void callback_zoom_inout (GtkWidget *toggle, gpointer data)
1105 struct graph *g = (struct graph * )data;
1107 if (GTK_TOGGLE_BUTTON (toggle)->active)
1108 g->zoom.flags &= ~ZOOM_OUT;
1110 g->zoom.flags |= ZOOM_OUT;
1113 static void callback_zoom_step (GtkWidget *spin, gpointer data)
1115 struct graph *g = (struct graph * )data;
1118 double *zoom_this, *zoom_other;
1119 GtkSpinButton *widget_this, *widget_other;
1122 direction = (int )gtk_object_get_data (GTK_OBJECT (spin), "direction");
1123 value = gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (spin));
1126 zoom_this = &g->zoom.step_y;
1127 zoom_other = &g->zoom.step_x;
1128 widget_this = g->zoom.widget.v_step;
1129 widget_other = g->zoom.widget.h_step;
1131 zoom_this = &g->zoom.step_x;
1132 zoom_other = &g->zoom.step_y;
1133 widget_this = g->zoom.widget.h_step;
1134 widget_other = g->zoom.widget.v_step;
1137 old_this = *zoom_this;
1139 if (g->zoom.flags & ZOOM_STEPS_SAME) {
1140 *zoom_other = value;
1141 gtk_spin_button_set_value (widget_other, *zoom_other);
1142 } else if (g->zoom.flags & ZOOM_STEPS_KEEP_RATIO) {
1143 double old_other = *zoom_other;
1144 *zoom_other *= value / old_this;
1145 if (*zoom_other < 1.0) {
1147 *zoom_this = old_this * 1.0 / old_other;
1148 gtk_spin_button_set_value (widget_this, *zoom_this);
1149 } else if (*zoom_other > 5.0) {
1151 *zoom_this = old_this * 5.0 / old_other;
1152 gtk_spin_button_set_value (widget_this, *zoom_this);
1154 gtk_spin_button_set_value (widget_other, *zoom_other);
1158 static void callback_zoom_flags (GtkWidget *toggle, gpointer data)
1160 struct graph *g = (struct graph * )data;
1161 int flag = (int )gtk_object_get_data (GTK_OBJECT (toggle), "flag");
1163 if (GTK_TOGGLE_BUTTON (toggle)->active)
1164 g->zoom.flags |= flag;
1166 g->zoom.flags &= ~flag;
1169 static void update_zoom_spins (struct graph *g)
1173 snprintf (s, 32, "%.3f", g->zoom.x / g->zoom.initial.x);
1174 gtk_entry_set_text (g->zoom.widget.h_zoom, s);
1175 snprintf (s, 32, "%.3f", g->zoom.y / g->zoom.initial.y);
1176 gtk_entry_set_text (g->zoom.widget.v_zoom, s);
1179 static GtkWidget *control_panel_create_magnify_group (struct graph *g)
1181 GtkWidget *mag_width_label, *mag_width;
1182 GtkWidget *mag_height_label, *mag_height;
1183 GtkWidget *mag_x_label, *mag_x;
1184 GtkWidget *mag_y_label, *mag_y;
1185 GtkWidget *mag_wh_table, *mag_zoom_frame, *mag_zoom_table;
1186 GtkWidget *mag_h_zoom_label, *mag_h_zoom;
1187 GtkWidget *mag_v_zoom_label, *mag_v_zoom;
1188 GtkWidget *mag_zoom_same, *mag_zoom_ratio;
1189 GtkAdjustment *mag_width_adj, *mag_height_adj, *mag_x_adj, *mag_y_adj;
1190 GtkAdjustment *mag_h_zoom_adj, *mag_v_zoom_adj;
1191 GtkWidget *mag_box, *mag_frame;
1193 mag_width_label = gtk_label_new ("Width:");
1194 mag_width_adj = (GtkAdjustment * )gtk_adjustment_new (250,100,600,1,10,0);
1195 mag_width = gtk_spin_button_new (mag_width_adj, 0, 0);
1197 mag_height_label = gtk_label_new ("Height:");
1198 mag_height_adj = (GtkAdjustment * )gtk_adjustment_new (250,100,600,1,10,0);
1199 mag_height = gtk_spin_button_new (mag_height_adj, 0, 0);
1201 mag_x_label = gtk_label_new ("X:");
1202 mag_x_adj = (GtkAdjustment * )gtk_adjustment_new (0,-1000,1000,1,10,0);
1203 mag_x = gtk_spin_button_new (mag_x_adj, 0, 0);
1205 mag_y_label = gtk_label_new ("Y:");
1206 mag_y_adj = (GtkAdjustment * )gtk_adjustment_new (0,-1000,1000,1,10,0);
1207 mag_y = gtk_spin_button_new (mag_y_adj, 0, 0);
1209 mag_wh_table = gtk_table_new (4, 2, FALSE);
1210 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_width_label, 0,1,0,1,
1211 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1212 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_width, 1,2,0,1,
1213 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1214 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_height_label, 0,1,1,2,
1215 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1216 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_height, 1,2,1,2,
1217 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1218 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_x_label, 0,1,2,3,
1219 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1220 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_x, 1,2,2,3,
1221 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1222 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_y_label, 0,1,3,4,
1223 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1224 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_y, 1,2,3,4,
1225 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1227 mag_h_zoom_label = gtk_label_new ("Horizontal:");
1228 mag_h_zoom_adj = (GtkAdjustment *)gtk_adjustment_new(10.0,1.0,25.0,0.1,1,0);
1229 mag_h_zoom = gtk_spin_button_new (mag_h_zoom_adj, 0, 1);
1231 mag_v_zoom_label = gtk_label_new ("Vertical:");
1232 mag_v_zoom_adj = (GtkAdjustment *)gtk_adjustment_new(10.0,1.0,25.0,0.1,1,0);
1233 mag_v_zoom = gtk_spin_button_new (mag_v_zoom_adj, 0, 1);
1235 mag_zoom_same = gtk_check_button_new_with_label ("Keep them the same");
1236 mag_zoom_ratio = gtk_check_button_new_with_label("Preserve their ratio");
1238 mag_zoom_table = gtk_table_new (4, 2, FALSE);
1239 gtk_table_attach (GTK_TABLE (mag_zoom_table), mag_h_zoom_label, 0,1,0,1,
1240 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
1241 gtk_table_attach (GTK_TABLE (mag_zoom_table), mag_h_zoom, 1,2,0,1,
1242 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
1243 gtk_table_attach (GTK_TABLE (mag_zoom_table), mag_v_zoom_label, 0,1,1,2,
1244 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
1245 gtk_table_attach (GTK_TABLE (mag_zoom_table), mag_v_zoom, 1,2,1,2,
1246 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
1247 gtk_table_attach (GTK_TABLE (mag_zoom_table), mag_zoom_same, 0,2,2,3,
1248 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
1249 gtk_table_attach (GTK_TABLE (mag_zoom_table), mag_zoom_ratio, 0,2,3,4,
1250 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
1252 mag_zoom_frame = gtk_frame_new ("Magnify zoom");
1253 gtk_container_add (GTK_CONTAINER (mag_zoom_frame), mag_zoom_table);
1254 gtk_container_set_border_width (GTK_CONTAINER (mag_zoom_frame), 3);
1256 mag_box = gtk_vbox_new (FALSE, 0);
1257 gtk_box_pack_start (GTK_BOX (mag_box), mag_wh_table, TRUE, TRUE, 0);
1258 gtk_box_pack_start (GTK_BOX (mag_box), mag_zoom_frame, TRUE, TRUE, 0);
1259 mag_frame = gtk_frame_new ("Magnify");
1260 gtk_container_add (GTK_CONTAINER (mag_frame), mag_box);
1262 g->magnify.widget.h_zoom = (GtkSpinButton * )mag_h_zoom;
1263 g->magnify.widget.v_zoom = (GtkSpinButton * )mag_v_zoom;
1264 gtk_object_set_data (GTK_OBJECT (mag_h_zoom), "direction", (gpointer )0);
1265 gtk_object_set_data (GTK_OBJECT (mag_v_zoom), "direction", (gpointer )1);
1266 gtk_object_set_data (GTK_OBJECT (mag_zoom_same), "flag",
1267 (gpointer )MAGZOOMS_SAME);
1268 gtk_object_set_data (GTK_OBJECT (mag_zoom_ratio), "flag",
1269 (gpointer )MAGZOOMS_SAME_RATIO);
1271 gtk_signal_connect (GTK_OBJECT (mag_width), "changed",
1272 (GtkSignalFunc )callback_mag_width, g);
1273 gtk_signal_connect (GTK_OBJECT (mag_height), "changed",
1274 (GtkSignalFunc )callback_mag_height, g);
1275 gtk_signal_connect (GTK_OBJECT (mag_x), "changed",
1276 (GtkSignalFunc )callback_mag_x, g);
1277 gtk_signal_connect (GTK_OBJECT (mag_y), "changed",
1278 (GtkSignalFunc )callback_mag_y, g);
1279 gtk_signal_connect (GTK_OBJECT (mag_h_zoom), "changed",
1280 (GtkSignalFunc )callback_mag_zoom, g);
1281 gtk_signal_connect (GTK_OBJECT (mag_v_zoom), "changed",
1282 (GtkSignalFunc )callback_mag_zoom, g);
1283 gtk_signal_connect (GTK_OBJECT (mag_zoom_same), "clicked",
1284 (GtkSignalFunc )callback_mag_flags, g);
1285 gtk_signal_connect (GTK_OBJECT (mag_zoom_ratio), "clicked",
1286 (GtkSignalFunc )callback_mag_flags, g);
1291 static void callback_mag_width (GtkWidget *spin, gpointer data)
1293 struct graph *g = (struct graph * )data;
1295 g->magnify.width = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(spin));
1298 static void callback_mag_height (GtkWidget *spin, gpointer data)
1300 struct graph *g = (struct graph * )data;
1302 g->magnify.height = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
1305 static void callback_mag_x (GtkWidget *spin, gpointer data)
1307 struct graph *g = (struct graph * )data;
1309 g->magnify.offset.x=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
1312 static void callback_mag_y (GtkWidget *spin, gpointer data)
1314 struct graph *g = (struct graph * )data;
1316 g->magnify.offset.y=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
1319 static void callback_mag_zoom (GtkWidget *spin, gpointer data)
1321 struct graph *g = (struct graph * )data;
1324 double *zoom_this, *zoom_other;
1325 GtkSpinButton *widget_this, *widget_other;
1328 if (g->magnify.flags & MAGZOOMS_IGNORE) {
1329 printf ("refusing callback for %s zoom widget.\n", (GtkSpinButton * )spin==g->magnify.widget.h_zoom ? "horizontal" : "vertical");
1330 g->magnify.flags &= ~MAGZOOMS_IGNORE;
1333 direction = (int )gtk_object_get_data (GTK_OBJECT (spin), "direction");
1334 value = gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (spin));
1337 zoom_this = &g->magnify.zoom.y;
1338 zoom_other = &g->magnify.zoom.x;
1339 widget_this = g->magnify.widget.v_zoom;
1340 widget_other = g->magnify.widget.h_zoom;
1342 zoom_this = &g->magnify.zoom.x;
1343 zoom_other = &g->magnify.zoom.y;
1344 widget_this = g->magnify.widget.h_zoom;
1345 widget_other = g->magnify.widget.v_zoom;
1348 old_this = *zoom_this;
1350 if (g->magnify.flags & MAGZOOMS_SAME) {
1351 *zoom_other = value;
1352 /* g->magnify.flags |= MAGZOOMS_IGNORE; */
1353 gtk_spin_button_set_value (widget_other, *zoom_other);
1354 } else if (g->magnify.flags & MAGZOOMS_SAME_RATIO) {
1355 double old_other = *zoom_other;
1356 *zoom_other *= value / old_this;
1357 if (*zoom_other < 1.0) {
1359 *zoom_this = old_this * 1.0 / old_other;
1360 /* g->magnify.flags |= MAGZOOMS_IGNORE; */
1361 gtk_spin_button_set_value (widget_this, *zoom_this);
1362 } else if (*zoom_other > 25.0) {
1364 *zoom_this = old_this * 25.0 / old_other;
1365 /* g->magnify.flags |= MAGZOOMS_IGNORE; */
1366 gtk_spin_button_set_value (widget_this, *zoom_this);
1368 /* g->magnify.flags |= MAGZOOMS_IGNORE; */
1369 gtk_spin_button_set_value (widget_other, *zoom_other);
1373 static void callback_mag_flags (GtkWidget *toggle, gpointer data)
1375 struct graph *g = (struct graph * )data;
1376 int flag = (int )gtk_object_get_data (GTK_OBJECT (toggle), "flag");
1378 if (GTK_TOGGLE_BUTTON (toggle)->active)
1379 g->magnify.flags |= flag;
1381 g->magnify.flags &= ~flag;
1384 static GtkWidget *control_panel_create_zoomlock_group (struct graph *g)
1386 GtkWidget *zoom_lock_h, *zoom_lock_v, *zoom_lock_none, *zoom_lock_box;
1387 GtkWidget *zoom_lock_frame;
1389 zoom_lock_none = gtk_radio_button_new_with_label (NULL, "none");
1390 zoom_lock_h = gtk_radio_button_new_with_label (
1391 gtk_radio_button_group (GTK_RADIO_BUTTON (zoom_lock_none)),
1393 zoom_lock_v = gtk_radio_button_new_with_label (
1394 gtk_radio_button_group (GTK_RADIO_BUTTON (zoom_lock_none)),
1396 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (zoom_lock_none), TRUE);
1397 zoom_lock_box = gtk_hbox_new (FALSE, 0);
1398 gtk_box_pack_start (GTK_BOX (zoom_lock_box), zoom_lock_none, TRUE, TRUE, 0);
1399 gtk_box_pack_start (GTK_BOX (zoom_lock_box), zoom_lock_h, TRUE, TRUE, 0);
1400 gtk_box_pack_start (GTK_BOX (zoom_lock_box), zoom_lock_v, TRUE, TRUE, 0);
1401 zoom_lock_frame = gtk_frame_new ("Zoom lock:");
1402 gtk_container_add (GTK_CONTAINER (zoom_lock_frame), zoom_lock_box);
1404 gtk_signal_connect (GTK_OBJECT (zoom_lock_h), "toggled",
1405 (GtkSignalFunc )callback_zoomlock_h, g);
1406 gtk_signal_connect (GTK_OBJECT (zoom_lock_v), "toggled",
1407 (GtkSignalFunc )callback_zoomlock_v, g);
1409 return zoom_lock_frame;
1412 static void callback_zoomlock_h (GtkWidget *toggle, gpointer data)
1414 struct graph *g = (struct graph * )data;
1416 if (GTK_TOGGLE_BUTTON (toggle)->active)
1417 g->zoom.flags |= ZOOM_HLOCK;
1419 g->zoom.flags &= ~ZOOM_HLOCK;
1422 static void callback_zoomlock_v (GtkWidget *toggle, gpointer data)
1424 struct graph *g = (struct graph * )data;
1426 if (GTK_TOGGLE_BUTTON (toggle)->active)
1427 g->zoom.flags |= ZOOM_VLOCK;
1429 g->zoom.flags &= ~ZOOM_VLOCK;
1432 static GtkWidget *control_panel_create_cross_group (struct graph *g)
1434 GtkWidget *on, *off, *box, *frame, *vbox, *label;
1436 label = gtk_label_new ("Crosshairs:");
1437 off = gtk_radio_button_new_with_label (NULL, "off");
1438 on = gtk_radio_button_new_with_label (
1439 gtk_radio_button_group (GTK_RADIO_BUTTON (off)), "on");
1440 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (off), TRUE);
1441 box = gtk_hbox_new (FALSE, 0);
1442 gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 10);
1443 gtk_box_pack_start (GTK_BOX (box), off, FALSE, FALSE, 10);
1444 gtk_box_pack_start (GTK_BOX (box), on, FALSE, FALSE, 0);
1445 vbox = gtk_vbox_new (FALSE, 0);
1446 gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, FALSE, 15);
1447 /* frame = gtk_frame_new ("Cross:"); */
1448 frame = gtk_frame_new (NULL);
1449 gtk_container_add (GTK_CONTAINER (frame), vbox);
1451 gtk_signal_connect (GTK_OBJECT (on), "toggled",
1452 (GtkSignalFunc )callback_cross_on_off, g);
1454 g->cross.on_toggle = (GtkToggleButton * )on;
1455 g->cross.off_toggle = (GtkToggleButton * )off;
1460 static void callback_cross_on_off (GtkWidget *toggle, gpointer data)
1462 struct graph *g = (struct graph * )data;
1464 if (GTK_TOGGLE_BUTTON (toggle)->active) {
1466 g->cross.draw = TRUE;
1467 gdk_window_get_pointer (g->drawing_area->window, &x, &y, 0);
1468 cross_draw (g, x, y);
1470 g->cross.draw = FALSE;
1475 static GtkWidget *control_panel_create_graph_type_group (struct graph *g)
1477 GtkWidget *graph_tseqttrace, *graph_tseqstevens;
1478 GtkWidget *graph_tput, *graph_rtt, *graph_sep, *graph_init, *graph_box;
1479 GtkWidget *graph_frame;
1481 graph_tput = gtk_radio_button_new_with_label (NULL, "Throughput");
1482 graph_tseqttrace = gtk_radio_button_new_with_label (
1483 gtk_radio_button_group (GTK_RADIO_BUTTON (graph_tput)),
1484 "Time/Sequence (tcptrace-style)");
1485 graph_tseqstevens = gtk_radio_button_new_with_label (
1486 gtk_radio_button_group (GTK_RADIO_BUTTON (graph_tput)),
1487 "Time/Sequence (Stevens'-style)");
1488 graph_rtt = gtk_radio_button_new_with_label (
1489 gtk_radio_button_group (GTK_RADIO_BUTTON (graph_tput)),
1492 case GRAPH_TSEQ_STEVENS:
1493 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(graph_tseqstevens),TRUE);
1495 case GRAPH_TSEQ_TCPTRACE:
1496 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(graph_tseqttrace),TRUE);
1498 case GRAPH_THROUGHPUT:
1499 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (graph_tput), TRUE);
1502 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (graph_rtt), TRUE);
1505 graph_init = gtk_check_button_new_with_label ("Init on change");
1506 graph_sep = gtk_hseparator_new ();
1507 graph_box = gtk_vbox_new (FALSE, 0);
1508 gtk_box_pack_start (GTK_BOX (graph_box), graph_tseqttrace, TRUE, TRUE, 0);
1509 gtk_box_pack_start (GTK_BOX (graph_box), graph_tseqstevens, TRUE, TRUE, 0);
1510 gtk_box_pack_start (GTK_BOX (graph_box), graph_tput, TRUE, TRUE, 0);
1511 gtk_box_pack_start (GTK_BOX (graph_box), graph_rtt, TRUE, TRUE, 0);
1512 gtk_box_pack_start (GTK_BOX (graph_box), graph_sep, TRUE, TRUE, 0);
1513 gtk_box_pack_start (GTK_BOX (graph_box), graph_init, TRUE, TRUE, 0);
1514 graph_frame = gtk_frame_new ("Graph type:");
1515 gtk_container_add (GTK_CONTAINER (graph_frame), graph_box);
1517 gtk_object_set_data (GTK_OBJECT (graph_tseqstevens), "new-graph-type",
1519 gtk_object_set_data (GTK_OBJECT (graph_tseqttrace), "new-graph-type",
1521 gtk_object_set_data (GTK_OBJECT (graph_tput), "new-graph-type",
1523 gtk_object_set_data (GTK_OBJECT (graph_rtt), "new-graph-type",
1526 gtk_signal_connect (GTK_OBJECT (graph_tseqttrace), "toggled",
1527 (GtkSignalFunc )callback_graph_type, g);
1528 gtk_signal_connect (GTK_OBJECT (graph_tseqstevens), "toggled",
1529 (GtkSignalFunc )callback_graph_type, g);
1530 gtk_signal_connect (GTK_OBJECT (graph_tput), "toggled",
1531 (GtkSignalFunc )callback_graph_type, g);
1532 gtk_signal_connect (GTK_OBJECT (graph_rtt), "toggled",
1533 (GtkSignalFunc )callback_graph_type, g);
1534 gtk_signal_connect (GTK_OBJECT (graph_init), "toggled",
1535 (GtkSignalFunc )callback_graph_init_on_typechg, g);
1540 static void callback_graph_type (GtkWidget *toggle, gpointer data)
1542 int old_type, new_type;
1543 struct graph *g = (struct graph * )data;
1545 new_type = (int )gtk_object_get_data (GTK_OBJECT (toggle),"new-graph-type");
1547 if (!GTK_TOGGLE_BUTTON (toggle)->active)
1553 graph_element_lists_free (g);
1554 graph_element_lists_initialize (g);
1556 if (old_type == GRAPH_THROUGHPUT || new_type == GRAPH_THROUGHPUT) {
1557 /* throughput graph uses differently constructed segment list so we
1558 * need to recreate it */
1559 graph_segment_list_free (g);
1560 graph_segment_list_get (g);
1563 if (g->flags & GRAPH_INIT_ON_TYPE_CHANGE) {
1564 g->geom.width = g->wp.width;
1565 g->geom.height = g->wp.height;
1566 g->geom.x = g->wp.x;
1567 g->geom.y = g->wp.y;
1569 g->x_axis->min = g->y_axis->min = 0;
1570 gtk_toggle_button_set_active (g->gui.time_orig_conn, TRUE);
1571 gtk_toggle_button_set_active (g->gui.seq_orig_isn, TRUE);
1572 graph_init_sequence (g);
1575 static void callback_graph_init_on_typechg (GtkWidget *toggle, gpointer data)
1577 ((struct graph * )data)->flags ^= GRAPH_INIT_ON_TYPE_CHANGE;
1580 static struct graph *graph_new (void)
1584 g = (struct graph * )calloc (1, sizeof (struct graph));
1585 graph_element_lists_initialize (g);
1587 g->x_axis = (struct axis * )calloc (1, sizeof (struct axis));
1588 g->y_axis = (struct axis * )calloc (1, sizeof (struct axis));
1590 g->x_axis->flags = 0;
1591 g->x_axis->flags |= AXIS_ORIENTATION;
1592 g->x_axis->s.x = g->x_axis->s.y = 0;
1593 g->x_axis->s.height = HAXIS_INIT_HEIGHT;
1594 g->x_axis->p.x = VAXIS_INIT_WIDTH;
1595 g->x_axis->p.height = HAXIS_INIT_HEIGHT;
1597 g->y_axis->flags = 0;
1598 g->y_axis->flags &= ~AXIS_ORIENTATION;
1599 g->y_axis->p.x = g->y_axis->p.y = 0;
1600 g->y_axis->p.width = VAXIS_INIT_WIDTH;
1602 g->y_axis->s.y = TITLEBAR_HEIGHT;
1603 g->y_axis->s.width = VAXIS_INIT_WIDTH;
1608 static void graph_initialize_values (struct graph *g)
1610 g->geom.width = g->wp.width = 750;
1611 g->geom.height = g->wp.height = 550;
1612 g->geom.x = g->wp.x = VAXIS_INIT_WIDTH;
1613 g->geom.y = g->wp.y = TITLEBAR_HEIGHT;
1615 /* g->zoom.x = g->zoom.y = 1.0; */
1616 g->zoom.step_x = g->zoom.step_y = 1.2;
1618 g->cross.draw = g->cross.erase_needed = 0;
1619 g->grab.grabbed = 0;
1620 g->magnify.active = 0;
1621 g->magnify.offset.x = g->magnify.offset.y = 0;
1622 g->magnify.width = g->magnify.height = 250;
1623 g->magnify.zoom.x = g->magnify.zoom.y = 10.0;
1624 g->magnify.flags = 0;
1627 static void graph_put (struct graph *graph)
1631 for (g=graphs; g->next; g=g->next);
1637 static void graph_init_sequence (struct graph *g)
1639 debug(DBS_FENTRY) puts ("graph_init_sequence()");
1641 graph_type_dependent_initialize (g);
1642 g->zoom.initial.x = g->zoom.x;
1643 g->zoom.initial.y = g->zoom.y;
1644 graph_element_lists_make (g);
1645 g->x_axis->s.width = g->wp.width;
1646 g->x_axis->p.width = g->x_axis->s.width + RMARGIN_WIDTH;
1647 g->x_axis->p.y = TITLEBAR_HEIGHT + g->wp.height;
1648 g->x_axis->s.height = g->x_axis->p.height = HAXIS_INIT_HEIGHT;
1649 g->y_axis->s.height = g->wp.height;
1650 g->y_axis->p.height = g->wp.height + TITLEBAR_HEIGHT;
1651 graph_pixmaps_create (g);
1652 axis_pixmaps_create (g->y_axis);
1653 axis_pixmaps_create (g->x_axis);
1654 graph_title_pixmap_create (g);
1655 graph_title_pixmap_draw (g);
1656 graph_title_pixmap_display (g);
1658 axis_display (g->y_axis);
1659 axis_display (g->x_axis);
1662 static void graph_type_dependent_initialize (struct graph *g)
1665 case GRAPH_TSEQ_STEVENS:
1666 case GRAPH_TSEQ_TCPTRACE:
1667 tseq_stevens_initialize (g);
1669 case GRAPH_THROUGHPUT:
1670 tput_initialize (g);
1680 static void graph_destroy (struct graph *g)
1683 struct graph *p=NULL;
1684 /* struct graph *tmp; */
1686 debug(DBS_FENTRY) puts ("graph_destroy()");
1688 for (gtmp=graphs; gtmp; p=gtmp, gtmp=gtmp->next)
1692 axis_destroy (g->x_axis);
1693 axis_destroy (g->y_axis);
1694 /* gtk_widget_destroy (g->drawing_area); */
1695 gtk_widget_destroy (g->gui.control_panel);
1696 gtk_widget_destroy (g->toplevel);
1697 /* gtk_widget_destroy (g->text); */
1698 gdk_gc_unref (g->fg_gc);
1699 gdk_gc_unref (g->bg_gc);
1700 gdk_font_unref (g->font);
1701 gdk_pixmap_unref (g->pixmap[0]);
1702 gdk_pixmap_unref (g->pixmap[1]);
1706 graph_segment_list_free (g);
1707 graph_element_lists_free (g);
1709 for (tmp=graphs; tmp; tmp=tmp->next)
1710 printf ("%p next: %p\n", tmp, tmp->next);
1711 printf ("p=%p, g=%p, p->next=%p, g->next=%p\n",
1712 p, g, p ? p->next : NULL, g->next);
1720 for (tmp=graphs; tmp; tmp=tmp->next)
1721 printf ("%p next: %p\n", tmp, tmp->next);
1725 /* here we collect all the external data we will ever need */
1726 static void graph_segment_list_get (struct graph *g)
1730 struct segment *segment=NULL, *last=NULL;
1731 struct segment current;
1734 debug(DBS_FENTRY) puts ("graph_segment_list_get()");
1735 get_headers (cfile.current_frame, cfile.pd, ¤t);
1736 if (g->type == GRAPH_THROUGHPUT)
1737 condition = COMPARE_CURR_DIR;
1739 condition = COMPARE_ANY_DIR;
1741 for (ptr=cfile.plist; ptr; ptr=ptr->next) {
1742 wtap_seek_read (cfile.wth, ptr->file_off, &cfile.pseudo_header,
1745 segment = (struct segment * )malloc (sizeof (struct segment));
1747 perror ("malloc failed");
1748 if (!get_headers (ptr, pd, segment))
1749 continue; /* not TCP over IP over Ethernet II */
1750 if (compare_headers (¤t, segment, condition)) {
1751 segment->next = NULL;
1752 segment->num = ptr->num;
1753 segment->rel_secs = ptr->rel_secs;
1754 segment->rel_usecs = ptr->rel_usecs;
1755 segment->abs_secs = ptr->abs_secs;
1756 segment->abs_usecs = ptr->abs_usecs;
1757 segment->data = ntohs (segment->iphdr.tot_len) -
1758 4*IHL(&(segment->iphdr)) - 4*DOFF(segment->tcphdr);
1760 last->next = segment;
1762 g->segments = segment;
1765 if (ptr==cfile.current_frame)
1766 g->current = segment;
1772 static int get_headers (frame_data *fd, char *pd, struct segment *hdrs)
1774 struct ether_header *e;
1775 struct ppp_header *p;
1780 * XXX - on Alpha, even fetching one-byte fields from structures
1781 * pointed to by unaligned pointers may be risky, as, unless
1782 * the BWX instructions are being used, a one-byte load is done
1783 * by loading the word containing the byte and then extracting
1786 * This means that the references to "p->ppp_type" and
1787 * "((struct iphdr *)ip)->protocol" may turn into a load of
1788 * an unaligned word.
1790 switch (fd->lnk_t) {
1792 case WTAP_ENCAP_ETHERNET:
1794 e = (struct ether_header *)pd;
1795 if (pntohs (&e->ether_type) != ETHERTYPE_IP)
1796 return FALSE; /* not IP */
1800 case WTAP_ENCAP_PPP:
1802 p = (struct ppp_header *)pd;
1803 if (p->ppp_type != PPPTYPE_IP)
1804 return FALSE; /* not IP */
1808 case WTAP_ENCAP_RAW_IP:
1814 /* Those are the only encapsulation types we handle */
1817 if (((struct iphdr *)ip)->protocol != IPPROTO_TCP) {
1818 /* printf ("transport protocol not TCP: %#1x\n", ip->protocol); */
1821 tcp = (struct tcphdr * )(ip + 4*IHL((struct iphdr *)ip));
1823 memcpy(&hdrs->iphdr, ip, sizeof (struct iphdr));
1824 memcpy(&hdrs->tcphdr, tcp, sizeof (struct tcphdr));
1828 static int compare_headers (struct segment *h1, struct segment *h2, int dir)
1830 if (dir == COMPARE_CURR_DIR)
1831 return h1->iphdr.saddr == h2->iphdr.saddr &&
1832 h1->iphdr.daddr == h2->iphdr.daddr &&
1833 h1->tcphdr.source == h2->tcphdr.source &&
1834 h1->tcphdr.dest == h2->tcphdr.dest;
1836 return (h1->iphdr.saddr == h2->iphdr.saddr &&
1837 h1->iphdr.daddr == h2->iphdr.daddr &&
1838 h1->tcphdr.source == h2->tcphdr.source &&
1839 h1->tcphdr.dest == h2->tcphdr.dest) ||
1840 (h1->iphdr.saddr == h2->iphdr.daddr &&
1841 h1->iphdr.daddr == h2->iphdr.saddr &&
1842 h1->tcphdr.source == h2->tcphdr.dest &&
1843 h1->tcphdr.dest == h2->tcphdr.source);
1846 static void graph_segment_list_free (struct graph *g)
1848 struct segment *segment;
1850 while (g->segments) {
1851 segment = g->segments->next;
1853 g->segments = segment;
1858 static void graph_element_lists_initialize (struct graph *g)
1860 g->elists = (struct element_list *)calloc (1, sizeof (struct element_list));
1863 static void graph_element_lists_make (struct graph *g)
1865 debug(DBS_FENTRY) puts ("graph_element_lists_make()");
1868 case GRAPH_TSEQ_STEVENS:
1869 tseq_stevens_make_elmtlist (g);
1871 case GRAPH_TSEQ_TCPTRACE:
1872 tseq_tcptrace_make_elmtlist (g);
1874 case GRAPH_THROUGHPUT:
1875 tput_make_elmtlist (g);
1878 rtt_make_elmtlist (g);
1881 printf ("graph_element_lists_make: unknown graph type: %d\n", g->type);
1886 static void graph_element_lists_free (struct graph *g)
1888 struct element_list *list, *next_list;
1891 for (list=g->elists; list; list=list->next)
1892 free (list->elements);
1893 while (g->elists->next) {
1894 list = g->elists->next->next;
1895 free (g->elists->next);
1896 g->elists->next = list;
1900 for (list=g->elists; list; list=next_list) {
1901 free (list->elements);
1902 next_list = list->next;
1905 g->elists = NULL; /* just to make debugging easier */
1908 static void graph_title_pixmap_create (struct graph *g)
1910 if (g->title_pixmap)
1911 gdk_pixmap_unref (g->title_pixmap);
1913 g->title_pixmap = gdk_pixmap_new (g->drawing_area->window,
1914 g->x_axis->p.width, g->wp.y, -1);
1917 static void graph_title_pixmap_draw (struct graph *g)
1921 gdk_draw_rectangle (g->title_pixmap, g->bg_gc, TRUE, 0, 0,
1922 g->x_axis->p.width, g->wp.y);
1923 for (i=0; g->title[i]; i++) {
1925 w = gdk_string_width (g->font, g->title[i]);
1926 h = gdk_string_height (g->font, g->title[i]);
1927 gdk_draw_string (g->title_pixmap, g->font, g->fg_gc,
1928 g->wp.width/2 - w/2, 20+h + i*(h+3), g->title[i]);
1932 static void graph_title_pixmap_display (struct graph *g)
1934 gdk_draw_pixmap (g->drawing_area->window, g->fg_gc, g->title_pixmap,
1935 0, 0, g->wp.x, 0, g->x_axis->p.width, g->wp.y);
1938 static void graph_pixmaps_create (struct graph *g)
1940 debug(DBS_FENTRY) puts ("graph_pixmaps_create()");
1943 gdk_pixmap_unref (g->pixmap[0]);
1945 gdk_pixmap_unref (g->pixmap[1]);
1947 g->pixmap[0] = gdk_pixmap_new (g->drawing_area->window,
1948 g->wp.width, g->wp.height, -1);
1949 g->pixmap[1] = gdk_pixmap_new (g->drawing_area->window,
1950 g->wp.width, g->wp.height, -1);
1955 static void graph_display (struct graph *g)
1957 graph_pixmap_draw (g);
1958 graph_pixmaps_switch (g);
1959 graph_pixmap_display (g);
1962 static void graph_pixmap_display (struct graph *g)
1964 gdk_draw_pixmap (g->drawing_area->window, g->fg_gc,
1965 g->pixmap[g->displayed], 0, 0, g->wp.x, g->wp.y,
1966 g->wp.width, g->wp.height);
1969 static void graph_pixmaps_switch (struct graph *g)
1971 g->displayed = 1 ^ g->displayed;
1974 static void graph_pixmap_draw (struct graph *g)
1976 struct element_list *list;
1980 debug(DBS_FENTRY) puts ("graph_display()");
1981 not_disp = 1 ^ g->displayed;
1983 gdk_draw_rectangle (g->pixmap[not_disp], g->bg_gc, TRUE,
1984 0, 0, g->wp.width, g->wp.height);
1986 for (list=g->elists; list; list=list->next)
1987 for (e=list->elements; e->type != ELMT_NONE; e++) {
1992 draw_element_line (g, e);
1995 draw_element_arc (g, e);
2003 static void draw_element_line (struct graph *g, struct element *e)
2007 debug(DBS_GRAPH_DRAWING) printf ("line element: (%.2f,%.2f)->(%.2f,%.2f), "
2008 "seg %d ... ", e->p.line.dim.x1, e->p.line.dim.y1,
2009 e->p.line.dim.x2, e->p.line.dim.y2, e->parent->num);
2010 x1 = (int )rint (e->p.line.dim.x1 + g->geom.x - g->wp.x);
2011 x2 = (int )rint (e->p.line.dim.x2 + g->geom.x - g->wp.x);
2012 y1 = (int )rint ((g->geom.height-1-e->p.line.dim.y1) + g->geom.y-g->wp.y);
2013 y2 = (int )rint ((g->geom.height-1-e->p.line.dim.y2) + g->geom.y-g->wp.y);
2024 if ((x1<0 && x2<0) || (x1>=g->wp.width && x2>=g->wp.width) ||
2025 (y1<0 && y2<0) || (y1>=g->wp.height && y2>=g->wp.height)) {
2026 debug(DBS_GRAPH_DRAWING) printf (" refusing: (%d,%d)->(%d,%d)\n",
2030 if (x2 > g->wp.width-1)
2034 if (y2 > g->wp.height-1)
2035 y2 = g->wp.height-1;
2038 debug(DBS_GRAPH_DRAWING) printf ("line: (%d,%d)->(%d,%d)\n", x1, y1, x2,y2);
2039 gdk_draw_line (g->pixmap[1^g->displayed], e->gc, x1, y1, x2, y2);
2042 static void draw_element_arc (struct graph *g, struct element *e)
2046 x1 = (int )rint (e->p.arc.dim.x + g->geom.x - g->wp.x);
2047 x2 = e->p.arc.dim.width;
2048 y1 = (int )rint (g->geom.height-1 - e->p.arc.dim.y + g->geom.y - g->wp.y);
2049 y2 = e->p.arc.dim.height;
2050 if (x1<-x2 || x1>=g->wp.width || y1<-y2 || y1>=g->wp.height)
2052 debug(DBS_GRAPH_DRAWING) printf ("arc: (%d,%d)->(%d,%d)\n", x1, y1, x2, y2);
2053 gdk_draw_arc (g->pixmap[1^g->displayed], e->gc, e->p.arc.filled, x1,
2054 y1, x2, y2, e->p.arc.angle1, e->p.arc.angle2);
2057 static void axis_pixmaps_create (struct axis *axis)
2059 debug(DBS_FENTRY) puts ("axis_pixmaps_create()");
2060 if (axis->pixmap[0])
2061 gdk_pixmap_unref (axis->pixmap[0]);
2062 if (axis->pixmap[1])
2063 gdk_pixmap_unref (axis->pixmap[1]);
2065 axis->pixmap[0] = gdk_pixmap_new (axis->drawing_area->window,
2066 axis->p.width, axis->p.height, -1);
2067 axis->pixmap[1] = gdk_pixmap_new (axis->drawing_area->window,
2068 axis->p.width, axis->p.height, -1);
2070 axis->displayed = 0;
2073 static void axis_destroy (struct axis *axis)
2075 gdk_pixmap_unref (axis->pixmap[0]);
2076 gdk_pixmap_unref (axis->pixmap[1]);
2080 static void axis_display (struct axis *axis)
2082 if (axis->flags & AXIS_ORIENTATION)
2083 h_axis_pixmap_draw (axis);
2085 v_axis_pixmap_draw (axis);
2086 axis_pixmaps_switch (axis);
2087 axis_pixmap_display (axis);
2090 static void v_axis_pixmap_draw (struct axis *axis)
2092 struct graph *g = axis->g;
2095 int not_disp, rdigits, offset, imin, imax;
2096 double bottom, top, j, fl, corr;
2098 debug(DBS_FENTRY) puts ("v_axis_pixmap_draw()");
2099 bottom = (g->geom.height - (g->wp.height + g->wp.y + (-g->geom.y))) /
2100 (double )g->geom.height * g->bounds.height;
2101 bottom += axis->min;
2102 top = (g->geom.height - (g->wp.y + (-g->geom.y))) /
2103 (double )g->geom.height * g->bounds.height;
2105 axis_compute_ticks (axis, bottom, top, AXIS_VERTICAL);
2107 j = axis->major - floor (axis->major);
2108 for (rdigits=0; rdigits<=6; rdigits++) {
2115 not_disp = 1 ^ axis->displayed;
2116 gdk_draw_rectangle (axis->pixmap[not_disp], g->bg_gc, TRUE, 0, 0,
2117 axis->p.width, axis->p.height);
2119 gdk_draw_line (axis->pixmap[not_disp], g->fg_gc, axis->p.width - 1,
2120 (axis->p.height-axis->s.height)/2.0, axis->s.width - 1,
2123 offset = g->wp.y + (-g->geom.y);
2124 fl = floor (axis->min / axis->major) * axis->major;
2125 corr = rint ((axis->min - fl) * g->zoom.y);
2128 major_tick = axis->major * g->zoom.y;
2129 imin = (g->geom.height - offset + corr - g->wp.height) / major_tick + 1;
2130 imax = (g->geom.height - offset + corr) / major_tick;
2131 for (i=imin; i <= imax; i++) {
2134 int y = g->geom.height-1 - (int )rint (i * major_tick) -
2135 offset + corr + axis->s.y;
2137 debug(DBS_AXES_DRAWING) printf ("%f @ %d\n", i*axis->major + fl, y);
2138 if (y < 0 || y > axis->p.height)
2140 gdk_draw_line (axis->pixmap[not_disp], g->fg_gc,
2141 axis->s.width - 15, y, axis->s.width - 1, y);
2142 snprintf (desc, 32, "%.*f", rdigits, i*axis->major + fl);
2143 w = gdk_string_width (g->font, desc);
2144 h = gdk_string_height (g->font, desc);
2145 gdk_draw_string (axis->pixmap[not_disp], g->font, g->fg_gc,
2146 axis->s.width-15-4-w, y + h/2, desc);
2150 double minor_tick = axis->minor * g->zoom.y;
2151 imin = (g->geom.height - offset + corr - g->wp.height)/minor_tick + 1;
2152 imax = (g->geom.height - offset + corr) / minor_tick;
2153 for (i=imin; i <= imax; i++) {
2154 int y = g->geom.height-1 - (int )rint (i*minor_tick) -
2155 offset + corr + axis->s.y;
2157 debug (DBS_AXES_DRAWING) printf ("%f @ %d\n", i*axis->minor+fl, y);
2158 if (y > 0 && y < axis->p.height)
2159 gdk_draw_line (axis->pixmap[not_disp], g->fg_gc,
2160 axis->s.width - 8, y, axis->s.width - 1, y);
2163 for (i=0; axis->label[i]; i++) {
2165 w = gdk_string_width (g->font, axis->label[i]);
2166 h = gdk_string_height (g->font, axis->label[i]);
2167 gdk_draw_string (axis->pixmap[not_disp], g->font, g->fg_gc,
2168 (axis->p.width - w)/2 , TITLEBAR_HEIGHT-15 - i*(h+3),
2173 static void h_axis_pixmap_draw (struct axis *axis)
2175 struct graph *g = axis->g;
2177 double major_tick, minor_tick;
2178 int not_disp, rdigits, offset, imin, imax;
2179 double left, right, j, fl, corr;
2181 debug(DBS_FENTRY) puts ("h_axis_pixmap_draw()");
2182 left = (g->wp.x-g->geom.x) /
2183 (double )g->geom.width * g->bounds.width;
2185 right = (g->wp.x-g->geom.x+g->wp.width) /
2186 (double )g->geom.width * g->bounds.width;
2188 axis_compute_ticks (axis, left, right, AXIS_HORIZONTAL);
2190 j = axis->major - floor (axis->major);
2191 for (rdigits=0; rdigits<=6; rdigits++) {
2198 not_disp = 1 ^ axis->displayed;
2199 gdk_draw_rectangle (axis->pixmap[not_disp], g->bg_gc, TRUE, 0, 0,
2200 axis->p.width, axis->p.height);
2202 gdk_draw_line (axis->pixmap[not_disp], g->fg_gc, 0, 0,
2203 axis->s.width + (axis->p.width-axis->s.width)/2.0, 0);
2204 offset = g->wp.x - g->geom.x;
2206 fl = floor (axis->min / axis->major) * axis->major;
2207 corr = rint ((axis->min - fl) * g->zoom.x);
2210 major_tick = axis->major*g->zoom.x;
2211 imin = (offset + corr) / major_tick + 1;
2212 imax = (offset + corr + axis->s.width) / major_tick;
2213 for (i=imin; i <= imax; i++) {
2216 int x = (int )rint (i * major_tick) - offset - corr;
2218 /* printf ("%f @ %d\n", i*axis->major + fl, x); */
2219 if (x < 0 || x > axis->s.width)
2221 gdk_draw_line (axis->pixmap[not_disp], g->fg_gc, x, 0, x, 15);
2222 snprintf (desc, 32, "%.*f", rdigits, i*axis->major + fl);
2223 w = gdk_string_width (g->font, desc);
2224 h = gdk_string_height (g->font, desc);
2225 gdk_draw_string (axis->pixmap[not_disp], g->font, g->fg_gc,
2226 x - w/2, 15+h+4, desc);
2228 if (axis->minor > 0) {
2230 minor_tick = axis->minor*g->zoom.x;
2231 imin = (offset + corr) / minor_tick + 1;
2232 imax = (offset + corr + g->wp.width) / minor_tick;
2233 for (i=imin; i <= imax; i++) {
2234 int x = (int )rint (i * minor_tick) - offset - corr;
2235 if (x > 0 && x < axis->s.width)
2236 gdk_draw_line (axis->pixmap[not_disp], g->fg_gc, x, 0, x, 8);
2239 for (i=0; axis->label[i]; i++) {
2241 w = gdk_string_width (g->font, axis->label[i]);
2242 h = gdk_string_height (g->font, axis->label[i]);
2243 gdk_draw_string (axis->pixmap[not_disp], g->font, g->fg_gc,
2244 axis->s.width - w - 50, 15+2*h+15 + i*(h+3),
2249 static void axis_pixmaps_switch (struct axis *axis)
2251 axis->displayed = 1 ^ axis->displayed;
2254 static void axis_pixmap_display (struct axis *axis)
2256 gdk_draw_pixmap (axis->drawing_area->window, axis->g->fg_gc,
2257 axis->pixmap[axis->displayed], 0, 0, axis->p.x, axis->p.y,
2258 axis->p.width, axis->p.height);
2261 static void axis_compute_ticks (struct axis *axis, double x0, double xmax, int dir)
2263 int i, j, ii, jj, ms;
2264 double zoom, x, steps[3]={ 0.1, 0.5 };
2265 int dim, check_needed, diminished;
2266 double majthresh[2]={2.0, 3.0};
2268 debug((DBS_FENTRY | DBS_AXES_TICKS)) puts ("axis_compute_ticks()");
2269 debug(DBS_AXES_TICKS)
2270 printf ("x0=%f xmax=%f dir=%s\n", x0,xmax, dir?"VERTICAL":"HORIZONTAL");
2272 zoom = axis_zoom_get (axis, dir);
2274 for (i=-9; i<=12; i++) {
2275 if (x / pow (10, i) < 1)
2279 ms = (int )(x / pow (10, i));
2289 axis->major = steps[j] * pow (10, i);
2291 debug(DBS_AXES_TICKS) printf ("zoom=%.1f, x=%f -> i=%d -> ms=%d -> j=%d ->"
2292 " axis->major=%f\n", zoom, x, i, ms, j, axis->major);
2294 /* let's compute minor ticks */
2297 axis_ticks_down (&ii, &jj);
2298 axis->minor = steps[jj] * pow (10, ii);
2299 /* we don't want minors if they would be less than 10 pixels apart */
2300 if (axis->minor*zoom < 10) {
2301 debug(DBS_AXES_TICKS) printf ("refusing axis->minor of %f: "
2302 "axis->minor*zoom == %f\n", axis->minor, axis->minor*zoom);
2306 check_needed = TRUE;
2308 while (check_needed) {
2309 check_needed = FALSE;
2310 dim = get_label_dim (axis, dir, xmax);
2311 debug(DBS_AXES_TICKS) printf ("axis->major==%.1f, axis->minor==%.1f =>"
2312 " axis->major*zoom/dim==%f, axis->minor*zoom/dim==%f\n",
2313 axis->major, axis->minor, axis->major*zoom/dim,
2314 axis->minor*zoom/dim);
2316 /* corrections: if majors are less than majthresh[dir] times label
2317 * dimension apart, we need to use bigger ones */
2318 if (axis->major*zoom / dim < majthresh[dir]) {
2319 axis_ticks_up (&ii, &jj);
2320 axis->minor = axis->major;
2321 axis_ticks_up (&i, &j);
2322 axis->major = steps[j] * pow (10, i);
2323 check_needed = TRUE;
2324 debug(DBS_AXES_TICKS) printf ("axis->major enlarged to %.1f\n",
2327 /* if minor ticks are bigger than majthresh[dir] times label dimension,
2328 * we could promote them to majors as well */
2329 if (axis->minor*zoom / dim > majthresh[dir] && !diminished) {
2330 axis_ticks_down (&i, &j);
2331 axis->major = axis->minor;
2332 axis_ticks_down (&ii, &jj);
2333 axis->minor = steps[jj] * pow (10, ii);
2334 check_needed = TRUE;
2337 debug(DBS_AXES_TICKS) printf ("axis->minor diminished to %.1f\n",
2340 if (axis->minor*zoom < 10) {
2341 debug(DBS_AXES_TICKS) printf ("refusing axis->minor of %f: "
2342 "axis->minor*zoom == %f\n", axis->minor, axis->minor*zoom);
2348 debug(DBS_AXES_TICKS) printf ("corrected: axis->major == %.1f -> "
2349 "axis->minor == %.1f\n", axis->major, axis->minor);
2352 static void axis_ticks_up (int *i, int *j)
2361 static void axis_ticks_down (int *i, int *j)
2370 static int get_label_dim (struct axis *axis, int dir, double label)
2376 /* First, let's compute how many digits to the right of radix
2377 * we need to print */
2378 y = axis->major - floor (axis->major);
2379 for (rdigits=0; rdigits<=6; rdigits++) {
2385 snprintf (str, 32, "%.*f", rdigits, label);
2387 case AXIS_HORIZONTAL:
2388 dim = gdk_string_width (axis->g->font, str);
2391 dim = gdk_string_height (axis->g->font, str);
2394 puts ("initialize axis: an axis must be either horizontal or vertical");
2401 static double axis_zoom_get (struct axis *axis, int dir)
2404 case AXIS_HORIZONTAL:
2405 return axis->g->zoom.x;
2408 return axis->g->zoom.y;
2416 static void graph_select_segment (struct graph *g, int x, int y)
2418 struct element_list *list;
2421 debug(DBS_FENTRY) puts ("graph_select_segment()");
2424 y = g->geom.height-1 - (y - g->geom.y);
2426 for (list=g->elists; list; list=list->next)
2427 for (e=list->elements; e->type != ELMT_NONE; e++) {
2432 if (line_detect_collision (e, x, y)) {
2433 int row = e->parent->num - 1;
2434 update_packet_list (row);
2438 if (arc_detect_collision (e, x, y)) {
2439 int row = e->parent->num - 1;
2440 update_packet_list (row);
2449 static int line_detect_collision (struct element *e, int x, int y)
2453 if (e->p.line.dim.x1 < e->p.line.dim.x2) {
2454 x1 = (int )rint (e->p.line.dim.x1);
2455 x2 = (int )rint (e->p.line.dim.x2);
2457 x1 = (int )rint (e->p.line.dim.x2);
2458 x2 = (int )rint (e->p.line.dim.x1);
2460 if (e->p.line.dim.y1 < e->p.line.dim.y2) {
2461 y1 = (int )rint (e->p.line.dim.y1);
2462 y2 = (int )rint (e->p.line.dim.y2);
2464 y1 = (int )rint (e->p.line.dim.y2);
2465 y2 = (int )rint (e->p.line.dim.y1);
2468 printf ("line: (%d,%d)->(%d,%d), clicked: (%d,%d)\n", x1, y1, x2, y2, x, y);
2470 if ((x1==x && x2==x && y1<=y && y<=y2)||(y1==y && y2==y && x1<=x && x<=x2))
2476 static int arc_detect_collision (struct element *e, int x, int y)
2480 x1 = (int )rint (e->p.arc.dim.x);
2481 x2 = (int )rint (e->p.arc.dim.x + e->p.arc.dim.width);
2482 y1 = (int )rint (e->p.arc.dim.y - e->p.arc.dim.height);
2483 y2 = (int )rint (e->p.arc.dim.y);
2485 printf ("arc: (%d,%d)->(%d,%d), clicked: (%d,%d)\n", x1, y1, x2, y2, x, y);
2487 if (x1<=x && x<=x2 && y1<=y && y<=y2)
2493 static void update_packet_list (int row)
2495 select_packet (&cfile, row);
2496 if (gtk_clist_row_is_visible(GTK_CLIST(packet_list), row) !=
2497 GTK_VISIBILITY_FULL)
2498 gtk_clist_moveto(GTK_CLIST(packet_list), row, -1, 0.5, 0.5);
2499 GTK_CLIST(packet_list)->focus_row = row;
2500 gtk_clist_select_row(GTK_CLIST(packet_list), row, -1);
2503 static void cross_xor (struct graph *g, int x, int y)
2505 if (x > g->wp.x && x < g->wp.x+g->wp.width &&
2506 y >= g->wp.y && y < g->wp.y+g->wp.height) {
2507 gdk_draw_line (g->drawing_area->window, xor_gc, g->wp.x,
2508 y, g->wp.x + g->wp.width, y);
2509 gdk_draw_line (g->drawing_area->window, xor_gc, x,
2510 g->wp.y, x, g->wp.y + g->wp.height);
2514 static void cross_draw (struct graph *g, int x, int y)
2516 cross_xor (g, x, y);
2519 g->cross.erase_needed = 1;
2522 static void cross_erase (struct graph *g)
2524 cross_xor (g, g->cross.x, g->cross.y);
2525 g->cross.erase_needed = 0;
2528 static void magnify_create (struct graph *g, int x, int y)
2531 struct element_list *list, *new_list;
2532 struct ipoint pos, offsetpos;
2535 mg = g->magnify.g = (struct graph * )malloc (sizeof (struct graph));
2536 memcpy ((void * )mg, (void * )g, sizeof (struct graph));
2538 mg->toplevel = gtk_window_new (GTK_WINDOW_POPUP);
2539 mg->drawing_area = mg->toplevel;
2540 gtk_widget_set_usize (mg->toplevel, g->magnify.width, g->magnify.height);
2541 gtk_widget_set_events (mg->drawing_area, GDK_EXPOSURE_MASK
2542 /* | GDK_ENTER_NOTIFY_MASK */
2543 /* | GDK_ALL_EVENTS_MASK */
2548 mg->wp.width = g->magnify.width;
2549 mg->wp.height = g->magnify.height;
2550 mg->geom.width = (int )rint (g->geom.width * g->magnify.zoom.x);
2551 mg->geom.height = (int )rint (g->geom.height * g->magnify.zoom.y);
2552 mg->zoom.x = (mg->geom.width - 1) / g->bounds.width;
2553 mg->zoom.y = (mg->geom.height- 1) / g->bounds.height;
2555 /* in order to keep original element lists intact we need our own */
2556 graph_element_lists_initialize (mg);
2557 list = g->elists->next;
2558 new_list = mg->elists;
2559 for ( ; list; list=list->next) {
2561 (struct element_list * )malloc (sizeof (struct element_list));
2562 new_list = new_list->next;
2563 new_list->next = NULL;
2564 new_list->elements = NULL;
2566 graph_element_lists_make (mg);
2568 gdk_window_get_position (GTK_WIDGET (g->toplevel)->window, &pos.x, &pos.y);
2569 g->magnify.x = pos.x + x - g->magnify.width/2;
2570 g->magnify.y = pos.y + y - g->magnify.height/2;
2571 offsetpos.x = g->magnify.x + g->magnify.offset.x;
2572 offsetpos.x = offsetpos.x >= 0 ? offsetpos.x : 0;
2573 offsetpos.y = g->magnify.y + g->magnify.offset.y;
2574 offsetpos.y = offsetpos.y >= 0 ? offsetpos.y : 0;
2575 gtk_widget_set_uposition (mg->drawing_area, offsetpos.x, offsetpos.y);
2576 magnify_get_geom (g, x, y);
2578 gtk_widget_show (mg->drawing_area);
2580 /* we need to wait for the first expose event before we start drawing */
2581 while (!gdk_events_pending ());
2583 e = gdk_event_get ();
2585 if (e->any.type == GDK_EXPOSE) {
2593 mg->pixmap[0] = mg->pixmap[1] = NULL;
2594 graph_pixmaps_create (mg);
2596 g->magnify.active = 1;
2599 static void magnify_move (struct graph *g, int x, int y)
2601 struct ipoint pos, offsetpos;
2603 gdk_window_get_position (GTK_WIDGET (g->toplevel)->window, &pos.x, &pos.y);
2604 g->magnify.x = pos.x + x - g->magnify.width/2;
2605 g->magnify.y = pos.y + y - g->magnify.height/2;
2606 offsetpos.x = g->magnify.x + g->magnify.offset.x;
2607 offsetpos.x = offsetpos.x >= 0 ? offsetpos.x : 0;
2608 offsetpos.y = g->magnify.y + g->magnify.offset.y;
2609 offsetpos.y = offsetpos.y >= 0 ? offsetpos.y : 0;
2610 magnify_get_geom (g, x, y);
2611 gtk_widget_set_uposition (g->magnify.g->drawing_area, offsetpos.x,
2616 static void magnify_destroy (struct graph *g)
2618 struct element_list *list;
2619 struct graph *mg = g->magnify.g;
2621 gtk_widget_destroy (GTK_WIDGET (mg->drawing_area));
2622 gdk_pixmap_unref (mg->pixmap[0]);
2623 gdk_pixmap_unref (mg->pixmap[1]);
2624 for (list=mg->elists; list; list=list->next)
2625 free (list->elements);
2626 while (mg->elists->next) {
2627 list = mg->elists->next->next;
2628 free (mg->elists->next);
2629 mg->elists->next = list;
2631 free (g->magnify.g);
2632 g->magnify.active = 0;
2635 static void magnify_get_geom (struct graph *g, int x, int y)
2639 gdk_window_get_position (GTK_WIDGET (g->toplevel)->window, &posx, &posy);
2641 g->magnify.g->geom.x = g->geom.x;
2642 g->magnify.g->geom.y = g->geom.y;
2644 g->magnify.g->geom.x -=
2645 (int )rint ((g->magnify.g->geom.width - g->geom.width) *
2646 ((x-g->geom.x)/(double )g->geom.width));
2647 g->magnify.g->geom.y -=
2648 (int )rint ((g->magnify.g->geom.height - g->geom.height) *
2649 ((y-g->geom.y)/(double )g->geom.height));
2651 /* we have coords of origin of graph relative to origin of g->toplevel.
2652 * now we need them to relate to origin of magnify window */
2653 g->magnify.g->geom.x -= (g->magnify.x - posx);
2654 g->magnify.g->geom.y -= (g->magnify.y - posy);
2657 static void magnify_draw (struct graph *g)
2659 int not_disp = 1 ^ g->magnify.g->displayed;
2661 graph_pixmap_draw (g->magnify.g);
2662 /* graph pixmap is almost ready, just add border */
2663 gdk_draw_line (g->magnify.g->pixmap[not_disp], g->fg_gc, 0, 0,
2664 g->magnify.width - 1, 0);
2665 gdk_draw_line (g->magnify.g->pixmap[not_disp], g->fg_gc,
2666 g->magnify.width - 1, 0, g->magnify.width - 1, g->magnify.height);
2667 gdk_draw_line (g->magnify.g->pixmap[not_disp], g->fg_gc, 0, 0,
2668 0, g->magnify.height - 1);
2669 gdk_draw_line (g->magnify.g->pixmap[not_disp], g->fg_gc, 0,
2670 g->magnify.height - 1, g->magnify.width - 1, g->magnify.height - 1);
2672 graph_pixmaps_switch (g->magnify.g);
2673 graph_pixmap_display (g->magnify.g);
2677 static gint configure_event (GtkWidget *widget, GdkEventConfigure *event)
2683 int cur_g_width, cur_g_height;
2684 int cur_wp_width, cur_wp_height;
2686 debug(DBS_FENTRY) puts ("configure_event()");
2688 for (g=graphs; g; g=g->next)
2689 if (g->drawing_area == widget)
2692 cur_wp_width = g->wp.width;
2693 cur_wp_height = g->wp.height;
2694 g->wp.width = event->width - g->y_axis->p.width - RMARGIN_WIDTH;
2695 g->wp.height = event->height - g->x_axis->p.height - g->wp.y;
2696 g->x_axis->s.width = g->wp.width;
2697 g->x_axis->p.width = g->wp.width + RMARGIN_WIDTH;
2698 g->y_axis->p.height = g->wp.height + g->wp.y;
2699 g->y_axis->s.height = g->wp.height;
2700 g->x_axis->p.y = g->y_axis->p.height;
2701 zoom.x = (double )g->wp.width / cur_wp_width;
2702 zoom.y = (double )g->wp.height / cur_wp_height;
2703 cur_g_width = g->geom.width;
2704 cur_g_height = g->geom.height;
2705 g->geom.width = (int )rint (g->geom.width * zoom.x);
2706 g->geom.height = (int )rint (g->geom.height * zoom.y);
2707 g->zoom.x = (double )(g->geom.width - 1) / g->bounds.width;
2708 g->zoom.y = (double )(g->geom.height -1) / g->bounds.height;
2709 /* g->zoom.initial.x = g->zoom.x; */
2710 /* g->zoom.initial.y = g->zoom.y; */
2712 g->geom.x = g->wp.x - (double )g->geom.width/cur_g_width *
2713 (g->wp.x - g->geom.x);
2714 g->geom.y = g->wp.y - (double )g->geom.height/cur_g_height *
2715 (g->wp.y - g->geom.y);
2717 printf ("configure: graph: (%d,%d), (%d,%d); viewport: (%d,%d), (%d,%d); "
2718 "zooms: (%f,%f)\n", g->geom.x, g->geom.y, g->geom.width,
2719 g->geom.height, g->wp.x, g->wp.y, g->wp.width, g->wp.height,
2720 g->zoom.x, g->zoom.y);
2723 update_zoom_spins (g);
2724 graph_element_lists_make (g);
2725 graph_pixmaps_create (g);
2726 graph_title_pixmap_create (g);
2727 axis_pixmaps_create (g->y_axis);
2728 axis_pixmaps_create (g->x_axis);
2729 /* we don't do actual drawing here; we leave it to expose handler */
2730 graph_pixmap_draw (g);
2731 graph_pixmaps_switch (g);
2732 graph_title_pixmap_draw (g);
2733 h_axis_pixmap_draw (g->x_axis);
2734 axis_pixmaps_switch (g->x_axis);
2735 v_axis_pixmap_draw (g->y_axis);
2736 axis_pixmaps_switch (g->y_axis);
2740 static gint expose_event (GtkWidget *widget, GdkEventExpose *event)
2744 debug(DBS_FENTRY) puts ("expose_event()");
2749 for (g=graphs; g; g=g->next)
2750 if (g->drawing_area == widget)
2753 /* lower left corner */
2754 gdk_draw_rectangle (g->drawing_area->window, g->bg_gc, TRUE, 0,
2755 g->wp.y + g->wp.height, g->y_axis->p.width, g->x_axis->p.height);
2757 gdk_draw_rectangle (g->drawing_area->window, g->bg_gc, TRUE,
2758 g->wp.x + g->wp.width, g->wp.y, RMARGIN_WIDTH, g->wp.height);
2760 graph_pixmap_display (g);
2761 graph_title_pixmap_display (g);
2762 axis_pixmap_display (g->x_axis);
2763 axis_pixmap_display (g->y_axis);
2768 static gint button_press_event (GtkWidget *widget, GdkEventButton *event)
2772 debug(DBS_FENTRY) puts ("button_press_event()");
2774 for (g=graphs; g; g=g->next)
2775 if (g->drawing_area == widget)
2778 if (event->button == 3) {
2779 if (event->state & GDK_CONTROL_MASK)
2780 magnify_create (g, (int )rint (event->x), (int )rint (event->y));
2782 g->grab.x = (int )rint (event->x) - g->geom.x;
2783 g->grab.y = (int )rint (event->y) - g->geom.y;
2784 g->grab.grabbed = TRUE;
2787 /* Windows mouse control: */
2788 /* [<ctrl>-left] - select packet */
2789 /* [left] - zoom in */
2790 /* [<shift>-left] - zoom out */
2791 } else if (event->button == 1) {
2792 if (event->state & GDK_CONTROL_MASK) {
2793 graph_select_segment (g, (int)event->x, (int)event->y);
2796 } else if (event->button == 2) {
2798 int cur_width = g->geom.width, cur_height = g->geom.height;
2799 struct { double x, y; } factor;
2801 if (g->zoom.flags & ZOOM_OUT) {
2802 if (g->zoom.flags & ZOOM_HLOCK)
2805 factor.x = 1 / g->zoom.step_x;
2806 if (g->zoom.flags & ZOOM_VLOCK)
2809 factor.y = 1 / g->zoom.step_y;
2811 if (g->zoom.flags & ZOOM_HLOCK)
2814 factor.x = g->zoom.step_x;
2815 if (g->zoom.flags & ZOOM_VLOCK)
2818 factor.y = g->zoom.step_y;
2821 g->geom.width = (int )rint (g->geom.width * factor.x);
2822 g->geom.height = (int )rint (g->geom.height * factor.y);
2823 if (g->geom.width < g->wp.width)
2824 g->geom.width = g->wp.width;
2825 if (g->geom.height < g->wp.height)
2826 g->geom.height = g->wp.height;
2827 g->zoom.x = (g->geom.width - 1) / g->bounds.width;
2828 g->zoom.y = (g->geom.height- 1) / g->bounds.height;
2830 g->geom.x -= (int )rint ((g->geom.width - cur_width) *
2831 ((event->x-g->geom.x)/(double )cur_width));
2832 g->geom.y -= (int )rint ((g->geom.height - cur_height) *
2833 ((event->y-g->geom.y)/(double )cur_height));
2835 if (g->geom.x > g->wp.x)
2836 g->geom.x = g->wp.x;
2837 if (g->geom.y > g->wp.y)
2838 g->geom.y = g->wp.y;
2839 if (g->wp.x + g->wp.width > g->geom.x + g->geom.width)
2840 g->geom.x = g->wp.width + g->wp.x - g->geom.width;
2841 if (g->wp.y + g->wp.height > g->geom.y + g->geom.height)
2842 g->geom.y = g->wp.height + g->wp.y - g->geom.height;
2844 printf ("button press: graph: (%d,%d), (%d,%d); viewport: (%d,%d), "
2845 "(%d,%d); zooms: (%f,%f)\n", g->geom.x, g->geom.y,
2846 g->geom.width, g->geom.height, g->wp.x, g->wp.y, g->wp.width,
2847 g->wp.height, g->zoom.x, g->zoom.y);
2849 graph_element_lists_make (g);
2851 axis_display (g->y_axis);
2852 axis_display (g->x_axis);
2853 update_zoom_spins (g);
2855 cross_draw (g, event->x, event->y);
2857 } else if (event->button == 1) {
2858 graph_select_segment (g, (int )event->x, (int )event->y);
2866 static gint motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
2870 GdkModifierType state;
2872 /* debug(DBS_FENTRY) puts ("motion_notify_event()"); */
2874 for (g=graphs; g; g=g->next)
2875 if (g->drawing_area == widget)
2879 gdk_window_get_pointer (event->window, &x, &y, &state);
2883 state = event->state;
2886 /* Testing just (state & GDK_BUTTON1_MASK) is not enough since when button1
2887 * is pressed while pointer is in motion, we will receive one more motion
2888 * notify *before* we get the button press. This last motion notify works
2889 * with stale grab coordinates */
2890 if (state & GDK_BUTTON3_MASK) {
2891 if (g->grab.grabbed) {
2892 g->geom.x = x-g->grab.x;
2893 g->geom.y = y-g->grab.y;
2895 if (g->geom.x > g->wp.x)
2896 g->geom.x = g->wp.x;
2897 if (g->geom.y > g->wp.y)
2898 g->geom.y = g->wp.y;
2899 if (g->wp.x + g->wp.width > g->geom.x + g->geom.width)
2900 g->geom.x = g->wp.width + g->wp.x - g->geom.width;
2901 if (g->wp.y + g->wp.height > g->geom.y + g->geom.height)
2902 g->geom.y = g->wp.height + g->wp.y - g->geom.height;
2904 axis_display (g->y_axis);
2905 axis_display (g->x_axis);
2907 cross_draw (g, x, y);
2908 } else if (g->magnify.active)
2909 magnify_move (g, x, y);
2910 } else if (state & GDK_BUTTON1_MASK) {
2911 graph_select_segment (g, x, y);
2912 if (g->cross.erase_needed)
2915 cross_draw (g, x, y);
2917 if (g->cross.erase_needed)
2920 cross_draw (g, x, y);
2926 static gint button_release_event (GtkWidget *widget, GdkEventButton *event)
2930 debug(DBS_FENTRY) puts ("button_release_event()");
2932 for (g=graphs; g; g=g->next)
2933 if (g->drawing_area == widget)
2936 if (event->button == 3)
2937 g->grab.grabbed = FALSE;
2939 if (g->magnify.active)
2940 magnify_destroy (g);
2944 static gint key_press_event (GtkWidget *widget, GdkEventKey *event)
2948 debug(DBS_FENTRY) puts ("key_press_event()");
2950 for (g=graphs; g; g=g->next)
2951 if (g->toplevel == widget)
2954 if (event->keyval == 32 /*space*/) {
2957 if (g->cross.draw) {
2959 gdk_window_get_pointer (g->drawing_area->window, &x, &y, 0);
2961 } else if (g->cross.erase_needed) {
2965 /* toggle buttons emit their "toggled" signals so don't bother doing
2966 * any real work here, it will be done in signal handlers */
2968 gtk_toggle_button_set_active (g->cross.on_toggle, TRUE);
2970 gtk_toggle_button_set_active (g->cross.off_toggle, TRUE);
2971 } else if (event->keyval == 't')
2972 toggle_time_origin (g);
2973 else if (event->keyval == 's')
2974 toggle_seq_origin (g);
2975 else if (event->keyval == GDK_Shift_L) {
2976 /* g->zoom.flags |= ZOOM_OUT; */
2977 gtk_toggle_button_set_active (g->zoom.widget.out_toggle, TRUE);
2982 static gint key_release_event (GtkWidget *widget, GdkEventKey *event)
2986 debug(DBS_FENTRY) puts ("key_release_event()");
2988 for (g=graphs; g; g=g->next)
2989 if (g->toplevel == widget)
2992 if (event->keyval == GDK_Shift_L || event->keyval == GDK_ISO_Prev_Group) {
2993 /* g->zoom.flags &= ~ZOOM_OUT; */
2994 gtk_toggle_button_set_active (g->zoom.widget.in_toggle, TRUE);
2999 static gint leave_notify_event (GtkWidget *widget, GdkEventCrossing *event)
3003 for (g=graphs; g; g=g->next)
3004 if (g->drawing_area == widget)
3007 if (g->cross.erase_needed)
3013 static gint enter_notify_event (GtkWidget *widget, GdkEventCrossing *event)
3017 for (g=graphs; g; g=g->next)
3018 if (g->drawing_area == widget)
3021 /* graph_pixmap_display (g); */
3022 if (g->cross.draw) {
3024 gdk_window_get_pointer (g->drawing_area->window, &x, &y, 0);
3025 cross_draw (g, x, y);
3030 static void toggle_time_origin (struct graph *g)
3033 case GRAPH_TSEQ_STEVENS:
3034 tseq_stevens_toggle_time_origin (g);
3036 case GRAPH_TSEQ_TCPTRACE:
3037 tseq_tcptrace_toggle_time_origin (g);
3039 case GRAPH_THROUGHPUT:
3040 tput_toggle_time_origin (g);
3045 axis_display (g->x_axis);
3048 static void toggle_seq_origin (struct graph *g)
3051 case GRAPH_TSEQ_STEVENS:
3052 tseq_stevens_toggle_seq_origin (g);
3053 axis_display (g->y_axis);
3055 case GRAPH_TSEQ_TCPTRACE:
3056 tseq_tcptrace_toggle_seq_origin (g);
3057 axis_display (g->y_axis);
3060 rtt_toggle_seq_origin (g);
3061 axis_display (g->x_axis);
3068 static int get_num_dsegs (struct graph *g)
3071 struct segment *tmp;
3073 for (tmp=g->segments, count=0; tmp; tmp=tmp->next) {
3074 if (compare_headers (g->current, tmp, COMPARE_CURR_DIR)) {
3081 static int get_num_acks (struct graph *g)
3084 struct segment *tmp;
3086 for (tmp=g->segments, count=0; tmp; tmp=tmp->next) {
3087 if (!compare_headers (g->current, tmp, COMPARE_CURR_DIR)) {
3095 * Stevens-style time-sequence grapH
3098 static void tseq_stevens_read_config (struct graph *g)
3100 debug(DBS_FENTRY) puts ("tseq_stevens_read_config()");
3102 g->s.tseq_stevens.seq_width = 4;
3103 g->s.tseq_stevens.seq_height = 4;
3104 g->s.tseq_stevens.flags = 0;
3106 g->title = (char ** )malloc (2 * sizeof (char *));
3107 g->title[0] = "Time/Sequence Graph";
3109 g->y_axis->label = (char ** )malloc (3 * sizeof (char * ));
3110 g->y_axis->label[0] = "number[B]";
3111 g->y_axis->label[1] = "Sequence";
3112 g->y_axis->label[2] = NULL;
3113 g->x_axis->label = (char ** )malloc (2 * sizeof (char * ));
3114 g->x_axis->label[0] = "Time[s]";
3115 g->x_axis->label[1] = NULL;
3118 static void tseq_stevens_initialize (struct graph *g)
3120 debug(DBS_FENTRY) puts ("tseq_stevens_initialize()");
3121 tseq_stevens_get_bounds (g);
3127 case GRAPH_TSEQ_STEVENS:
3128 tseq_stevens_read_config(g);
3130 case GRAPH_TSEQ_TCPTRACE:
3131 tseq_tcptrace_read_config(g);
3136 static void tseq_stevens_get_bounds (struct graph *g)
3138 struct segment *tmp, *last, *first;
3139 double t0, tmax, y0, ymax;
3141 for (first=g->segments; first->next; first=first->next) {
3142 if (compare_headers (g->current, first, COMPARE_CURR_DIR))
3147 for (tmp=g->segments; tmp; tmp=tmp->next) {
3148 unsigned int highest_byte_num;
3150 if (compare_headers (g->current, tmp, COMPARE_CURR_DIR))
3151 highest_byte_num = ntohl (tmp->tcphdr.seq) + tmp->data;
3153 highest_byte_num = ntohl (tmp->tcphdr.ack_seq);
3154 if (highest_byte_num > ymax)
3155 ymax = highest_byte_num;
3158 puts ("tseq_stevens_get_bounds: segment list corrupted!");
3162 t0 = g->segments->rel_secs + g->segments->rel_usecs / 1000000.0;
3163 tmax = last->rel_secs + last->rel_usecs / 1000000.0;
3164 y0 = ntohl (first->tcphdr.seq);
3168 g->bounds.width = tmax - t0;
3169 g->bounds.height = ymax - y0;
3170 g->zoom.x = (g->geom.width - 1) / g->bounds.width;
3171 g->zoom.y = (g->geom.height -1) / g->bounds.height;
3174 static void tseq_stevens_make_elmtlist (struct graph *g)
3176 struct segment *tmp;
3177 struct element *elements, *e;
3178 double x0 = g->bounds.x0, y0 = g->bounds.y0;
3180 debug(DBS_FENTRY) puts ("tseq_stevens_make_elmtlist()");
3181 if (g->elists->elements == NULL) {
3182 int n = 1 + get_num_dsegs (g);
3183 e = elements = (struct element * )malloc (n*sizeof (struct element));
3185 e = elements = g->elists->elements;
3187 for (tmp=g->segments; tmp; tmp=tmp->next) {
3190 if (!compare_headers (g->current, tmp, COMPARE_CURR_DIR))
3193 secs = g->zoom.x * (tmp->rel_secs + tmp->rel_usecs / 1000000.0 - x0);
3194 seqno = g->zoom.y * (ntohl (tmp->tcphdr.seq) - y0);
3199 e->p.arc.dim.width = g->s.tseq_stevens.seq_width;
3200 e->p.arc.dim.height = g->s.tseq_stevens.seq_height;
3201 e->p.arc.dim.x = secs - g->s.tseq_stevens.seq_width/2.0;
3202 e->p.arc.dim.y = seqno + g->s.tseq_stevens.seq_height/2.0;
3203 e->p.arc.filled = TRUE;
3204 e->p.arc.angle1 = 0;
3205 e->p.arc.angle2 = 23040;
3208 e->type = ELMT_NONE;
3209 g->elists->elements = elements;
3212 static void tseq_stevens_toggle_seq_origin (struct graph *g)
3214 g->s.tseq_stevens.flags ^= SEQ_ORIGIN;
3216 if ((g->s.tseq_stevens.flags & SEQ_ORIGIN) == SEQ_ORIGIN_ZERO)
3217 g->y_axis->min = g->bounds.y0;
3218 else /* g->tseq_stevens.flags & SEQ_ORIGIN == SEQ_ORIGIN_ISN */
3222 static void tseq_stevens_toggle_time_origin (struct graph *g)
3224 g->s.tseq_stevens.flags ^= TIME_ORIGIN;
3226 if ((g->s.tseq_stevens.flags & TIME_ORIGIN) == TIME_ORIGIN_CAP)
3227 g->x_axis->min = g->bounds.x0;
3228 else /* g->tseq_stevens.flags & TIME_ORIGIN == TIME_ORIGIN_CONN */
3233 * tcptrace-style time-sequence graph
3236 static void tseq_tcptrace_read_config (struct graph *g)
3238 GdkColormap *colormap;
3241 g->s.tseq_tcptrace.flags = 0;
3242 g->s.tseq_tcptrace.gc_seq = gdk_gc_new (g->drawing_area->window);
3243 g->s.tseq_tcptrace.gc_ack[0] = gdk_gc_new (g->drawing_area->window);
3244 g->s.tseq_tcptrace.gc_ack[1] = gdk_gc_new (g->drawing_area->window);
3245 colormap = gdk_window_get_colormap (g->drawing_area->window);
3246 gdk_color_parse ("black", &color);
3247 gdk_colormap_alloc_color (colormap, &color, FALSE, TRUE);
3248 gdk_gc_set_foreground (g->s.tseq_tcptrace.gc_seq, &color);
3249 gdk_color_parse ("LightSlateGray", &color);
3250 gdk_colormap_alloc_color (colormap, &color, FALSE, TRUE);
3251 gdk_gc_set_foreground (g->s.tseq_tcptrace.gc_ack[0], &color);
3252 gdk_color_parse ("LightGray", &color);
3253 gdk_colormap_alloc_color (colormap, &color, FALSE, TRUE);
3254 gdk_gc_set_foreground (g->s.tseq_tcptrace.gc_ack[1], &color);
3256 g->elists->next = (struct element_list * )
3257 malloc (sizeof (struct element_list));
3258 g->elists->next->next = NULL;
3259 g->elists->next->elements = NULL;
3261 g->title = (char ** )malloc (2 * sizeof (char *));
3262 g->title[0] = "Time/Sequence Graph";
3264 g->y_axis->label = (char ** )malloc (3 * sizeof (char * ));
3265 g->y_axis->label[0] = "number[B]";
3266 g->y_axis->label[1] = "Sequence";
3267 g->y_axis->label[2] = NULL;
3268 g->x_axis->label = (char ** )malloc (2 * sizeof (char * ));
3269 g->x_axis->label[0] = "Time[s]";
3270 g->x_axis->label[1] = NULL;
3273 static void tseq_tcptrace_make_elmtlist (struct graph *g)
3275 struct segment *tmp;
3276 struct element *elements0, *e0; /* list of elmts with prio 0 */
3277 struct element *elements1, *e1; /* list of elmts with prio 1 */
3279 double p_t; /* ackno, window and time of previous segment */
3280 double p_ackno, p_win;
3283 debug(DBS_FENTRY) puts ("tseq_tcptrace_make_elmtlist()");
3285 if (g->elists->elements == NULL) {
3286 int n = 1 + 4*get_num_acks(g);
3287 e0 = elements0 = (struct element * )malloc (n*sizeof (struct element));
3289 e0 = elements0 = g->elists->elements;
3291 if (g->elists->next->elements == NULL ) {
3292 int n = 1 + 3*get_num_dsegs(g);
3293 e1 = elements1 = (struct element * )malloc (n*sizeof (struct element));
3295 e1 = elements1 = g->elists->next->elements;
3299 /* initialize "previous" values */
3300 for (tmp=g->segments; tmp; tmp=tmp->next)
3301 if (!compare_headers (g->current, tmp, COMPARE_CURR_DIR))
3304 p_ackno = (unsigned int )(g->zoom.y * (ntohl (tmp->tcphdr.ack_seq) - y0));
3307 p_win = g->zoom.y * ntohs (tmp->tcphdr.window);
3308 p_t = g->segments->rel_secs + g->segments->rel_usecs/1000000.0 - x0;
3309 for (tmp=g->segments; tmp; tmp=tmp->next) {
3310 double secs, seqno, data;
3313 secs = tmp->rel_secs + tmp->rel_usecs / 1000000.0;
3316 if (compare_headers (g->current, tmp, COMPARE_CURR_DIR)) {
3317 /* forward direction -> we need seqno and amount of data */
3320 seqno = ntohl (tmp->tcphdr.seq);
3321 if (TCP_SYN (tmp->tcphdr))
3326 y1 = g->zoom.y * (seqno - y0);
3327 y2 = g->zoom.y * (seqno - y0 + data);
3328 e1->type = ELMT_LINE;
3330 e1->gc = g->s.tseq_tcptrace.gc_seq;
3331 e1->p.line.dim.x1 = e1->p.line.dim.x2 = x;
3332 e1->p.line.dim.y1 = y1;
3333 e1->p.line.dim.y2 = y2;
3335 e1->type = ELMT_LINE;
3337 e1->gc = g->s.tseq_tcptrace.gc_seq;
3338 e1->p.line.dim.x1 = x - 1;
3339 e1->p.line.dim.x2 = x + 1;
3340 e1->p.line.dim.y1 = e1->p.line.dim.y2 = y1;
3342 e1->type = ELMT_LINE;
3344 e1->gc = g->s.tseq_tcptrace.gc_seq;
3345 e1->p.line.dim.x1 = x + 1;
3346 e1->p.line.dim.x2 = x - 1;
3347 e1->p.line.dim.y1 = e1->p.line.dim.y2 = y2;
3351 if (TCP_SYN (tmp->tcphdr) && ! TCP_ACK (tmp->tcphdr))
3352 /* SYN's have ACK==0 and are useless here */
3354 /* backward direction -> we need ackno and window */
3355 ackno = (ntohl (tmp->tcphdr.ack_seq) - y0) * g->zoom.y;
3356 win = ntohs (tmp->tcphdr.window) * g->zoom.y;
3359 e0->type = ELMT_LINE;
3361 e0->gc = g->s.tseq_tcptrace.gc_ack[toggle];
3362 e0->p.line.dim.x1 = p_t;
3363 e0->p.line.dim.y1 = p_ackno;
3364 e0->p.line.dim.x2 = x;
3365 e0->p.line.dim.y2 = p_ackno;
3367 e0->type = ELMT_LINE;
3369 e0->gc = g->s.tseq_tcptrace.gc_ack[toggle];
3370 e0->p.line.dim.x1 = x;
3371 e0->p.line.dim.y1 = p_ackno;
3372 e0->p.line.dim.x2 = x;
3373 e0->p.line.dim.y2 = ackno!=p_ackno || ackno<4 ? ackno : ackno-4;
3376 e0->type = ELMT_LINE;
3378 e0->gc = g->s.tseq_tcptrace.gc_ack[toggle];
3379 e0->p.line.dim.x1 = p_t;
3380 e0->p.line.dim.y1 = p_win + p_ackno;
3381 e0->p.line.dim.x2 = x;
3382 e0->p.line.dim.y2 = p_win + p_ackno;
3384 e0->type = ELMT_LINE;
3386 e0->gc = g->s.tseq_tcptrace.gc_ack[toggle];
3387 e0->p.line.dim.x1 = x;
3388 e0->p.line.dim.y1 = p_win + p_ackno;
3389 e0->p.line.dim.x2 = x;
3390 e0->p.line.dim.y2 = win + ackno;
3398 e0->type = ELMT_NONE;
3399 e1->type = ELMT_NONE;
3400 g->elists->elements = elements0;
3401 g->elists->next->elements = elements1;
3404 static void tseq_tcptrace_toggle_seq_origin (struct graph *g)
3406 g->s.tseq_tcptrace.flags ^= SEQ_ORIGIN;
3408 if ((g->s.tseq_tcptrace.flags & SEQ_ORIGIN) == SEQ_ORIGIN_ZERO)
3409 g->y_axis->min = g->bounds.y0;
3410 else /* g->tseq_stevens.flags & SEQ_ORIGIN == SEQ_ORIGIN_ISN */
3414 static void tseq_tcptrace_toggle_time_origin (struct graph *g)
3416 g->s.tseq_tcptrace.flags ^= TIME_ORIGIN;
3418 if ((g->s.tseq_tcptrace.flags & TIME_ORIGIN) == TIME_ORIGIN_CAP)
3419 g->x_axis->min = g->bounds.x0;
3420 else /* g->tseq_stevens.flags & TIME_ORIGIN == TIME_ORIGIN_CONN */
3428 static void tput_make_elmtlist (struct graph *g)
3430 struct segment *tmp, *oldest;
3431 struct element *elements, *e;
3435 if (g->elists->elements == NULL) {
3436 int n = 1 + get_num_dsegs (g);
3437 e = elements = (struct element * )malloc (n*sizeof (struct element));
3439 e = elements = g->elists->elements;
3441 for (oldest=g->segments,tmp=g->segments->next,i=0; tmp; tmp=tmp->next,i++) {
3442 double time = tmp->rel_secs + tmp->rel_usecs/1000000.0;
3443 dtime = time - (oldest->rel_secs + oldest->rel_usecs/1000000.0);
3444 if (i>g->s.tput.nsegs) {
3445 sum -= oldest->data;
3446 oldest=oldest->next;
3450 /* debug(DBS_TPUT_ELMTS) printf ("tput=%f\n", tput); */
3455 e->p.arc.dim.width = g->s.tput.width;
3456 e->p.arc.dim.height = g->s.tput.height;
3457 e->p.arc.dim.x = g->zoom.x*(time - g->bounds.x0) - g->s.tput.width/2.0;
3458 e->p.arc.dim.y = g->zoom.y*tput + g->s.tput.height/2.0;
3459 e->p.arc.filled = TRUE;
3460 e->p.arc.angle1 = 0;
3461 e->p.arc.angle2 = 23040;
3464 e->type = ELMT_NONE;
3465 g->elists->elements = elements;
3468 /* Purpose of <graph_type>_initialize functions:
3469 * - find maximum and minimum for both axes
3470 * - call setup routine for style struct */
3471 static void tput_initialize (struct graph *g)
3473 struct segment *tmp, *oldest, *last;
3475 double dtime, tput, tputmax=0;
3476 double t0, tmax, y0, ymax;
3478 debug(DBS_FENTRY) puts ("tput_initialize()");
3480 tput_read_config(g);
3482 for (last=g->segments; last->next; last=last->next);
3483 for (oldest=g->segments,tmp=g->segments->next,i=0; tmp; tmp=tmp->next,i++) {
3484 dtime = tmp->rel_secs + tmp->rel_usecs/1000000.0 -
3485 (oldest->rel_secs + oldest->rel_usecs/1000000.0);
3486 if (i>g->s.tput.nsegs) {
3487 sum -= oldest->data;
3488 oldest=oldest->next;
3492 debug(DBS_TPUT_ELMTS) printf ("tput=%f\n", tput);
3497 t0 = g->segments->rel_secs + g->segments->rel_usecs / 1000000.0;
3498 tmax = last->rel_secs + last->rel_usecs / 1000000.0;
3504 g->bounds.width = tmax - t0;
3505 g->bounds.height = ymax - y0;
3506 g->zoom.x = (g->geom.width - 1) / g->bounds.width;
3507 g->zoom.y = (g->geom.height -1) / g->bounds.height;
3510 static void tput_read_config (struct graph *g)
3512 debug(DBS_FENTRY) puts ("tput_read_config()");
3514 g->s.tput.width = 4;
3515 g->s.tput.height = 4;
3516 g->s.tput.nsegs = 20;
3518 g->title = (char ** )malloc (2 * sizeof (char *));
3519 g->title[0] = "Throughput Graph";
3521 g->y_axis->label = (char ** )malloc (3 * sizeof (char * ));
3522 g->y_axis->label[0] = "[B/s]";
3523 g->y_axis->label[1] = "Throughput";
3524 g->y_axis->label[2] = NULL;
3525 g->x_axis->label = (char ** )malloc (2 * sizeof (char * ));
3526 g->x_axis->label[0] = "Time[s]";
3527 g->x_axis->label[1] = NULL;
3528 g->s.tput.flags = 0;
3531 static void tput_toggle_time_origin (struct graph *g)
3533 g->s.tput.flags ^= TIME_ORIGIN;
3535 if ((g->s.tput.flags & TIME_ORIGIN) == TIME_ORIGIN_CAP)
3536 g->x_axis->min = g->bounds.x0;
3537 else /* g->s.tput.flags & TIME_ORIGIN == TIME_ORIGIN_CONN */
3543 static void rtt_read_config (struct graph *g)
3545 debug(DBS_FENTRY) puts ("rtt_read_config()");
3548 g->s.rtt.height = 4;
3551 g->title = (char ** )malloc (2 * sizeof (char *));
3552 g->title[0] = "Round Trip Time Graph";
3554 g->y_axis->label = (char ** )malloc (3 * sizeof (char * ));
3555 g->y_axis->label[0] = "RTT [s]";
3556 g->y_axis->label[1] = NULL;
3557 g->x_axis->label = (char ** )malloc (2 * sizeof (char * ));
3558 g->x_axis->label[0] = "Sequence Number[B]";
3559 g->x_axis->label[1] = NULL;
3562 static void rtt_initialize (struct graph *g)
3564 struct segment *tmp, *first=NULL;
3565 struct unack *unack = NULL, *u;
3567 double x0, xmax=0, y0, ymax;
3569 debug(DBS_FENTRY) puts ("rtt_initialize()");
3571 rtt_read_config (g);
3573 for (tmp=g->segments; tmp; tmp=tmp->next) {
3574 if (compare_headers (g->current, tmp, COMPARE_CURR_DIR)) {
3575 unsigned int seqno = ntohl (tmp->tcphdr.seq);
3580 if (tmp->data && !rtt_is_retrans (unack, seqno)) {
3581 double time = tmp->rel_secs + tmp->rel_usecs / 1000000.0;
3582 u = rtt_get_new_unack (time, seqno);
3584 rtt_put_unack_on_list (&unack, u);
3587 if (seqno + tmp->data > xmax)
3588 xmax = seqno + tmp->data;
3590 unsigned int ackno = ntohl (tmp->tcphdr.ack_seq);
3591 double time = tmp->rel_secs + tmp->rel_usecs / 1000000.0;
3594 for (u=unack; u; u=v)
3595 if (ackno > u->seqno) {
3596 double rtt = time - u->time;
3600 rtt_delete_unack_from_list (&unack, u);
3606 x0 = ntohl (first->tcphdr.seq);
3612 g->bounds.width = xmax - x0;
3613 g->bounds.height = ymax - y0;
3614 g->zoom.x = g->geom.width / g->bounds.width;
3615 g->zoom.y = g->geom.height / g->bounds.height;
3618 static int rtt_is_retrans (struct unack *list, unsigned int seqno)
3622 for (u=list; u; u=u->next)
3623 if (u->seqno == seqno)
3629 static struct unack *rtt_get_new_unack (double time, unsigned int seqno)
3633 u = (struct unack * )malloc (sizeof (struct unack));
3642 static void rtt_put_unack_on_list (struct unack **l, struct unack *new)
3644 struct unack *u, *list = *l;
3646 for (u=list; u; u=u->next)
3656 static void rtt_delete_unack_from_list (struct unack **l, struct unack *dead)
3658 struct unack *u, *list = *l;
3667 for (u=list; u; u=u->next)
3668 if (u->next == dead) {
3669 u->next = u->next->next;
3675 static void rtt_make_elmtlist (struct graph *g)
3677 struct segment *tmp;
3678 struct unack *unack = NULL, *u;
3679 struct element *elements, *e;
3681 debug(DBS_FENTRY) puts ("rtt_make_elmtlist()");
3683 if (g->elists->elements == NULL) {
3684 int n = 1 + get_num_dsegs (g);
3685 e = elements = (struct element * )malloc (n*sizeof (struct element));
3687 e = elements = g->elists->elements;
3689 for (tmp=g->segments; tmp; tmp=tmp->next) {
3690 if (compare_headers (g->current, tmp, COMPARE_CURR_DIR)) {
3691 unsigned int seqno = ntohl (tmp->tcphdr.seq);
3693 if (tmp->data && !rtt_is_retrans (unack, seqno)) {
3694 double time = tmp->rel_secs + tmp->rel_usecs / 1000000.0;
3695 u = rtt_get_new_unack (time, seqno);
3697 rtt_put_unack_on_list (&unack, u);
3700 unsigned int ackno = ntohl (tmp->tcphdr.ack_seq);
3701 double time = tmp->rel_secs + tmp->rel_usecs / 1000000.0;
3704 for (u=unack; u; u=v)
3705 if (ackno > u->seqno) {
3706 double rtt = time - u->time;
3711 e->p.arc.dim.width = g->s.rtt.width;
3712 e->p.arc.dim.height = g->s.rtt.height;
3713 e->p.arc.dim.x = g->zoom.x * (u->seqno - g->bounds.x0)
3714 - g->s.rtt.width/2.0;
3715 e->p.arc.dim.y = g->zoom.y * rtt + g->s.rtt.height/2.0;
3716 e->p.arc.filled = TRUE;
3717 e->p.arc.angle1 = 0;
3718 e->p.arc.angle2 = 23040;
3722 rtt_delete_unack_from_list (&unack, u);
3727 e->type = ELMT_NONE;
3728 g->elists->elements = elements;
3731 static void rtt_toggle_seq_origin (struct graph *g)
3733 g->s.rtt.flags ^= SEQ_ORIGIN;
3735 if ((g->s.rtt.flags & SEQ_ORIGIN) == SEQ_ORIGIN_ZERO)
3736 g->x_axis->min = g->bounds.x0;
3742 /* replacement of Unix rint() for Windows */
3743 static int rint (double x)
3748 buf = _fcvt(x, 0, &dec, &sig);