2 * TCP graph drawing code
3 * By Pavel Mores <pvl@uh.cz>
4 * Win32 port: rwh@unifiedtech.com
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
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.
35 #if defined(GDK_DISABLE_DEPRECATED)
36 # undef GDK_DISABLE_DEPRECATED
40 #include <gdk/gdkkeysyms.h>
41 #if GTK_CHECK_VERSION(3,0,0)
42 # include <gdk/gdkkeysyms-compat.h>
45 #include <epan/packet.h>
46 #include <epan/ipproto.h>
47 #include <epan/etypes.h>
48 #include <epan/ppptypes.h>
49 #include <epan/epan_dissect.h>
50 #include <epan/dissectors/packet-tcp.h>
51 #include <epan/address.h>
54 #include "../globals.h"
55 #include "../simple_dialog.h"
56 #include "../stat_menu.h"
58 #include "gtk/gui_utils.h"
59 #include "gtk/dlg_utils.h"
60 #include "gtk/gui_stat_menu.h"
62 #include "gtk/old-gtk-compat.h"
71 #define TCP_SYN(flags) ( flags & TH_SYN )
72 #define TCP_ACK(flags) ( flags & TH_ACK )
73 #define TCP_FIN(flags) ( flags & TH_FIN )
76 #define TXT_HEIGHT 550
78 /* for compare_headers() */
79 /* segment went the same direction as the currently selected one */
80 #define COMPARE_CURR_DIR 0
81 #define COMPARE_ANY_DIR 1
83 /* initalize_axis() */
84 #define AXIS_HORIZONTAL 0
85 #define AXIS_VERTICAL 1
87 #define WINDOW_TITLE_LENGTH 256
89 #define MOUSE_BUTTON_LEFT 1
90 #define MOUSE_BUTTON_MIDDLE 2
91 #define MOUSE_BUTTON_RIGHT 3
104 guint32 th_win; /* make it 32 bits so we can handle some scaling */
113 double x, y, width, height;
117 double x1, y1, x2, y2;
121 int x, y, width, height;
144 struct ellipse_params {
150 GdkColor *elment_color_p;
151 struct segment *parent;
153 struct ellipse_params ellipse;
154 struct rect_params rect;
155 struct line_params line;
159 struct element_list {
160 struct element_list *next;
161 struct element *elements;
165 struct graph *g; /* which graph we belong to */
166 GtkWidget *drawing_area;
167 #if GTK_CHECK_VERSION(2,22,0)
168 cairo_surface_t *surface[2];
170 GdkPixmap *pixmap[2];
173 #define AXIS_ORIENTATION 1 << 0
175 /* dim and orig (relative to origin of window) of axis' pixmap */
177 /* dim and orig (relative to origin of axis' pixmap) of scale itself */
180 gdouble major, minor; /* major and minor ticks */
184 #define HAXIS_INIT_HEIGHT 70
185 #define VAXIS_INIT_WIDTH 100
186 #define TITLEBAR_HEIGHT 50
187 #define RMARGIN_WIDTH 30
189 struct style_tseq_tcptrace {
191 GdkColor ack_color[2];
195 struct style_tseq_stevens {
212 struct style_wscale {
219 #define SEQ_ORIGIN 0x1
220 /* show absolute sequence numbers (not differences from isn) */
221 #define SEQ_ORIGIN_ZERO 0x1
222 #define SEQ_ORIGIN_ISN 0x0
223 #define TIME_ORIGIN 0x10
224 /* show time from beginning of capture as opposed to time from beginning
225 * of the connection */
226 #define TIME_ORIGIN_CAP 0x10
227 #define TIME_ORIGIN_CONN 0x0
229 /* this is used by rtt module only */
238 int draw; /* indicates whether we should draw cross at all */
240 GtkToggleButton *on_toggle;
241 GtkToggleButton *off_toggle;
245 double x0, y0, width, height;
254 double step_x, step_y;
256 #define ZOOM_OUT (1 << 0)
257 #define ZOOM_HLOCK (1 << 1)
258 #define ZOOM_VLOCK (1 << 2)
259 #define ZOOM_STEPS_SAME (1 << 3)
260 #define ZOOM_STEPS_KEEP_RATIO (1 << 4)
262 /* unfortunately, we need them both because gtk_toggle_button_set_active ()
263 * with second argument FALSE doesn't do anything, somehow */
265 GtkToggleButton *in_toggle;
266 GtkToggleButton *out_toggle;
269 GtkSpinButton *h_step;
270 GtkSpinButton *v_step;
282 struct ipoint offset;
286 #define MAGZOOMS_SAME (1U << 0)
287 #define MAGZOOMS_SAME_RATIO (1U << 1)
288 #define MAGZOOMS_IGNORE (1U << 31)
291 GtkSpinButton *h_zoom, *v_zoom;
297 #define GRAPH_TSEQ_STEVENS 0
298 #define GRAPH_TSEQ_TCPTRACE 1
299 #define GRAPH_THROUGHPUT 2
301 #define GRAPH_WSCALE 4
303 #define GRAPH_DESTROYED (1 << 0)
304 #define GRAPH_INIT_ON_TYPE_CHANGE (1 << 1)
306 GtkWidget *toplevel; /* keypress handler needs this */
307 GtkWidget *drawing_area;
308 GtkWidget *text; /* text widget for seg list - probably
311 PangoFontDescription *font; /* font used for annotations etc. */
312 #if GTK_CHECK_VERSION(3,0,0)
316 #if GTK_CHECK_VERSION(2,22,0)
317 cairo_surface_t *title_surface;
318 cairo_surface_t *surface[2];
320 GdkPixmap *title_pixmap;
321 GdkPixmap *pixmap[2];
323 int displayed; /* which of both pixmaps is on screen right now */
325 GtkWidget *control_panel;
326 /* this belongs to style structs of graph types that make use of it */
327 GtkToggleButton *time_orig_conn, *seq_orig_isn;
330 /* Next 4 attribs describe the graph in natural units, before any scaling.
331 * For example, if we want to display graph of TCP conversation that
332 * started 112.309845 s after beginning of the capture and ran until
333 * 479.093582 s, 237019 B went through the connection (in one direction)
334 * starting with isn 31934022, then (bounds.x0, bounds.y0)=(112.309845,
335 * 31934022) and (bounds.width, bounds.height)=(366.783737, 237019). */
336 struct bounds bounds;
337 /* dimensions and position of the graph, both expressed already in pixels.
338 * x and y give the position of upper left corner of the graph relative
339 * to origin of the graph window, size is basically bounds*zoom */
341 /* viewport (=graph window area which is reserved for graph itself), its
342 * size and position relative to origin of the graph window */
345 /* If we need to display 237019 sequence numbers (=bytes) onto say 500
346 * pixels, we have to scale the graph down by factor of 0.002109. This
347 * number would be zoom.y. Obviously, both directions have separate zooms.*/
350 struct magnify magnify;
351 struct axis *x_axis, *y_axis;
352 struct segment *segments;
353 struct segment *current;
354 struct element_list *elists; /* element lists */
356 struct style_tseq_stevens tseq_stevens;
357 struct style_tseq_tcptrace tseq_tcptrace;
358 struct style_tput tput;
359 struct style_rtt rtt;
360 struct style_wscale wscale;
362 /* This allows keyboard to set the radio button */
364 GtkToggleButton *graph_rtt, *graph_tput, *graph_tseqstevens, *graph_tseqttrace;
365 GtkToggleButton *graph_wscale;
369 #if GTK_CHECK_VERSION(3,0,0)
371 static GdkGC *xor_gc = NULL;
375 #define debug(section) if (debugging & section)
376 /* print function entry points */
377 #define DBS_FENTRY (1 << 0)
378 #define DBS_AXES_TICKS (1 << 1)
379 #define DBS_AXES_DRAWING (1 << 2)
380 #define DBS_GRAPH_DRAWING (1 << 3)
381 #define DBS_TPUT_ELMTS (1 << 4)
382 /*int debugging = DBS_FENTRY;*/
383 static int debugging = 0;
384 /*int debugging = DBS_AXES_TICKS;*/
385 /*int debugging = DBS_AXES_DRAWING;*/
386 /*int debugging = DBS_GRAPH_DRAWING;*/
387 /*int debugging = DBS_TPUT_ELMTS;*/
389 static void create_gui (struct graph * );
391 static void create_text_widget (struct graph * );
392 static void display_text (struct graph * );
394 static void create_drawing_area (struct graph * );
395 static void control_panel_create (struct graph * );
396 static GtkWidget *control_panel_create_zoom_group (struct graph * );
397 static GtkWidget *control_panel_create_magnify_group (struct graph * );
398 static GtkWidget *control_panel_create_cross_group (struct graph * );
399 static GtkWidget *control_panel_create_zoomlock_group (struct graph * );
400 static GtkWidget *control_panel_create_graph_type_group (struct graph * );
401 static void control_panel_add_zoom_page (struct graph * , GtkWidget * );
402 static void control_panel_add_magnify_page (struct graph * , GtkWidget * );
403 static void control_panel_add_origin_page (struct graph * , GtkWidget * );
404 static void control_panel_add_cross_page (struct graph * , GtkWidget * );
405 static void control_panel_add_graph_type_page (struct graph * , GtkWidget * );
406 static void callback_toplevel_destroy (GtkWidget * , gpointer );
407 static gboolean callback_delete_event(GtkWidget * , GdkEvent * , gpointer);
408 static void callback_close (GtkWidget * , gpointer );
409 static void callback_time_origin (GtkWidget * , gpointer );
410 static void callback_seq_origin (GtkWidget * , gpointer );
411 static void callback_zoomlock_h (GtkWidget * , gpointer );
412 static void callback_zoomlock_v (GtkWidget * , gpointer );
413 static void callback_zoom_inout (GtkWidget * , gpointer );
414 static void callback_zoom_step (GtkWidget * , gpointer );
415 static void callback_zoom_flags (GtkWidget * , gpointer );
416 static void callback_cross_on_off (GtkWidget * , gpointer );
417 static void callback_mag_width (GtkWidget * , gpointer );
418 static void callback_mag_height (GtkWidget * , gpointer );
419 static void callback_mag_x (GtkWidget * , gpointer );
420 static void callback_mag_y (GtkWidget * , gpointer );
421 static void callback_mag_zoom (GtkWidget * , gpointer );
422 static void callback_mag_flags (GtkWidget * , gpointer );
423 static void callback_graph_type (GtkWidget * , gpointer );
424 static void callback_graph_init_on_typechg (GtkWidget * , gpointer );
425 static void callback_create_help (GtkWidget * , gpointer );
426 static void update_zoom_spins (struct graph * );
427 static struct tcpheader *select_tcpip_session (capture_file *, struct segment * );
428 static int compare_headers (address *saddr1, address *daddr1, guint16 sport1, guint16 dport1, address *saddr2, address *daddr2, guint16 sport2, guint16 dport2, int dir);
429 static int get_num_dsegs (struct graph * );
430 static int get_num_acks (struct graph * );
431 static void graph_type_dependent_initialize (struct graph * );
432 static struct graph *graph_new (void);
433 static void graph_destroy (struct graph * );
434 static void graph_initialize_values (struct graph * );
435 static void graph_init_sequence (struct graph * );
436 static void draw_element_line (struct graph * , struct element * );
437 static void draw_element_ellipse (struct graph * , struct element * );
438 static void graph_display (struct graph * );
439 static void graph_pixmaps_create (struct graph * );
440 static void graph_pixmaps_switch (struct graph * );
441 static void graph_pixmap_draw (struct graph * );
442 static void graph_pixmap_display (struct graph * );
443 static void graph_element_lists_make (struct graph * );
444 static void graph_element_lists_free (struct graph * );
445 static void graph_element_lists_initialize (struct graph * );
446 static void graph_title_pixmap_create (struct graph * );
447 static void graph_title_pixmap_draw (struct graph * );
448 static void graph_title_pixmap_display (struct graph * );
449 static void graph_segment_list_get (struct graph * );
450 static void graph_segment_list_free (struct graph * );
451 static void graph_select_segment (struct graph * , int , int );
452 static int line_detect_collision (struct element * , int , int );
453 static int ellipse_detect_collision (struct element * , int , int );
454 static void axis_pixmaps_create (struct axis * );
455 static void axis_pixmaps_switch (struct axis * );
456 static void axis_display (struct axis * );
457 static void v_axis_pixmap_draw (struct axis * );
458 static void h_axis_pixmap_draw (struct axis * );
459 static void axis_pixmap_display (struct axis * );
460 static void axis_compute_ticks (struct axis * , double , double , int );
461 static double axis_zoom_get (struct axis * , int );
462 static void axis_ticks_up (int * , int * );
463 static void axis_ticks_down (int * , int * );
464 static void axis_destroy (struct axis * );
465 static int get_label_dim (struct axis * , int , double );
466 static void toggle_crosshairs (struct graph *g);
467 static void toggle_time_origin (struct graph * );
468 static void toggle_seq_origin (struct graph * );
469 static void restore_initial_graph_view (struct graph *g);
470 static void cross_xor (struct graph * , int , int );
471 static void cross_draw (struct graph * , int , int );
472 static void cross_erase (struct graph * );
473 static void magnify_create (struct graph * , int , int );
474 static void magnify_move (struct graph * , int , int );
475 static void magnify_destroy (struct graph * );
476 static void magnify_draw (struct graph * );
477 static void magnify_get_geom (struct graph * , int , int );
478 static gboolean configure_event (GtkWidget * , GdkEventConfigure * , gpointer );
479 static gboolean expose_event (GtkWidget * , GdkEventExpose * , gpointer );
480 static gboolean button_press_event (GtkWidget * , GdkEventButton * , gpointer );
481 static gboolean button_release_event (GtkWidget * , GdkEventButton * , gpointer );
482 static gboolean motion_notify_event (GtkWidget * , GdkEventMotion * , gpointer );
483 static gboolean key_press_event (GtkWidget * , GdkEventKey * , gpointer );
484 static gboolean key_release_event (GtkWidget * , GdkEventKey * , gpointer );
485 static gboolean leave_notify_event (GtkWidget * , GdkEventCrossing * , gpointer );
486 static gboolean enter_notify_event (GtkWidget * , GdkEventCrossing * , gpointer );
487 static void tseq_initialize (struct graph * );
488 static void tseq_get_bounds (struct graph * );
489 static void tseq_stevens_read_config (struct graph * );
490 static void tseq_stevens_make_elmtlist (struct graph * );
491 static void tseq_stevens_toggle_seq_origin (struct graph * );
492 static void tseq_stevens_toggle_time_origin (struct graph * );
493 static void tseq_tcptrace_read_config (struct graph * );
494 static void tseq_tcptrace_make_elmtlist (struct graph * );
495 static void tseq_tcptrace_toggle_seq_origin (struct graph * );
496 static void tseq_tcptrace_toggle_time_origin (struct graph * );
497 static void tput_initialize (struct graph * );
498 static void tput_read_config (struct graph * );
499 static void tput_make_elmtlist (struct graph * );
500 static void tput_toggle_time_origin (struct graph * );
501 static void rtt_read_config (struct graph * );
502 static void rtt_initialize (struct graph * );
503 static int rtt_is_retrans (struct unack * , unsigned int );
504 static struct unack *rtt_get_new_unack (double , unsigned int );
505 static void rtt_put_unack_on_list (struct unack ** , struct unack * );
506 static void rtt_delete_unack_from_list (struct unack ** , struct unack * );
507 static void rtt_make_elmtlist (struct graph * );
508 static void rtt_toggle_seq_origin (struct graph * );
509 static void wscale_initialize(struct graph *);
510 static void wscale_read_config(struct graph *);
511 static void wscale_make_elmtlist(struct graph *);
512 #if defined(_WIN32) && !defined(__MINGW32__)
513 static int rint (double ); /* compiler template for Windows */
517 * Uncomment the following define to revert WIN32 to
518 * use original mouse button controls
521 /* #define ORIGINAL_WIN32_BUTTONS 1 */
523 /* XXX - what about OS X? */
524 static char helptext[] =
525 "Here's what you can do:\n"
527 #ifdef ORIGINAL_WIN32_BUTTONS
528 " <Ctrl>-Left Mouse Button selects segment under cursor in Wireshark's packet list\n"
530 " Left Mouse Button zooms in (towards area under mouse pointer)\n"
531 " <Shift>-Left Mouse Button zooms out\n"
533 " Right Mouse Button moves the graph (if zoomed in)\n"
534 " <Ctrl>-Right Mouse Button displays a portion of graph under cursor magnified\n"
535 #else /* !ORIGINAL_WIN32_BUTTONS */
536 " Left Mouse Button selects segment under cursor in Wireshark's packet list\n"
538 " Middle Mouse Button zooms in (towards area under cursor)\n"
539 " <Shift>-Middle Mouse Button zooms out\n"
541 " Right Mouse Button moves the graph (if zoomed in)\n"
542 " <Ctrl>-Right Mouse Button displays a portion of graph under cursor magnified\n"
546 " '1' display Round Trip Time Graph\n"
547 " '2' display Throughput Graph\n"
548 " '3' display Time/Sequence Graph (Stevens)\n"
549 " '4' display Time/Sequence Graph (tcptrace)\n"
550 " '5' display Window Scaling Graph\n"
552 " <Space bar> toggles crosshairs on/off\n"
554 " 'i' or '+' zoom in (towards area under mouse pointer)\n"
555 " 'o' or '-' zoom out\n"
556 " 'r' or <Home> restore graph to initial state (zoom out max)\n"
557 " 's' toggles relative/absolute sequence numbers\n"
558 " 't' toggles time origin\n"
559 " 'g' go to frame under cursor in Wireshark's packet list (if possible)\n"
561 " <Left> move view left by 100 pixels (if zoomed in)\n"
562 " <Right> move view right 100 pixels (if zoomed in)\n"
563 " <Up> move view up by 100 pixels (if zoomed in)\n"
564 " <Down> move view down by 100 pixels (if zoomed in)\n"
566 " <Shift><Left> move view left by 10 pixels (if zoomed in)\n"
567 " <Shift><Right> move view right 10 pixels (if zoomed in)\n"
568 " <Shift><Up> move view up by 10 pixels (if zoomed in)\n"
569 " <Shift><Down> move view down by 10 pixels (if zoomed in)\n"
571 " <Ctrl><Left> move view left by 1 pixel (if zoomed in)\n"
572 " <Ctrl><Right> move view right 1 pixel (if zoomed in)\n"
573 " <Ctrl><Up> move view up by 1 pixel (if zoomed in)\n"
574 " <Ctrl><Down> move view down by 1 pixel (if zoomed in)\n"
578 static void debug_coord (struct graph *g, const char *c)
580 static unsigned count = 0;
583 printf("%u: %s\n", count, c);
584 printf("%u: g->geom.width %d\n", count, g->geom.width);
585 printf("%u: g->geom.height %d\n", count, g->geom.height);
586 printf("%u: g->geom.x %d\n", count, g->geom.x);
587 printf("%u: g->geom.y %d\n", count, g->geom.y);
589 printf("%u: g->wp.width %d\n", count, g->wp.width);
590 printf("%u: g->wp.height %d\n", count, g->wp.height);
591 printf("%u: g->wp.x %d\n", count, g->wp.x);
592 printf("%u: g->wp.y %d\n", count, g->wp.y);
593 printf("---------------\n");
597 static void set_busy_cursor(GdkWindow *w)
601 cursor = gdk_cursor_new(GDK_WATCH);
602 gdk_window_set_cursor(w, cursor);
604 gdk_cursor_unref(cursor);
607 static void unset_busy_cursor(GdkWindow *w)
609 gdk_window_set_cursor(w, NULL);
612 #ifdef MAIN_MENU_USE_UIMANAGER
613 void tcp_graph_cb (GtkAction *action, gpointer user_data _U_)
615 struct segment current;
620 name = gtk_action_get_name (action);
621 if(strcmp(name, "Analyze/StatisticsMenu/TCPStreamGraphMenu/Time-Sequence-Graph-Stevens") == 0){
622 graph_type = GRAPH_TSEQ_STEVENS;
623 }else if(strcmp(name, "/Analyze/StatisticsMenu/TCPStreamGraphMenu/Time-Sequence-Graph-tcptrace") == 0){
624 graph_type = GRAPH_TSEQ_TCPTRACE;
625 }else if(strcmp(name, "StatisticsMenu/TCPStreamGraphMenu/Throughput-Graph") == 0){
626 graph_type = GRAPH_THROUGHPUT;
627 }else if(strcmp(name, "/Analyze/StatisticsMenu/TCPStreamGraphMenu/RTT-Graph") == 0){
628 graph_type = GRAPH_RTT;
629 }else if(strcmp(name, "/Analyze/StatisticsMenu/TCPStreamGraphMenu/Window-Scaling-Graph") == 0){
630 graph_type = GRAPH_WSCALE;
635 debug(DBS_FENTRY) puts ("tcp_graph_cb()");
637 if (! (g = graph_new()))
641 graph_initialize_values (g);
643 g->type = graph_type;
644 if (!select_tcpip_session (&cfile, ¤t)) {
648 graph_segment_list_get(g);
650 /* display_text(g); */
651 graph_init_sequence(g);
655 static void tcp_graph_cb (GtkWidget *w _U_, gpointer data, guint callback_action /*graph_type*/ _U_)
657 struct segment current;
660 guint graph_type = GPOINTER_TO_INT(data);
662 debug(DBS_FENTRY) puts ("tcp_graph_cb()");
664 if (! (g = graph_new()))
668 graph_initialize_values (g);
670 g->type = graph_type;
671 if (!select_tcpip_session (&cfile, ¤t)) {
675 graph_segment_list_get(g);
677 /* display_text(g); */
678 graph_init_sequence(g);
681 static void create_gui (struct graph *g)
683 debug(DBS_FENTRY) puts ("create_gui()");
684 /* create_text_widget(g); */
685 control_panel_create (g);
686 create_drawing_area(g);
691 static void create_drawing_area (struct graph *g)
693 #if GTK_CHECK_VERSION(3,0,0)
694 GtkStyleContext *context;
696 GdkColormap *colormap;
699 char window_title[WINDOW_TITLE_LENGTH];
700 struct segment current;
701 struct tcpheader *thdr;
702 GtkAllocation widget_alloc;
704 /* Prep. to include the controls in the graph window */
709 debug(DBS_FENTRY) puts ("create_drawing_area()");
710 thdr=select_tcpip_session (&cfile, ¤t);
711 g_snprintf (window_title, WINDOW_TITLE_LENGTH, "TCP Graph %d: %s %s:%d -> %s:%d",
713 cf_get_display_name(&cfile),
714 ep_address_to_str(&(thdr->ip_src)),
716 ep_address_to_str(&(thdr->ip_dst)),
719 g->toplevel = dlg_window_new ("Tcp Graph");
720 gtk_window_set_title(GTK_WINDOW(g->toplevel), window_title);
721 gtk_widget_set_name (g->toplevel, "Test Graph");
722 g_object_set_data(G_OBJECT(g->toplevel), "graph", g);
724 /* Create the drawing area */
725 g->drawing_area = gtk_drawing_area_new ();
726 g_object_set_data(G_OBJECT(g->drawing_area), "graph", g);
727 g->x_axis->drawing_area = g->y_axis->drawing_area = g->drawing_area;
728 gtk_widget_set_size_request (g->drawing_area,
729 g->wp.width + g->wp.x + RMARGIN_WIDTH,
730 g->wp.height + g->wp.y + g->x_axis->s.height);
731 gtk_widget_show (g->drawing_area);
733 g_signal_connect(g->drawing_area, "expose_event", G_CALLBACK(expose_event), NULL);
734 /* this has to be done later, after the widget has been shown */
736 g_signal_connect(g->drawing_area,"configure_event", G_CALLBACK(configure_event),
739 g_signal_connect(g->drawing_area, "motion_notify_event",
740 G_CALLBACK(motion_notify_event), NULL);
741 g_signal_connect(g->drawing_area, "button_press_event",
742 G_CALLBACK(button_press_event), NULL);
743 g_signal_connect(g->drawing_area, "button_release_event",
744 G_CALLBACK(button_release_event), NULL);
745 g_signal_connect(g->drawing_area, "leave_notify_event",
746 G_CALLBACK(leave_notify_event), NULL);
747 g_signal_connect(g->drawing_area, "enter_notify_event",
748 G_CALLBACK(enter_notify_event), NULL);
749 g_signal_connect(g->toplevel, "destroy", G_CALLBACK(callback_toplevel_destroy), g);
750 /* why doesn't drawing area send key_press_signals? */
751 g_signal_connect(g->toplevel, "key_press_event", G_CALLBACK(key_press_event), NULL);
752 g_signal_connect(g->toplevel, "key_release_event", G_CALLBACK(key_release_event),
754 gtk_widget_set_events(g->toplevel,
755 GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK);
757 gtk_widget_set_events (g->drawing_area,
759 | GDK_LEAVE_NOTIFY_MASK
760 | GDK_ENTER_NOTIFY_MASK
761 | GDK_BUTTON_PRESS_MASK
762 | GDK_BUTTON_RELEASE_MASK
763 | GDK_POINTER_MOTION_MASK
764 | GDK_POINTER_MOTION_HINT_MASK);
767 /* Prep. to include the controls in the graph window */
769 vbox = gtk_vbox_new (FALSE, 0);
770 gtk_container_add (GTK_CONTAINER (g->toplevel), vbox);
771 gtk_container_set_border_width (GTK_CONTAINER (g->toplevel), 5);
772 gtk_widget_show (vbox);
774 frame = gtk_frame_new (NULL);
775 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
776 gtk_container_add (GTK_CONTAINER (frame), g->drawing_area);
777 gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
778 gtk_widget_show (frame);
781 /*gtk_box_pack_start (GTK_BOX (vbox), g->gui.control_panel, FALSE, FALSE, 0);*/
783 hbox=gtk_hbox_new(FALSE, 3);
784 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
785 gtk_container_set_border_width(GTK_CONTAINER(hbox), 3);
786 gtk_box_set_child_packing(GTK_BOX(vbox), hbox, FALSE, FALSE, 0, GTK_PACK_START);
787 gtk_widget_show(hbox);
789 create_ctrl_area(g, hbox);
793 gtk_container_add (GTK_CONTAINER (g->toplevel), g->drawing_area);
794 gtk_widget_show (g->toplevel);
796 /* in case we didn't get what we asked for */
797 gtk_widget_get_allocation(GTK_WIDGET (g->drawing_area), &widget_alloc);
798 g->wp.width = widget_alloc.width - g->wp.x - RMARGIN_WIDTH;
799 g->wp.height = widget_alloc.height - g->wp.y - g->x_axis->s.height;
801 #if GTK_CHECK_VERSION(3,0,0)
802 context = gtk_widget_get_style_context (g->drawing_area);
803 gtk_style_context_get (context, GTK_STATE_NORMAL,
807 g->font = gtk_widget_get_style(g->drawing_area)->font_desc;
809 #if GTK_CHECK_VERSION(3,0,0)
811 colormap = gtk_widget_get_colormap(GTK_WIDGET(g->drawing_area));
813 xor_gc = gdk_gc_new (gtk_widget_get_window(g->drawing_area));
814 gdk_gc_set_function (xor_gc, GDK_XOR);
815 if (!gdk_color_parse ("gray15", &color)) {
817 * XXX - do more than just warn.
819 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
820 "Could not parse color gray15.");
822 if (!gdk_colormap_alloc_color (colormap, &color, FALSE, TRUE)) {
824 * XXX - do more than just warn.
826 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
827 "Could not allocate color gray15.");
829 gdk_gc_set_foreground (xor_gc, &color);
831 g->fg_gc = gdk_gc_new (gtk_widget_get_window(g->drawing_area));
833 /* this is probably quite an ugly way to get rid of the first configure
835 * immediatelly after gtk_widget_show (window) drawing_area gets a configure
836 * event which is handled during the next return to gtk_main which is
837 * probably the gdk_gc_new() call. configure handler calls
838 * graph_element_lists_make() which is not good because the graph struct is
839 * not fully set up yet - namely we're not sure about actual geometry
840 * and we don't have the GC's at all. so we just postpone installation
841 * of configure handler until we're ready to deal with it.
843 * !!! NEMLLO BY TO BYT NA KONCI graph_init_sequence()? !!!
847 g_signal_connect(g->drawing_area, "configure_event", G_CALLBACK(configure_event),
850 /* puts ("exiting create_drawing_area()"); */
853 static void callback_toplevel_destroy (GtkWidget *widget _U_, gpointer data)
855 struct graph *g = (struct graph * )data;
857 if (!(g->flags & GRAPH_DESTROYED)) {
858 g->flags |= GRAPH_DESTROYED;
859 graph_destroy ((struct graph * )data);
863 static void control_panel_create (struct graph *g)
865 GtkWidget *toplevel, *notebook;
867 GtkWidget *help_bt, *close_bt, *bbox;
868 char window_title[WINDOW_TITLE_LENGTH];
870 debug(DBS_FENTRY) puts ("control_panel_create()");
872 notebook = gtk_notebook_new ();
873 control_panel_add_zoom_page (g, notebook);
874 control_panel_add_magnify_page (g, notebook);
875 control_panel_add_origin_page (g, notebook);
876 control_panel_add_cross_page (g, notebook);
877 control_panel_add_graph_type_page (g, notebook);
879 g_snprintf (window_title, WINDOW_TITLE_LENGTH,
880 "Graph %d - Control - Wireshark", refnum);
881 toplevel = dlg_window_new ("tcp-graph-control");
882 gtk_window_set_title(GTK_WINDOW(toplevel), window_title);
884 table = gtk_table_new (2, 1, FALSE);
885 gtk_container_add (GTK_CONTAINER (toplevel), table);
887 gtk_table_attach (GTK_TABLE (table), notebook, 0, 1, 0, 1,
888 GTK_FILL|GTK_EXPAND, GTK_FILL, 5, 5);
891 bbox = dlg_button_row_new(GTK_STOCK_HELP, GTK_STOCK_CLOSE, NULL);
892 gtk_table_attach (GTK_TABLE (table), bbox, 0, 1, 1, 2,
893 GTK_FILL|GTK_EXPAND, GTK_FILL, 5, 5);
895 help_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
896 g_signal_connect(help_bt, "clicked", G_CALLBACK(callback_create_help), g);
898 close_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
899 window_set_cancel_button(toplevel, close_bt, NULL);
900 g_signal_connect(close_bt, "clicked", G_CALLBACK(callback_close), g);
902 g_signal_connect(toplevel, "delete_event", G_CALLBACK(callback_delete_event), g);
903 g_signal_connect(toplevel, "destroy", G_CALLBACK(callback_toplevel_destroy), g);
905 /* gtk_widget_show_all (table); */
906 /* g->gui.control_panel = table; */
907 gtk_widget_show_all (toplevel);
908 window_present(toplevel);
910 g->gui.control_panel = toplevel;
913 static void control_panel_add_zoom_page (struct graph *g, GtkWidget *n)
915 GtkWidget *zoom_frame;
916 GtkWidget *zoom_lock_frame;
920 zoom_frame = control_panel_create_zoom_group (g);
921 gtk_container_set_border_width (GTK_CONTAINER (zoom_frame), 5);
922 zoom_lock_frame = control_panel_create_zoomlock_group (g);
923 gtk_container_set_border_width (GTK_CONTAINER (zoom_lock_frame), 5);
924 box = gtk_vbox_new (FALSE, 0);
925 gtk_box_pack_start (GTK_BOX (box), zoom_frame, TRUE, TRUE, 0);
926 gtk_box_pack_start (GTK_BOX (box), zoom_lock_frame, TRUE, TRUE, 0);
927 gtk_widget_show (box);
928 label = gtk_label_new ("Zoom");
929 gtk_notebook_append_page (GTK_NOTEBOOK (n), box, label);
932 static void control_panel_add_magnify_page (struct graph *g, GtkWidget *n)
934 GtkWidget *mag_frame, *label;
936 mag_frame = control_panel_create_magnify_group (g);
937 gtk_container_set_border_width (GTK_CONTAINER (mag_frame), 5);
938 label = gtk_label_new ("Magnify");
939 gtk_notebook_append_page (GTK_NOTEBOOK (n), mag_frame, label);
942 static void control_panel_add_origin_page (struct graph *g, GtkWidget *n)
944 GtkWidget *time_orig_cap, *time_orig_conn, *time_orig_box, *time_orig_frame;
945 GtkWidget *seq_orig_isn, *seq_orig_zero, *seq_orig_box, *seq_orig_frame;
946 GtkWidget *box, *label;
948 /* time origin box */
950 gtk_radio_button_new_with_label (NULL, "beginning of capture");
951 time_orig_conn = gtk_radio_button_new_with_label (
952 gtk_radio_button_get_group (GTK_RADIO_BUTTON (time_orig_cap)),
953 "beginning of this TCP connection");
954 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (time_orig_conn), TRUE);
955 time_orig_box = gtk_vbox_new (TRUE, 0);
956 gtk_box_pack_start (GTK_BOX (time_orig_box), time_orig_conn, TRUE, TRUE, 0);
957 gtk_box_pack_start (GTK_BOX (time_orig_box), time_orig_cap, TRUE, TRUE, 0);
958 time_orig_frame = gtk_frame_new ("Time origin");
959 gtk_container_set_border_width (GTK_CONTAINER (time_orig_frame), 5);
960 gtk_container_add (GTK_CONTAINER (time_orig_frame), time_orig_box);
962 /* sequence number origin group */
964 gtk_radio_button_new_with_label (NULL, "initial sequence number");
965 seq_orig_zero = gtk_radio_button_new_with_label (gtk_radio_button_get_group (
966 GTK_RADIO_BUTTON (seq_orig_isn)), "0 (=absolute)");
967 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (seq_orig_isn), TRUE);
968 seq_orig_box = gtk_vbox_new (TRUE, 0);
969 gtk_box_pack_start (GTK_BOX (seq_orig_box), seq_orig_isn, TRUE, TRUE, 0);
970 gtk_box_pack_start (GTK_BOX (seq_orig_box), seq_orig_zero, TRUE, TRUE, 0);
971 seq_orig_frame = gtk_frame_new ("Sequence number origin");
972 gtk_container_set_border_width (GTK_CONTAINER (seq_orig_frame), 5);
973 gtk_container_add (GTK_CONTAINER (seq_orig_frame), seq_orig_box);
975 g->gui.time_orig_conn = (GtkToggleButton * )time_orig_conn;
976 g->gui.seq_orig_isn = (GtkToggleButton * )seq_orig_isn;
978 g_signal_connect(time_orig_conn, "toggled", G_CALLBACK(callback_time_origin), g);
979 g_signal_connect(seq_orig_isn, "toggled", G_CALLBACK(callback_seq_origin), g);
981 box = gtk_vbox_new (FALSE, 0);
982 gtk_container_set_border_width (GTK_CONTAINER (box), 5);
983 gtk_box_pack_start (GTK_BOX (box), time_orig_frame, TRUE, TRUE, 0);
984 gtk_box_pack_start (GTK_BOX (box), seq_orig_frame, TRUE, TRUE, 0);
985 gtk_widget_show (box);
986 label = gtk_label_new ("Origin");
987 gtk_notebook_append_page (GTK_NOTEBOOK (n), box, label);
990 static void control_panel_add_cross_page (struct graph *g, GtkWidget *n)
992 GtkWidget *cross_frame, *label;
994 cross_frame = control_panel_create_cross_group (g);
995 gtk_container_set_border_width (GTK_CONTAINER (cross_frame), 5);
996 label = gtk_label_new ("Cross");
997 gtk_notebook_append_page (GTK_NOTEBOOK (n), cross_frame, label);
1000 static void control_panel_add_graph_type_page (struct graph *g, GtkWidget *n)
1002 GtkWidget *frame, *label;
1004 frame = control_panel_create_graph_type_group (g);
1005 gtk_container_set_border_width (GTK_CONTAINER (frame), 5);
1006 label = gtk_label_new ("Graph type");
1007 gtk_notebook_append_page (GTK_NOTEBOOK (n), frame, label);
1010 /* Treat this as a cancel, by calling "callback_close()" */
1012 callback_delete_event(GtkWidget *widget _U_, GdkEvent *event _U_,
1015 callback_close(NULL, data);
1019 static void callback_close (GtkWidget *widget _U_, gpointer data)
1021 struct graph *g = (struct graph * )data;
1023 if (!(g->flags & GRAPH_DESTROYED)) {
1024 g->flags |= GRAPH_DESTROYED;
1025 graph_destroy ((struct graph * )data);
1029 static void callback_create_help(GtkWidget *widget _U_, gpointer data _U_)
1031 GtkWidget *toplevel, *vbox, *text, *scroll, *bbox, *close_bt;
1034 toplevel = dlg_window_new ("Help for TCP graphing");
1035 gtk_window_set_default_size(GTK_WINDOW(toplevel), 500, 400);
1037 vbox = gtk_vbox_new (FALSE, 3);
1038 gtk_container_set_border_width(GTK_CONTAINER(vbox), 12);
1039 gtk_container_add (GTK_CONTAINER (toplevel), vbox);
1041 scroll = scrolled_window_new (NULL, NULL);
1042 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll),
1044 gtk_box_pack_start (GTK_BOX (vbox), scroll, TRUE, TRUE, 0);
1045 text = gtk_text_view_new();
1046 gtk_text_view_set_editable(GTK_TEXT_VIEW(text), FALSE);
1047 buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text));
1048 gtk_text_buffer_set_text(buf, helptext, -1);
1049 gtk_container_add (GTK_CONTAINER (scroll), text);
1052 bbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL);
1053 gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
1054 gtk_widget_show(bbox);
1056 close_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
1057 window_set_cancel_button(toplevel, close_bt, window_cancel_button_cb);
1059 g_signal_connect(toplevel, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
1061 gtk_widget_show_all (toplevel);
1062 window_present(toplevel);
1065 static void callback_time_origin (GtkWidget *toggle _U_, gpointer data)
1067 toggle_time_origin ((struct graph * )data);
1070 static void callback_seq_origin (GtkWidget *toggle _U_, gpointer data)
1072 toggle_seq_origin ((struct graph * )data);
1075 static GtkWidget *control_panel_create_zoom_group (struct graph *g)
1077 GtkWidget *zoom_in, *zoom_out, *zoom_box, *zoom_frame;
1078 GtkAdjustment *zoom_h_adj, *zoom_v_adj;
1079 GtkWidget *zoom_inout_box, *zoom_h_step_label, *zoom_h_step;
1080 GtkWidget *zoom_v_step_label, *zoom_v_step;
1081 GtkWidget *zoom_separator1, *zoom_separator2, *zoom_step_table, *zoom_table;
1082 GtkWidget *zoom_ratio_toggle, *zoom_same_toggle;
1083 GtkWidget *zoom_h_entry, *zoom_v_entry;
1084 GtkWidget *zoom_h_label, *zoom_v_label;
1086 zoom_in = gtk_radio_button_new_with_label (NULL, "in");
1087 zoom_out = gtk_radio_button_new_with_label (
1088 gtk_radio_button_get_group (GTK_RADIO_BUTTON (zoom_in)), "out");
1089 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (zoom_in), TRUE);
1090 zoom_inout_box = gtk_hbox_new (FALSE, 0);
1091 gtk_box_pack_start (GTK_BOX (zoom_inout_box), zoom_in, FALSE, FALSE, 10);
1092 gtk_box_pack_start (GTK_BOX (zoom_inout_box), zoom_out, FALSE, FALSE, 0);
1094 zoom_separator1 = gtk_hseparator_new ();
1096 zoom_h_entry = gtk_entry_new ();
1097 gtk_entry_set_text (GTK_ENTRY (zoom_h_entry), "1.000");
1098 gtk_editable_set_editable (GTK_EDITABLE (zoom_h_entry), FALSE);
1099 zoom_h_label = gtk_label_new ("Horizontal:");
1101 zoom_v_entry = gtk_entry_new ();
1102 gtk_entry_set_text (GTK_ENTRY (zoom_v_entry), "1.000");
1103 gtk_editable_set_editable (GTK_EDITABLE (zoom_v_entry), FALSE);
1104 zoom_v_label = gtk_label_new ("Vertical:");
1106 g->zoom.widget.h_zoom = (GtkEntry * )zoom_h_entry;
1107 g->zoom.widget.v_zoom = (GtkEntry * )zoom_v_entry;
1109 zoom_table = gtk_table_new (2, 2, FALSE);
1110 gtk_table_attach (GTK_TABLE (zoom_table), zoom_h_label, 0,1,0,1,
1111 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1112 gtk_table_attach (GTK_TABLE (zoom_table), zoom_h_entry, 1, 2, 0, 1,
1113 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1114 gtk_table_attach (GTK_TABLE (zoom_table), zoom_v_label, 0,1,1,2,
1115 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1116 gtk_table_attach (GTK_TABLE (zoom_table), zoom_v_entry, 1, 2, 1, 2,
1117 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1119 zoom_separator2 = gtk_hseparator_new ();
1121 zoom_h_adj = (GtkAdjustment * )gtk_adjustment_new ((gfloat)1.2, 1.0, 5, (gfloat)0.1, 1, 0);
1122 zoom_h_step = gtk_spin_button_new (zoom_h_adj, 0, 1);
1123 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (zoom_h_step), TRUE);
1124 zoom_h_step_label = gtk_label_new ("Horizontal step:");
1126 zoom_v_adj = (GtkAdjustment * )gtk_adjustment_new ((gfloat)1.2, 1.0, 5, (gfloat)0.1, 1, 0);
1127 zoom_v_step = gtk_spin_button_new (zoom_v_adj, 0, 1);
1128 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (zoom_v_step), TRUE);
1129 zoom_v_step_label = gtk_label_new ("Vertical step:");
1131 g->zoom.widget.h_step = (GtkSpinButton * )zoom_h_step;
1132 g->zoom.widget.v_step = (GtkSpinButton * )zoom_v_step;
1134 zoom_same_toggle = gtk_check_button_new_with_label("Keep them the same");
1135 zoom_ratio_toggle = gtk_check_button_new_with_label("Preserve their ratio");
1136 g_object_set_data(G_OBJECT(zoom_same_toggle), "flag", (gpointer)ZOOM_STEPS_SAME);
1137 g_object_set_data(G_OBJECT(zoom_ratio_toggle), "flag",
1138 (gpointer)ZOOM_STEPS_KEEP_RATIO);
1139 g_signal_connect(zoom_same_toggle, "clicked", G_CALLBACK(callback_zoom_flags), g);
1140 g_signal_connect(zoom_ratio_toggle, "clicked", G_CALLBACK(callback_zoom_flags), g);
1142 zoom_step_table = gtk_table_new (4, 2, FALSE);
1143 gtk_table_attach (GTK_TABLE (zoom_step_table), zoom_h_step_label, 0,1,0,1,
1144 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1145 gtk_table_attach (GTK_TABLE (zoom_step_table), zoom_h_step, 1, 2, 0, 1,
1146 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1147 gtk_table_attach (GTK_TABLE (zoom_step_table), zoom_v_step_label, 0,1,1,2,
1148 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1149 gtk_table_attach (GTK_TABLE (zoom_step_table), zoom_v_step, 1, 2, 1, 2,
1150 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1151 gtk_table_attach (GTK_TABLE (zoom_step_table), zoom_same_toggle, 0,2,2,3,
1152 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1153 gtk_table_attach (GTK_TABLE (zoom_step_table), zoom_ratio_toggle, 0,2,3,4,
1154 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1156 zoom_box = gtk_vbox_new (FALSE, 0);
1157 gtk_box_pack_start (GTK_BOX (zoom_box), zoom_inout_box, TRUE, TRUE, 0);
1158 gtk_box_pack_start (GTK_BOX (zoom_box), zoom_separator1, TRUE, TRUE, 0);
1159 gtk_box_pack_start (GTK_BOX (zoom_box), zoom_table, TRUE, TRUE, 0);
1160 gtk_box_pack_start (GTK_BOX (zoom_box), zoom_separator2, TRUE, TRUE, 0);
1161 gtk_box_pack_start (GTK_BOX (zoom_box), zoom_step_table, TRUE, TRUE, 0);
1162 zoom_frame = gtk_frame_new ("Zoom");
1163 gtk_container_add (GTK_CONTAINER (zoom_frame), zoom_box);
1165 g_object_set_data(G_OBJECT(zoom_h_step), "direction", GINT_TO_POINTER(0));
1166 g_object_set_data(G_OBJECT(zoom_v_step), "direction", GINT_TO_POINTER(1));
1168 g_signal_connect(zoom_in, "toggled", G_CALLBACK(callback_zoom_inout), g);
1169 g_signal_connect(zoom_h_step, "changed", G_CALLBACK(callback_zoom_step), g);
1170 g_signal_connect(zoom_v_step, "changed", G_CALLBACK(callback_zoom_step), g);
1172 g->zoom.widget.in_toggle = (GtkToggleButton * )zoom_in;
1173 g->zoom.widget.out_toggle = (GtkToggleButton * )zoom_out;
1177 static void callback_zoom_inout (GtkWidget *toggle, gpointer data)
1179 struct graph *g = (struct graph * )data;
1181 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (toggle)))
1182 g->zoom.flags &= ~ZOOM_OUT;
1184 g->zoom.flags |= ZOOM_OUT;
1187 static void callback_zoom_step (GtkWidget *spin, gpointer data)
1189 struct graph *g = (struct graph * )data;
1192 double *zoom_this, *zoom_other;
1193 GtkSpinButton *widget_this, *widget_other;
1196 direction = (long)g_object_get_data(G_OBJECT(spin), "direction");
1197 value = gtk_spin_button_get_value (GTK_SPIN_BUTTON (spin));
1200 zoom_this = &g->zoom.step_y;
1201 zoom_other = &g->zoom.step_x;
1202 widget_this = g->zoom.widget.v_step;
1203 widget_other = g->zoom.widget.h_step;
1205 zoom_this = &g->zoom.step_x;
1206 zoom_other = &g->zoom.step_y;
1207 widget_this = g->zoom.widget.h_step;
1208 widget_other = g->zoom.widget.v_step;
1211 old_this = *zoom_this;
1213 if (g->zoom.flags & ZOOM_STEPS_SAME) {
1214 *zoom_other = value;
1215 gtk_spin_button_set_value (widget_other, (gfloat) *zoom_other);
1216 } else if (g->zoom.flags & ZOOM_STEPS_KEEP_RATIO) {
1217 double old_other = *zoom_other;
1218 *zoom_other *= value / old_this;
1219 if (*zoom_other < 1.0) {
1221 *zoom_this = old_this * 1.0 / old_other;
1222 gtk_spin_button_set_value (widget_this, (gfloat) *zoom_this);
1223 } else if (*zoom_other > 5.0) {
1225 *zoom_this = old_this * 5.0 / old_other;
1226 gtk_spin_button_set_value (widget_this, (gfloat) *zoom_this);
1228 gtk_spin_button_set_value (widget_other, (gfloat) *zoom_other);
1232 static void callback_zoom_flags (GtkWidget *toggle, gpointer data)
1234 struct graph *g = (struct graph * )data;
1235 int flag = (long)g_object_get_data(G_OBJECT(toggle), "flag");
1237 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (toggle)))
1238 g->zoom.flags |= flag;
1240 g->zoom.flags &= ~flag;
1243 static void update_zoom_spins (struct graph *g)
1247 g_snprintf (s, sizeof(s), "%.3f", g->zoom.x / g->zoom.initial.x);
1248 gtk_entry_set_text (g->zoom.widget.h_zoom, s);
1249 g_snprintf (s, sizeof(s), "%.3f", g->zoom.y / g->zoom.initial.y);
1250 gtk_entry_set_text (g->zoom.widget.v_zoom, s);
1253 static GtkWidget *control_panel_create_magnify_group (struct graph *g)
1255 GtkWidget *mag_width_label, *mag_width;
1256 GtkWidget *mag_height_label, *mag_height;
1257 GtkWidget *mag_x_label, *mag_x;
1258 GtkWidget *mag_y_label, *mag_y;
1259 GtkWidget *mag_wh_table, *mag_zoom_frame, *mag_zoom_table;
1260 GtkWidget *mag_h_zoom_label, *mag_h_zoom;
1261 GtkWidget *mag_v_zoom_label, *mag_v_zoom;
1262 GtkWidget *mag_zoom_same, *mag_zoom_ratio;
1263 GtkAdjustment *mag_width_adj, *mag_height_adj, *mag_x_adj, *mag_y_adj;
1264 GtkAdjustment *mag_h_zoom_adj, *mag_v_zoom_adj;
1265 GtkWidget *mag_box, *mag_frame;
1267 mag_width_label = gtk_label_new ("Width:");
1268 mag_width_adj = (GtkAdjustment * )gtk_adjustment_new (250,100,600,1,10,0);
1269 mag_width = gtk_spin_button_new (mag_width_adj, 0, 0);
1271 mag_height_label = gtk_label_new ("Height:");
1272 mag_height_adj = (GtkAdjustment * )gtk_adjustment_new (250,100,600,1,10,0);
1273 mag_height = gtk_spin_button_new (mag_height_adj, 0, 0);
1275 mag_x_label = gtk_label_new ("X:");
1276 mag_x_adj = (GtkAdjustment * )gtk_adjustment_new (0,-1000,1000,1,10,0);
1277 mag_x = gtk_spin_button_new (mag_x_adj, 0, 0);
1279 mag_y_label = gtk_label_new ("Y:");
1280 mag_y_adj = (GtkAdjustment * )gtk_adjustment_new (0,-1000,1000,1,10,0);
1281 mag_y = gtk_spin_button_new (mag_y_adj, 0, 0);
1283 mag_wh_table = gtk_table_new (4, 2, FALSE);
1284 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_width_label, 0,1,0,1,
1285 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1286 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_width, 1,2,0,1,
1287 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1288 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_height_label, 0,1,1,2,
1289 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1290 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_height, 1,2,1,2,
1291 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1292 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_x_label, 0,1,2,3,
1293 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1294 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_x, 1,2,2,3,
1295 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1296 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_y_label, 0,1,3,4,
1297 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1298 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_y, 1,2,3,4,
1299 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1301 mag_h_zoom_label = gtk_label_new ("Horizontal:");
1302 mag_h_zoom_adj = (GtkAdjustment *)gtk_adjustment_new(10.0, 1.0, 25.0, (gfloat)0.1, 1, 0);
1303 mag_h_zoom = gtk_spin_button_new (mag_h_zoom_adj, 0, 1);
1305 mag_v_zoom_label = gtk_label_new ("Vertical:");
1306 mag_v_zoom_adj = (GtkAdjustment *)gtk_adjustment_new(10.0, 1.0, 25.0, (gfloat)0.1, 1, 0);
1307 mag_v_zoom = gtk_spin_button_new (mag_v_zoom_adj, 0, 1);
1309 mag_zoom_same = gtk_check_button_new_with_label ("Keep them the same");
1310 mag_zoom_ratio = gtk_check_button_new_with_label("Preserve their ratio");
1312 mag_zoom_table = gtk_table_new (4, 2, FALSE);
1313 gtk_table_attach (GTK_TABLE (mag_zoom_table), mag_h_zoom_label, 0,1,0,1,
1314 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
1315 gtk_table_attach (GTK_TABLE (mag_zoom_table), mag_h_zoom, 1,2,0,1,
1316 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
1317 gtk_table_attach (GTK_TABLE (mag_zoom_table), mag_v_zoom_label, 0,1,1,2,
1318 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
1319 gtk_table_attach (GTK_TABLE (mag_zoom_table), mag_v_zoom, 1,2,1,2,
1320 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
1321 gtk_table_attach (GTK_TABLE (mag_zoom_table), mag_zoom_same, 0,2,2,3,
1322 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
1323 gtk_table_attach (GTK_TABLE (mag_zoom_table), mag_zoom_ratio, 0,2,3,4,
1324 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
1326 mag_zoom_frame = gtk_frame_new ("Magnify zoom");
1327 gtk_container_add (GTK_CONTAINER (mag_zoom_frame), mag_zoom_table);
1328 gtk_container_set_border_width (GTK_CONTAINER (mag_zoom_frame), 3);
1330 mag_box = gtk_vbox_new (FALSE, 0);
1331 gtk_box_pack_start (GTK_BOX (mag_box), mag_wh_table, TRUE, TRUE, 0);
1332 gtk_box_pack_start (GTK_BOX (mag_box), mag_zoom_frame, TRUE, TRUE, 0);
1333 mag_frame = gtk_frame_new ("Magnify");
1334 gtk_container_add (GTK_CONTAINER (mag_frame), mag_box);
1336 g->magnify.widget.h_zoom = (GtkSpinButton * )mag_h_zoom;
1337 g->magnify.widget.v_zoom = (GtkSpinButton * )mag_v_zoom;
1338 g_object_set_data(G_OBJECT(mag_h_zoom), "direction", GINT_TO_POINTER(0));
1339 g_object_set_data(G_OBJECT(mag_v_zoom), "direction", GINT_TO_POINTER(1));
1340 g_object_set_data(G_OBJECT(mag_zoom_same), "flag", (gpointer)MAGZOOMS_SAME);
1341 g_object_set_data(G_OBJECT(mag_zoom_ratio), "flag", (gpointer)MAGZOOMS_SAME_RATIO);
1343 g_signal_connect(mag_width, "changed", G_CALLBACK(callback_mag_width), g);
1344 g_signal_connect(mag_height, "changed", G_CALLBACK(callback_mag_height), g);
1345 g_signal_connect(mag_x, "changed", G_CALLBACK(callback_mag_x), g);
1346 g_signal_connect(mag_y, "changed", G_CALLBACK(callback_mag_y), g);
1347 g_signal_connect(mag_h_zoom, "changed", G_CALLBACK(callback_mag_zoom), g);
1348 g_signal_connect(mag_v_zoom, "changed", G_CALLBACK(callback_mag_zoom), g);
1349 g_signal_connect(mag_zoom_same, "clicked", G_CALLBACK(callback_mag_flags), g);
1350 g_signal_connect(mag_zoom_ratio, "clicked", G_CALLBACK(callback_mag_flags), g);
1355 static void callback_mag_width (GtkWidget *spin, gpointer data)
1357 struct graph *g = (struct graph * )data;
1359 g->magnify.width = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(spin));
1362 static void callback_mag_height (GtkWidget *spin, gpointer data)
1364 struct graph *g = (struct graph * )data;
1366 g->magnify.height = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
1369 static void callback_mag_x (GtkWidget *spin, gpointer data)
1371 struct graph *g = (struct graph * )data;
1373 g->magnify.offset.x=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
1376 static void callback_mag_y (GtkWidget *spin, gpointer data)
1378 struct graph *g = (struct graph * )data;
1380 g->magnify.offset.y=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
1383 static void callback_mag_zoom (GtkWidget *spin, gpointer data)
1385 struct graph *g = (struct graph * )data;
1388 double *zoom_this, *zoom_other;
1389 GtkSpinButton *widget_this, *widget_other;
1392 if (g->magnify.flags & MAGZOOMS_IGNORE) {
1393 printf ("refusing callback for %s zoom widget.\n", (GtkSpinButton * )spin==g->magnify.widget.h_zoom ? "horizontal" : "vertical");
1394 g->magnify.flags &= ~MAGZOOMS_IGNORE;
1397 direction = (long)g_object_get_data(G_OBJECT(spin), "direction");
1398 value = gtk_spin_button_get_value (GTK_SPIN_BUTTON (spin));
1401 zoom_this = &g->magnify.zoom.y;
1402 zoom_other = &g->magnify.zoom.x;
1403 widget_this = g->magnify.widget.v_zoom;
1404 widget_other = g->magnify.widget.h_zoom;
1406 zoom_this = &g->magnify.zoom.x;
1407 zoom_other = &g->magnify.zoom.y;
1408 widget_this = g->magnify.widget.h_zoom;
1409 widget_other = g->magnify.widget.v_zoom;
1412 old_this = *zoom_this;
1414 if (g->magnify.flags & MAGZOOMS_SAME) {
1415 *zoom_other = value;
1416 /* g->magnify.flags |= MAGZOOMS_IGNORE; */
1417 gtk_spin_button_set_value (widget_other, (gfloat) *zoom_other);
1418 } else if (g->magnify.flags & MAGZOOMS_SAME_RATIO) {
1419 double old_other = *zoom_other;
1420 *zoom_other *= value / old_this;
1421 if (*zoom_other < 1.0) {
1423 *zoom_this = old_this * 1.0 / old_other;
1424 /* g->magnify.flags |= MAGZOOMS_IGNORE; */
1425 gtk_spin_button_set_value (widget_this, (gfloat) *zoom_this);
1426 } else if (*zoom_other > 25.0) {
1428 *zoom_this = old_this * 25.0 / old_other;
1429 /* g->magnify.flags |= MAGZOOMS_IGNORE; */
1430 gtk_spin_button_set_value (widget_this, (gfloat) *zoom_this);
1432 /* g->magnify.flags |= MAGZOOMS_IGNORE; */
1433 gtk_spin_button_set_value (widget_other, (gfloat) *zoom_other);
1437 static void callback_mag_flags (GtkWidget *toggle, gpointer data)
1439 struct graph *g = (struct graph * )data;
1440 int flag = (long)g_object_get_data(G_OBJECT(toggle), "flag");
1442 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (toggle)))
1443 g->magnify.flags |= flag;
1445 g->magnify.flags &= ~flag;
1448 static GtkWidget *control_panel_create_zoomlock_group (struct graph *g)
1450 GtkWidget *zoom_lock_h, *zoom_lock_v, *zoom_lock_none, *zoom_lock_box;
1451 GtkWidget *zoom_lock_frame;
1453 zoom_lock_none = gtk_radio_button_new_with_label (NULL, "none");
1454 zoom_lock_h = gtk_radio_button_new_with_label (
1455 gtk_radio_button_get_group (GTK_RADIO_BUTTON (zoom_lock_none)),
1457 zoom_lock_v = gtk_radio_button_new_with_label (
1458 gtk_radio_button_get_group (GTK_RADIO_BUTTON (zoom_lock_none)),
1460 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (zoom_lock_none), TRUE);
1461 zoom_lock_box = gtk_hbox_new (FALSE, 0);
1462 gtk_box_pack_start(GTK_BOX(zoom_lock_box), zoom_lock_none,
1464 gtk_box_pack_start(GTK_BOX(zoom_lock_box), zoom_lock_h, TRUE, TRUE, 0);
1465 gtk_box_pack_start(GTK_BOX(zoom_lock_box), zoom_lock_v, TRUE, TRUE, 0);
1466 zoom_lock_frame = gtk_frame_new ("Zoom lock:");
1467 gtk_container_add (GTK_CONTAINER (zoom_lock_frame), zoom_lock_box);
1469 g_signal_connect(zoom_lock_h, "toggled", G_CALLBACK(callback_zoomlock_h), g);
1470 g_signal_connect(zoom_lock_v, "toggled", G_CALLBACK(callback_zoomlock_v), g);
1472 return zoom_lock_frame;
1475 static void callback_zoomlock_h (GtkWidget *toggle, gpointer data)
1477 struct graph *g = (struct graph * )data;
1479 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (toggle)))
1480 g->zoom.flags |= ZOOM_HLOCK;
1482 g->zoom.flags &= ~ZOOM_HLOCK;
1485 static void callback_zoomlock_v (GtkWidget *toggle, gpointer data)
1487 struct graph *g = (struct graph * )data;
1489 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (toggle)))
1490 g->zoom.flags |= ZOOM_VLOCK;
1492 g->zoom.flags &= ~ZOOM_VLOCK;
1495 static GtkWidget *control_panel_create_cross_group (struct graph *g)
1497 GtkWidget *on, *off, *box, *frame, *vbox, *label;
1499 label = gtk_label_new ("Crosshairs:");
1500 off = gtk_radio_button_new_with_label (NULL, "off");
1501 on = gtk_radio_button_new_with_label (
1502 gtk_radio_button_get_group (GTK_RADIO_BUTTON (off)), "on");
1503 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (off), TRUE);
1504 box = gtk_hbox_new (FALSE, 0);
1505 gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 10);
1506 gtk_box_pack_start (GTK_BOX (box), off, FALSE, FALSE, 10);
1507 gtk_box_pack_start (GTK_BOX (box), on, FALSE, FALSE, 0);
1508 vbox = gtk_vbox_new (FALSE, 0);
1509 gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, FALSE, 15);
1510 /* frame = gtk_frame_new ("Cross:"); */
1511 frame = gtk_frame_new (NULL);
1512 gtk_container_add (GTK_CONTAINER (frame), vbox);
1514 g_signal_connect(on, "toggled", G_CALLBACK(callback_cross_on_off), g);
1516 g->cross.on_toggle = (GtkToggleButton * )on;
1517 g->cross.off_toggle = (GtkToggleButton * )off;
1522 static void callback_cross_on_off (GtkWidget *toggle, gpointer data)
1524 struct graph *g = (struct graph * )data;
1526 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (toggle))) {
1528 g->cross.draw = TRUE;
1529 gdk_window_get_pointer (gtk_widget_get_window(g->drawing_area), &x, &y, 0);
1530 cross_draw (g, x, y);
1532 g->cross.draw = FALSE;
1537 static GtkWidget *control_panel_create_graph_type_group (struct graph *g)
1539 GtkWidget *graph_tseqttrace, *graph_tseqstevens;
1540 GtkWidget *graph_tput, *graph_rtt, *graph_sep, *graph_init, *graph_box;
1541 GtkWidget *graph_frame;
1542 GtkWidget *graph_wscale;
1544 graph_tput = gtk_radio_button_new_with_label (NULL, "Throughput");
1545 graph_tseqttrace = gtk_radio_button_new_with_label (
1546 gtk_radio_button_get_group (GTK_RADIO_BUTTON (graph_tput)),
1547 "Time/Sequence (tcptrace-style)");
1548 graph_tseqstevens = gtk_radio_button_new_with_label (
1549 gtk_radio_button_get_group (GTK_RADIO_BUTTON (graph_tput)),
1550 "Time/Sequence (Stevens'-style)");
1551 graph_rtt = gtk_radio_button_new_with_label (
1552 gtk_radio_button_get_group (GTK_RADIO_BUTTON (graph_tput)),
1554 graph_wscale = gtk_radio_button_new_with_label (
1555 gtk_radio_button_get_group (GTK_RADIO_BUTTON (graph_tput)),
1559 case GRAPH_TSEQ_STEVENS:
1560 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(graph_tseqstevens),TRUE);
1562 case GRAPH_TSEQ_TCPTRACE:
1563 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(graph_tseqttrace),TRUE);
1565 case GRAPH_THROUGHPUT:
1566 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (graph_tput), TRUE);
1569 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (graph_rtt), TRUE);
1572 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (graph_wscale), TRUE);
1575 graph_init = gtk_check_button_new_with_label ("Init on change");
1576 graph_sep = gtk_hseparator_new ();
1577 graph_box = gtk_vbox_new (FALSE, 0);
1578 gtk_box_pack_start (GTK_BOX (graph_box), graph_rtt, TRUE, TRUE, 0);
1579 gtk_box_pack_start (GTK_BOX (graph_box), graph_tput, TRUE, TRUE, 0);
1580 gtk_box_pack_start (GTK_BOX (graph_box), graph_tseqstevens, TRUE, TRUE, 0);
1581 gtk_box_pack_start (GTK_BOX (graph_box), graph_tseqttrace, TRUE, TRUE, 0);
1582 gtk_box_pack_start (GTK_BOX (graph_box), graph_wscale, TRUE, TRUE, 0);
1583 gtk_box_pack_start (GTK_BOX (graph_box), graph_sep, TRUE, TRUE, 0);
1584 gtk_box_pack_start (GTK_BOX (graph_box), graph_init, TRUE, TRUE, 0);
1585 graph_frame = gtk_frame_new ("Graph type:");
1586 gtk_container_add (GTK_CONTAINER (graph_frame), graph_box);
1588 g_object_set_data(G_OBJECT(graph_tseqstevens), "new-graph-type",
1589 GINT_TO_POINTER(0));
1590 g_object_set_data(G_OBJECT(graph_tseqttrace), "new-graph-type", GINT_TO_POINTER(1));
1591 g_object_set_data(G_OBJECT(graph_tput), "new-graph-type", GINT_TO_POINTER(2));
1592 g_object_set_data(G_OBJECT(graph_rtt), "new-graph-type", GINT_TO_POINTER(3));
1593 g_object_set_data(G_OBJECT(graph_wscale), "new-graph-type", GINT_TO_POINTER(GRAPH_WSCALE));
1595 g->gt.graph_wscale = (GtkToggleButton *)graph_wscale;
1596 g->gt.graph_rtt = (GtkToggleButton * )graph_rtt;
1597 g->gt.graph_tput = (GtkToggleButton * )graph_tput;
1598 g->gt.graph_tseqstevens = (GtkToggleButton * )graph_tseqstevens;
1599 g->gt.graph_tseqttrace = (GtkToggleButton * )graph_tseqttrace;
1601 g_signal_connect(graph_tseqttrace, "toggled", G_CALLBACK(callback_graph_type), g);
1602 g_signal_connect(graph_tseqstevens, "toggled", G_CALLBACK(callback_graph_type), g);
1603 g_signal_connect(graph_tput, "toggled", G_CALLBACK(callback_graph_type), g);
1604 g_signal_connect(graph_rtt, "toggled", G_CALLBACK(callback_graph_type), g);
1605 g_signal_connect(graph_wscale, "toggled", G_CALLBACK(callback_graph_type), g);
1606 g_signal_connect(graph_init, "toggled", G_CALLBACK(callback_graph_init_on_typechg), g);
1611 static void callback_graph_type (GtkWidget *toggle, gpointer data)
1613 int old_type, new_type;
1614 struct graph *g = (struct graph * )data;
1616 new_type = (long)g_object_get_data(G_OBJECT(toggle),"new-graph-type");
1618 if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (toggle)))
1624 graph_element_lists_free (g);
1625 graph_element_lists_initialize (g);
1627 if (old_type == GRAPH_THROUGHPUT || new_type == GRAPH_THROUGHPUT) {
1628 /* throughput graph uses differently constructed segment list so we
1629 * need to recreate it */
1630 graph_segment_list_free (g);
1631 graph_segment_list_get (g);
1634 if (g->flags & GRAPH_INIT_ON_TYPE_CHANGE) {
1635 g->geom.width = g->wp.width;
1636 g->geom.height = g->wp.height;
1637 g->geom.x = g->wp.x;
1638 g->geom.y = g->wp.y;
1640 g->x_axis->min = g->y_axis->min = 0;
1641 gtk_toggle_button_set_active (g->gui.time_orig_conn, TRUE);
1642 gtk_toggle_button_set_active (g->gui.seq_orig_isn, TRUE);
1643 graph_init_sequence (g);
1646 static void callback_graph_init_on_typechg (GtkWidget *toggle _U_, gpointer data)
1648 ((struct graph * )data)->flags ^= GRAPH_INIT_ON_TYPE_CHANGE;
1651 static struct graph *graph_new (void)
1655 g = (struct graph * )g_malloc0 (sizeof (struct graph));
1656 graph_element_lists_initialize (g);
1658 g->x_axis = (struct axis * )g_malloc0 (sizeof (struct axis));
1659 g->y_axis = (struct axis * )g_malloc0 (sizeof (struct axis));
1661 g->x_axis->flags = 0;
1662 g->x_axis->flags |= AXIS_ORIENTATION;
1663 g->x_axis->s.x = g->x_axis->s.y = 0;
1664 g->x_axis->s.height = HAXIS_INIT_HEIGHT;
1665 g->x_axis->p.x = VAXIS_INIT_WIDTH;
1666 g->x_axis->p.height = HAXIS_INIT_HEIGHT;
1668 g->y_axis->flags = 0;
1669 g->y_axis->flags &= ~AXIS_ORIENTATION;
1670 g->y_axis->p.x = g->y_axis->p.y = 0;
1671 g->y_axis->p.width = VAXIS_INIT_WIDTH;
1673 g->y_axis->s.y = TITLEBAR_HEIGHT;
1674 g->y_axis->s.width = VAXIS_INIT_WIDTH;
1679 static void graph_initialize_values (struct graph *g)
1681 g->geom.width = g->wp.width = 750;
1682 g->geom.height = g->wp.height = 550;
1683 g->geom.x = g->wp.x = VAXIS_INIT_WIDTH;
1684 g->geom.y = g->wp.y = TITLEBAR_HEIGHT;
1686 /* g->zoom.x = g->zoom.y = 1.0; */
1687 g->zoom.step_x = g->zoom.step_y = 1.2;
1689 g->cross.draw = g->cross.erase_needed = 0;
1690 g->grab.grabbed = 0;
1691 g->magnify.active = 0;
1692 g->magnify.offset.x = g->magnify.offset.y = 0;
1693 g->magnify.width = g->magnify.height = 250;
1694 g->magnify.zoom.x = g->magnify.zoom.y = 10.0;
1695 g->magnify.flags = 0;
1698 static void graph_init_sequence (struct graph *g)
1700 debug(DBS_FENTRY) puts ("graph_init_sequence()");
1702 graph_type_dependent_initialize (g);
1703 g->zoom.initial.x = g->zoom.x;
1704 g->zoom.initial.y = g->zoom.y;
1705 graph_element_lists_make (g);
1706 g->x_axis->s.width = g->wp.width;
1707 g->x_axis->p.width = g->x_axis->s.width + RMARGIN_WIDTH;
1708 g->x_axis->p.y = TITLEBAR_HEIGHT + g->wp.height;
1709 g->x_axis->s.height = g->x_axis->p.height = HAXIS_INIT_HEIGHT;
1710 g->y_axis->s.height = g->wp.height;
1711 g->y_axis->p.height = g->wp.height + TITLEBAR_HEIGHT;
1712 graph_pixmaps_create (g);
1713 axis_pixmaps_create (g->y_axis);
1714 axis_pixmaps_create (g->x_axis);
1715 graph_title_pixmap_create (g);
1716 graph_title_pixmap_draw (g);
1717 graph_title_pixmap_display (g);
1719 axis_display (g->y_axis);
1720 axis_display (g->x_axis);
1723 static void graph_type_dependent_initialize (struct graph *g)
1726 case GRAPH_TSEQ_STEVENS:
1727 case GRAPH_TSEQ_TCPTRACE:
1728 tseq_initialize (g);
1730 case GRAPH_THROUGHPUT:
1731 tput_initialize (g);
1737 wscale_initialize (g);
1744 static void graph_destroy (struct graph *g)
1746 debug(DBS_FENTRY) puts ("graph_destroy()");
1748 axis_destroy (g->x_axis);
1749 axis_destroy (g->y_axis);
1750 /* window_destroy (g->drawing_area); */
1751 window_destroy (g->gui.control_panel);
1752 window_destroy (g->toplevel);
1753 /* window_destroy (g->text); */
1754 #if GTK_CHECK_VERSION(2,22,0)
1755 if(g->title_surface){
1756 cairo_surface_destroy (g->title_surface);
1759 cairo_surface_destroy (g->surface[0]);
1762 cairo_surface_destroy (g->surface[1]);
1765 g_object_unref (g->pixmap[0]);
1766 g_object_unref (g->pixmap[1]);
1767 #endif /* GTK_CHECK_VERSION(2,22,0) */
1770 g_free ( (gpointer) (g->title) );
1771 graph_segment_list_free (g);
1772 graph_element_lists_free (g);
1778 typedef struct _tcp_scan_t {
1779 struct segment *current;
1782 struct segment *last;
1786 tapall_tcpip_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip)
1788 static struct segment *segment=NULL;
1789 tcp_scan_t *ts=(tcp_scan_t *)pct;
1790 struct tcpheader *tcphdr=(struct tcpheader *)vip;
1793 segment=g_malloc(sizeof (struct segment));
1797 if (compare_headers(&ts->current->ip_src, &ts->current->ip_dst,
1798 ts->current->th_sport, ts->current->th_dport,
1799 &tcphdr->ip_src, &tcphdr->ip_dst,
1800 tcphdr->th_sport, tcphdr->th_dport,
1802 segment->next = NULL;
1803 segment->num = pinfo->fd->num;
1804 segment->rel_secs = (guint32) pinfo->fd->rel_ts.secs;
1805 segment->rel_usecs = pinfo->fd->rel_ts.nsecs/1000;
1806 segment->abs_secs = (guint32) pinfo->fd->abs_ts.secs;
1807 segment->abs_usecs = pinfo->fd->abs_ts.nsecs/1000;
1808 segment->th_seq=tcphdr->th_seq;
1809 segment->th_ack=tcphdr->th_ack;
1810 segment->th_win=tcphdr->th_win;
1811 segment->th_flags=tcphdr->th_flags;
1812 segment->th_sport=tcphdr->th_sport;
1813 segment->th_dport=tcphdr->th_dport;
1814 segment->th_seglen=tcphdr->th_seglen;
1815 COPY_ADDRESS(&segment->ip_src, &tcphdr->ip_src);
1816 COPY_ADDRESS(&segment->ip_dst, &tcphdr->ip_dst);
1817 if (ts->g->segments) {
1818 ts->last->next = segment;
1820 ts->g->segments = segment;
1823 if(pinfo->fd->num==ts->current->num){
1824 ts->g->current = segment;
1835 /* here we collect all the external data we will ever need */
1836 static void graph_segment_list_get (struct graph *g)
1838 struct segment current;
1839 GString *error_string;
1843 debug(DBS_FENTRY) puts ("graph_segment_list_get()");
1844 select_tcpip_session (&cfile, ¤t);
1845 if (g->type == GRAPH_THROUGHPUT)
1846 ts.direction = COMPARE_CURR_DIR;
1848 ts.direction = COMPARE_ANY_DIR;
1850 /* rescan all the packets and pick up all interesting tcp headers.
1851 * we only filter for TCP here for speed and do the actual compare
1852 * in the tap listener
1854 ts.current=¤t;
1857 error_string=register_tap_listener("tcp", &ts, "tcp", 0, NULL, tapall_tcpip_packet, NULL);
1859 fprintf(stderr, "wireshark: Couldn't register tcp_graph tap: %s\n",
1861 g_string_free(error_string, TRUE);
1864 cf_retap_packets(&cfile);
1865 remove_tap_listener(&ts);
1869 typedef struct _th_t {
1871 struct tcpheader *tcphdr;
1875 tap_tcpip_packet(void *pct, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *vip)
1880 th->tcphdr=(struct tcpheader *)vip;
1887 /* XXX should be enhanced so that if we have multiple TCP layers in the trace
1888 * then present the user with a dialog where the user can select WHICH tcp
1891 static struct tcpheader *select_tcpip_session (capture_file *cf, struct segment *hdrs)
1896 GString *error_string;
1897 th_t th = {0, NULL};
1899 fdata = cf->current_frame;
1901 /* no real filter yet */
1902 if (!dfilter_compile("tcp", &sfcode)) {
1903 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", dfilter_error_msg);
1907 /* dissect the current frame */
1908 if (!cf_read_frame(cf, fdata))
1909 return NULL; /* error reading the frame */
1912 error_string=register_tap_listener("tcp", &th, NULL, 0, NULL, tap_tcpip_packet, NULL);
1914 fprintf(stderr, "wireshark: Couldn't register tcp_graph tap: %s\n",
1916 g_string_free(error_string, TRUE);
1920 epan_dissect_init(&edt, TRUE, FALSE);
1921 epan_dissect_prime_dfilter(&edt, sfcode);
1922 tap_queue_init(&edt);
1923 epan_dissect_run(&edt, &cf->pseudo_header, cf->pd, fdata, NULL);
1924 tap_push_tapped_queue(&edt);
1925 epan_dissect_cleanup(&edt);
1926 remove_tap_listener(&th);
1929 /* This "shouldn't happen", as our menu items shouldn't
1930 * even be enabled if the selected packet isn't a TCP
1931 * segment, as tcp_graph_selected_packet_enabled() is used
1932 * to determine whether to enable any of our menu items. */
1933 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1934 "Selected packet isn't a TCP segment");
1937 /* XXX fix this later, we should show a dialog allowing the user
1938 to select which session he wants here
1941 /* can only handle a single tcp layer yet */
1942 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1943 "The selected packet has more than one TCP"
1948 hdrs->num = fdata->num;
1949 hdrs->rel_secs = (guint32) fdata->rel_ts.secs;
1950 hdrs->rel_usecs = fdata->rel_ts.nsecs/1000;
1951 hdrs->abs_secs = (guint32) fdata->abs_ts.secs;
1952 hdrs->abs_usecs = fdata->abs_ts.nsecs/1000;
1953 hdrs->th_seq=th.tcphdr->th_seq;
1954 hdrs->th_ack=th.tcphdr->th_ack;
1955 hdrs->th_win=th.tcphdr->th_win;
1956 hdrs->th_flags=th.tcphdr->th_flags;
1957 hdrs->th_sport=th.tcphdr->th_sport;
1958 hdrs->th_dport=th.tcphdr->th_dport;
1959 hdrs->th_seglen=th.tcphdr->th_seglen;
1960 COPY_ADDRESS(&hdrs->ip_src, &th.tcphdr->ip_src);
1961 COPY_ADDRESS(&hdrs->ip_dst, &th.tcphdr->ip_dst);
1966 static int compare_headers (address *saddr1, address *daddr1, guint16 sport1, guint16 dport1, address *saddr2, address *daddr2, guint16 sport2, guint16 dport2, int dir)
1970 dir1 = ((!(CMP_ADDRESS(saddr1, saddr2))) &&
1971 (!(CMP_ADDRESS(daddr1, daddr2))) &&
1975 if(dir==COMPARE_CURR_DIR){
1978 dir2 = ((!(CMP_ADDRESS(saddr1, daddr2))) &&
1979 (!(CMP_ADDRESS(daddr1, saddr2))) &&
1982 return dir1 || dir2;
1986 static void graph_segment_list_free (struct graph *g)
1988 struct segment *segment;
1990 while (g->segments) {
1991 segment = g->segments->next;
1992 g_free (g->segments);
1993 g->segments = segment;
1998 static void graph_element_lists_initialize (struct graph *g)
2000 g->elists = (struct element_list *)g_malloc0 (sizeof (struct element_list));
2003 static void graph_element_lists_make (struct graph *g)
2005 debug(DBS_FENTRY) puts ("graph_element_lists_make()");
2008 case GRAPH_TSEQ_STEVENS:
2009 tseq_stevens_make_elmtlist (g);
2011 case GRAPH_TSEQ_TCPTRACE:
2012 tseq_tcptrace_make_elmtlist (g);
2014 case GRAPH_THROUGHPUT:
2015 tput_make_elmtlist (g);
2018 rtt_make_elmtlist (g);
2021 wscale_make_elmtlist (g);
2024 printf ("graph_element_lists_make: unknown graph type: %d\n", g->type);
2029 static void graph_element_lists_free (struct graph *g)
2031 struct element_list *list, *next_list;
2034 for (list=g->elists; list; list=list->next)
2035 g_free (list->elements);
2036 while (g->elists->next) {
2037 list = g->elists->next->next;
2038 g_free (g->elists->next);
2039 g->elists->next = list;
2043 for (list=g->elists; list; list=next_list) {
2044 g_free (list->elements);
2045 next_list = list->next;
2048 g->elists = NULL; /* just to make debugging easier */
2051 static void graph_title_pixmap_create (struct graph *g)
2053 #if GTK_CHECK_VERSION(2,22,0)
2054 if(g->title_surface){
2055 cairo_surface_destroy (g->title_surface);
2056 g->title_surface = NULL;
2059 g->title_surface = gdk_window_create_similar_surface (gtk_widget_get_window(g->drawing_area),
2060 CAIRO_CONTENT_COLOR,
2065 if (g->title_pixmap)
2066 g_object_unref (g->title_pixmap);
2068 g->title_pixmap = gdk_pixmap_new (gtk_widget_get_window(g->drawing_area),
2069 g->x_axis->p.width, g->wp.y, -1);
2073 static void graph_title_pixmap_draw (struct graph *g)
2078 #if GTK_CHECK_VERSION(2,22,0)
2079 cr = cairo_create (g->title_surface);
2081 cr = gdk_cairo_create (g->title_pixmap);
2083 cairo_set_source_rgb (cr, 1, 1, 1);
2084 cairo_rectangle (cr, 0, 0, g->x_axis->p.width, g->wp.y);
2089 for (i=0; g->title[i]; i++) {
2091 PangoLayout *layout;
2092 layout = gtk_widget_create_pango_layout(g->drawing_area,
2094 pango_layout_get_pixel_size(layout, &w, &h);
2095 #if GTK_CHECK_VERSION(2,22,0)
2096 cr = cairo_create (g->title_surface);
2098 cr = gdk_cairo_create (g->title_pixmap);
2100 cairo_move_to (cr, g->wp.width/2 - w/2, 20 + i*(h+3));
2101 pango_cairo_show_layout (cr, layout);
2103 g_object_unref(G_OBJECT(layout));
2107 static void graph_title_pixmap_display (struct graph *g)
2111 cr = gdk_cairo_create (gtk_widget_get_window(g->drawing_area));
2112 #if GTK_CHECK_VERSION(2,22,0)
2113 cairo_set_source_surface (cr, g->title_surface, g->wp.x, 0);
2115 gdk_cairo_set_source_pixmap (cr, g->title_pixmap, g->wp.x, 0);
2117 cairo_rectangle (cr, g->wp.x, 0, g->x_axis->p.width, g->wp.y);
2122 static void graph_pixmaps_create (struct graph *g)
2124 debug(DBS_FENTRY) puts ("graph_pixmaps_create()");
2125 #if GTK_CHECK_VERSION(2,22,0)
2127 cairo_surface_destroy (g->surface[0]);
2128 g->surface[0] = NULL;
2132 cairo_surface_destroy (g->surface[1]);
2133 g->surface[1] = NULL;
2136 g->surface[0] = gdk_window_create_similar_surface (gtk_widget_get_window(g->drawing_area),
2137 CAIRO_CONTENT_COLOR,
2141 g->surface[1] = gdk_window_create_similar_surface (gtk_widget_get_window(g->drawing_area),
2142 CAIRO_CONTENT_COLOR,
2149 g_object_unref (g->pixmap[0]);
2151 g_object_unref (g->pixmap[1]);
2153 g->pixmap[0] = gdk_pixmap_new (gtk_widget_get_window(g->drawing_area),
2154 g->wp.width, g->wp.height, -1);
2155 g->pixmap[1] = gdk_pixmap_new (gtk_widget_get_window(g->drawing_area),
2156 g->wp.width, g->wp.height, -1);
2159 #endif /* GTK_CHECK_VERSION(2,22,0) */
2162 static void graph_display (struct graph *g)
2164 set_busy_cursor (gtk_widget_get_window(g->drawing_area));
2165 graph_pixmap_draw (g);
2166 unset_busy_cursor (gtk_widget_get_window(g->drawing_area));
2167 graph_pixmaps_switch (g);
2168 graph_pixmap_display (g);
2171 static void graph_pixmap_display (struct graph *g)
2175 cr = gdk_cairo_create (gtk_widget_get_window(g->drawing_area));
2176 #if GTK_CHECK_VERSION(2,22,0)
2177 cairo_set_source_surface (cr, g->surface[g->displayed], g->wp.x, g->wp.y);
2179 gdk_cairo_set_source_pixmap (cr, g->pixmap[g->displayed], g->wp.x, g->wp.y);
2180 #endif /* GTK_CHECK_VERSION(2,22,0) */
2181 cairo_rectangle (cr, g->wp.x, g->wp.y, g->wp.width, g->wp.height);
2185 if (g->cross.erase_needed) {
2186 cross_xor(g, g->cross.x, g->cross.y);
2190 static void graph_pixmaps_switch (struct graph *g)
2192 g->displayed = 1 ^ g->displayed;
2195 static void graph_pixmap_draw (struct graph *g)
2197 struct element_list *list;
2202 debug(DBS_FENTRY) puts ("graph_display()");
2203 not_disp = 1 ^ g->displayed;
2205 #if GTK_CHECK_VERSION(2,22,0)
2206 cr = cairo_create (g->surface[not_disp]);
2208 cr = gdk_cairo_create (g->pixmap[not_disp]);
2209 #endif /* GTK_CHECK_VERSION(2,22,0) */
2210 cairo_set_source_rgb (cr, 1, 1, 1);
2211 cairo_rectangle (cr, 0, 0, g->wp.width, g->wp.height);
2216 for (list=g->elists; list; list=list->next)
2217 for (e=list->elements; e->type != ELMT_NONE; e++) {
2222 draw_element_line (g, e);
2225 draw_element_ellipse (g, e);
2233 static void draw_element_line (struct graph *g, struct element *e)
2235 int xx1, xx2, yy1, yy2;
2238 debug(DBS_GRAPH_DRAWING) printf ("line element: (%.2f,%.2f)->(%.2f,%.2f), "
2239 "seg %d ... ", e->p.line.dim.x1, e->p.line.dim.y1,
2240 e->p.line.dim.x2, e->p.line.dim.y2, e->parent->num);
2241 xx1 = (int )rint (e->p.line.dim.x1 + g->geom.x - g->wp.x);
2242 xx2 = (int )rint (e->p.line.dim.x2 + g->geom.x - g->wp.x);
2243 yy1 = (int )rint ((g->geom.height-1-e->p.line.dim.y1) + g->geom.y-g->wp.y);
2244 yy2 = (int )rint ((g->geom.height-1-e->p.line.dim.y2) + g->geom.y-g->wp.y);
2255 if ((xx1<0 && xx2<0) || (xx1>=g->wp.width && xx2>=g->wp.width) ||
2256 (yy1<0 && yy2<0) || (yy1>=g->wp.height && yy2>=g->wp.height)) {
2257 debug(DBS_GRAPH_DRAWING) printf (" refusing: (%d,%d)->(%d,%d)\n",
2258 xx1, yy1, xx2, yy2);
2261 if (xx2 > g->wp.width-1)
2262 xx2 = g->wp.width-1;
2265 if (yy2 > g->wp.height-1)
2266 yy2 = g->wp.height-1;
2269 debug(DBS_GRAPH_DRAWING) printf ("line: (%d,%d)->(%d,%d)\n", xx1, yy1, xx2,yy2);
2271 g_assert(e->elment_color_p!=NULL);
2273 #if GTK_CHECK_VERSION(2,22,0)
2274 cr = cairo_create (g->surface[1^g->displayed]);
2276 cr = gdk_cairo_create (g->pixmap[1^g->displayed]);
2278 cairo_set_line_width (cr, 1.0);
2279 if(e->elment_color_p!=NULL){
2280 gdk_cairo_set_source_color (cr, e->elment_color_p);
2282 cairo_move_to(cr, xx1+0.5, yy1+0.5);
2283 cairo_line_to(cr, xx2+0.5, yy2+0.5);
2288 static void draw_element_ellipse (struct graph *g, struct element *e)
2290 #if GTK_CHECK_VERSION(2,22,0)
2292 gdouble w = e->p.ellipse.dim.width;
2293 gdouble h = e->p.ellipse.dim.height;
2294 gdouble x = e->p.ellipse.dim.x + g->geom.x - g->wp.x;
2295 gdouble y = g->geom.height-1 - e->p.ellipse.dim.y + g->geom.y - g->wp.y;
2297 debug(DBS_GRAPH_DRAWING) printf ("ellipse: (x, y) -> (w, h): (%f, %f) -> (%f, %f)\n", x, y, w, h);
2299 cr = cairo_create (g->surface[1^g->displayed]);
2300 cairo_translate (cr, x + w / 2., y + h / 2.);
2301 cairo_scale (cr, w / 2., h / 2.);
2302 cairo_arc (cr, 0., 0., 1., 0., 2 * G_PI);
2306 int xx1, xx2, yy1, yy2;
2308 xx1 = (int )rint (e->p.ellipse.dim.x + g->geom.x - g->wp.x);
2309 xx2 = (int )e->p.ellipse.dim.width;
2310 yy1 = (int )rint (g->geom.height-1 - e->p.ellipse.dim.y + g->geom.y - g->wp.y);
2311 yy2 = (int )e->p.ellipse.dim.height;
2312 if (xx1<-xx2 || xx1>=g->wp.width || yy1<-yy2 || yy1>=g->wp.height)
2314 debug(DBS_GRAPH_DRAWING) printf ("ellipse: (%d,%d)->(%d,%d)\n", xx1, yy1, xx2, yy2);
2316 gdk_draw_arc (g->pixmap[1^g->displayed], g->fg_gc, TRUE, xx1,
2317 yy1, xx2, yy2, 0, 23040);
2319 /* NOTE the coordinates and angels needs to be recalculated as cairo_arc works differently */
2322 static void axis_pixmaps_create (struct axis *axis)
2324 debug(DBS_FENTRY) puts ("axis_pixmaps_create()");
2325 #if GTK_CHECK_VERSION(2,22,0)
2326 if(axis->surface[0]){
2327 cairo_surface_destroy (axis->surface[0]);
2328 axis->surface[0] = NULL;
2330 if(axis->surface[1]){
2331 cairo_surface_destroy (axis->surface[1]);
2332 axis->surface[1] = NULL;
2334 axis->surface[0] = gdk_window_create_similar_surface (gtk_widget_get_window(axis->drawing_area),
2335 CAIRO_CONTENT_COLOR,
2339 axis->surface[1] = gdk_window_create_similar_surface (gtk_widget_get_window(axis->drawing_area),
2340 CAIRO_CONTENT_COLOR,
2344 axis->displayed = 0;
2346 if (axis->pixmap[0])
2347 g_object_unref (axis->pixmap[0]);
2348 if (axis->pixmap[1])
2349 g_object_unref (axis->pixmap[1]);
2351 axis->pixmap[0] = gdk_pixmap_new (gtk_widget_get_window(axis->drawing_area),
2352 axis->p.width, axis->p.height, -1);
2353 axis->pixmap[1] = gdk_pixmap_new (gtk_widget_get_window(axis->drawing_area),
2354 axis->p.width, axis->p.height, -1);
2356 axis->displayed = 0;
2360 static void axis_destroy (struct axis *axis)
2362 #if GTK_CHECK_VERSION(2,22,0)
2363 if(axis->surface[0]){
2364 cairo_surface_destroy (axis->surface[0]);
2365 axis->surface[0] = NULL;
2367 if(axis->surface[1]){
2368 cairo_surface_destroy (axis->surface[1]);
2369 axis->surface[1] = NULL;
2372 g_object_unref (axis->pixmap[0]);
2373 g_object_unref (axis->pixmap[1]);
2375 g_free ( (gpointer) (axis->label) );
2378 static void axis_display (struct axis *axis)
2380 if (axis->flags & AXIS_ORIENTATION)
2381 h_axis_pixmap_draw (axis);
2383 v_axis_pixmap_draw (axis);
2384 axis_pixmaps_switch (axis);
2385 axis_pixmap_display (axis);
2388 static void v_axis_pixmap_draw (struct axis *axis)
2390 struct graph *g = axis->g;
2393 int not_disp, rdigits, offset, imin, imax;
2394 double bottom, top, j, fl, corr;
2395 PangoLayout *layout;
2398 debug(DBS_FENTRY) puts ("v_axis_pixmap_draw()");
2399 bottom = (g->geom.height - (g->wp.height + g->wp.y + (-g->geom.y))) /
2400 (double )g->geom.height * g->bounds.height;
2401 bottom += axis->min;
2402 top = (g->geom.height - (g->wp.y + (-g->geom.y))) /
2403 (double )g->geom.height * g->bounds.height;
2405 axis_compute_ticks (axis, bottom, top, AXIS_VERTICAL);
2407 j = axis->major - floor (axis->major);
2408 for (rdigits=0; rdigits<=6; rdigits++) {
2415 not_disp = 1 ^ axis->displayed;
2417 #if GTK_CHECK_VERSION(2,22,0)
2418 cr = cairo_create (axis->surface[not_disp]);
2420 cr = gdk_cairo_create (axis->pixmap[not_disp]);
2422 cairo_set_source_rgb (cr, 1, 1, 1);
2423 cairo_rectangle (cr, 0, 0, axis->p.width, axis->p.height);
2429 #if GTK_CHECK_VERSION(2,22,0)
2430 cr = cairo_create (axis->surface[not_disp]);
2432 cr = gdk_cairo_create (axis->pixmap[not_disp]);
2434 cairo_set_line_width (cr, 1.0);
2435 cairo_move_to(cr, axis->p.width - 1.5, (axis->p.height-axis->s.height)/2.0);
2436 cairo_line_to(cr, axis->s.width - 1.5, axis->p.height);
2441 offset = g->wp.y + (-g->geom.y);
2442 fl = floor (axis->min / axis->major) * axis->major;
2443 corr = rint ((axis->min - fl) * g->zoom.y);
2446 major_tick = axis->major * g->zoom.y;
2447 imin = (int) ((g->geom.height - offset + corr - g->wp.height) / major_tick + 1);
2448 imax = (int) ((g->geom.height - offset + corr) / major_tick);
2449 for (i=imin; i <= imax; i++) {
2452 int y = (int) (g->geom.height-1 - (int )rint (i * major_tick) -
2453 offset + corr + axis->s.y);
2455 debug(DBS_AXES_DRAWING) printf("%f @ %d\n",
2456 i*axis->major + fl, y);
2457 if (y < 0 || y > axis->p.height)
2460 #if GTK_CHECK_VERSION(2,22,0)
2461 cr = cairo_create (axis->surface[not_disp]);
2463 cr = gdk_cairo_create (axis->pixmap[not_disp]);
2465 cairo_set_line_width (cr, 1.0);
2466 cairo_move_to(cr, axis->p.width - 15, y+0.5);
2467 cairo_line_to(cr, axis->s.width - 1, y+0.5);
2472 g_snprintf (desc, sizeof(desc), "%.*f", rdigits, i*axis->major + fl);
2473 layout = gtk_widget_create_pango_layout(g->drawing_area, desc);
2474 pango_layout_get_pixel_size(layout, &w, &h);
2475 #if GTK_CHECK_VERSION(2,22,0)
2476 cr = cairo_create (axis->surface[not_disp]);
2478 cr = gdk_cairo_create (axis->pixmap[not_disp]);
2480 cairo_move_to (cr, axis->s.width-14-4-w, y - h/2);
2481 pango_cairo_show_layout (cr, layout);
2484 g_object_unref(G_OBJECT(layout));
2488 double minor_tick = axis->minor * g->zoom.y;
2489 imin = (int) ((g->geom.height - offset + corr - g->wp.height)/minor_tick + 1);
2490 imax = (int) ((g->geom.height - offset + corr) / minor_tick);
2491 for (i=imin; i <= imax; i++) {
2492 int y = (int) (g->geom.height-1 - (int )rint (i*minor_tick) -
2493 offset + corr + axis->s.y);
2495 debug (DBS_AXES_DRAWING) printf ("%f @ %d\n", i*axis->minor+fl, y);
2496 if (y > 0 && y < axis->p.height)
2497 #if GTK_CHECK_VERSION(2,22,0)
2498 cr = cairo_create (axis->surface[not_disp]);
2500 cr = gdk_cairo_create (axis->pixmap[not_disp]);
2502 cairo_set_line_width (cr, 1.0);
2503 cairo_move_to(cr, axis->s.width - 8, y+0.5);
2504 cairo_line_to(cr, axis->s.width - 1, y+0.5);
2510 for (i=0; axis->label[i]; i++) {
2512 layout = gtk_widget_create_pango_layout(g->drawing_area,
2514 pango_layout_get_pixel_size(layout, &w, &h);
2515 #if GTK_CHECK_VERSION(2,22,0)
2516 cr = cairo_create (axis->surface[not_disp]);
2518 cr = gdk_cairo_create (axis->pixmap[not_disp]);
2520 cairo_move_to (cr, (axis->p.width - w)/2, TITLEBAR_HEIGHT-10 - i*(h+3) - h);
2521 pango_cairo_show_layout (cr, layout);
2524 g_object_unref(G_OBJECT(layout));
2528 static void h_axis_pixmap_draw (struct axis *axis)
2530 struct graph *g = axis->g;
2532 double major_tick, minor_tick;
2533 int not_disp, rdigits, offset, imin, imax;
2534 double left, right, j, fl, corr;
2535 PangoLayout *layout;
2538 debug(DBS_FENTRY) puts ("h_axis_pixmap_draw()");
2539 left = (g->wp.x-g->geom.x) /
2540 (double )g->geom.width * g->bounds.width;
2542 right = (g->wp.x-g->geom.x+g->wp.width) /
2543 (double )g->geom.width * g->bounds.width;
2545 axis_compute_ticks (axis, left, right, AXIS_HORIZONTAL);
2547 j = axis->major - floor (axis->major);
2548 for (rdigits=0; rdigits<=6; rdigits++) {
2555 not_disp = 1 ^ axis->displayed;
2557 #if GTK_CHECK_VERSION(2,22,0)
2558 cr = cairo_create (axis->surface[not_disp]);
2560 cr = gdk_cairo_create (axis->pixmap[not_disp]);
2562 cairo_set_source_rgb (cr, 1, 1, 1);
2563 cairo_rectangle (cr, 0, 0, axis->p.width, axis->p.height);
2569 #if GTK_CHECK_VERSION(2,22,0)
2570 cr = cairo_create (axis->surface[not_disp]);
2572 cr = gdk_cairo_create (axis->pixmap[not_disp]);
2574 cairo_set_line_width (cr, 1.0);
2575 cairo_move_to(cr, 0, 0.5);
2576 cairo_line_to(cr, axis->s.width + (axis->p.width-axis->s.width)/2.0, 0.5);
2581 offset = g->wp.x - g->geom.x;
2583 fl = floor (axis->min / axis->major) * axis->major;
2584 corr = rint ((axis->min - fl) * g->zoom.x);
2587 major_tick = axis->major*g->zoom.x;
2588 imin = (int) ((offset + corr) / major_tick + 1);
2589 imax = (int) ((offset + corr + axis->s.width) / major_tick);
2590 for (i=imin; i <= imax; i++) {
2593 int x = (int ) (rint (i * major_tick) - offset - corr);
2595 /* printf ("%f @ %d\n", i*axis->major + fl, x); */
2596 if (x < 0 || x > axis->s.width)
2598 #if GTK_CHECK_VERSION(2,22,0)
2599 cr = cairo_create (axis->surface[not_disp]);
2601 cr = gdk_cairo_create (axis->pixmap[not_disp]);
2603 cairo_set_line_width (cr, 1.0);
2604 cairo_move_to(cr, x+0.5, 0);
2605 cairo_line_to(cr, x+0.5, 15);
2610 g_snprintf (desc, sizeof(desc), "%.*f", rdigits, i*axis->major + fl);
2611 layout = gtk_widget_create_pango_layout(g->drawing_area, desc);
2612 pango_layout_get_pixel_size(layout, &w, &h);
2613 #if GTK_CHECK_VERSION(2,22,0)
2614 cr = cairo_create (axis->surface[not_disp]);
2616 cr = gdk_cairo_create (axis->pixmap[not_disp]);
2618 cairo_move_to (cr, x - w/2, 15+4);
2619 pango_cairo_show_layout (cr, layout);
2623 g_object_unref(G_OBJECT(layout));
2625 if (axis->minor > 0) {
2627 minor_tick = axis->minor*g->zoom.x;
2628 imin = (int) ((offset + corr) / minor_tick + 1);
2629 imax = (int) ((offset + corr + g->wp.width) / minor_tick);
2630 for (i=imin; i <= imax; i++) {
2631 int x = (int) (rint (i * minor_tick) - offset - corr);
2632 if (x > 0 && x < axis->s.width){
2633 #if GTK_CHECK_VERSION(2,22,0)
2634 cr = cairo_create (axis->surface[not_disp]);
2636 cr = gdk_cairo_create (axis->pixmap[not_disp]);
2638 cairo_set_line_width (cr, 1.0);
2639 cairo_move_to(cr, x+0.5, 0);
2640 cairo_line_to(cr, x+0.5, 8);
2647 for (i=0; axis->label[i]; i++) {
2649 layout = gtk_widget_create_pango_layout(g->drawing_area,
2651 pango_layout_get_pixel_size(layout, &w, &h);
2652 #if GTK_CHECK_VERSION(2,22,0)
2653 cr = cairo_create (axis->surface[not_disp]);
2655 cr = gdk_cairo_create (axis->pixmap[not_disp]);
2657 cairo_move_to (cr, axis->s.width - w - 50, 15+h+15 + i*(h+3));
2658 pango_cairo_show_layout (cr, layout);
2661 g_object_unref(G_OBJECT(layout));
2665 static void axis_pixmaps_switch (struct axis *axis)
2667 axis->displayed = 1 ^ axis->displayed;
2670 static void axis_pixmap_display (struct axis *axis)
2674 cr = gdk_cairo_create (gtk_widget_get_window(axis->drawing_area));
2675 #if GTK_CHECK_VERSION(2,22,0)
2676 cairo_set_source_surface (cr, axis->surface[axis->displayed], axis->p.x, axis->p.y);
2678 gdk_cairo_set_source_pixmap (cr, axis->pixmap[axis->displayed], axis->p.x, axis->p.y);
2680 cairo_rectangle (cr, axis->p.x, axis->p.y, axis->p.width, axis->p.height);
2686 static void axis_compute_ticks (struct axis *axis, double x0, double xmax, int dir)
2688 int i, j, ii, jj, ms;
2689 double zoom, x, steps[3]={ 0.1, 0.5 };
2690 int dim, check_needed, diminished;
2691 double majthresh[2]={2.0, 3.0};
2693 debug((DBS_FENTRY | DBS_AXES_TICKS)) puts ("axis_compute_ticks()");
2694 debug(DBS_AXES_TICKS)
2695 printf ("x0=%f xmax=%f dir=%s\n", x0,xmax, dir?"VERTICAL":"HORIZONTAL");
2697 zoom = axis_zoom_get (axis, dir);
2699 for (i=-9; i<=12; i++) {
2700 if (x / pow (10, i) < 1)
2704 ms = (int )(x / pow (10, i));
2714 axis->major = steps[j] * pow (10, i);
2716 debug(DBS_AXES_TICKS) printf ("zoom=%.1f, x=%f -> i=%d -> ms=%d -> j=%d ->"
2717 " axis->major=%f\n", zoom, x, i, ms, j, axis->major);
2719 /* let's compute minor ticks */
2722 axis_ticks_down (&ii, &jj);
2723 axis->minor = steps[jj] * pow (10, ii);
2724 /* we don't want minors if they would be less than 10 pixels apart */
2725 if (axis->minor*zoom < 10) {
2726 debug(DBS_AXES_TICKS) printf ("refusing axis->minor of %f: "
2727 "axis->minor*zoom == %f\n", axis->minor, axis->minor*zoom);
2731 check_needed = TRUE;
2733 while (check_needed) {
2734 check_needed = FALSE;
2735 dim = get_label_dim (axis, dir, xmax);
2736 debug(DBS_AXES_TICKS) printf ("axis->major==%.1f, axis->minor==%.1f =>"
2737 " axis->major*zoom/dim==%f, axis->minor*zoom/dim==%f\n",
2738 axis->major, axis->minor, axis->major*zoom/dim,
2739 axis->minor*zoom/dim);
2741 /* corrections: if majors are less than majthresh[dir] times label
2742 * dimension apart, we need to use bigger ones */
2743 if (axis->major*zoom / dim < majthresh[dir]) {
2744 axis_ticks_up (&ii, &jj);
2745 axis->minor = axis->major;
2746 axis_ticks_up (&i, &j);
2747 axis->major = steps[j] * pow (10, i);
2748 check_needed = TRUE;
2749 debug(DBS_AXES_TICKS) printf ("axis->major enlarged to %.1f\n",
2752 /* if minor ticks are bigger than majthresh[dir] times label dimension,
2753 * we could promote them to majors as well */
2754 if (axis->minor*zoom / dim > majthresh[dir] && !diminished) {
2755 axis_ticks_down (&i, &j);
2756 axis->major = axis->minor;
2757 axis_ticks_down (&ii, &jj);
2758 axis->minor = steps[jj] * pow (10, ii);
2759 check_needed = TRUE;
2762 debug(DBS_AXES_TICKS) printf ("axis->minor diminished to %.1f\n",
2765 if (axis->minor*zoom < 10) {
2766 debug(DBS_AXES_TICKS) printf ("refusing axis->minor of %f: "
2767 "axis->minor*zoom == %f\n", axis->minor, axis->minor*zoom);
2773 debug(DBS_AXES_TICKS) printf ("corrected: axis->major == %.1f -> "
2774 "axis->minor == %.1f\n", axis->major, axis->minor);
2777 static void axis_ticks_up (int *i, int *j)
2786 static void axis_ticks_down (int *i, int *j)
2795 static int get_label_dim (struct axis *axis, int dir, double label)
2800 PangoLayout *layout;
2802 /* First, let's compute how many digits to the right of radix
2803 * we need to print */
2804 y = axis->major - floor (axis->major);
2805 for (rdigits=0; rdigits<=6; rdigits++) {
2811 g_snprintf (str, sizeof(str), "%.*f", rdigits, label);
2813 case AXIS_HORIZONTAL:
2814 layout = gtk_widget_create_pango_layout(axis->g->drawing_area,
2816 pango_layout_get_pixel_size(layout, &dim, NULL);
2817 g_object_unref(G_OBJECT(layout));
2820 layout = gtk_widget_create_pango_layout(axis->g->drawing_area,
2822 pango_layout_get_pixel_size(layout, NULL, &dim);
2823 g_object_unref(G_OBJECT(layout));
2826 puts ("initialize axis: an axis must be either horizontal or vertical");
2832 static double axis_zoom_get (struct axis *axis, int dir)
2835 case AXIS_HORIZONTAL:
2836 return axis->g->zoom.x;
2838 return axis->g->zoom.y;
2844 static void graph_select_segment (struct graph *g, int x, int y)
2846 struct element_list *list;
2850 debug(DBS_FENTRY) puts ("graph_select_segment()");
2853 y = g->geom.height-1 - (y - g->geom.y);
2855 set_busy_cursor (gtk_widget_get_window(g->drawing_area));
2857 for (list=g->elists; list; list=list->next)
2858 for (e=list->elements; e->type != ELMT_NONE; e++) {
2863 if (line_detect_collision (e, x, y)) {
2864 num = e->parent->num;
2868 if (ellipse_detect_collision (e, x, y)) {
2869 num = e->parent->num;
2879 cf_goto_frame(&cfile, num);
2881 unset_busy_cursor (gtk_widget_get_window(g->drawing_area));
2884 static int line_detect_collision (struct element *e, int x, int y)
2886 int xx1, yy1, xx2, yy2;
2888 if (e->p.line.dim.x1 < e->p.line.dim.x2) {
2889 xx1 = (int )rint (e->p.line.dim.x1);
2890 xx2 = (int )rint (e->p.line.dim.x2);
2892 xx1 = (int )rint (e->p.line.dim.x2);
2893 xx2 = (int )rint (e->p.line.dim.x1);
2895 if (e->p.line.dim.y1 < e->p.line.dim.y2) {
2896 yy1 = (int )rint (e->p.line.dim.y1);
2897 yy2 = (int )rint (e->p.line.dim.y2);
2899 yy1 = (int )rint (e->p.line.dim.y2);
2900 yy2 = (int )rint (e->p.line.dim.y1);
2903 printf ("line: (%d,%d)->(%d,%d), clicked: (%d,%d)\n", xx1, yy1, xx2, yy2, x, y);
2905 if ((xx1==x && xx2==x && yy1<=y && y<=yy2)||(yy1==y && yy2==y && xx1<=x && x<=xx2))
2911 static int ellipse_detect_collision (struct element *e, int x, int y)
2913 int xx1, yy1, xx2, yy2;
2915 xx1 = (int )rint (e->p.ellipse.dim.x);
2916 xx2 = (int )rint (e->p.ellipse.dim.x + e->p.ellipse.dim.width);
2917 yy1 = (int )rint (e->p.ellipse.dim.y - e->p.ellipse.dim.height);
2918 yy2 = (int )rint (e->p.ellipse.dim.y);
2920 printf ("ellipse: (%d,%d)->(%d,%d), clicked: (%d,%d)\n", xx1, yy1, xx2, yy2, x, y);
2922 if (xx1<=x && x<=xx2 && yy1<=y && y<=yy2)
2928 static void cross_xor (struct graph *g, int x, int y)
2930 #if GTK_CHECK_VERSION(3,0,0)
2931 GdkColor color_gray15 = {0x0, 0x2626, 0x2626, 0x2626};
2934 /* XXX Fix me: lines do not disapere */
2935 if (x > g->wp.x && x < g->wp.x+g->wp.width &&
2936 y >= g->wp.y && y < g->wp.y+g->wp.height) {
2937 /* Draw horisontal line */
2938 cr = gdk_cairo_create (gtk_widget_get_window(g->drawing_area));
2939 cairo_set_operator (cr, CAIRO_OPERATOR_XOR);
2940 gdk_cairo_set_source_color (cr, &color_gray15);
2941 cairo_set_line_width (cr, 1.0);
2942 cairo_move_to(cr, g->wp.x, y);
2943 cairo_line_to(cr, g->wp.x + g->wp.width, y);
2946 /* draw vertical line */
2947 cr = gdk_cairo_create (gtk_widget_get_window(g->drawing_area));
2948 cairo_set_operator (cr, CAIRO_OPERATOR_XOR);
2949 gdk_cairo_set_source_color (cr, &color_gray15);
2950 cairo_set_line_width (cr, 1.0);
2951 cairo_move_to(cr, x, g->wp.y);
2952 cairo_line_to(cr, x, g->wp.y + g->wp.height);
2959 if (x > g->wp.x && x < g->wp.x+g->wp.width &&
2960 y >= g->wp.y && y < g->wp.y+g->wp.height) {
2961 gdk_draw_line (gtk_widget_get_window(g->drawing_area), xor_gc, g->wp.x,
2962 y, g->wp.x + g->wp.width, y);
2963 gdk_draw_line (gtk_widget_get_window(g->drawing_area), xor_gc, x,
2964 g->wp.y, x, g->wp.y + g->wp.height);
2969 static void cross_draw (struct graph *g, int x, int y)
2971 cross_xor (g, x, y);
2974 g->cross.erase_needed = 1;
2977 static void cross_erase (struct graph *g)
2979 cross_xor (g, g->cross.x, g->cross.y);
2980 g->cross.erase_needed = 0;
2983 static void magnify_create (struct graph *g, int x, int y)
2986 struct element_list *list, *new_list;
2987 struct ipoint pos, offsetpos;
2990 mg = g->magnify.g = (struct graph * )g_malloc (sizeof (struct graph));
2991 memcpy ((void * )mg, (void * )g, sizeof (struct graph));
2993 mg->toplevel = dlg_window_new("tcp graph magnify");
2994 mg->drawing_area = mg->toplevel;
2995 gtk_window_set_default_size(GTK_WINDOW(mg->toplevel), g->magnify.width, g->magnify.height);
2996 gtk_widget_set_events (mg->drawing_area, GDK_EXPOSURE_MASK
2997 /* | GDK_ENTER_NOTIFY_MASK */
2998 /* | GDK_ALL_EVENTS_MASK */
3003 mg->wp.width = g->magnify.width;
3004 mg->wp.height = g->magnify.height;
3005 mg->geom.width = (int )rint (g->geom.width * g->magnify.zoom.x);
3006 mg->geom.height = (int )rint (g->geom.height * g->magnify.zoom.y);
3007 mg->zoom.x = (mg->geom.width - 1) / g->bounds.width;
3008 mg->zoom.y = (mg->geom.height- 1) / g->bounds.height;
3010 /* in order to keep original element lists intact we need our own */
3011 graph_element_lists_initialize (mg);
3012 list = g->elists->next;
3013 new_list = mg->elists;
3014 for ( ; list; list=list->next) {
3016 (struct element_list * )g_malloc (sizeof (struct element_list));
3017 new_list = new_list->next;
3018 new_list->next = NULL;
3019 new_list->elements = NULL;
3021 graph_element_lists_make (mg);
3023 gdk_window_get_position (gtk_widget_get_window(GTK_WIDGET (g->toplevel)), &pos.x, &pos.y);
3024 g->magnify.x = pos.x + x - g->magnify.width/2;
3025 g->magnify.y = pos.y + y - g->magnify.height/2;
3026 offsetpos.x = g->magnify.x + g->magnify.offset.x;
3027 offsetpos.x = offsetpos.x >= 0 ? offsetpos.x : 0;
3028 offsetpos.y = g->magnify.y + g->magnify.offset.y;
3029 offsetpos.y = offsetpos.y >= 0 ? offsetpos.y : 0;
3030 gtk_window_set_position (GTK_WINDOW(mg->drawing_area), GTK_WIN_POS_NONE);
3031 magnify_get_geom (g, x, y);
3033 gtk_widget_show (mg->drawing_area);
3035 /* we need to wait for the first expose event before we start drawing */
3036 while (!gdk_events_pending ());
3038 e = gdk_event_get ();
3040 if (e->any.type == GDK_EXPOSE) {
3048 #if GTK_CHECK_VERSION(2,22,0)
3049 mg->surface[0] = mg->surface[1] = NULL;
3051 mg->pixmap[0] = mg->pixmap[1] = NULL;
3052 #endif /* GTK_CHECK_VERSION(2,22,0) */
3053 graph_pixmaps_create (mg);
3055 g->magnify.active = 1;
3058 static void magnify_move (struct graph *g, int x, int y)
3060 struct ipoint pos, offsetpos;
3062 gdk_window_get_position (gtk_widget_get_window(GTK_WIDGET (g->toplevel)), &pos.x, &pos.y);
3063 g->magnify.x = pos.x + x - g->magnify.width/2;
3064 g->magnify.y = pos.y + y - g->magnify.height/2;
3065 offsetpos.x = g->magnify.x + g->magnify.offset.x;
3066 offsetpos.x = offsetpos.x >= 0 ? offsetpos.x : 0;
3067 offsetpos.y = g->magnify.y + g->magnify.offset.y;
3068 offsetpos.y = offsetpos.y >= 0 ? offsetpos.y : 0;
3069 magnify_get_geom (g, x, y);
3073 static void magnify_destroy (struct graph *g)
3075 struct element_list *list;
3076 struct graph *mg = g->magnify.g;
3078 window_destroy (GTK_WIDGET (mg->drawing_area));
3080 #if GTK_CHECK_VERSION(2,22,0)
3082 cairo_surface_destroy (mg->surface[0]);
3085 cairo_surface_destroy (mg->surface[1]);
3088 g_object_unref (mg->pixmap[0]);
3089 g_object_unref (mg->pixmap[1]);
3090 #endif /* GTK_CHECK_VERSION(2,22,0) */
3091 for (list=mg->elists; list; list=list->next)
3092 g_free (list->elements);
3095 while (mg->elists->next) {
3096 list = mg->elists->next->next;
3097 g_free (mg->elists->next);
3098 mg->elists->next = list;
3101 g_free (g->magnify.g);
3102 g->magnify.active = 0;
3105 static void magnify_get_geom (struct graph *g, int x, int y)
3109 gdk_window_get_position (gtk_widget_get_window(GTK_WIDGET (g->toplevel)), &posx, &posy);
3111 g->magnify.g->geom.x = g->geom.x;
3112 g->magnify.g->geom.y = g->geom.y;
3114 g->magnify.g->geom.x -=
3115 (int )rint ((g->magnify.g->geom.width - g->geom.width) *
3116 ((x-g->geom.x)/(double )g->geom.width));
3117 g->magnify.g->geom.y -=
3118 (int )rint ((g->magnify.g->geom.height - g->geom.height) *
3119 ((y-g->geom.y)/(double )g->geom.height));
3121 /* we have coords of origin of graph relative to origin of g->toplevel.
3122 * now we need them to relate to origin of magnify window */
3123 g->magnify.g->geom.x -= (g->magnify.x - posx);
3124 g->magnify.g->geom.y -= (g->magnify.y - posy);
3127 static void magnify_draw (struct graph *g)
3130 int not_disp = 1 ^ g->magnify.g->displayed;
3132 graph_pixmap_draw (g->magnify.g);
3133 /* graph pixmap is almost ready, just add border */
3134 #if GTK_CHECK_VERSION(2,22,0)
3135 cr = cairo_create (g->magnify.g->surface[not_disp]);
3137 cr = gdk_cairo_create (g->magnify.g->pixmap[not_disp]);
3138 #endif /* GTK_CHECK_VERSION(2,22,0) */
3139 cairo_set_line_width (cr, 1.0);
3140 cairo_move_to(cr, 0, 0);
3141 cairo_line_to(cr, g->magnify.width - 1, 0);
3144 cairo_move_to(cr, g->magnify.width - 1, 0);
3145 cairo_line_to(cr, g->magnify.width - 1, g->magnify.height);
3148 cairo_move_to(cr, 0, 0);
3149 cairo_line_to(cr, 0,g->magnify.height - 1);
3152 cairo_move_to(cr, 0, g->magnify.height - 1);
3153 cairo_line_to(cr, g->magnify.width - 1, g->magnify.height - 1);
3157 graph_pixmaps_switch (g->magnify.g);
3158 graph_pixmap_display (g->magnify.g);
3162 static gboolean configure_event (GtkWidget *widget, GdkEventConfigure *event, gpointer user_data _U_)
3164 struct graph *g = (struct graph *) g_object_get_data(G_OBJECT(widget), "graph");
3168 int cur_g_width, cur_g_height;
3169 int cur_wp_width, cur_wp_height;
3171 debug(DBS_FENTRY) puts ("configure_event()");
3173 cur_wp_width = g->wp.width;
3174 cur_wp_height = g->wp.height;
3175 g->wp.width = event->width - g->y_axis->p.width - RMARGIN_WIDTH;
3176 g->wp.height = event->height - g->x_axis->p.height - g->wp.y;
3177 g->x_axis->s.width = g->wp.width;
3178 g->x_axis->p.width = g->wp.width + RMARGIN_WIDTH;
3179 g->y_axis->p.height = g->wp.height + g->wp.y;
3180 g->y_axis->s.height = g->wp.height;
3181 g->x_axis->p.y = g->y_axis->p.height;
3182 zoom.x = (double )g->wp.width / cur_wp_width;
3183 zoom.y = (double )g->wp.height / cur_wp_height;
3184 cur_g_width = g->geom.width;
3185 cur_g_height = g->geom.height;
3186 g->geom.width = (int )rint (g->geom.width * zoom.x);
3187 g->geom.height = (int )rint (g->geom.height * zoom.y);
3188 g->zoom.x = (double )(g->geom.width - 1) / g->bounds.width;
3189 g->zoom.y = (double )(g->geom.height -1) / g->bounds.height;
3190 /* g->zoom.initial.x = g->zoom.x; */
3191 /* g->zoom.initial.y = g->zoom.y; */
3193 g->geom.x = (int) (g->wp.x - (double )g->geom.width/cur_g_width *
3194 (g->wp.x - g->geom.x));
3195 g->geom.y = (int) (g->wp.y - (double )g->geom.height/cur_g_height *
3196 (g->wp.y - g->geom.y));
3198 printf ("configure: graph: (%d,%d), (%d,%d); viewport: (%d,%d), (%d,%d); "
3199 "zooms: (%f,%f)\n", g->geom.x, g->geom.y, g->geom.width,
3200 g->geom.height, g->wp.x, g->wp.y, g->wp.width, g->wp.height,
3201 g->zoom.x, g->zoom.y);
3204 update_zoom_spins (g);
3205 graph_element_lists_make (g);
3206 graph_pixmaps_create (g);
3207 graph_title_pixmap_create (g);
3208 axis_pixmaps_create (g->y_axis);
3209 axis_pixmaps_create (g->x_axis);
3210 /* we don't do actual drawing here; we leave it to expose handler */
3211 graph_pixmap_draw (g);
3212 graph_pixmaps_switch (g);
3213 graph_title_pixmap_draw (g);
3214 h_axis_pixmap_draw (g->x_axis);
3215 axis_pixmaps_switch (g->x_axis);
3216 v_axis_pixmap_draw (g->y_axis);
3217 axis_pixmaps_switch (g->y_axis);
3221 static gboolean expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data _U_)
3223 struct graph *g = (struct graph *) g_object_get_data(G_OBJECT(widget), "graph");
3226 debug(DBS_FENTRY) puts ("expose_event()");
3231 /* lower left corner */
3232 cr = gdk_cairo_create (gtk_widget_get_window(g->drawing_area));
3233 cairo_set_source_rgb (cr, 1, 1, 1);
3234 cairo_rectangle (cr, 0, g->wp.y + g->wp.height, g->y_axis->p.width, g->x_axis->p.height);
3240 cr = gdk_cairo_create (gtk_widget_get_window(g->drawing_area));
3241 cairo_set_source_rgb (cr, 1, 1, 1);
3242 cairo_rectangle (cr, g->wp.x + g->wp.width, g->wp.y, RMARGIN_WIDTH, g->wp.height);
3247 graph_pixmap_display (g);
3248 graph_title_pixmap_display (g);
3249 axis_pixmap_display (g->x_axis);
3250 axis_pixmap_display (g->y_axis);
3255 static void do_zoom_mouse (struct graph *g, GdkEventButton *event)
3257 int cur_width = g->geom.width, cur_height = g->geom.height;
3258 struct { double x, y; } factor;
3260 if (g->zoom.flags & ZOOM_OUT) {
3261 if (g->zoom.flags & ZOOM_HLOCK)
3264 factor.x = 1 / g->zoom.step_x;
3265 if (g->zoom.flags & ZOOM_VLOCK)
3268 factor.y = 1 / g->zoom.step_y;
3270 if (g->zoom.flags & ZOOM_HLOCK)
3273 factor.x = g->zoom.step_x;
3274 if (g->zoom.flags & ZOOM_VLOCK)
3277 factor.y = g->zoom.step_y;
3280 g->geom.width = (int )rint (g->geom.width * factor.x);
3281 g->geom.height = (int )rint (g->geom.height * factor.y);
3282 if (g->geom.width < g->wp.width)
3283 g->geom.width = g->wp.width;
3284 if (g->geom.height < g->wp.height)
3285 g->geom.height = g->wp.height;
3286 g->zoom.x = (g->geom.width - 1) / g->bounds.width;
3287 g->zoom.y = (g->geom.height- 1) / g->bounds.height;
3289 g->geom.x -= (int )rint ((g->geom.width - cur_width) *
3290 ((event->x-g->geom.x)/(double )cur_width));
3291 g->geom.y -= (int )rint ((g->geom.height - cur_height) *
3292 ((event->y-g->geom.y)/(double )cur_height));
3294 if (g->geom.x > g->wp.x)
3295 g->geom.x = g->wp.x;
3296 if (g->geom.y > g->wp.y)
3297 g->geom.y = g->wp.y;
3298 if (g->wp.x + g->wp.width > g->geom.x + g->geom.width)
3299 g->geom.x = g->wp.width + g->wp.x - g->geom.width;
3300 if (g->wp.y + g->wp.height > g->geom.y + g->geom.height)
3301 g->geom.y = g->wp.height + g->wp.y - g->geom.height;
3303 printf ("button press: graph: (%d,%d), (%d,%d); viewport: (%d,%d), "
3304 "(%d,%d); zooms: (%f,%f)\n", g->geom.x, g->geom.y,
3305 g->geom.width, g->geom.height, g->wp.x, g->wp.y, g->wp.width,
3306 g->wp.height, g->zoom.x, g->zoom.y);
3308 graph_element_lists_make (g);
3309 g->cross.erase_needed = 0;
3311 axis_display (g->y_axis);
3312 axis_display (g->x_axis);
3313 update_zoom_spins (g);
3315 cross_draw (g, (int) event->x, (int) event->y);
3318 static void do_zoom_keyboard (struct graph *g)
3320 int cur_width = g->geom.width, cur_height = g->geom.height;
3321 struct { double x, y; } factor;
3322 int pointer_x, pointer_y;
3324 gdk_window_get_pointer (gtk_widget_get_window(g->drawing_area), &pointer_x, &pointer_y, 0);
3326 if (g->zoom.flags & ZOOM_OUT) {
3327 if (g->zoom.flags & ZOOM_HLOCK)
3330 factor.x = 1 / g->zoom.step_x;
3331 if (g->zoom.flags & ZOOM_VLOCK)
3334 factor.y = 1 / g->zoom.step_y;
3336 if (g->zoom.flags & ZOOM_HLOCK)
3339 factor.x = g->zoom.step_x;
3340 if (g->zoom.flags & ZOOM_VLOCK)
3343 factor.y = g->zoom.step_y;
3346 g->geom.width = (int )rint (g->geom.width * factor.x);
3347 g->geom.height = (int )rint (g->geom.height * factor.y);
3348 if (g->geom.width < g->wp.width)
3349 g->geom.width = g->wp.width;
3350 if (g->geom.height < g->wp.height)
3351 g->geom.height = g->wp.height;
3352 g->zoom.x = (g->geom.width - 1) / g->bounds.width;
3353 g->zoom.y = (g->geom.height- 1) / g->bounds.height;
3355 g->geom.x -= (int )rint ((g->geom.width - cur_width) *
3356 ((pointer_x - g->geom.x)/(double )cur_width));
3357 g->geom.y -= (int )rint ((g->geom.height - cur_height) *
3358 ((pointer_y - g->geom.y)/(double )cur_height));
3360 if (g->geom.x > g->wp.x)
3361 g->geom.x = g->wp.x;
3362 if (g->geom.y > g->wp.y)
3363 g->geom.y = g->wp.y;
3364 if (g->wp.x + g->wp.width > g->geom.x + g->geom.width)
3365 g->geom.x = g->wp.width + g->wp.x - g->geom.width;
3366 if (g->wp.y + g->wp.height > g->geom.y + g->geom.height)
3367 g->geom.y = g->wp.height + g->wp.y - g->geom.height;
3369 printf ("key press: graph: (%d,%d), (%d,%d); viewport: (%d,%d), "
3370 "(%d,%d); zooms: (%f,%f)\n", g->geom.x, g->geom.y,
3371 g->geom.width, g->geom.height, g->wp.x, g->wp.y, g->wp.width,
3372 g->wp.height, g->zoom.x, g->zoom.y);
3375 graph_element_lists_make (g);
3376 g->cross.erase_needed = 0;
3378 axis_display (g->y_axis);
3379 axis_display (g->x_axis);
3380 update_zoom_spins (g);
3382 cross_draw (g, pointer_x, pointer_y);
3385 static void do_zoom_in_keyboard (struct graph *g)
3387 gtk_toggle_button_set_active (g->zoom.widget.in_toggle, TRUE);
3388 do_zoom_keyboard (g);
3391 static void do_zoom_out_keyboard (struct graph *g)
3393 gtk_toggle_button_set_active (g->zoom.widget.out_toggle, TRUE);
3394 do_zoom_keyboard (g);
3395 gtk_toggle_button_set_active (g->zoom.widget.in_toggle, TRUE);
3398 static void do_select_segment (struct graph *g)
3400 int pointer_x, pointer_y;
3402 gdk_window_get_pointer (gtk_widget_get_window(g->drawing_area), &pointer_x, &pointer_y, 0);
3403 graph_select_segment (g, pointer_x, pointer_y);
3406 static void do_wscale_graph (struct graph *g)
3408 gtk_toggle_button_set_active (g->gt.graph_wscale, TRUE);
3411 static void do_rtt_graph (struct graph *g)
3413 gtk_toggle_button_set_active (g->gt.graph_rtt, TRUE);
3416 static void do_throughput_graph (struct graph *g)
3418 gtk_toggle_button_set_active (g->gt.graph_tput, TRUE);
3421 static void do_ts_graph_stevens (struct graph *g)
3423 gtk_toggle_button_set_active (g->gt.graph_tseqstevens, TRUE);
3426 static void do_ts_graph_tcptrace (struct graph *g)
3428 gtk_toggle_button_set_active (g->gt.graph_tseqttrace, TRUE);
3431 static void do_magnify_create (struct graph *g)
3433 int pointer_x, pointer_y;
3435 gdk_window_get_pointer (gtk_widget_get_window(g->drawing_area), &pointer_x, &pointer_y, 0);
3437 magnify_create (g, (int )rint (pointer_x), (int )rint (pointer_y));
3440 static void do_key_motion (struct graph *g)
3442 if (g->geom.x > g->wp.x)
3443 g->geom.x = g->wp.x;
3444 if (g->geom.y > g->wp.y)
3445 g->geom.y = g->wp.y;
3446 if (g->wp.x + g->wp.width > g->geom.x + g->geom.width)
3447 g->geom.x = g->wp.width + g->wp.x - g->geom.width;
3448 if (g->wp.y + g->wp.height > g->geom.y + g->geom.height)
3449 g->geom.y = g->wp.height + g->wp.y - g->geom.height;
3450 g->cross.erase_needed = 0;
3452 axis_display (g->y_axis);
3453 axis_display (g->x_axis);
3454 if (g->cross.draw) {
3455 int pointer_x, pointer_y;
3456 gdk_window_get_pointer (gtk_widget_get_window(g->drawing_area), &pointer_x, &pointer_y, 0);
3457 cross_draw (g, pointer_x, pointer_y);
3461 static void do_key_motion_up (struct graph *g, int step)
3467 static void do_key_motion_down (struct graph *g, int step)
3473 static void do_key_motion_left (struct graph *g, int step)
3479 static void do_key_motion_right (struct graph *g, int step)
3485 static gboolean button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data _U_)
3487 struct graph *g = (struct graph *) g_object_get_data(G_OBJECT(widget), "graph");
3489 debug(DBS_FENTRY) puts ("button_press_event()");
3491 if (event->button == MOUSE_BUTTON_RIGHT) {
3492 if (event->state & GDK_CONTROL_MASK) {
3493 magnify_create (g, (int )rint (event->x), (int )rint (event->y));
3495 g->grab.x = (int )rint (event->x) - g->geom.x;
3496 g->grab.y = (int )rint (event->y) - g->geom.y;
3497 g->grab.grabbed = TRUE;
3499 #ifdef ORIGINAL_WIN32_BUTTONS
3500 /* Windows mouse control: */
3501 /* [<ctrl>-left] - select packet */
3502 /* [left] - zoom in */
3503 /* [<shift>-left] - zoom out */
3504 } else if (event->button == MOUSE_BUTTON_LEFT) {
3505 if (event->state & GDK_CONTROL_MASK) {
3506 graph_select_segment (g, (int)event->x, (int)event->y);
3508 #else /* !ORIGINAL_WIN32_BUTTONS */
3509 } else if (event->button == MOUSE_BUTTON_MIDDLE) {
3511 do_zoom_mouse(g, event);
3512 #ifndef ORIGINAL_WIN32_BUTTONS
3513 } else if (event->button == MOUSE_BUTTON_LEFT) {
3514 graph_select_segment (g, (int )event->x, (int )event->y);
3515 #else /* ORIGINAL_WIN32_BUTTONS*/
3522 static gboolean motion_notify_event (GtkWidget *widget, GdkEventMotion *event, gpointer user_data _U_)
3524 struct graph *g = (struct graph *) g_object_get_data(G_OBJECT(widget), "graph");
3526 GdkModifierType state;
3528 /* debug(DBS_FENTRY) puts ("motion_notify_event()"); */
3531 gdk_window_get_pointer (event->window, &x, &y, &state);
3535 state = event->state;
3538 /* Testing just (state & GDK_BUTTON1_MASK) is not enough since when button1
3539 * is pressed while pointer is in motion, we will receive one more motion
3540 * notify *before* we get the button press. This last motion notify works
3541 * with stale grab coordinates */
3542 if (state & GDK_BUTTON3_MASK) {
3543 if (g->grab.grabbed) {
3544 g->geom.x = x-g->grab.x;
3545 g->geom.y = y-g->grab.y;
3547 if (g->geom.x > g->wp.x)
3548 g->geom.x = g->wp.x;
3549 if (g->geom.y > g->wp.y)
3550 g->geom.y = g->wp.y;
3551 if (g->wp.x + g->wp.width > g->geom.x + g->geom.width)
3552 g->geom.x = g->wp.width + g->wp.x - g->geom.width;
3553 if (g->wp.y + g->wp.height > g->geom.y + g->geom.height)
3554 g->geom.y = g->wp.height + g->wp.y - g->geom.height;
3555 g->cross.erase_needed = 0;
3557 axis_display (g->y_axis);
3558 axis_display (g->x_axis);
3560 cross_draw (g, x, y);
3561 } else if (g->magnify.active)
3562 magnify_move (g, x, y);
3563 } else if (state & GDK_BUTTON1_MASK) {
3564 graph_select_segment (g, x, y);
3565 if (g->cross.erase_needed)
3568 cross_draw (g, x, y);
3570 if (g->cross.erase_needed)
3573 cross_draw (g, x, y);
3579 static gboolean button_release_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data _U_)
3581 struct graph *g = (struct graph *) g_object_get_data(G_OBJECT(widget), "graph");
3583 debug(DBS_FENTRY) puts ("button_release_event()");
3585 if (event->button == MOUSE_BUTTON_RIGHT)
3586 g->grab.grabbed = FALSE;
3588 if (g->magnify.active)
3589 magnify_destroy (g);
3593 static gboolean key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data _U_)
3595 struct graph *g = (struct graph *) g_object_get_data(G_OBJECT(widget), "graph");
3598 debug(DBS_FENTRY) puts ("key_press_event()");
3600 if((event->state & GDK_CONTROL_MASK) && (event->state & GDK_SHIFT_MASK))
3602 else if (event->state & GDK_CONTROL_MASK)
3604 else if (event->state & GDK_SHIFT_MASK)
3609 switch (event->keyval) {
3611 toggle_crosshairs (g);
3614 toggle_time_origin (g);
3617 toggle_seq_origin (g);
3621 restore_initial_graph_view (g);
3625 do_zoom_in_keyboard (g);
3629 do_zoom_out_keyboard (g);
3632 do_magnify_create (g);
3635 do_select_segment (g);
3641 do_throughput_graph (g);
3644 do_ts_graph_stevens (g);
3647 do_ts_graph_tcptrace (g);
3653 do_key_motion_left (g, step);
3656 do_key_motion_up (g, step);
3659 do_key_motion_right (g, step);
3662 do_key_motion_down (g, step);
3665 callback_create_help (NULL, NULL);
3673 static gboolean key_release_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data _U_)
3675 struct graph *g = (struct graph *) g_object_get_data(G_OBJECT(widget), "graph");
3677 debug(DBS_FENTRY) puts ("key_release_event()");
3679 if (event->keyval == GDK_Shift_L || event->keyval == GDK_ISO_Prev_Group) {
3680 /* g->zoom.flags &= ~ZOOM_OUT; */
3681 gtk_toggle_button_set_active (g->zoom.widget.in_toggle, TRUE);
3686 static gboolean leave_notify_event (GtkWidget *widget, GdkEventCrossing *event _U_, gpointer user_data _U_)
3688 struct graph *g = (struct graph *) g_object_get_data(G_OBJECT(widget), "graph");
3690 if (g->cross.erase_needed)
3696 static gboolean enter_notify_event (GtkWidget *widget, GdkEventCrossing *event _U_, gpointer user_data _U_)
3698 struct graph *g = (struct graph *) g_object_get_data(G_OBJECT(widget), "graph");
3700 /* graph_pixmap_display (g); */
3701 if (g->cross.draw) {
3703 gdk_window_get_pointer (gtk_widget_get_window(g->drawing_area), &x, &y, 0);
3704 cross_draw (g, x, y);
3709 static void toggle_crosshairs (struct graph *g)
3713 if (g->cross.draw) {
3715 gdk_window_get_pointer (gtk_widget_get_window(g->drawing_area), &x, &y, 0);
3717 } else if (g->cross.erase_needed) {
3721 /* toggle buttons emit their "toggled" signals so don't bother doing
3722 * any real work here, it will be done in signal handlers */
3724 gtk_toggle_button_set_active (g->cross.on_toggle, TRUE);
3726 gtk_toggle_button_set_active (g->cross.off_toggle, TRUE);
3729 static void toggle_time_origin (struct graph *g)
3732 case GRAPH_TSEQ_STEVENS:
3733 tseq_stevens_toggle_time_origin (g);
3735 case GRAPH_TSEQ_TCPTRACE:
3736 tseq_tcptrace_toggle_time_origin (g);
3738 case GRAPH_THROUGHPUT:
3739 tput_toggle_time_origin (g);
3744 axis_display (g->x_axis);
3747 static void toggle_seq_origin (struct graph *g)
3750 case GRAPH_TSEQ_STEVENS:
3751 tseq_stevens_toggle_seq_origin (g);
3752 axis_display (g->y_axis);
3754 case GRAPH_TSEQ_TCPTRACE:
3755 tseq_tcptrace_toggle_seq_origin (g);
3756 axis_display (g->y_axis);
3759 rtt_toggle_seq_origin (g);
3760 axis_display (g->x_axis);
3767 static void restore_initial_graph_view (struct graph *g)
3769 g->geom.width = g->wp.width;
3770 g->geom.height = g->wp.height;
3771 g->geom.x = g->wp.x;
3772 g->geom.y = g->wp.y;
3773 graph_init_sequence (g);
3776 static int get_num_dsegs (struct graph *g)
3779 struct segment *tmp;
3781 for (tmp=g->segments, count=0; tmp; tmp=tmp->next) {
3782 if(compare_headers(&g->current->ip_src, &g->current->ip_dst,
3783 g->current->th_sport, g->current->th_dport,
3784 &tmp->ip_src, &tmp->ip_dst,
3785 tmp->th_sport, tmp->th_dport,
3786 COMPARE_CURR_DIR)) {
3793 static int get_num_acks (struct graph *g)
3796 struct segment *tmp;
3798 for (tmp=g->segments, count=0; tmp; tmp=tmp->next) {
3799 if(!compare_headers(&g->current->ip_src, &g->current->ip_dst,
3800 g->current->th_sport, g->current->th_dport,
3801 &tmp->ip_src, &tmp->ip_dst,
3802 tmp->th_sport, tmp->th_dport,
3803 COMPARE_CURR_DIR)) {
3811 * Stevens-style time-sequence grapH
3814 static void tseq_stevens_read_config (struct graph *g)
3816 debug(DBS_FENTRY) puts ("tseq_stevens_read_config()");
3818 g->s.tseq_stevens.seq_width = 4;
3819 g->s.tseq_stevens.seq_height = 4;
3820 g->s.tseq_stevens.flags = 0;
3822 g->title = (const char ** )g_malloc (2 * sizeof (char *));
3823 g->title[0] = "Time/Sequence Graph (Stevens)";
3825 g->y_axis->label = (const char ** )g_malloc (3 * sizeof (char * ));
3826 g->y_axis->label[0] = "number[B]";
3827 g->y_axis->label[1] = "Sequence";
3828 g->y_axis->label[2] = NULL;
3829 g->x_axis->label = (const char ** )g_malloc (2 * sizeof (char * ));
3830 g->x_axis->label[0] = "Time[s]";
3831 g->x_axis->label[1] = NULL;
3834 /* Used by both 'stevens' and 'tcptrace' */
3835 static void tseq_initialize (struct graph *g)
3837 debug(DBS_FENTRY) puts ("tseq_initialize()");
3838 tseq_get_bounds (g);
3844 case GRAPH_TSEQ_STEVENS:
3845 tseq_stevens_read_config(g);
3847 case GRAPH_TSEQ_TCPTRACE:
3848 tseq_tcptrace_read_config(g);
3854 /* Determine "bounds"
3855 * Essentially: look for lowest/highest time and seq in the list of segments
3856 * Note that for tcptrace the "(ack + window) sequence number" would normally be expected
3857 * to be the upper bound; However, just to be safe, include the data seg sequence numbers
3858 * in the comparison for tcptrace
3859 * (e.g. to handle the case of only data segments).
3862 /* ToDo: worry about handling cases such as trying to plot seq of just 1 frame */
3864 static void tseq_get_bounds (struct graph *g)
3866 struct segment *tmp;
3868 gboolean data_frame_seen=FALSE;
3869 double data_tim_low=0;
3870 double data_tim_high=0;
3871 guint32 data_seq_cur;
3872 guint32 data_seq_nxt;
3873 guint32 data_seq_low=0;
3874 guint32 data_seq_high=0;
3875 gboolean ack_frame_seen=FALSE;
3876 double ack_tim_low=0;
3877 double ack_tim_high=0;
3878 guint32 ack_seq_cur;
3879 guint32 ack_seq_low=0;
3880 guint32 win_seq_cur;
3881 guint32 win_seq_high=0;
3883 /* go thru all segments to determine "bounds" */
3884 for (tmp=g->segments; tmp; tmp=tmp->next) {
3885 if(compare_headers(&g->current->ip_src, &g->current->ip_dst,
3886 g->current->th_sport, g->current->th_dport,
3887 &tmp->ip_src, &tmp->ip_dst,
3888 tmp->th_sport, tmp->th_dport,
3889 COMPARE_CURR_DIR)) {
3892 tim = tmp->rel_secs + tmp->rel_usecs / 1000000.0;
3893 data_seq_cur = tmp->th_seq;
3894 data_seq_nxt = data_seq_cur + tmp->th_seglen;
3895 if (! data_frame_seen) {
3896 data_tim_low = data_tim_high = tim;
3897 data_seq_low = data_seq_cur;
3898 data_seq_high = data_seq_nxt;
3899 data_frame_seen = TRUE;
3901 if (tim < data_tim_low) data_tim_low = tim;
3902 if (tim > data_tim_high) data_tim_high = tim;
3903 if (data_seq_cur < data_seq_low) data_seq_low = data_seq_cur;
3904 if (data_seq_nxt > data_seq_high) data_seq_high = data_seq_nxt;
3906 else { /* ack seg */
3907 /* skip ack processing if no ACK (e.g. in RST) */
3908 if (TCP_ACK (tmp->th_flags)) {
3909 tim = tmp->rel_secs + tmp->rel_usecs / 1000000.0;
3910 ack_seq_cur = tmp->th_ack;
3911 win_seq_cur = ack_seq_cur + tmp->th_win;
3912 if (! ack_frame_seen) {
3913 ack_tim_low = ack_tim_high = tim;
3914 ack_seq_low = ack_seq_cur;
3915 win_seq_high = win_seq_cur;
3916 ack_frame_seen = TRUE;
3918 if (tim < ack_tim_low) ack_tim_low = tim;
3919 if (tim > ack_tim_high) ack_tim_high = tim;
3920 if (ack_seq_cur < ack_seq_low) ack_seq_low = ack_seq_cur;
3921 if (win_seq_cur > win_seq_high) win_seq_high = win_seq_cur;
3926 /* if 'stevens': use only data segments to determine bounds */
3927 /* if 'tcptrace': use both data and ack segments to determine bounds */
3929 case GRAPH_TSEQ_STEVENS:
3930 g->bounds.x0 = data_tim_low;
3931 g->bounds.width = data_tim_high - data_tim_low;
3932 g->bounds.y0 = data_seq_low;
3933 g->bounds.height = data_seq_high - data_seq_low;
3935 case GRAPH_TSEQ_TCPTRACE:
3936 /* If (ack_frame_seen == false) -> use 'data' segments.
3937 * Else If (data_frame_seen == false) -> use 'ack' segments.
3938 * Else -> use both data and ack segments.
3940 g->bounds.x0 = ((data_tim_low <= ack_tim_low && data_frame_seen) || (! ack_frame_seen)) ? data_tim_low : ack_tim_low;
3941 g->bounds.width = (((data_tim_high >= ack_tim_high && data_frame_seen) || (! ack_frame_seen)) ? data_tim_high : ack_tim_high) - g->bounds.x0;
3942 g->bounds.y0 = ((data_seq_low <= ack_seq_low && data_frame_seen) || (! ack_frame_seen)) ? data_seq_low : ack_seq_low;
3943 g->bounds.height = (((data_seq_high >= win_seq_high && data_frame_seen) || (! ack_frame_seen)) ? data_seq_high : win_seq_high) - g->bounds.y0;
3947 g->zoom.x = (g->geom.width - 1) / g->bounds.width;
3948 g->zoom.y = (g->geom.height -1) / g->bounds.height;
3952 static void tseq_stevens_make_elmtlist (struct graph *g)
3954 struct segment *tmp;
3955 struct element *elements, *e;
3956 double xx0 = g->bounds.x0, yy0 = g->bounds.y0;
3957 guint32 seq_base = (guint32) yy0;
3960 debug(DBS_FENTRY) puts ("tseq_stevens_make_elmtlist()");
3961 if (g->elists->elements == NULL) {
3962 int n = 1 + get_num_dsegs (g);
3963 e = elements = (struct element * )g_malloc (n*sizeof (struct element));
3965 e = elements = g->elists->elements;
3967 for (tmp=g->segments; tmp; tmp=tmp->next) {
3970 if(!compare_headers(&g->current->ip_src, &g->current->ip_dst,
3971 g->current->th_sport, g->current->th_dport,
3972 &tmp->ip_src, &tmp->ip_dst,
3973 tmp->th_sport, tmp->th_dport,
3974 COMPARE_CURR_DIR)) {
3978 seq_cur = tmp->th_seq - seq_base;
3979 secs = g->zoom.x * (tmp->rel_secs + tmp->rel_usecs / 1000000.0 - xx0);
3980 seqno = g->zoom.y * seq_cur;
3982 e->type = ELMT_ELLIPSE;
3984 e->p.ellipse.dim.width = g->s.tseq_stevens.seq_width;
3985 e->p.ellipse.dim.height = g->s.tseq_stevens.seq_height;
3986 e->p.ellipse.dim.x = secs - g->s.tseq_stevens.seq_width/2.0;
3987 e->p.ellipse.dim.y = seqno + g->s.tseq_stevens.seq_height/2.0;
3990 e->type = ELMT_NONE;
3991 g->elists->elements = elements;
3994 static void tseq_stevens_toggle_seq_origin (struct graph *g)
3996 g->s.tseq_stevens.flags ^= SEQ_ORIGIN;
3998 if ((g->s.tseq_stevens.flags & SEQ_ORIGIN) == SEQ_ORIGIN_ZERO)
3999 g->y_axis->min = g->bounds.y0;
4000 else /* g->tseq_stevens.flags & SEQ_ORIGIN == SEQ_ORIGIN_ISN */
4004 static void tseq_stevens_toggle_time_origin (struct graph *g)
4006 g->s.tseq_stevens.flags ^= TIME_ORIGIN;
4008 if ((g->s.tseq_stevens.flags & TIME_ORIGIN) == TIME_ORIGIN_CAP)
4009 g->x_axis->min = g->bounds.x0;
4010 else /* g->tseq_stevens.flags & TIME_ORIGIN == TIME_ORIGIN_CONN */
4015 * tcptrace-style time-sequence graph
4018 static void tseq_tcptrace_read_config (struct graph *g)
4022 g->s.tseq_tcptrace.seq_color.pixel=0;
4023 g->s.tseq_tcptrace.seq_color.red=0;
4024 g->s.tseq_tcptrace.seq_color.green=0;
4025 g->s.tseq_tcptrace.seq_color.blue=0;
4027 /* LightSlateGray */
4028 g->s.tseq_tcptrace.ack_color[0].pixel=0;
4029 g->s.tseq_tcptrace.ack_color[0].red=0x7777;
4030 g->s.tseq_tcptrace.ack_color[0].green=0x8888;
4031 g->s.tseq_tcptrace.ack_color[0].blue=0x9999;
4034 g->s.tseq_tcptrace.ack_color[1].pixel=0;
4035 g->s.tseq_tcptrace.ack_color[1].red=0xd3d3;
4036 g->s.tseq_tcptrace.ack_color[1].green=0xd3d3;
4037 g->s.tseq_tcptrace.ack_color[1].blue=0xd3d3;
4039 g->s.tseq_tcptrace.flags = 0;
4041 g->elists->next = (struct element_list * )
4042 g_malloc (sizeof (struct element_list));
4043 g->elists->next->next = NULL;
4044 g->elists->next->elements = NULL;
4046 g->title = (const char ** )g_malloc (2 * sizeof (char *));
4047 g->title[0] = "Time/Sequence Graph (tcptrace)";
4049 g->y_axis->label = (const char ** )g_malloc (3 * sizeof (char * ));
4050 g->y_axis->label[0] = "number[B]";
4051 g->y_axis->label[1] = "Sequence";
4052 g->y_axis->label[2] = NULL;
4053 g->x_axis->label = (const char ** )g_malloc (2 * sizeof (char * ));
4054 g->x_axis->label[0] = "Time[s]";
4055 g->x_axis->label[1] = NULL;
4058 static void tseq_tcptrace_make_elmtlist (struct graph *g)
4060 struct segment *tmp;
4061 struct element *elements0, *e0; /* list of elmts with prio 0 */
4062 struct element *elements1, *e1; /* list of elmts with prio 1 */
4064 double p_t = 0; /* ackno, window and time of previous segment */
4065 double p_ackno = 0, p_win = 0;
4066 gboolean ack_seen=FALSE;
4071 debug(DBS_FENTRY) puts ("tseq_tcptrace_make_elmtlist()");
4073 if (g->elists->elements == NULL) {
4074 int n = 1 + 4*get_num_acks(g);
4075 e0 = elements0 = (struct element * )g_malloc (n*sizeof (struct element));
4077 e0 = elements0 = g->elists->elements;
4079 if (g->elists->next->elements == NULL ) {
4080 int n = 1 + 3*get_num_dsegs(g);
4081 e1 = elements1 = (struct element * )g_malloc (n*sizeof (struct element));
4083 e1 = elements1 = g->elists->next->elements;
4087 seq_base = (guint32) yy0;
4089 for (tmp=g->segments; tmp; tmp=tmp->next) {
4093 secs = tmp->rel_secs + tmp->rel_usecs / 1000000.0;
4096 if(compare_headers(&g->current->ip_src, &g->current->ip_dst,
4097 g->current->th_sport, g->current->th_dport,
4098 &tmp->ip_src, &tmp->ip_dst,
4099 tmp->th_sport, tmp->th_dport,
4100 COMPARE_CURR_DIR)) {
4101 /* forward direction -> we need seqno and amount of data */
4104 seq_cur = tmp->th_seq - seq_base;
4105 if (TCP_SYN (tmp->th_flags) || TCP_FIN (tmp->th_flags))
4108 data = tmp->th_seglen;
4110 yy1 = g->zoom.y * (seq_cur);
4111 yy2 = g->zoom.y * (seq_cur + data);
4112 e1->type = ELMT_LINE;
4114 /* Set the drawing color */
4115 e1->elment_color_p = &g->s.tseq_tcptrace.seq_color;
4116 e1->p.line.dim.x1 = e1->p.line.dim.x2 = x;
4117 e1->p.line.dim.y1 = yy1;
4118 e1->p.line.dim.y2 = yy2;
4120 e1->type = ELMT_LINE;
4122 /* Set the drawing color */
4123 e1->elment_color_p = &g->s.tseq_tcptrace.seq_color;
4124 e1->p.line.dim.x1 = x - 1;
4125 e1->p.line.dim.x2 = x + 1;
4126 e1->p.line.dim.y1 = e1->p.line.dim.y2 = yy1;
4128 e1->type = ELMT_LINE;
4130 /* Set the drawing color */
4131 e1->elment_color_p = &g->s.tseq_tcptrace.seq_color;
4132 e1->p.line.dim.x1 = x + 1;
4133 e1->p.line.dim.x2 = x - 1;
4134 e1->p.line.dim.y1 = e1->p.line.dim.y2 = yy2;
4138 if (! TCP_ACK (tmp->th_flags))
4139 /* SYN's and RST's do not necessarily have ACK's*/
4141 /* backward direction -> we need ackno and window */
4142 seq_cur = tmp->th_ack - seq_base;
4143 ackno = seq_cur * g->zoom.y;
4144 win = tmp->th_win * g->zoom.y;
4147 if (ack_seen == TRUE) { /* don't plot the first ack */
4148 e0->type = ELMT_LINE;
4150 /* Set the drawing color */
4151 e0->elment_color_p = &g->s.tseq_tcptrace.ack_color[toggle];
4152 e0->p.line.dim.x1 = p_t;
4153 e0->p.line.dim.y1 = p_ackno;
4154 e0->p.line.dim.x2 = x;
4155 e0->p.line.dim.y2 = p_ackno;
4157 e0->type = ELMT_LINE;
4159 /* Set the drawing color */
4160 e0->elment_color_p = &g->s.tseq_tcptrace.ack_color[toggle];
4161 e0->p.line.dim.x1 = x;
4162 e0->p.line.dim.y1 = p_ackno;
4163 e0->p.line.dim.x2 = x;
4164 e0->p.line.dim.y2 = ackno!=p_ackno || ackno<4 ? ackno : ackno-4;
4167 e0->type = ELMT_LINE;
4169 /* Set the drawing color */
4170 e0->elment_color_p = &g->s.tseq_tcptrace.ack_color[toggle];
4171 e0->p.line.dim.x1 = p_t;
4172 e0->p.line.dim.y1 = p_win + p_ackno;
4173 e0->p.line.dim.x2 = x;
4174 e0->p.line.dim.y2 = p_win + p_ackno;
4176 e0->type = ELMT_LINE;
4178 /* Set the drawing color */
4179 e0->elment_color_p = &g->s.tseq_tcptrace.ack_color[toggle];
4180 e0->p.line.dim.x1 = x;
4181 e0->p.line.dim.y1 = p_win + p_ackno;
4182 e0->p.line.dim.x2 = x;
4183 e0->p.line.dim.y2 = win + ackno;
4193 e0->type = ELMT_NONE;
4194 e1->type = ELMT_NONE;
4195 g->elists->elements = elements0;
4196 g->elists->next->elements = elements1;
4199 static void tseq_tcptrace_toggle_seq_origin (struct graph *g)
4201 g->s.tseq_tcptrace.flags ^= SEQ_ORIGIN;
4203 if ((g->s.tseq_tcptrace.flags & SEQ_ORIGIN) == SEQ_ORIGIN_ZERO)
4204 g->y_axis->min = g->bounds.y0;
4205 else /* g->tseq_stevens.flags & SEQ_ORIGIN == SEQ_ORIGIN_ISN */
4209 static void tseq_tcptrace_toggle_time_origin (struct graph *g)
4211 g->s.tseq_tcptrace.flags ^= TIME_ORIGIN;
4213 if ((g->s.tseq_tcptrace.flags & TIME_ORIGIN) == TIME_ORIGIN_CAP)
4214 g->x_axis->min = g->bounds.x0;
4215 else /* g->tseq_stevens.flags & TIME_ORIGIN == TIME_ORIGIN_CONN */
4223 static void tput_make_elmtlist (struct graph *g)
4225 struct segment *tmp, *oldest;
4226 struct element *elements, *e;
4230 if (g->elists->elements == NULL) {
4231 int n = 1 + get_num_dsegs (g);
4232 e = elements = (struct element * )g_malloc (n*sizeof (struct element));
4234 e = elements = g->elists->elements;
4236 for (oldest=g->segments,tmp=g->segments->next,i=0; tmp; tmp=tmp->next,i++) {
4237 double time_val = tmp->rel_secs + tmp->rel_usecs/1000000.0;
4238 dtime = time_val - (oldest->rel_secs + oldest->rel_usecs/1000000.0);
4239 if (i>g->s.tput.nsegs) {
4240 sum -= oldest->th_seglen;
4241 oldest=oldest->next;
4243 sum += tmp->th_seglen;
4245 /* debug(DBS_TPUT_ELMTS) printf ("tput=%f\n", tput); */
4247 e->type = ELMT_ELLIPSE;
4249 e->p.ellipse.dim.width = g->s.tput.width;
4250 e->p.ellipse.dim.height = g->s.tput.height;
4251 e->p.ellipse.dim.x = g->zoom.x*(time_val - g->bounds.x0) - g->s.tput.width/2.0;
4252 e->p.ellipse.dim.y = g->zoom.y*tput + g->s.tput.height/2.0;
4255 e->type = ELMT_NONE;
4256 g->elists->elements = elements;
4259 /* Purpose of <graph_type>_initialize functions:
4260 * - find maximum and minimum for both axes
4261 * - call setup routine for style struct */
4262 static void tput_initialize (struct graph *g)
4264 struct segment *tmp, *oldest, *last;
4266 double dtime, tput, tputmax=0;
4267 double t, t0, tmax = 0, yy0, ymax;
4269 debug(DBS_FENTRY) puts ("tput_initialize()");
4271 tput_read_config(g);
4273 for (last=g->segments; last->next; last=last->next);
4274 for (oldest=g->segments,tmp=g->segments->next,i=0; tmp; tmp=tmp->next,i++) {
4275 dtime = tmp->rel_secs + tmp->rel_usecs/1000000.0 -
4276 (oldest->rel_secs + oldest->rel_usecs/1000000.0);
4277 if (i>g->s.tput.nsegs) {
4278 sum -= oldest->th_seglen;
4279 oldest=oldest->next;
4281 sum += tmp->th_seglen;
4283 debug(DBS_TPUT_ELMTS) printf ("tput=%f\n", tput);
4286 t = tmp->rel_secs + tmp->rel_usecs / 1000000.0;
4291 t0 = g->segments->rel_secs + g->segments->rel_usecs / 1000000.0;
4297 g->bounds.width = tmax - t0;
4298 g->bounds.height = ymax - yy0;
4299 g->zoom.x = (g->geom.width - 1) / g->bounds.width;
4300 g->zoom.y = (g->geom.height -1) / g->bounds.height;
4303 static void tput_read_config (struct graph *g)
4305 debug(DBS_FENTRY) puts ("tput_read_config()");
4307 g->s.tput.width = 4;
4308 g->s.tput.height = 4;
4309 g->s.tput.nsegs = 20;
4311 g->title = (const char ** )g_malloc (2 * sizeof (char *));
4312 g->title[0] = "Throughput Graph";
4314 g->y_axis->label = (const char ** )g_malloc (3 * sizeof (char * ));
4315 g->y_axis->label[0] = "[B/s]";
4316 g->y_axis->label[1] = "Throughput";
4317 g->y_axis->label[2] = NULL;
4318 g->x_axis->label = (const char ** )g_malloc (2 * sizeof (char * ));
4319 g->x_axis->label[0] = "Time[s]";
4320 g->x_axis->label[1] = NULL;
4321 g->s.tput.flags = 0;
4324 static void tput_toggle_time_origin (struct graph *g)
4326 g->s.tput.flags ^= TIME_ORIGIN;
4328 if ((g->s.tput.flags & TIME_ORIGIN) == TIME_ORIGIN_CAP)
4329 g->x_axis->min = g->bounds.x0;
4330 else /* g->s.tput.flags & TIME_ORIGIN == TIME_ORIGIN_CONN */
4336 static void rtt_read_config (struct graph *g)
4338 debug(DBS_FENTRY) puts ("rtt_read_config()");
4341 g->s.rtt.height = 4;
4344 g->title = (const char ** )g_malloc (2 * sizeof (char *));
4345 g->title[0] = "Round Trip Time Graph";
4347 g->y_axis->label = (const char ** )g_malloc (3 * sizeof (char * ));
4348 g->y_axis->label[0] = "RTT [s]";
4349 g->y_axis->label[1] = NULL;
4350 g->x_axis->label = (const char ** )g_malloc (2 * sizeof (char * ));
4351 g->x_axis->label[0] = "Sequence Number[B]";
4352 g->x_axis->label[1] = NULL;
4355 static void rtt_initialize (struct graph *g)
4357 struct segment *tmp, *first=NULL;
4358 struct unack *unack = NULL, *u;
4360 double xx0, yy0, ymax;
4362 guint32 seq_base = 0;
4364 debug(DBS_FENTRY) puts ("rtt_initialize()");
4366 rtt_read_config (g);
4368 for (tmp=g->segments; tmp; tmp=tmp->next) {
4369 if(compare_headers(&g->current->ip_src, &g->current->ip_dst,
4370 g->current->th_sport, g->current->th_dport,
4371 &tmp->ip_src, &tmp->ip_dst,
4372 tmp->th_sport, tmp->th_dport,
4373 COMPARE_CURR_DIR)) {
4374 guint32 seqno = tmp->th_seq;
4381 if (tmp->th_seglen && !rtt_is_retrans (unack, seqno)) {
4382 double time_val = tmp->rel_secs + tmp->rel_usecs / 1000000.0;
4383 u = rtt_get_new_unack (time_val, seqno);
4385 rtt_put_unack_on_list (&unack, u);
4388 if (seqno + tmp->th_seglen > xmax)
4389 xmax = seqno + tmp->th_seglen;
4391 guint32 ackno = tmp->th_ack -seq_base;
4392 double time_val = tmp->rel_secs + tmp->rel_usecs / 1000000.0;
4395 for (u=unack; u; u=v)
4396 if (ackno > u->seqno) {
4397 double rtt = time_val - u->time;
4401 rtt_delete_unack_from_list (&unack, u);
4413 g->bounds.width = xmax;
4414 g->bounds.height = ymax - yy0;
4415 g->zoom.x = g->geom.width / g->bounds.width;
4416 g->zoom.y = g->geom.height / g->bounds.height;
4419 static int rtt_is_retrans (struct unack *list, unsigned int seqno)
4423 for (u=list; u; u=u->next)
4424 if (u->seqno== seqno)
4430 static struct unack *rtt_get_new_unack (double time_val, unsigned int seqno)
4434 u = (struct unack * )g_malloc (sizeof (struct unack));
4443 static void rtt_put_unack_on_list (struct unack **l, struct unack *new)
4445 struct unack *u, *list = *l;
4447 for (u=list; u; u=u->next)
4457 static void rtt_delete_unack_from_list (struct unack **l, struct unack *dead)
4459 struct unack *u, *list = *l;
4468 for (u=list; u; u=u->next)
4469 if (u->next == dead) {
4470 u->next = u->next->next;
4476 static void rtt_make_elmtlist (struct graph *g)
4478 struct segment *tmp;
4479 struct unack *unack = NULL, *u;
4480 struct element *elements, *e;
4481 guint32 seq_base = (guint32) g->bounds.x0;
4483 debug(DBS_FENTRY) puts ("rtt_make_elmtlist()");
4485 if (g->elists->elements == NULL) {
4486 int n = 1 + get_num_dsegs (g);
4487 e = elements = (struct element * )g_malloc (n*sizeof (struct element));
4489 e = elements = g->elists->elements;
4492 for (tmp=g->segments; tmp; tmp=tmp->next) {
4493 if(compare_headers(&g->current->ip_src, &g->current->ip_dst,
4494 g->current->th_sport, g->current->th_dport,
4495 &tmp->ip_src, &tmp->ip_dst,
4496 tmp->th_sport, tmp->th_dport,
4497 COMPARE_CURR_DIR)) {
4498 guint32 seqno = tmp->th_seq -seq_base;
4500 if (tmp->th_seglen && !rtt_is_retrans (unack, seqno)) {
4501 double time_val = tmp->rel_secs + tmp->rel_usecs / 1000000.0;
4502 u = rtt_get_new_unack (time_val, seqno);
4504 rtt_put_unack_on_list (&unack, u);
4507 guint32 ackno = tmp->th_ack -seq_base;
4508 double time_val = tmp->rel_secs + tmp->rel_usecs / 1000000.0;
4511 for (u=unack; u; u=v)
4512 if (ackno > u->seqno) {
4513 double rtt = time_val - u->time;
4515 e->type = ELMT_ELLIPSE;
4517 e->p.ellipse.dim.width = g->s.rtt.width;
4518 e->p.ellipse.dim.height = g->s.rtt.height;
4519 e->p.ellipse.dim.x = g->zoom.x * u->seqno - g->s.rtt.width/2.0;
4520 e->p.ellipse.dim.y = g->zoom.y * rtt + g->s.rtt.height/2.0;
4524 rtt_delete_unack_from_list (&unack, u);
4529 e->type = ELMT_NONE;
4530 g->elists->elements = elements;
4533 static void rtt_toggle_seq_origin (struct graph *g)
4535 g->s.rtt.flags ^= SEQ_ORIGIN;
4537 if ((g->s.rtt.flags & SEQ_ORIGIN) == SEQ_ORIGIN_ZERO)
4538 g->x_axis->min = g->bounds.x0;
4545 static void wscale_read_config(struct graph* g)
4547 debug(DBS_FENTRY) puts ("wscale_read_config()");
4549 g->s.wscale.win_width = 4;
4550 g->s.wscale.win_height = 4;
4551 g->s.wscale.flags = 0;
4553 g->title = (const char ** )g_malloc (2 * sizeof (char *));
4554 g->title[0] = "Window Scaling Graph";
4556 g->y_axis->label = (const char ** )g_malloc (3 * sizeof (char * ));
4557 g->y_axis->label[0] = "[bytes]";
4558 g->y_axis->label[1] = "Windowsize";
4559 g->y_axis->label[2] = NULL;
4560 g->x_axis->label = (const char ** )g_malloc (2 * sizeof (char * ));
4561 g->x_axis->label[0] = "Time [s]";
4562 g->x_axis->label[1] = NULL;
4566 (1) Find maximum and minimum values for Window-Size(scaled) and seconds
4567 (2) call function to define window related values
4569 static void wscale_initialize(struct graph* g)
4572 struct segment* segm = NULL;
4573 guint32 wsize_max = 0;
4574 guint32 wsize_min = 0;
4575 gdouble sec_max = 0.0;
4576 gdouble sec_base = -1.0;
4578 wscale_read_config (g);
4580 debug(DBS_FENTRY) puts ("wscale_initialize()");
4582 for (segm = g->segments; segm; segm = segm->next)
4584 if (compare_headers(&g->current->ip_src, &g->current->ip_dst,
4585 g->current->th_sport, g->current->th_dport,
4586 &segm->ip_src, &segm->ip_dst,
4587 segm->th_sport, segm->th_dport,
4590 gdouble sec = segm->rel_secs + ( segm->rel_usecs / 1000000.0 );
4591 guint16 flags = segm->th_flags;
4592 guint32 wsize = segm->th_win;
4594 /* only data segments */
4595 if ( (flags & (TH_SYN|TH_RST)) == 0 )
4596 if ( wsize > wsize_max )
4599 /* remind time of first probe */
4600 if ( sec_base < 0 && sec > 0 )
4603 if ( sec_max < sec )
4611 g->bounds.y0 = wsize_min;
4612 g->bounds.width = sec_max - sec_base + 5;
4613 g->bounds.height = wsize_max + 5;
4614 g->zoom.x = g->geom.width / g->bounds.width;
4615 g->zoom.y = g->geom.height / g->bounds.height;
4620 (1) Fill & allocate memory for segments times elements,
4622 static void wscale_make_elmtlist(struct graph* g)
4624 struct segment* segm = NULL;
4625 struct element* elements = NULL;
4626 struct element* e = NULL;
4627 gdouble sec_base = -1.0;
4629 debug(DBS_FENTRY) puts ("wscale_make_elmtlist()");
4631 /* Allocate memory for elements if not already done */
4632 if (g->elists->elements == NULL)
4634 int n = 1 + get_num_dsegs(g);
4635 e = elements = (struct element*)g_malloc(n*sizeof(struct element));
4638 e = elements = g->elists->elements;
4641 for ( segm = g->segments; segm; segm = segm->next )
4643 if (compare_headers(&g->current->ip_src, &g->current->ip_dst,
4644 g->current->th_sport, g->current->th_dport,
4645 &segm->ip_src, &segm->ip_dst,
4646 segm->th_sport, segm->th_dport,
4649 gdouble sec = segm->rel_secs + (segm->rel_usecs / 1000000.0);
4650 guint16 flags = segm->th_flags;
4651 guint32 wsize = segm->th_win;
4653 /* remind time of first probe */
4654 if ( sec_base < 0 && sec > 0 )
4657 /* only data or ack segments */
4658 if ( (flags & (TH_SYN|TH_RST)) == 0 )
4660 e->type = ELMT_ELLIPSE;
4662 e->p.ellipse.dim.width = g->s.wscale.win_width;
4663 e->p.ellipse.dim.height = g->s.wscale.win_height;
4664 e->p.ellipse.dim.x = g->zoom.x * (sec - sec_base) - g->s.wscale.win_width / 2.0;
4665 e->p.ellipse.dim.y = g->zoom.y * wsize - g->s.wscale.win_height / 2.0;
4670 /* finished populating element list */
4671 e->type = ELMT_NONE;
4672 g->elists->elements = elements;
4676 #if defined(_WIN32) && !defined(__MINGW32__)
4677 /* replacement of Unix rint() for Windows */
4678 static int rint (double x)
4683 buf = _fcvt(x, 0, &dec, &sig);
4692 #ifdef MAIN_MENU_USE_UIMANAGER
4693 gboolean tcp_graph_selected_packet_enabled(frame_data *current_frame, epan_dissect_t *edt, gpointer callback_data _U_)
4696 gboolean tcp_graph_selected_packet_enabled(frame_data *current_frame, epan_dissect_t *edt, gpointer callback_data _U_)
4699 return current_frame != NULL ? (edt->pi.ipproto == IP_PROTO_TCP) : FALSE;
4704 register_tap_listener_tcp_graph(void)
4706 #ifdef MAIN_MENU_USE_UIMANAGER
4708 register_stat_menu_item("TCP Stream Graph/Time-Sequence Graph (Stevens)", REGISTER_STAT_GROUP_UNSORTED,
4709 tcp_graph_cb, tcp_graph_selected_packet_enabled, NULL, GINT_TO_POINTER(0));
4710 register_stat_menu_item("TCP Stream Graph/Time-Sequence Graph (tcptrace)", REGISTER_STAT_GROUP_UNSORTED,
4711 tcp_graph_cb, tcp_graph_selected_packet_enabled, NULL, GINT_TO_POINTER(1));
4712 register_stat_menu_item("TCP Stream Graph/Throughput Graph", REGISTER_STAT_GROUP_UNSORTED,
4713 tcp_graph_cb, tcp_graph_selected_packet_enabled, NULL, GINT_TO_POINTER(2));
4714 register_stat_menu_item("TCP Stream Graph/Round Trip Time Graph", REGISTER_STAT_GROUP_UNSORTED,
4715 tcp_graph_cb, tcp_graph_selected_packet_enabled, NULL, GINT_TO_POINTER(3));
4716 register_stat_menu_item("TCP Stream Graph/Window Scaling Graph", REGISTER_STAT_GROUP_UNSORTED,
4717 tcp_graph_cb, tcp_graph_selected_packet_enabled, NULL, GINT_TO_POINTER(GRAPH_WSCALE));