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.
36 #include <gdk/gdkkeysyms.h>
38 #include <epan/packet.h>
39 #include <epan/ipproto.h>
40 #include <epan/etypes.h>
41 #include <epan/ppptypes.h>
42 #include <epan/epan_dissect.h>
43 #include <epan/dissectors/packet-tcp.h>
44 #include <epan/address.h>
47 #include "../globals.h"
48 #include "../simple_dialog.h"
50 #include "../stat_menu.h"
52 #include "gtk/gui_utils.h"
53 #include "gtk/dlg_utils.h"
54 #include "gtk/gui_stat_menu.h"
64 #define TCP_SYN(flags) ( flags & TH_SYN )
65 #define TCP_ACK(flags) ( flags & TH_ACK )
66 #define TCP_FIN(flags) ( flags & TH_FIN )
69 #define TXT_HEIGHT 550
71 /* for compare_headers() */
72 /* segment went the same direction as the currently selected one */
73 #define COMPARE_CURR_DIR 0
74 #define COMPARE_ANY_DIR 1
76 /* initalize_axis() */
77 #define AXIS_HORIZONTAL 0
78 #define AXIS_VERTICAL 1
80 #define WINDOW_TITLE_LENGTH 256
82 #define MOUSE_BUTTON_LEFT 1
83 #define MOUSE_BUTTON_MIDDLE 2
84 #define MOUSE_BUTTON_RIGHT 3
97 guint32 th_win; /* make it 32 bits so we can handle some scaling */
106 double x, y, width, height;
110 double x1, y1, x2, y2;
114 int x, y, width, height;
146 struct segment *parent;
148 struct arc_params arc;
149 struct rect_params rect;
150 struct line_params line;
154 struct element_list {
155 struct element_list *next;
156 struct element *elements;
160 struct graph *g; /* which graph we belong to */
161 GtkWidget *drawing_area;
162 GdkPixmap *pixmap[2];
164 #define AXIS_ORIENTATION 1 << 0
166 /* dim and orig (relative to origin of window) of axis' pixmap */
168 /* dim and orig (relative to origin of axis' pixmap) of scale itself */
171 gdouble major, minor; /* major and minor ticks */
175 #define HAXIS_INIT_HEIGHT 70
176 #define VAXIS_INIT_WIDTH 100
177 #define TITLEBAR_HEIGHT 50
178 #define RMARGIN_WIDTH 30
180 struct style_tseq_tcptrace {
186 struct style_tseq_stevens {
204 #define SEQ_ORIGIN 0x1
205 /* show absolute sequence numbers (not differences from isn) */
206 #define SEQ_ORIGIN_ZERO 0x1
207 #define SEQ_ORIGIN_ISN 0x0
208 #define TIME_ORIGIN 0x10
209 /* show time from beginning of capture as opposed to time from beginning
210 * of the connection */
211 #define TIME_ORIGIN_CAP 0x10
212 #define TIME_ORIGIN_CONN 0x0
214 /* this is used by rtt module only */
223 int draw; /* indicates whether we should draw cross at all */
225 GtkToggleButton *on_toggle;
226 GtkToggleButton *off_toggle;
230 double x0, y0, width, height;
239 double step_x, step_y;
241 #define ZOOM_OUT (1 << 0)
242 #define ZOOM_HLOCK (1 << 1)
243 #define ZOOM_VLOCK (1 << 2)
244 #define ZOOM_STEPS_SAME (1 << 3)
245 #define ZOOM_STEPS_KEEP_RATIO (1 << 4)
247 /* unfortunately, we need them both because gtk_toggle_button_set_active ()
248 * with second argument FALSE doesn't do anything, somehow */
250 GtkToggleButton *in_toggle;
251 GtkToggleButton *out_toggle;
254 GtkSpinButton *h_step;
255 GtkSpinButton *v_step;
267 struct ipoint offset;
271 #define MAGZOOMS_SAME (1U << 0)
272 #define MAGZOOMS_SAME_RATIO (1U << 1)
273 #define MAGZOOMS_IGNORE (1U << 31)
276 GtkSpinButton *h_zoom, *v_zoom;
282 #define GRAPH_TSEQ_STEVENS 0
283 #define GRAPH_TSEQ_TCPTRACE 1
284 #define GRAPH_THROUGHPUT 2
287 #define GRAPH_DESTROYED (1 << 0)
288 #define GRAPH_INIT_ON_TYPE_CHANGE (1 << 1)
290 GtkWidget *toplevel; /* keypress handler needs this */
291 GtkWidget *drawing_area;
292 GtkWidget *text; /* text widget for seg list - probably
294 PangoFontDescription *font; /* font used for annotations etc. */
297 GdkPixmap *title_pixmap;
298 GdkPixmap *pixmap[2];
299 int displayed; /* which of both pixmaps is on screen right now */
301 GtkWidget *control_panel;
302 /* this belongs to style structs of graph types that make use of it */
303 GtkToggleButton *time_orig_conn, *seq_orig_isn;
306 /* Next 4 attribs describe the graph in natural units, before any scaling.
307 * For example, if we want to display graph of TCP conversation that
308 * started 112.309845 s after beginning of the capture and ran until
309 * 479.093582 s, 237019 B went through the connection (in one direction)
310 * starting with isn 31934022, then (bounds.x0, bounds.y0)=(112.309845,
311 * 31934022) and (bounds.width, bounds.height)=(366.783737, 237019). */
312 struct bounds bounds;
313 /* dimensions and position of the graph, both expressed already in pixels.
314 * x and y give the position of upper left corner of the graph relative
315 * to origin of the graph window, size is basically bounds*zoom */
317 /* viewport (=graph window area which is reserved for graph itself), its
318 * size and position relative to origin of the graph window */
321 /* If we need to display 237019 sequence numbers (=bytes) onto say 500
322 * pixels, we have to scale the graph down by factor of 0.002109. This
323 * number would be zoom.y. Obviously, both directions have separate zooms.*/
326 struct magnify magnify;
327 struct axis *x_axis, *y_axis;
328 struct segment *segments;
329 struct segment *current;
330 struct element_list *elists; /* element lists */
332 struct style_tseq_stevens tseq_stevens;
333 struct style_tseq_tcptrace tseq_tcptrace;
334 struct style_tput tput;
335 struct style_rtt rtt;
337 /* This allows keyboard to set the radio button */
339 GtkToggleButton *graph_rtt, *graph_tput, *graph_tseqstevens, *graph_tseqttrace;
343 static GdkGC *xor_gc = NULL;
346 #define debug(section) if (debugging & section)
347 /* print function entry points */
348 #define DBS_FENTRY (1 << 0)
349 #define DBS_AXES_TICKS (1 << 1)
350 #define DBS_AXES_DRAWING (1 << 2)
351 #define DBS_GRAPH_DRAWING (1 << 3)
352 #define DBS_TPUT_ELMTS (1 << 4)
353 /*int debugging = DBS_FENTRY;*/
354 static int debugging = 0;
355 /*int debugging = DBS_AXES_TICKS;*/
356 /*int debugging = DBS_AXES_DRAWING;*/
357 /*int debugging = DBS_GRAPH_DRAWING;*/
358 /*int debugging = DBS_TPUT_ELMTS;*/
360 static void create_gui (struct graph * );
362 static void create_text_widget (struct graph * );
363 static void display_text (struct graph * );
365 static void create_drawing_area (struct graph * );
366 static void control_panel_create (struct graph * );
367 static GtkWidget *control_panel_create_zoom_group (struct graph * );
368 static GtkWidget *control_panel_create_magnify_group (struct graph * );
369 static GtkWidget *control_panel_create_cross_group (struct graph * );
370 static GtkWidget *control_panel_create_zoomlock_group (struct graph * );
371 static GtkWidget *control_panel_create_graph_type_group (struct graph * );
372 static void control_panel_add_zoom_page (struct graph * , GtkWidget * );
373 static void control_panel_add_magnify_page (struct graph * , GtkWidget * );
374 static void control_panel_add_origin_page (struct graph * , GtkWidget * );
375 static void control_panel_add_cross_page (struct graph * , GtkWidget * );
376 static void control_panel_add_graph_type_page (struct graph * , GtkWidget * );
377 static void callback_toplevel_destroy (GtkWidget * , gpointer );
378 static gboolean callback_delete_event(GtkWidget * , GdkEvent * , gpointer);
379 static void callback_close (GtkWidget * , gpointer );
380 static void callback_time_origin (GtkWidget * , gpointer );
381 static void callback_seq_origin (GtkWidget * , gpointer );
382 static void callback_zoomlock_h (GtkWidget * , gpointer );
383 static void callback_zoomlock_v (GtkWidget * , gpointer );
384 static void callback_zoom_inout (GtkWidget * , gpointer );
385 static void callback_zoom_step (GtkWidget * , gpointer );
386 static void callback_zoom_flags (GtkWidget * , gpointer );
387 static void callback_cross_on_off (GtkWidget * , gpointer );
388 static void callback_mag_width (GtkWidget * , gpointer );
389 static void callback_mag_height (GtkWidget * , gpointer );
390 static void callback_mag_x (GtkWidget * , gpointer );
391 static void callback_mag_y (GtkWidget * , gpointer );
392 static void callback_mag_zoom (GtkWidget * , gpointer );
393 static void callback_mag_flags (GtkWidget * , gpointer );
394 static void callback_graph_type (GtkWidget * , gpointer );
395 static void callback_graph_init_on_typechg (GtkWidget * , gpointer );
396 static void callback_create_help (GtkWidget * , gpointer );
397 static void update_zoom_spins (struct graph * );
398 static struct tcpheader *select_tcpip_session (capture_file *, struct segment * );
399 static int compare_headers (address *saddr1, address *daddr1, guint16 sport1, guint16 dport1, address *saddr2, address *daddr2, guint16 sport2, guint16 dport2, int dir);
400 static int get_num_dsegs (struct graph * );
401 static int get_num_acks (struct graph * );
402 static void graph_type_dependent_initialize (struct graph * );
403 static struct graph *graph_new (void);
404 static void graph_destroy (struct graph * );
405 static void graph_initialize_values (struct graph * );
406 static void graph_init_sequence (struct graph * );
407 static void draw_element_line (struct graph * , struct element * );
408 static void draw_element_arc (struct graph * , struct element * );
409 static void graph_display (struct graph * );
410 static void graph_pixmaps_create (struct graph * );
411 static void graph_pixmaps_switch (struct graph * );
412 static void graph_pixmap_draw (struct graph * );
413 static void graph_pixmap_display (struct graph * );
414 static void graph_element_lists_make (struct graph * );
415 static void graph_element_lists_free (struct graph * );
416 static void graph_element_lists_initialize (struct graph * );
417 static void graph_title_pixmap_create (struct graph * );
418 static void graph_title_pixmap_draw (struct graph * );
419 static void graph_title_pixmap_display (struct graph * );
420 static void graph_segment_list_get (struct graph * );
421 static void graph_segment_list_free (struct graph * );
422 static void graph_select_segment (struct graph * , int , int );
423 static int line_detect_collision (struct element * , int , int );
424 static int arc_detect_collision (struct element * , int , int );
425 static void axis_pixmaps_create (struct axis * );
426 static void axis_pixmaps_switch (struct axis * );
427 static void axis_display (struct axis * );
428 static void v_axis_pixmap_draw (struct axis * );
429 static void h_axis_pixmap_draw (struct axis * );
430 static void axis_pixmap_display (struct axis * );
431 static void axis_compute_ticks (struct axis * , double , double , int );
432 static double axis_zoom_get (struct axis * , int );
433 static void axis_ticks_up (int * , int * );
434 static void axis_ticks_down (int * , int * );
435 static void axis_destroy (struct axis * );
436 static int get_label_dim (struct axis * , int , double );
437 static void toggle_crosshairs (struct graph *g);
438 static void toggle_time_origin (struct graph * );
439 static void toggle_seq_origin (struct graph * );
440 static void restore_initial_graph_view (struct graph *g);
441 static void cross_xor (struct graph * , int , int );
442 static void cross_draw (struct graph * , int , int );
443 static void cross_erase (struct graph * );
444 static void magnify_create (struct graph * , int , int );
445 static void magnify_move (struct graph * , int , int );
446 static void magnify_destroy (struct graph * );
447 static void magnify_draw (struct graph * );
448 static void magnify_get_geom (struct graph * , int , int );
449 static gboolean configure_event (GtkWidget * , GdkEventConfigure * , gpointer );
450 static gboolean expose_event (GtkWidget * , GdkEventExpose * , gpointer );
451 static gboolean button_press_event (GtkWidget * , GdkEventButton * , gpointer );
452 static gboolean button_release_event (GtkWidget * , GdkEventButton * , gpointer );
453 static gboolean motion_notify_event (GtkWidget * , GdkEventMotion * , gpointer );
454 static gboolean key_press_event (GtkWidget * , GdkEventKey * , gpointer );
455 static gboolean key_release_event (GtkWidget * , GdkEventKey * , gpointer );
456 static gboolean leave_notify_event (GtkWidget * , GdkEventCrossing * , gpointer );
457 static gboolean enter_notify_event (GtkWidget * , GdkEventCrossing * , gpointer );
458 static void tseq_initialize (struct graph * );
459 static void tseq_get_bounds (struct graph * );
460 static void tseq_stevens_read_config (struct graph * );
461 static void tseq_stevens_make_elmtlist (struct graph * );
462 static void tseq_stevens_toggle_seq_origin (struct graph * );
463 static void tseq_stevens_toggle_time_origin (struct graph * );
464 static void tseq_tcptrace_read_config (struct graph * );
465 static void tseq_tcptrace_make_elmtlist (struct graph * );
466 static void tseq_tcptrace_toggle_seq_origin (struct graph * );
467 static void tseq_tcptrace_toggle_time_origin (struct graph * );
468 static void tput_initialize (struct graph * );
469 static void tput_read_config (struct graph * );
470 static void tput_make_elmtlist (struct graph * );
471 static void tput_toggle_time_origin (struct graph * );
472 static void rtt_read_config (struct graph * );
473 static void rtt_initialize (struct graph * );
474 static int rtt_is_retrans (struct unack * , unsigned int );
475 static struct unack *rtt_get_new_unack (double , unsigned int );
476 static void rtt_put_unack_on_list (struct unack ** , struct unack * );
477 static void rtt_delete_unack_from_list (struct unack ** , struct unack * );
478 static void rtt_make_elmtlist (struct graph * );
479 static void rtt_toggle_seq_origin (struct graph * );
480 #if defined(_WIN32) && !defined(__MINGW32__)
481 static int rint (double ); /* compiler template for Windows */
485 * Uncomment the following define to revert WIN32 to
486 * use original mouse button controls
489 /* #define ORIGINAL_WIN32_BUTTONS 1 */
491 /* XXX - what about OS X? */
492 static char helptext[] =
493 "Here's what you can do:\n"
495 #ifdef ORIGINAL_WIN32_BUTTONS
496 " <Ctrl>-Left Mouse Button selects segment under cursor in Wireshark's packet list\n"
498 " Left Mouse Button zooms in (towards area under mouse pointer)\n"
499 " <Shift>-Left Mouse Button zooms out\n"
501 " Right Mouse Button moves the graph (if zoomed in)\n"
502 " <Ctrl>-Right Mouse Button displays a portion of graph under cursor magnified\n"
503 #else /* !ORIGINAL_WIN32_BUTTONS */
504 " Left Mouse Button selects segment under cursor in Wireshark's packet list\n"
506 " Middle Mouse Button zooms in (towards area under cousor)\n"
507 " <Shift>-Middle Mouse Button zooms out\n"
509 " Right Mouse Button moves the graph (if zoomed in)\n"
510 " <Ctrl>-Right Mouse Button displays a portion of graph under cursor magnified\n"
514 " '1' display Round Trip Time Graph\n"
515 " '2' display Throughput Graph\n"
516 " '3' display Time/Sequence Graph (Stevens)\n"
517 " '4' display Time/Sequence Graph (tcptrace)\n"
519 " <Space bar> toggles crosshairs on/off\n"
521 " 'i' or '+' zoom in (towards area under mouse pointer)\n"
522 " 'o' or '-' zoom out\n"
523 " 'r' or <Home> restore graph to initial state (zoom out max)\n"
524 " 's' toggles relative/absolute sequence numbers\n"
525 " 't' toggles time origin\n"
526 " 'g' go to frame under cursor in Wireshark's packet list (if possible)\n"
528 " <Left> move view left by 100 pixels (if zoomed in)\n"
529 " <Right> move view right 100 pixels (if zoomed in)\n"
530 " <Up> move view up by 100 pixels (if zoomed in)\n"
531 " <Down> move view down by 100 pixels (if zoomed in)\n"
533 " <Shift><Left> move view left by 10 pixels (if zoomed in)\n"
534 " <Shift><Right> move view right 10 pixels (if zoomed in)\n"
535 " <Shift><Up> move view up by 10 pixels (if zoomed in)\n"
536 " <Shift><Down> move view down by 10 pixels (if zoomed in)\n"
538 " <Ctrl><Left> move view left by 1 pixel (if zoomed in)\n"
539 " <Ctrl><Right> move view right 1 pixel (if zoomed in)\n"
540 " <Ctrl><Up> move view up by 1 pixel (if zoomed in)\n"
541 " <Ctrl><Down> move view down by 1 pixel (if zoomed in)\n"
545 static void debug_coord (struct graph *g, const char *c)
547 static unsigned count = 0;
550 printf("%u: %s\n", count, c);
551 printf("%u: g->geom.width %d\n", count, g->geom.width);
552 printf("%u: g->geom.height %d\n", count, g->geom.height);
553 printf("%u: g->geom.x %d\n", count, g->geom.x);
554 printf("%u: g->geom.y %d\n", count, g->geom.y);
556 printf("%u: g->wp.width %d\n", count, g->wp.width);
557 printf("%u: g->wp.height %d\n", count, g->wp.height);
558 printf("%u: g->wp.x %d\n", count, g->wp.x);
559 printf("%u: g->wp.y %d\n", count, g->wp.y);
560 printf("---------------\n");
564 static void set_busy_cursor(GdkWindow *w)
568 cursor = gdk_cursor_new(GDK_WATCH);
569 gdk_window_set_cursor(w, cursor);
571 gdk_cursor_destroy(cursor);
574 static void unset_busy_cursor(GdkWindow *w)
576 gdk_window_set_cursor(w, NULL);
580 static void tcp_graph_cb (GtkWidget *w _U_, gpointer data, guint callback_action /*graph_type*/ _U_)
582 struct segment current;
585 guint graph_type = GPOINTER_TO_INT(data);
587 debug(DBS_FENTRY) puts ("tcp_graph_cb()");
589 if (! (g = graph_new()))
593 graph_initialize_values (g);
595 g->type = graph_type;
596 if (!select_tcpip_session (&cfile, ¤t)) {
600 graph_segment_list_get(g);
602 /* display_text(g); */
603 graph_init_sequence(g);
606 static void create_gui (struct graph *g)
608 debug(DBS_FENTRY) puts ("create_gui()");
609 /* create_text_widget(g); */
610 control_panel_create (g);
611 create_drawing_area(g);
616 static void create_drawing_area (struct graph *g)
618 GdkColormap *colormap;
620 char window_title[WINDOW_TITLE_LENGTH];
621 struct segment current;
622 struct tcpheader *thdr;
624 debug(DBS_FENTRY) puts ("create_drawing_area()");
626 g->font = gdk_font_load ("-sony-fixed-medium-r-normal--16-150-75-75"
628 g->font = gdk_font_load ("-biznet-fotinostypewriter-medium-r-normal-*-*-120"
629 "-*-*-m-*-iso8859-2");
631 thdr=select_tcpip_session (&cfile, ¤t);
632 g_snprintf (window_title, WINDOW_TITLE_LENGTH, "TCP Graph %d: %s %s:%d -> %s:%d",
634 cf_get_display_name(&cfile),
635 ep_address_to_str(&(thdr->ip_src)),
637 ep_address_to_str(&(thdr->ip_dst)),
640 g->toplevel = dlg_window_new ("Tcp Graph");
641 gtk_window_set_title(GTK_WINDOW(g->toplevel), window_title);
642 gtk_widget_set_name (g->toplevel, "Test Graph");
643 g_object_set_data(G_OBJECT(g->toplevel), "graph", g);
645 /* Create the drawing area */
646 g->drawing_area = gtk_drawing_area_new ();
647 g_object_set_data(G_OBJECT(g->drawing_area), "graph", g);
648 g->x_axis->drawing_area = g->y_axis->drawing_area = g->drawing_area;
649 gtk_widget_set_size_request (g->drawing_area,
650 g->wp.width + g->wp.x + RMARGIN_WIDTH,
651 g->wp.height + g->wp.y + g->x_axis->s.height);
652 gtk_widget_show (g->drawing_area);
654 g_signal_connect(g->drawing_area, "expose_event", G_CALLBACK(expose_event), NULL);
655 /* this has to be done later, after the widget has been shown */
657 g_signal_connect(g->drawing_area,"configure_event", G_CALLBACK(configure_event),
660 g_signal_connect(g->drawing_area, "motion_notify_event",
661 G_CALLBACK(motion_notify_event), NULL);
662 g_signal_connect(g->drawing_area, "button_press_event",
663 G_CALLBACK(button_press_event), NULL);
664 g_signal_connect(g->drawing_area, "button_release_event",
665 G_CALLBACK(button_release_event), NULL);
666 g_signal_connect(g->drawing_area, "leave_notify_event",
667 G_CALLBACK(leave_notify_event), NULL);
668 g_signal_connect(g->drawing_area, "enter_notify_event",
669 G_CALLBACK(enter_notify_event), NULL);
670 g_signal_connect(g->toplevel, "destroy", G_CALLBACK(callback_toplevel_destroy), g);
671 /* why doesn't drawing area send key_press_signals? */
672 g_signal_connect(g->toplevel, "key_press_event", G_CALLBACK(key_press_event), NULL);
673 g_signal_connect(g->toplevel, "key_release_event", G_CALLBACK(key_release_event),
675 gtk_widget_set_events(g->toplevel,
676 GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK);
678 gtk_widget_set_events (g->drawing_area,
680 | GDK_LEAVE_NOTIFY_MASK
681 | GDK_ENTER_NOTIFY_MASK
682 | GDK_BUTTON_PRESS_MASK
683 | GDK_BUTTON_RELEASE_MASK
684 | GDK_POINTER_MOTION_MASK
685 | GDK_POINTER_MOTION_HINT_MASK);
688 frame = gtk_frame_new (NULL);
689 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
690 gtk_container_add (GTK_CONTAINER (frame), g->drawing_area);
692 box = gtk_hbox_new (FALSE, 0);
693 gtk_box_pack_start (GTK_BOX (box), g->gui.control_panel, FALSE, FALSE, 0);
694 gtk_box_pack_start (GTK_BOX (box), frame, TRUE, TRUE, 0);
695 gtk_container_add (GTK_CONTAINER (g->toplevel), box);
696 gtk_container_set_border_width (GTK_CONTAINER (g->toplevel), 5);
697 gtk_widget_show (frame);
698 gtk_widget_show (box);
701 gtk_container_add (GTK_CONTAINER (g->toplevel), g->drawing_area);
702 gtk_widget_show (g->toplevel);
704 /* in case we didn't get what we asked for */
705 g->wp.width = GTK_WIDGET (g->drawing_area)->allocation.width -
706 g->wp.x - RMARGIN_WIDTH;
707 g->wp.height = GTK_WIDGET (g->drawing_area)->allocation.height -
708 g->wp.y - g->x_axis->s.height;
710 g->font = g->drawing_area->style->font_desc;
712 colormap = gdk_window_get_colormap (g->drawing_area->window);
714 xor_gc = gdk_gc_new (g->drawing_area->window);
715 gdk_gc_set_function (xor_gc, GDK_XOR);
716 if (!gdk_color_parse ("gray15", &color)) {
718 * XXX - do more than just warn.
720 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
721 "Could not parse color gray15.");
723 if (!gdk_colormap_alloc_color (colormap, &color, FALSE, TRUE)) {
725 * XXX - do more than just warn.
727 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
728 "Could not allocate color gray15.");
730 gdk_gc_set_foreground (xor_gc, &color);
732 g->fg_gc = gdk_gc_new (g->drawing_area->window);
733 g->bg_gc = gdk_gc_new (g->drawing_area->window);
734 if (!gdk_color_parse ("white", &color)) {
736 * XXX - do more than just warn.
738 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
739 "Could not parse color white.");
741 if (!gdk_colormap_alloc_color (colormap, &color, FALSE, TRUE)) {
743 * XXX - do more than just warn.
745 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
746 "Could not allocate color white.");
748 gdk_gc_set_foreground (g->bg_gc, &color);
750 /* this is probably quite an ugly way to get rid of the first configure
752 * immediatelly after gtk_widget_show (window) drawing_area gets a configure
753 * event which is handled during the next return to gtk_main which is
754 * probably the gdk_gc_new() call. configure handler calls
755 * graph_element_lists_make() which is not good because the graph struct is
756 * not fully set up yet - namely we're not sure about actual geometry
757 * and we don't have the GC's at all. so we just postpone installation
758 * of configure handler until we're ready to deal with it.
760 * !!! NEMLLO BY TO BYT NA KONCI graph_init_sequence()? !!!
763 g_signal_connect(g->drawing_area, "configure_event", G_CALLBACK(configure_event),
766 /* puts ("exiting create_drawing_area()"); */
769 static void callback_toplevel_destroy (GtkWidget *widget _U_, gpointer data)
771 struct graph *g = (struct graph * )data;
773 if (!(g->flags & GRAPH_DESTROYED)) {
774 g->flags |= GRAPH_DESTROYED;
775 graph_destroy ((struct graph * )data);
779 static void control_panel_create (struct graph *g)
781 GtkWidget *toplevel, *notebook;
783 GtkWidget *help_bt, *close_bt, *bbox;
784 char window_title[WINDOW_TITLE_LENGTH];
786 debug(DBS_FENTRY) puts ("control_panel_create()");
788 notebook = gtk_notebook_new ();
789 control_panel_add_zoom_page (g, notebook);
790 control_panel_add_magnify_page (g, notebook);
791 control_panel_add_origin_page (g, notebook);
792 control_panel_add_cross_page (g, notebook);
793 control_panel_add_graph_type_page (g, notebook);
795 g_snprintf (window_title, WINDOW_TITLE_LENGTH,
796 "Graph %d - Control - Wireshark", refnum);
797 toplevel = dlg_window_new ("tcp-graph-control");
798 gtk_window_set_title(GTK_WINDOW(toplevel), window_title);
800 table = gtk_table_new (2, 1, FALSE);
801 gtk_container_add (GTK_CONTAINER (toplevel), table);
803 gtk_table_attach (GTK_TABLE (table), notebook, 0, 1, 0, 1,
804 GTK_FILL|GTK_EXPAND, GTK_FILL, 5, 5);
807 bbox = dlg_button_row_new(GTK_STOCK_HELP, GTK_STOCK_CLOSE, NULL);
808 gtk_table_attach (GTK_TABLE (table), bbox, 0, 1, 1, 2,
809 GTK_FILL|GTK_EXPAND, GTK_FILL, 5, 5);
811 help_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
812 g_signal_connect(help_bt, "clicked", G_CALLBACK(callback_create_help), g);
814 close_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
815 window_set_cancel_button(toplevel, close_bt, NULL);
816 g_signal_connect(close_bt, "clicked", G_CALLBACK(callback_close), g);
818 g_signal_connect(toplevel, "delete_event", G_CALLBACK(callback_delete_event), g);
819 g_signal_connect(toplevel, "destroy", G_CALLBACK(callback_toplevel_destroy), g);
821 /* gtk_widget_show_all (table); */
822 /* g->gui.control_panel = table; */
823 gtk_widget_show_all (toplevel);
824 window_present(toplevel);
826 g->gui.control_panel = toplevel;
829 static void control_panel_add_zoom_page (struct graph *g, GtkWidget *n)
831 GtkWidget *zoom_frame;
832 GtkWidget *zoom_lock_frame;
836 zoom_frame = control_panel_create_zoom_group (g);
837 gtk_container_set_border_width (GTK_CONTAINER (zoom_frame), 5);
838 zoom_lock_frame = control_panel_create_zoomlock_group (g);
839 gtk_container_set_border_width (GTK_CONTAINER (zoom_lock_frame), 5);
840 box = gtk_vbox_new (FALSE, 0);
841 gtk_box_pack_start (GTK_BOX (box), zoom_frame, TRUE, TRUE, 0);
842 gtk_box_pack_start (GTK_BOX (box), zoom_lock_frame, TRUE, TRUE, 0);
843 gtk_widget_show (box);
844 label = gtk_label_new ("Zoom");
845 gtk_notebook_append_page (GTK_NOTEBOOK (n), box, label);
848 static void control_panel_add_magnify_page (struct graph *g, GtkWidget *n)
850 GtkWidget *mag_frame, *label;
852 mag_frame = control_panel_create_magnify_group (g);
853 gtk_container_set_border_width (GTK_CONTAINER (mag_frame), 5);
854 label = gtk_label_new ("Magnify");
855 gtk_notebook_append_page (GTK_NOTEBOOK (n), mag_frame, label);
858 static void control_panel_add_origin_page (struct graph *g, GtkWidget *n)
860 GtkWidget *time_orig_cap, *time_orig_conn, *time_orig_box, *time_orig_frame;
861 GtkWidget *seq_orig_isn, *seq_orig_zero, *seq_orig_box, *seq_orig_frame;
862 GtkWidget *box, *label;
864 /* time origin box */
866 gtk_radio_button_new_with_label (NULL, "beginning of capture");
867 time_orig_conn = gtk_radio_button_new_with_label (
868 gtk_radio_button_get_group (GTK_RADIO_BUTTON (time_orig_cap)),
869 "beginning of this TCP connection");
870 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (time_orig_conn), TRUE);
871 time_orig_box = gtk_vbox_new (TRUE, 0);
872 gtk_box_pack_start (GTK_BOX (time_orig_box), time_orig_conn, TRUE, TRUE, 0);
873 gtk_box_pack_start (GTK_BOX (time_orig_box), time_orig_cap, TRUE, TRUE, 0);
874 time_orig_frame = gtk_frame_new ("Time origin");
875 gtk_container_set_border_width (GTK_CONTAINER (time_orig_frame), 5);
876 gtk_container_add (GTK_CONTAINER (time_orig_frame), time_orig_box);
878 /* sequence number origin group */
880 gtk_radio_button_new_with_label (NULL, "initial sequence number");
881 seq_orig_zero = gtk_radio_button_new_with_label (gtk_radio_button_get_group (
882 GTK_RADIO_BUTTON (seq_orig_isn)), "0 (=absolute)");
883 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (seq_orig_isn), TRUE);
884 seq_orig_box = gtk_vbox_new (TRUE, 0);
885 gtk_box_pack_start (GTK_BOX (seq_orig_box), seq_orig_isn, TRUE, TRUE, 0);
886 gtk_box_pack_start (GTK_BOX (seq_orig_box), seq_orig_zero, TRUE, TRUE, 0);
887 seq_orig_frame = gtk_frame_new ("Sequence number origin");
888 gtk_container_set_border_width (GTK_CONTAINER (seq_orig_frame), 5);
889 gtk_container_add (GTK_CONTAINER (seq_orig_frame), seq_orig_box);
891 g->gui.time_orig_conn = (GtkToggleButton * )time_orig_conn;
892 g->gui.seq_orig_isn = (GtkToggleButton * )seq_orig_isn;
894 g_signal_connect(time_orig_conn, "toggled", G_CALLBACK(callback_time_origin), g);
895 g_signal_connect(seq_orig_isn, "toggled", G_CALLBACK(callback_seq_origin), g);
897 box = gtk_vbox_new (FALSE, 0);
898 gtk_container_set_border_width (GTK_CONTAINER (box), 5);
899 gtk_box_pack_start (GTK_BOX (box), time_orig_frame, TRUE, TRUE, 0);
900 gtk_box_pack_start (GTK_BOX (box), seq_orig_frame, TRUE, TRUE, 0);
901 gtk_widget_show (box);
902 label = gtk_label_new ("Origin");
903 gtk_notebook_append_page (GTK_NOTEBOOK (n), box, label);
906 static void control_panel_add_cross_page (struct graph *g, GtkWidget *n)
908 GtkWidget *cross_frame, *label;
910 cross_frame = control_panel_create_cross_group (g);
911 gtk_container_set_border_width (GTK_CONTAINER (cross_frame), 5);
912 label = gtk_label_new ("Cross");
913 gtk_notebook_append_page (GTK_NOTEBOOK (n), cross_frame, label);
916 static void control_panel_add_graph_type_page (struct graph *g, GtkWidget *n)
918 GtkWidget *frame, *label;
920 frame = control_panel_create_graph_type_group (g);
921 gtk_container_set_border_width (GTK_CONTAINER (frame), 5);
922 label = gtk_label_new ("Graph type");
923 gtk_notebook_append_page (GTK_NOTEBOOK (n), frame, label);
926 /* Treat this as a cancel, by calling "callback_close()" */
928 callback_delete_event(GtkWidget *widget _U_, GdkEvent *event _U_,
931 callback_close(NULL, data);
935 static void callback_close (GtkWidget *widget _U_, gpointer data)
937 struct graph *g = (struct graph * )data;
939 if (!(g->flags & GRAPH_DESTROYED)) {
940 g->flags |= GRAPH_DESTROYED;
941 graph_destroy ((struct graph * )data);
945 static void callback_create_help(GtkWidget *widget _U_, gpointer data _U_)
947 GtkWidget *toplevel, *vbox, *text, *scroll, *bbox, *close_bt;
950 toplevel = dlg_window_new ("Help for TCP graphing");
951 gtk_window_set_default_size(GTK_WINDOW(toplevel), 500, 400);
953 vbox = gtk_vbox_new (FALSE, 3);
954 gtk_container_set_border_width(GTK_CONTAINER(vbox), 12);
955 gtk_container_add (GTK_CONTAINER (toplevel), vbox);
957 scroll = scrolled_window_new (NULL, NULL);
958 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll),
960 gtk_box_pack_start (GTK_BOX (vbox), scroll, TRUE, TRUE, 0);
961 text = gtk_text_view_new();
962 gtk_text_view_set_editable(GTK_TEXT_VIEW(text), FALSE);
963 buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text));
964 gtk_text_buffer_set_text(buf, helptext, -1);
965 gtk_container_add (GTK_CONTAINER (scroll), text);
968 bbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL);
969 gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
970 gtk_widget_show(bbox);
972 close_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
973 window_set_cancel_button(toplevel, close_bt, window_cancel_button_cb);
975 g_signal_connect(toplevel, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
977 gtk_widget_show_all (toplevel);
978 window_present(toplevel);
981 static void callback_time_origin (GtkWidget *toggle _U_, gpointer data)
983 toggle_time_origin ((struct graph * )data);
986 static void callback_seq_origin (GtkWidget *toggle _U_, gpointer data)
988 toggle_seq_origin ((struct graph * )data);
991 static GtkWidget *control_panel_create_zoom_group (struct graph *g)
993 GtkWidget *zoom_in, *zoom_out, *zoom_box, *zoom_frame;
994 GtkAdjustment *zoom_h_adj, *zoom_v_adj;
995 GtkWidget *zoom_inout_box, *zoom_h_step_label, *zoom_h_step;
996 GtkWidget *zoom_v_step_label, *zoom_v_step;
997 GtkWidget *zoom_separator1, *zoom_separator2, *zoom_step_table, *zoom_table;
998 GtkWidget *zoom_ratio_toggle, *zoom_same_toggle;
999 GtkWidget *zoom_h_entry, *zoom_v_entry;
1000 GtkWidget *zoom_h_label, *zoom_v_label;
1002 zoom_in = gtk_radio_button_new_with_label (NULL, "in");
1003 zoom_out = gtk_radio_button_new_with_label (
1004 gtk_radio_button_get_group (GTK_RADIO_BUTTON (zoom_in)), "out");
1005 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (zoom_in), TRUE);
1006 zoom_inout_box = gtk_hbox_new (FALSE, 0);
1007 gtk_box_pack_start (GTK_BOX (zoom_inout_box), zoom_in, FALSE, FALSE, 10);
1008 gtk_box_pack_start (GTK_BOX (zoom_inout_box), zoom_out, FALSE, FALSE, 0);
1010 zoom_separator1 = gtk_hseparator_new ();
1012 zoom_h_entry = gtk_entry_new ();
1013 gtk_entry_set_text (GTK_ENTRY (zoom_h_entry), "1.000");
1014 gtk_editable_set_editable (GTK_EDITABLE (zoom_h_entry), FALSE);
1015 zoom_h_label = gtk_label_new ("Horizontal:");
1017 zoom_v_entry = gtk_entry_new ();
1018 gtk_entry_set_text (GTK_ENTRY (zoom_v_entry), "1.000");
1019 gtk_editable_set_editable (GTK_EDITABLE (zoom_v_entry), FALSE);
1020 zoom_v_label = gtk_label_new ("Vertical:");
1022 g->zoom.widget.h_zoom = (GtkEntry * )zoom_h_entry;
1023 g->zoom.widget.v_zoom = (GtkEntry * )zoom_v_entry;
1025 zoom_table = gtk_table_new (2, 2, FALSE);
1026 gtk_table_attach (GTK_TABLE (zoom_table), zoom_h_label, 0,1,0,1,
1027 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1028 gtk_table_attach (GTK_TABLE (zoom_table), zoom_h_entry, 1, 2, 0, 1,
1029 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1030 gtk_table_attach (GTK_TABLE (zoom_table), zoom_v_label, 0,1,1,2,
1031 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1032 gtk_table_attach (GTK_TABLE (zoom_table), zoom_v_entry, 1, 2, 1, 2,
1033 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1035 zoom_separator2 = gtk_hseparator_new ();
1037 zoom_h_adj = (GtkAdjustment * )gtk_adjustment_new ((gfloat)1.2, 1.0, 5, (gfloat)0.1, 1, 0);
1038 zoom_h_step = gtk_spin_button_new (zoom_h_adj, 0, 1);
1039 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (zoom_h_step), TRUE);
1040 zoom_h_step_label = gtk_label_new ("Horizontal step:");
1042 zoom_v_adj = (GtkAdjustment * )gtk_adjustment_new ((gfloat)1.2, 1.0, 5, (gfloat)0.1, 1, 0);
1043 zoom_v_step = gtk_spin_button_new (zoom_v_adj, 0, 1);
1044 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (zoom_v_step), TRUE);
1045 zoom_v_step_label = gtk_label_new ("Vertical step:");
1047 g->zoom.widget.h_step = (GtkSpinButton * )zoom_h_step;
1048 g->zoom.widget.v_step = (GtkSpinButton * )zoom_v_step;
1050 zoom_same_toggle = gtk_check_button_new_with_label("Keep them the same");
1051 zoom_ratio_toggle = gtk_check_button_new_with_label("Preserve their ratio");
1052 g_object_set_data(G_OBJECT(zoom_same_toggle), "flag", (gpointer)ZOOM_STEPS_SAME);
1053 g_object_set_data(G_OBJECT(zoom_ratio_toggle), "flag",
1054 (gpointer)ZOOM_STEPS_KEEP_RATIO);
1055 g_signal_connect(zoom_same_toggle, "clicked", G_CALLBACK(callback_zoom_flags), g);
1056 g_signal_connect(zoom_ratio_toggle, "clicked", G_CALLBACK(callback_zoom_flags), g);
1058 zoom_step_table = gtk_table_new (4, 2, FALSE);
1059 gtk_table_attach (GTK_TABLE (zoom_step_table), zoom_h_step_label, 0,1,0,1,
1060 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1061 gtk_table_attach (GTK_TABLE (zoom_step_table), zoom_h_step, 1, 2, 0, 1,
1062 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1063 gtk_table_attach (GTK_TABLE (zoom_step_table), zoom_v_step_label, 0,1,1,2,
1064 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1065 gtk_table_attach (GTK_TABLE (zoom_step_table), zoom_v_step, 1, 2, 1, 2,
1066 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1067 gtk_table_attach (GTK_TABLE (zoom_step_table), zoom_same_toggle, 0,2,2,3,
1068 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1069 gtk_table_attach (GTK_TABLE (zoom_step_table), zoom_ratio_toggle, 0,2,3,4,
1070 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1072 zoom_box = gtk_vbox_new (FALSE, 0);
1073 gtk_box_pack_start (GTK_BOX (zoom_box), zoom_inout_box, TRUE, TRUE, 0);
1074 gtk_box_pack_start (GTK_BOX (zoom_box), zoom_separator1, TRUE, TRUE, 0);
1075 gtk_box_pack_start (GTK_BOX (zoom_box), zoom_table, TRUE, TRUE, 0);
1076 gtk_box_pack_start (GTK_BOX (zoom_box), zoom_separator2, TRUE, TRUE, 0);
1077 gtk_box_pack_start (GTK_BOX (zoom_box), zoom_step_table, TRUE, TRUE, 0);
1078 zoom_frame = gtk_frame_new ("Zoom");
1079 gtk_container_add (GTK_CONTAINER (zoom_frame), zoom_box);
1081 g_object_set_data(G_OBJECT(zoom_h_step), "direction", GINT_TO_POINTER(0));
1082 g_object_set_data(G_OBJECT(zoom_v_step), "direction", GINT_TO_POINTER(1));
1084 g_signal_connect(zoom_in, "toggled", G_CALLBACK(callback_zoom_inout), g);
1085 g_signal_connect(zoom_h_step, "changed", G_CALLBACK(callback_zoom_step), g);
1086 g_signal_connect(zoom_v_step, "changed", G_CALLBACK(callback_zoom_step), g);
1088 g->zoom.widget.in_toggle = (GtkToggleButton * )zoom_in;
1089 g->zoom.widget.out_toggle = (GtkToggleButton * )zoom_out;
1093 static void callback_zoom_inout (GtkWidget *toggle, gpointer data)
1095 struct graph *g = (struct graph * )data;
1097 if (GTK_TOGGLE_BUTTON (toggle)->active)
1098 g->zoom.flags &= ~ZOOM_OUT;
1100 g->zoom.flags |= ZOOM_OUT;
1103 static void callback_zoom_step (GtkWidget *spin, gpointer data)
1105 struct graph *g = (struct graph * )data;
1108 double *zoom_this, *zoom_other;
1109 GtkSpinButton *widget_this, *widget_other;
1112 direction = (long)g_object_get_data(G_OBJECT(spin), "direction");
1113 value = gtk_spin_button_get_value (GTK_SPIN_BUTTON (spin));
1116 zoom_this = &g->zoom.step_y;
1117 zoom_other = &g->zoom.step_x;
1118 widget_this = g->zoom.widget.v_step;
1119 widget_other = g->zoom.widget.h_step;
1121 zoom_this = &g->zoom.step_x;
1122 zoom_other = &g->zoom.step_y;
1123 widget_this = g->zoom.widget.h_step;
1124 widget_other = g->zoom.widget.v_step;
1127 old_this = *zoom_this;
1129 if (g->zoom.flags & ZOOM_STEPS_SAME) {
1130 *zoom_other = value;
1131 gtk_spin_button_set_value (widget_other, (gfloat) *zoom_other);
1132 } else if (g->zoom.flags & ZOOM_STEPS_KEEP_RATIO) {
1133 double old_other = *zoom_other;
1134 *zoom_other *= value / old_this;
1135 if (*zoom_other < 1.0) {
1137 *zoom_this = old_this * 1.0 / old_other;
1138 gtk_spin_button_set_value (widget_this, (gfloat) *zoom_this);
1139 } else if (*zoom_other > 5.0) {
1141 *zoom_this = old_this * 5.0 / old_other;
1142 gtk_spin_button_set_value (widget_this, (gfloat) *zoom_this);
1144 gtk_spin_button_set_value (widget_other, (gfloat) *zoom_other);
1148 static void callback_zoom_flags (GtkWidget *toggle, gpointer data)
1150 struct graph *g = (struct graph * )data;
1151 int flag = (long)g_object_get_data(G_OBJECT(toggle), "flag");
1153 if (GTK_TOGGLE_BUTTON (toggle)->active)
1154 g->zoom.flags |= flag;
1156 g->zoom.flags &= ~flag;
1159 static void update_zoom_spins (struct graph *g)
1163 g_snprintf (s, sizeof(s), "%.3f", g->zoom.x / g->zoom.initial.x);
1164 gtk_entry_set_text (g->zoom.widget.h_zoom, s);
1165 g_snprintf (s, sizeof(s), "%.3f", g->zoom.y / g->zoom.initial.y);
1166 gtk_entry_set_text (g->zoom.widget.v_zoom, s);
1169 static GtkWidget *control_panel_create_magnify_group (struct graph *g)
1171 GtkWidget *mag_width_label, *mag_width;
1172 GtkWidget *mag_height_label, *mag_height;
1173 GtkWidget *mag_x_label, *mag_x;
1174 GtkWidget *mag_y_label, *mag_y;
1175 GtkWidget *mag_wh_table, *mag_zoom_frame, *mag_zoom_table;
1176 GtkWidget *mag_h_zoom_label, *mag_h_zoom;
1177 GtkWidget *mag_v_zoom_label, *mag_v_zoom;
1178 GtkWidget *mag_zoom_same, *mag_zoom_ratio;
1179 GtkAdjustment *mag_width_adj, *mag_height_adj, *mag_x_adj, *mag_y_adj;
1180 GtkAdjustment *mag_h_zoom_adj, *mag_v_zoom_adj;
1181 GtkWidget *mag_box, *mag_frame;
1183 mag_width_label = gtk_label_new ("Width:");
1184 mag_width_adj = (GtkAdjustment * )gtk_adjustment_new (250,100,600,1,10,0);
1185 mag_width = gtk_spin_button_new (mag_width_adj, 0, 0);
1187 mag_height_label = gtk_label_new ("Height:");
1188 mag_height_adj = (GtkAdjustment * )gtk_adjustment_new (250,100,600,1,10,0);
1189 mag_height = gtk_spin_button_new (mag_height_adj, 0, 0);
1191 mag_x_label = gtk_label_new ("X:");
1192 mag_x_adj = (GtkAdjustment * )gtk_adjustment_new (0,-1000,1000,1,10,0);
1193 mag_x = gtk_spin_button_new (mag_x_adj, 0, 0);
1195 mag_y_label = gtk_label_new ("Y:");
1196 mag_y_adj = (GtkAdjustment * )gtk_adjustment_new (0,-1000,1000,1,10,0);
1197 mag_y = gtk_spin_button_new (mag_y_adj, 0, 0);
1199 mag_wh_table = gtk_table_new (4, 2, FALSE);
1200 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_width_label, 0,1,0,1,
1201 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1202 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_width, 1,2,0,1,
1203 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1204 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_height_label, 0,1,1,2,
1205 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1206 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_height, 1,2,1,2,
1207 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1208 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_x_label, 0,1,2,3,
1209 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1210 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_x, 1,2,2,3,
1211 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1212 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_y_label, 0,1,3,4,
1213 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1214 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_y, 1,2,3,4,
1215 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1217 mag_h_zoom_label = gtk_label_new ("Horizontal:");
1218 mag_h_zoom_adj = (GtkAdjustment *)gtk_adjustment_new(10.0, 1.0, 25.0, (gfloat)0.1, 1, 0);
1219 mag_h_zoom = gtk_spin_button_new (mag_h_zoom_adj, 0, 1);
1221 mag_v_zoom_label = gtk_label_new ("Vertical:");
1222 mag_v_zoom_adj = (GtkAdjustment *)gtk_adjustment_new(10.0, 1.0, 25.0, (gfloat)0.1, 1, 0);
1223 mag_v_zoom = gtk_spin_button_new (mag_v_zoom_adj, 0, 1);
1225 mag_zoom_same = gtk_check_button_new_with_label ("Keep them the same");
1226 mag_zoom_ratio = gtk_check_button_new_with_label("Preserve their ratio");
1228 mag_zoom_table = gtk_table_new (4, 2, FALSE);
1229 gtk_table_attach (GTK_TABLE (mag_zoom_table), mag_h_zoom_label, 0,1,0,1,
1230 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
1231 gtk_table_attach (GTK_TABLE (mag_zoom_table), mag_h_zoom, 1,2,0,1,
1232 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
1233 gtk_table_attach (GTK_TABLE (mag_zoom_table), mag_v_zoom_label, 0,1,1,2,
1234 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
1235 gtk_table_attach (GTK_TABLE (mag_zoom_table), mag_v_zoom, 1,2,1,2,
1236 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
1237 gtk_table_attach (GTK_TABLE (mag_zoom_table), mag_zoom_same, 0,2,2,3,
1238 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
1239 gtk_table_attach (GTK_TABLE (mag_zoom_table), mag_zoom_ratio, 0,2,3,4,
1240 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
1242 mag_zoom_frame = gtk_frame_new ("Magnify zoom");
1243 gtk_container_add (GTK_CONTAINER (mag_zoom_frame), mag_zoom_table);
1244 gtk_container_set_border_width (GTK_CONTAINER (mag_zoom_frame), 3);
1246 mag_box = gtk_vbox_new (FALSE, 0);
1247 gtk_box_pack_start (GTK_BOX (mag_box), mag_wh_table, TRUE, TRUE, 0);
1248 gtk_box_pack_start (GTK_BOX (mag_box), mag_zoom_frame, TRUE, TRUE, 0);
1249 mag_frame = gtk_frame_new ("Magnify");
1250 gtk_container_add (GTK_CONTAINER (mag_frame), mag_box);
1252 g->magnify.widget.h_zoom = (GtkSpinButton * )mag_h_zoom;
1253 g->magnify.widget.v_zoom = (GtkSpinButton * )mag_v_zoom;
1254 g_object_set_data(G_OBJECT(mag_h_zoom), "direction", GINT_TO_POINTER(0));
1255 g_object_set_data(G_OBJECT(mag_v_zoom), "direction", GINT_TO_POINTER(1));
1256 g_object_set_data(G_OBJECT(mag_zoom_same), "flag", (gpointer)MAGZOOMS_SAME);
1257 g_object_set_data(G_OBJECT(mag_zoom_ratio), "flag", (gpointer)MAGZOOMS_SAME_RATIO);
1259 g_signal_connect(mag_width, "changed", G_CALLBACK(callback_mag_width), g);
1260 g_signal_connect(mag_height, "changed", G_CALLBACK(callback_mag_height), g);
1261 g_signal_connect(mag_x, "changed", G_CALLBACK(callback_mag_x), g);
1262 g_signal_connect(mag_y, "changed", G_CALLBACK(callback_mag_y), g);
1263 g_signal_connect(mag_h_zoom, "changed", G_CALLBACK(callback_mag_zoom), g);
1264 g_signal_connect(mag_v_zoom, "changed", G_CALLBACK(callback_mag_zoom), g);
1265 g_signal_connect(mag_zoom_same, "clicked", G_CALLBACK(callback_mag_flags), g);
1266 g_signal_connect(mag_zoom_ratio, "clicked", G_CALLBACK(callback_mag_flags), g);
1271 static void callback_mag_width (GtkWidget *spin, gpointer data)
1273 struct graph *g = (struct graph * )data;
1275 g->magnify.width = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(spin));
1278 static void callback_mag_height (GtkWidget *spin, gpointer data)
1280 struct graph *g = (struct graph * )data;
1282 g->magnify.height = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
1285 static void callback_mag_x (GtkWidget *spin, gpointer data)
1287 struct graph *g = (struct graph * )data;
1289 g->magnify.offset.x=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
1292 static void callback_mag_y (GtkWidget *spin, gpointer data)
1294 struct graph *g = (struct graph * )data;
1296 g->magnify.offset.y=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
1299 static void callback_mag_zoom (GtkWidget *spin, gpointer data)
1301 struct graph *g = (struct graph * )data;
1304 double *zoom_this, *zoom_other;
1305 GtkSpinButton *widget_this, *widget_other;
1308 if (g->magnify.flags & MAGZOOMS_IGNORE) {
1309 printf ("refusing callback for %s zoom widget.\n", (GtkSpinButton * )spin==g->magnify.widget.h_zoom ? "horizontal" : "vertical");
1310 g->magnify.flags &= ~MAGZOOMS_IGNORE;
1313 direction = (long)g_object_get_data(G_OBJECT(spin), "direction");
1314 value = gtk_spin_button_get_value (GTK_SPIN_BUTTON (spin));
1317 zoom_this = &g->magnify.zoom.y;
1318 zoom_other = &g->magnify.zoom.x;
1319 widget_this = g->magnify.widget.v_zoom;
1320 widget_other = g->magnify.widget.h_zoom;
1322 zoom_this = &g->magnify.zoom.x;
1323 zoom_other = &g->magnify.zoom.y;
1324 widget_this = g->magnify.widget.h_zoom;
1325 widget_other = g->magnify.widget.v_zoom;
1328 old_this = *zoom_this;
1330 if (g->magnify.flags & MAGZOOMS_SAME) {
1331 *zoom_other = value;
1332 /* g->magnify.flags |= MAGZOOMS_IGNORE; */
1333 gtk_spin_button_set_value (widget_other, (gfloat) *zoom_other);
1334 } else if (g->magnify.flags & MAGZOOMS_SAME_RATIO) {
1335 double old_other = *zoom_other;
1336 *zoom_other *= value / old_this;
1337 if (*zoom_other < 1.0) {
1339 *zoom_this = old_this * 1.0 / old_other;
1340 /* g->magnify.flags |= MAGZOOMS_IGNORE; */
1341 gtk_spin_button_set_value (widget_this, (gfloat) *zoom_this);
1342 } else if (*zoom_other > 25.0) {
1344 *zoom_this = old_this * 25.0 / old_other;
1345 /* g->magnify.flags |= MAGZOOMS_IGNORE; */
1346 gtk_spin_button_set_value (widget_this, (gfloat) *zoom_this);
1348 /* g->magnify.flags |= MAGZOOMS_IGNORE; */
1349 gtk_spin_button_set_value (widget_other, (gfloat) *zoom_other);
1353 static void callback_mag_flags (GtkWidget *toggle, gpointer data)
1355 struct graph *g = (struct graph * )data;
1356 int flag = (long)g_object_get_data(G_OBJECT(toggle), "flag");
1358 if (GTK_TOGGLE_BUTTON (toggle)->active)
1359 g->magnify.flags |= flag;
1361 g->magnify.flags &= ~flag;
1364 static GtkWidget *control_panel_create_zoomlock_group (struct graph *g)
1366 GtkWidget *zoom_lock_h, *zoom_lock_v, *zoom_lock_none, *zoom_lock_box;
1367 GtkWidget *zoom_lock_frame;
1369 zoom_lock_none = gtk_radio_button_new_with_label (NULL, "none");
1370 zoom_lock_h = gtk_radio_button_new_with_label (
1371 gtk_radio_button_get_group (GTK_RADIO_BUTTON (zoom_lock_none)),
1373 zoom_lock_v = gtk_radio_button_new_with_label (
1374 gtk_radio_button_get_group (GTK_RADIO_BUTTON (zoom_lock_none)),
1376 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (zoom_lock_none), TRUE);
1377 zoom_lock_box = gtk_hbox_new (FALSE, 0);
1378 gtk_box_pack_start(GTK_BOX(zoom_lock_box), zoom_lock_none,
1380 gtk_box_pack_start(GTK_BOX(zoom_lock_box), zoom_lock_h, TRUE, TRUE, 0);
1381 gtk_box_pack_start(GTK_BOX(zoom_lock_box), zoom_lock_v, TRUE, TRUE, 0);
1382 zoom_lock_frame = gtk_frame_new ("Zoom lock:");
1383 gtk_container_add (GTK_CONTAINER (zoom_lock_frame), zoom_lock_box);
1385 g_signal_connect(zoom_lock_h, "toggled", G_CALLBACK(callback_zoomlock_h), g);
1386 g_signal_connect(zoom_lock_v, "toggled", G_CALLBACK(callback_zoomlock_v), g);
1388 return zoom_lock_frame;
1391 static void callback_zoomlock_h (GtkWidget *toggle, gpointer data)
1393 struct graph *g = (struct graph * )data;
1395 if (GTK_TOGGLE_BUTTON (toggle)->active)
1396 g->zoom.flags |= ZOOM_HLOCK;
1398 g->zoom.flags &= ~ZOOM_HLOCK;
1401 static void callback_zoomlock_v (GtkWidget *toggle, gpointer data)
1403 struct graph *g = (struct graph * )data;
1405 if (GTK_TOGGLE_BUTTON (toggle)->active)
1406 g->zoom.flags |= ZOOM_VLOCK;
1408 g->zoom.flags &= ~ZOOM_VLOCK;
1411 static GtkWidget *control_panel_create_cross_group (struct graph *g)
1413 GtkWidget *on, *off, *box, *frame, *vbox, *label;
1415 label = gtk_label_new ("Crosshairs:");
1416 off = gtk_radio_button_new_with_label (NULL, "off");
1417 on = gtk_radio_button_new_with_label (
1418 gtk_radio_button_get_group (GTK_RADIO_BUTTON (off)), "on");
1419 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (off), TRUE);
1420 box = gtk_hbox_new (FALSE, 0);
1421 gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 10);
1422 gtk_box_pack_start (GTK_BOX (box), off, FALSE, FALSE, 10);
1423 gtk_box_pack_start (GTK_BOX (box), on, FALSE, FALSE, 0);
1424 vbox = gtk_vbox_new (FALSE, 0);
1425 gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, FALSE, 15);
1426 /* frame = gtk_frame_new ("Cross:"); */
1427 frame = gtk_frame_new (NULL);
1428 gtk_container_add (GTK_CONTAINER (frame), vbox);
1430 g_signal_connect(on, "toggled", G_CALLBACK(callback_cross_on_off), g);
1432 g->cross.on_toggle = (GtkToggleButton * )on;
1433 g->cross.off_toggle = (GtkToggleButton * )off;
1438 static void callback_cross_on_off (GtkWidget *toggle, gpointer data)
1440 struct graph *g = (struct graph * )data;
1442 if (GTK_TOGGLE_BUTTON (toggle)->active) {
1444 g->cross.draw = TRUE;
1445 gdk_window_get_pointer (g->drawing_area->window, &x, &y, 0);
1446 cross_draw (g, x, y);
1448 g->cross.draw = FALSE;
1453 static GtkWidget *control_panel_create_graph_type_group (struct graph *g)
1455 GtkWidget *graph_tseqttrace, *graph_tseqstevens;
1456 GtkWidget *graph_tput, *graph_rtt, *graph_sep, *graph_init, *graph_box;
1457 GtkWidget *graph_frame;
1459 graph_tput = gtk_radio_button_new_with_label (NULL, "Throughput");
1460 graph_tseqttrace = gtk_radio_button_new_with_label (
1461 gtk_radio_button_get_group (GTK_RADIO_BUTTON (graph_tput)),
1462 "Time/Sequence (tcptrace-style)");
1463 graph_tseqstevens = gtk_radio_button_new_with_label (
1464 gtk_radio_button_get_group (GTK_RADIO_BUTTON (graph_tput)),
1465 "Time/Sequence (Stevens'-style)");
1466 graph_rtt = gtk_radio_button_new_with_label (
1467 gtk_radio_button_get_group (GTK_RADIO_BUTTON (graph_tput)),
1470 case GRAPH_TSEQ_STEVENS:
1471 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(graph_tseqstevens),TRUE);
1473 case GRAPH_TSEQ_TCPTRACE:
1474 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(graph_tseqttrace),TRUE);
1476 case GRAPH_THROUGHPUT:
1477 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (graph_tput), TRUE);
1480 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (graph_rtt), TRUE);
1483 graph_init = gtk_check_button_new_with_label ("Init on change");
1484 graph_sep = gtk_hseparator_new ();
1485 graph_box = gtk_vbox_new (FALSE, 0);
1486 gtk_box_pack_start (GTK_BOX (graph_box), graph_rtt, TRUE, TRUE, 0);
1487 gtk_box_pack_start (GTK_BOX (graph_box), graph_tput, TRUE, TRUE, 0);
1488 gtk_box_pack_start (GTK_BOX (graph_box), graph_tseqstevens, TRUE, TRUE, 0);
1489 gtk_box_pack_start (GTK_BOX (graph_box), graph_tseqttrace, TRUE, TRUE, 0);
1490 gtk_box_pack_start (GTK_BOX (graph_box), graph_sep, TRUE, TRUE, 0);
1491 gtk_box_pack_start (GTK_BOX (graph_box), graph_init, TRUE, TRUE, 0);
1492 graph_frame = gtk_frame_new ("Graph type:");
1493 gtk_container_add (GTK_CONTAINER (graph_frame), graph_box);
1495 g_object_set_data(G_OBJECT(graph_tseqstevens), "new-graph-type",
1496 GINT_TO_POINTER(0));
1497 g_object_set_data(G_OBJECT(graph_tseqttrace), "new-graph-type", GINT_TO_POINTER(1));
1498 g_object_set_data(G_OBJECT(graph_tput), "new-graph-type", GINT_TO_POINTER(2));
1499 g_object_set_data(G_OBJECT(graph_rtt), "new-graph-type", GINT_TO_POINTER(3));
1501 g->gt.graph_rtt = (GtkToggleButton * )graph_rtt;
1502 g->gt.graph_tput = (GtkToggleButton * )graph_tput;
1503 g->gt.graph_tseqstevens = (GtkToggleButton * )graph_tseqstevens;
1504 g->gt.graph_tseqttrace = (GtkToggleButton * )graph_tseqttrace;
1506 g_signal_connect(graph_tseqttrace, "toggled", G_CALLBACK(callback_graph_type), g);
1507 g_signal_connect(graph_tseqstevens, "toggled", G_CALLBACK(callback_graph_type), g);
1508 g_signal_connect(graph_tput, "toggled", G_CALLBACK(callback_graph_type), g);
1509 g_signal_connect(graph_rtt, "toggled", G_CALLBACK(callback_graph_type), g);
1510 g_signal_connect(graph_init, "toggled", G_CALLBACK(callback_graph_init_on_typechg), g);
1515 static void callback_graph_type (GtkWidget *toggle, gpointer data)
1517 int old_type, new_type;
1518 struct graph *g = (struct graph * )data;
1520 new_type = (long)g_object_get_data(G_OBJECT(toggle),"new-graph-type");
1522 if (!GTK_TOGGLE_BUTTON (toggle)->active)
1528 graph_element_lists_free (g);
1529 graph_element_lists_initialize (g);
1531 if (old_type == GRAPH_THROUGHPUT || new_type == GRAPH_THROUGHPUT) {
1532 /* throughput graph uses differently constructed segment list so we
1533 * need to recreate it */
1534 graph_segment_list_free (g);
1535 graph_segment_list_get (g);
1538 if (g->flags & GRAPH_INIT_ON_TYPE_CHANGE) {
1539 g->geom.width = g->wp.width;
1540 g->geom.height = g->wp.height;
1541 g->geom.x = g->wp.x;
1542 g->geom.y = g->wp.y;
1544 g->x_axis->min = g->y_axis->min = 0;
1545 gtk_toggle_button_set_active (g->gui.time_orig_conn, TRUE);
1546 gtk_toggle_button_set_active (g->gui.seq_orig_isn, TRUE);
1547 graph_init_sequence (g);
1550 static void callback_graph_init_on_typechg (GtkWidget *toggle _U_, gpointer data)
1552 ((struct graph * )data)->flags ^= GRAPH_INIT_ON_TYPE_CHANGE;
1555 static struct graph *graph_new (void)
1559 g = (struct graph * )g_malloc0 (sizeof (struct graph));
1560 graph_element_lists_initialize (g);
1562 g->x_axis = (struct axis * )g_malloc0 (sizeof (struct axis));
1563 g->y_axis = (struct axis * )g_malloc0 (sizeof (struct axis));
1565 g->x_axis->flags = 0;
1566 g->x_axis->flags |= AXIS_ORIENTATION;
1567 g->x_axis->s.x = g->x_axis->s.y = 0;
1568 g->x_axis->s.height = HAXIS_INIT_HEIGHT;
1569 g->x_axis->p.x = VAXIS_INIT_WIDTH;
1570 g->x_axis->p.height = HAXIS_INIT_HEIGHT;
1572 g->y_axis->flags = 0;
1573 g->y_axis->flags &= ~AXIS_ORIENTATION;
1574 g->y_axis->p.x = g->y_axis->p.y = 0;
1575 g->y_axis->p.width = VAXIS_INIT_WIDTH;
1577 g->y_axis->s.y = TITLEBAR_HEIGHT;
1578 g->y_axis->s.width = VAXIS_INIT_WIDTH;
1583 static void graph_initialize_values (struct graph *g)
1585 g->geom.width = g->wp.width = 750;
1586 g->geom.height = g->wp.height = 550;
1587 g->geom.x = g->wp.x = VAXIS_INIT_WIDTH;
1588 g->geom.y = g->wp.y = TITLEBAR_HEIGHT;
1590 /* g->zoom.x = g->zoom.y = 1.0; */
1591 g->zoom.step_x = g->zoom.step_y = 1.2;
1593 g->cross.draw = g->cross.erase_needed = 0;
1594 g->grab.grabbed = 0;
1595 g->magnify.active = 0;
1596 g->magnify.offset.x = g->magnify.offset.y = 0;
1597 g->magnify.width = g->magnify.height = 250;
1598 g->magnify.zoom.x = g->magnify.zoom.y = 10.0;
1599 g->magnify.flags = 0;
1602 static void graph_init_sequence (struct graph *g)
1604 debug(DBS_FENTRY) puts ("graph_init_sequence()");
1606 graph_type_dependent_initialize (g);
1607 g->zoom.initial.x = g->zoom.x;
1608 g->zoom.initial.y = g->zoom.y;
1609 graph_element_lists_make (g);
1610 g->x_axis->s.width = g->wp.width;
1611 g->x_axis->p.width = g->x_axis->s.width + RMARGIN_WIDTH;
1612 g->x_axis->p.y = TITLEBAR_HEIGHT + g->wp.height;
1613 g->x_axis->s.height = g->x_axis->p.height = HAXIS_INIT_HEIGHT;
1614 g->y_axis->s.height = g->wp.height;
1615 g->y_axis->p.height = g->wp.height + TITLEBAR_HEIGHT;
1616 graph_pixmaps_create (g);
1617 axis_pixmaps_create (g->y_axis);
1618 axis_pixmaps_create (g->x_axis);
1619 graph_title_pixmap_create (g);
1620 graph_title_pixmap_draw (g);
1621 graph_title_pixmap_display (g);
1623 axis_display (g->y_axis);
1624 axis_display (g->x_axis);
1627 static void graph_type_dependent_initialize (struct graph *g)
1630 case GRAPH_TSEQ_STEVENS:
1631 case GRAPH_TSEQ_TCPTRACE:
1632 tseq_initialize (g);
1634 case GRAPH_THROUGHPUT:
1635 tput_initialize (g);
1645 static void graph_destroy (struct graph *g)
1647 debug(DBS_FENTRY) puts ("graph_destroy()");
1649 axis_destroy (g->x_axis);
1650 axis_destroy (g->y_axis);
1651 /* window_destroy (g->drawing_area); */
1652 window_destroy (g->gui.control_panel);
1653 window_destroy (g->toplevel);
1654 /* window_destroy (g->text); */
1655 gdk_gc_unref (g->fg_gc);
1656 gdk_gc_unref (g->bg_gc);
1657 gdk_pixmap_unref (g->pixmap[0]);
1658 gdk_pixmap_unref (g->pixmap[1]);
1661 g_free ( (gpointer) (g->title) );
1662 graph_segment_list_free (g);
1663 graph_element_lists_free (g);
1669 typedef struct _tcp_scan_t {
1670 struct segment *current;
1673 struct segment *last;
1677 tapall_tcpip_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip)
1679 static struct segment *segment=NULL;
1680 tcp_scan_t *ts=(tcp_scan_t *)pct;
1681 struct tcpheader *tcphdr=(struct tcpheader *)vip;
1684 segment=g_malloc(sizeof (struct segment));
1688 if (compare_headers(&ts->current->ip_src, &ts->current->ip_dst,
1689 ts->current->th_sport, ts->current->th_dport,
1690 &tcphdr->ip_src, &tcphdr->ip_dst,
1691 tcphdr->th_sport, tcphdr->th_dport,
1693 segment->next = NULL;
1694 segment->num = pinfo->fd->num;
1695 segment->rel_secs = (guint32) pinfo->fd->rel_ts.secs;
1696 segment->rel_usecs = pinfo->fd->rel_ts.nsecs/1000;
1697 segment->abs_secs = (guint32) pinfo->fd->abs_ts.secs;
1698 segment->abs_usecs = pinfo->fd->abs_ts.nsecs/1000;
1699 segment->th_seq=tcphdr->th_seq;
1700 segment->th_ack=tcphdr->th_ack;
1701 segment->th_win=tcphdr->th_win;
1702 segment->th_flags=tcphdr->th_flags;
1703 segment->th_sport=tcphdr->th_sport;
1704 segment->th_dport=tcphdr->th_dport;
1705 segment->th_seglen=tcphdr->th_seglen;
1706 COPY_ADDRESS(&segment->ip_src, &tcphdr->ip_src);
1707 COPY_ADDRESS(&segment->ip_dst, &tcphdr->ip_dst);
1708 if (ts->g->segments) {
1709 ts->last->next = segment;
1711 ts->g->segments = segment;
1714 if(pinfo->fd->num==ts->current->num){
1715 ts->g->current = segment;
1726 /* here we collect all the external data we will ever need */
1727 static void graph_segment_list_get (struct graph *g)
1729 struct segment current;
1730 GString *error_string;
1734 debug(DBS_FENTRY) puts ("graph_segment_list_get()");
1735 select_tcpip_session (&cfile, ¤t);
1736 if (g->type == GRAPH_THROUGHPUT)
1737 ts.direction = COMPARE_CURR_DIR;
1739 ts.direction = COMPARE_ANY_DIR;
1741 /* rescan all the packets and pick up all interesting tcp headers.
1742 * we only filter for TCP here for speed and do the actual compare
1743 * in the tap listener
1745 ts.current=¤t;
1748 error_string=register_tap_listener("tcp", &ts, "tcp", 0, NULL, tapall_tcpip_packet, NULL);
1750 fprintf(stderr, "wireshark: Couldn't register tcp_graph tap: %s\n",
1752 g_string_free(error_string, TRUE);
1755 cf_retap_packets(&cfile);
1756 remove_tap_listener(&ts);
1760 typedef struct _th_t {
1762 struct tcpheader *tcphdr;
1766 tap_tcpip_packet(void *pct, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *vip)
1771 th->tcphdr=(struct tcpheader *)vip;
1778 /* XXX should be enhanced so that if we have multiple TCP layers in the trace
1779 * then present the user with a dialog where the user can select WHICH tcp
1782 static struct tcpheader *select_tcpip_session (capture_file *cf, struct segment *hdrs)
1787 GString *error_string;
1788 th_t th = {0, NULL};
1790 fdata = cf->current_frame;
1792 /* no real filter yet */
1793 if (!dfilter_compile("tcp", &sfcode)) {
1794 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", dfilter_error_msg);
1798 /* dissect the current frame */
1799 if (!cf_read_frame(cf, fdata))
1800 return NULL; /* error reading the frame */
1803 error_string=register_tap_listener("tcp", &th, NULL, 0, NULL, tap_tcpip_packet, NULL);
1805 fprintf(stderr, "wireshark: Couldn't register tcp_graph tap: %s\n",
1807 g_string_free(error_string, TRUE);
1811 epan_dissect_init(&edt, TRUE, FALSE);
1812 epan_dissect_prime_dfilter(&edt, sfcode);
1813 tap_queue_init(&edt);
1814 epan_dissect_run(&edt, &cf->pseudo_header, cf->pd, fdata, NULL);
1815 tap_push_tapped_queue(&edt);
1816 epan_dissect_cleanup(&edt);
1817 remove_tap_listener(&th);
1820 /* This "shouldn't happen", as our menu items shouldn't
1821 * even be enabled if the selected packet isn't a TCP
1822 * segment, as tcp_graph_selected_packet_enabled() is used
1823 * to determine whether to enable any of our menu items. */
1824 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1825 "Selected packet isn't a TCP segment");
1828 /* XXX fix this later, we should show a dialog allowing the user
1829 to select which session he wants here
1832 /* can only handle a single tcp layer yet */
1833 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1834 "The selected packet has more than one TCP"
1839 hdrs->num = fdata->num;
1840 hdrs->rel_secs = (guint32) fdata->rel_ts.secs;
1841 hdrs->rel_usecs = fdata->rel_ts.nsecs/1000;
1842 hdrs->abs_secs = (guint32) fdata->abs_ts.secs;
1843 hdrs->abs_usecs = fdata->abs_ts.nsecs/1000;
1844 hdrs->th_seq=th.tcphdr->th_seq;
1845 hdrs->th_ack=th.tcphdr->th_ack;
1846 hdrs->th_win=th.tcphdr->th_win;
1847 hdrs->th_flags=th.tcphdr->th_flags;
1848 hdrs->th_sport=th.tcphdr->th_sport;
1849 hdrs->th_dport=th.tcphdr->th_dport;
1850 hdrs->th_seglen=th.tcphdr->th_seglen;
1851 COPY_ADDRESS(&hdrs->ip_src, &th.tcphdr->ip_src);
1852 COPY_ADDRESS(&hdrs->ip_dst, &th.tcphdr->ip_dst);
1857 static int compare_headers (address *saddr1, address *daddr1, guint16 sport1, guint16 dport1, address *saddr2, address *daddr2, guint16 sport2, guint16 dport2, int dir)
1861 dir1 = ((!(CMP_ADDRESS(saddr1, saddr2))) &&
1862 (!(CMP_ADDRESS(daddr1, daddr2))) &&
1866 if(dir==COMPARE_CURR_DIR){
1869 dir2 = ((!(CMP_ADDRESS(saddr1, daddr2))) &&
1870 (!(CMP_ADDRESS(daddr1, saddr2))) &&
1873 return dir1 || dir2;
1877 static void graph_segment_list_free (struct graph *g)
1879 struct segment *segment;
1881 while (g->segments) {
1882 segment = g->segments->next;
1883 g_free (g->segments);
1884 g->segments = segment;
1889 static void graph_element_lists_initialize (struct graph *g)
1891 g->elists = (struct element_list *)g_malloc0 (sizeof (struct element_list));
1894 static void graph_element_lists_make (struct graph *g)
1896 debug(DBS_FENTRY) puts ("graph_element_lists_make()");
1899 case GRAPH_TSEQ_STEVENS:
1900 tseq_stevens_make_elmtlist (g);
1902 case GRAPH_TSEQ_TCPTRACE:
1903 tseq_tcptrace_make_elmtlist (g);
1905 case GRAPH_THROUGHPUT:
1906 tput_make_elmtlist (g);
1909 rtt_make_elmtlist (g);
1912 printf ("graph_element_lists_make: unknown graph type: %d\n", g->type);
1917 static void graph_element_lists_free (struct graph *g)
1919 struct element_list *list, *next_list;
1922 for (list=g->elists; list; list=list->next)
1923 g_free (list->elements);
1924 while (g->elists->next) {
1925 list = g->elists->next->next;
1926 g_free (g->elists->next);
1927 g->elists->next = list;
1931 for (list=g->elists; list; list=next_list) {
1932 g_free (list->elements);
1933 next_list = list->next;
1936 g->elists = NULL; /* just to make debugging easier */
1939 static void graph_title_pixmap_create (struct graph *g)
1941 if (g->title_pixmap)
1942 gdk_pixmap_unref (g->title_pixmap);
1944 g->title_pixmap = gdk_pixmap_new (g->drawing_area->window,
1945 g->x_axis->p.width, g->wp.y, -1);
1948 static void graph_title_pixmap_draw (struct graph *g)
1952 gdk_draw_rectangle(g->title_pixmap, g->bg_gc, TRUE, 0, 0,
1953 g->x_axis->p.width, g->wp.y);
1954 for (i=0; g->title[i]; i++) {
1956 PangoLayout *layout;
1957 layout = gtk_widget_create_pango_layout(g->drawing_area,
1959 pango_layout_get_pixel_size(layout, &w, &h);
1960 gdk_draw_layout(g->title_pixmap, g->fg_gc,
1961 g->wp.width/2 - w/2, 20 + i*(h+3), layout);
1962 g_object_unref(G_OBJECT(layout));
1966 static void graph_title_pixmap_display (struct graph *g)
1968 gdk_draw_pixmap (g->drawing_area->window, g->fg_gc, g->title_pixmap,
1969 0, 0, g->wp.x, 0, g->x_axis->p.width, g->wp.y);
1972 static void graph_pixmaps_create (struct graph *g)
1974 debug(DBS_FENTRY) puts ("graph_pixmaps_create()");
1977 gdk_pixmap_unref (g->pixmap[0]);
1979 gdk_pixmap_unref (g->pixmap[1]);
1981 g->pixmap[0] = gdk_pixmap_new (g->drawing_area->window,
1982 g->wp.width, g->wp.height, -1);
1983 g->pixmap[1] = gdk_pixmap_new (g->drawing_area->window,
1984 g->wp.width, g->wp.height, -1);
1989 static void graph_display (struct graph *g)
1991 set_busy_cursor (g->drawing_area->window);
1992 graph_pixmap_draw (g);
1993 unset_busy_cursor (g->drawing_area->window);
1994 graph_pixmaps_switch (g);
1995 graph_pixmap_display (g);
1998 static void graph_pixmap_display (struct graph *g)
2000 gdk_draw_pixmap (g->drawing_area->window, g->fg_gc,
2001 g->pixmap[g->displayed], 0, 0, g->wp.x, g->wp.y,
2002 g->wp.width, g->wp.height);
2003 if (g->cross.erase_needed) {
2004 cross_xor(g, g->cross.x, g->cross.y);
2008 static void graph_pixmaps_switch (struct graph *g)
2010 g->displayed = 1 ^ g->displayed;
2013 static void graph_pixmap_draw (struct graph *g)
2015 struct element_list *list;
2019 debug(DBS_FENTRY) puts ("graph_display()");
2020 not_disp = 1 ^ g->displayed;
2022 gdk_draw_rectangle (g->pixmap[not_disp], g->bg_gc, TRUE,
2023 0, 0, g->wp.width, g->wp.height);
2024 for (list=g->elists; list; list=list->next)
2025 for (e=list->elements; e->type != ELMT_NONE; e++) {
2030 draw_element_line (g, e);
2033 draw_element_arc (g, e);
2041 static void draw_element_line (struct graph *g, struct element *e)
2043 int xx1, xx2, yy1, yy2;
2045 debug(DBS_GRAPH_DRAWING) printf ("line element: (%.2f,%.2f)->(%.2f,%.2f), "
2046 "seg %d ... ", e->p.line.dim.x1, e->p.line.dim.y1,
2047 e->p.line.dim.x2, e->p.line.dim.y2, e->parent->num);
2048 xx1 = (int )rint (e->p.line.dim.x1 + g->geom.x - g->wp.x);
2049 xx2 = (int )rint (e->p.line.dim.x2 + g->geom.x - g->wp.x);
2050 yy1 = (int )rint ((g->geom.height-1-e->p.line.dim.y1) + g->geom.y-g->wp.y);
2051 yy2 = (int )rint ((g->geom.height-1-e->p.line.dim.y2) + g->geom.y-g->wp.y);
2062 if ((xx1<0 && xx2<0) || (xx1>=g->wp.width && xx2>=g->wp.width) ||
2063 (yy1<0 && yy2<0) || (yy1>=g->wp.height && yy2>=g->wp.height)) {
2064 debug(DBS_GRAPH_DRAWING) printf (" refusing: (%d,%d)->(%d,%d)\n",
2065 xx1, yy1, xx2, yy2);
2068 if (xx2 > g->wp.width-1)
2069 xx2 = g->wp.width-1;
2072 if (yy2 > g->wp.height-1)
2073 yy2 = g->wp.height-1;
2076 debug(DBS_GRAPH_DRAWING) printf ("line: (%d,%d)->(%d,%d)\n", xx1, yy1, xx2,yy2);
2077 gdk_draw_line (g->pixmap[1^g->displayed], e->gc, xx1, yy1, xx2, yy2);
2080 static void draw_element_arc (struct graph *g, struct element *e)
2082 int xx1, xx2, yy1, yy2;
2084 xx1 = (int )rint (e->p.arc.dim.x + g->geom.x - g->wp.x);
2085 xx2 = (int )e->p.arc.dim.width;
2086 yy1 = (int )rint (g->geom.height-1 - e->p.arc.dim.y + g->geom.y - g->wp.y);
2087 yy2 = (int )e->p.arc.dim.height;
2088 if (xx1<-xx2 || xx1>=g->wp.width || yy1<-yy2 || yy1>=g->wp.height)
2090 debug(DBS_GRAPH_DRAWING) printf ("arc: (%d,%d)->(%d,%d)\n", xx1, yy1, xx2, yy2);
2091 gdk_draw_arc (g->pixmap[1^g->displayed], e->gc, e->p.arc.filled, xx1,
2092 yy1, xx2, yy2, e->p.arc.angle1, e->p.arc.angle2);
2095 static void axis_pixmaps_create (struct axis *axis)
2097 debug(DBS_FENTRY) puts ("axis_pixmaps_create()");
2098 if (axis->pixmap[0])
2099 gdk_pixmap_unref (axis->pixmap[0]);
2100 if (axis->pixmap[1])
2101 gdk_pixmap_unref (axis->pixmap[1]);
2103 axis->pixmap[0] = gdk_pixmap_new (axis->drawing_area->window,
2104 axis->p.width, axis->p.height, -1);
2105 axis->pixmap[1] = gdk_pixmap_new (axis->drawing_area->window,
2106 axis->p.width, axis->p.height, -1);
2108 axis->displayed = 0;
2111 static void axis_destroy (struct axis *axis)
2113 gdk_pixmap_unref (axis->pixmap[0]);
2114 gdk_pixmap_unref (axis->pixmap[1]);
2115 g_free ( (gpointer) (axis->label) );
2118 static void axis_display (struct axis *axis)
2120 if (axis->flags & AXIS_ORIENTATION)
2121 h_axis_pixmap_draw (axis);
2123 v_axis_pixmap_draw (axis);
2124 axis_pixmaps_switch (axis);
2125 axis_pixmap_display (axis);
2128 static void v_axis_pixmap_draw (struct axis *axis)
2130 struct graph *g = axis->g;
2133 int not_disp, rdigits, offset, imin, imax;
2134 double bottom, top, j, fl, corr;
2135 PangoLayout *layout;
2137 debug(DBS_FENTRY) puts ("v_axis_pixmap_draw()");
2138 bottom = (g->geom.height - (g->wp.height + g->wp.y + (-g->geom.y))) /
2139 (double )g->geom.height * g->bounds.height;
2140 bottom += axis->min;
2141 top = (g->geom.height - (g->wp.y + (-g->geom.y))) /
2142 (double )g->geom.height * g->bounds.height;
2144 axis_compute_ticks (axis, bottom, top, AXIS_VERTICAL);
2146 j = axis->major - floor (axis->major);
2147 for (rdigits=0; rdigits<=6; rdigits++) {
2154 not_disp = 1 ^ axis->displayed;
2155 gdk_draw_rectangle (axis->pixmap[not_disp], g->bg_gc, TRUE, 0, 0,
2156 axis->p.width, axis->p.height);
2158 gdk_draw_line (axis->pixmap[not_disp], g->fg_gc, axis->p.width - 1,
2159 (gint) ((axis->p.height-axis->s.height)/2.0), axis->s.width - 1,
2162 offset = g->wp.y + (-g->geom.y);
2163 fl = floor (axis->min / axis->major) * axis->major;
2164 corr = rint ((axis->min - fl) * g->zoom.y);
2167 major_tick = axis->major * g->zoom.y;
2168 imin = (int) ((g->geom.height - offset + corr - g->wp.height) / major_tick + 1);
2169 imax = (int) ((g->geom.height - offset + corr) / major_tick);
2170 for (i=imin; i <= imax; i++) {
2173 int y = (int) (g->geom.height-1 - (int )rint (i * major_tick) -
2174 offset + corr + axis->s.y);
2176 debug(DBS_AXES_DRAWING) printf("%f @ %d\n",
2177 i*axis->major + fl, y);
2178 if (y < 0 || y > axis->p.height)
2180 gdk_draw_line (axis->pixmap[not_disp], g->fg_gc,
2181 axis->s.width - 15, y, axis->s.width - 1, y);
2182 g_snprintf (desc, sizeof(desc), "%.*f", rdigits, i*axis->major + fl);
2183 layout = gtk_widget_create_pango_layout(g->drawing_area, desc);
2184 pango_layout_get_pixel_size(layout, &w, &h);
2185 gdk_draw_layout(axis->pixmap[not_disp], g->fg_gc,
2186 axis->s.width-14-4-w, y - h/2, layout);
2187 g_object_unref(G_OBJECT(layout));
2191 double minor_tick = axis->minor * g->zoom.y;
2192 imin = (int) ((g->geom.height - offset + corr - g->wp.height)/minor_tick + 1);
2193 imax = (int) ((g->geom.height - offset + corr) / minor_tick);
2194 for (i=imin; i <= imax; i++) {
2195 int y = (int) (g->geom.height-1 - (int )rint (i*minor_tick) -
2196 offset + corr + axis->s.y);
2198 debug (DBS_AXES_DRAWING) printf ("%f @ %d\n", i*axis->minor+fl, y);
2199 if (y > 0 && y < axis->p.height)
2200 gdk_draw_line (axis->pixmap[not_disp], g->fg_gc,
2201 axis->s.width - 8, y,
2202 axis->s.width - 1, y);
2205 for (i=0; axis->label[i]; i++) {
2207 layout = gtk_widget_create_pango_layout(g->drawing_area,
2209 pango_layout_get_pixel_size(layout, &w, &h);
2210 gdk_draw_layout(axis->pixmap[not_disp], g->fg_gc,
2211 (axis->p.width - w)/2,
2212 TITLEBAR_HEIGHT-10 - i*(h+3) - h,
2214 g_object_unref(G_OBJECT(layout));
2218 static void h_axis_pixmap_draw (struct axis *axis)
2220 struct graph *g = axis->g;
2222 double major_tick, minor_tick;
2223 int not_disp, rdigits, offset, imin, imax;
2224 double left, right, j, fl, corr;
2225 PangoLayout *layout;
2227 debug(DBS_FENTRY) puts ("h_axis_pixmap_draw()");
2228 left = (g->wp.x-g->geom.x) /
2229 (double )g->geom.width * g->bounds.width;
2231 right = (g->wp.x-g->geom.x+g->wp.width) /
2232 (double )g->geom.width * g->bounds.width;
2234 axis_compute_ticks (axis, left, right, AXIS_HORIZONTAL);
2236 j = axis->major - floor (axis->major);
2237 for (rdigits=0; rdigits<=6; rdigits++) {
2244 not_disp = 1 ^ axis->displayed;
2245 gdk_draw_rectangle (axis->pixmap[not_disp], g->bg_gc, TRUE, 0, 0,
2246 axis->p.width, axis->p.height);
2248 gdk_draw_line (axis->pixmap[not_disp], g->fg_gc, 0, 0,
2249 (gint) (axis->s.width + (axis->p.width-axis->s.width)/2.0), 0);
2250 offset = g->wp.x - g->geom.x;
2252 fl = floor (axis->min / axis->major) * axis->major;
2253 corr = rint ((axis->min - fl) * g->zoom.x);
2256 major_tick = axis->major*g->zoom.x;
2257 imin = (int) ((offset + corr) / major_tick + 1);
2258 imax = (int) ((offset + corr + axis->s.width) / major_tick);
2259 for (i=imin; i <= imax; i++) {
2262 int x = (int ) (rint (i * major_tick) - offset - corr);
2264 /* printf ("%f @ %d\n", i*axis->major + fl, x); */
2265 if (x < 0 || x > axis->s.width)
2267 gdk_draw_line (axis->pixmap[not_disp], g->fg_gc, x, 0, x, 15);
2268 g_snprintf (desc, sizeof(desc), "%.*f", rdigits, i*axis->major + fl);
2269 layout = gtk_widget_create_pango_layout(g->drawing_area, desc);
2270 pango_layout_get_pixel_size(layout, &w, &h);
2271 gdk_draw_layout(axis->pixmap[not_disp], g->fg_gc,
2272 x - w/2, 15+4, layout);
2273 g_object_unref(G_OBJECT(layout));
2275 if (axis->minor > 0) {
2277 minor_tick = axis->minor*g->zoom.x;
2278 imin = (int) ((offset + corr) / minor_tick + 1);
2279 imax = (int) ((offset + corr + g->wp.width) / minor_tick);
2280 for (i=imin; i <= imax; i++) {
2281 int x = (int) (rint (i * minor_tick) - offset - corr);
2282 if (x > 0 && x < axis->s.width)
2283 gdk_draw_line (axis->pixmap[not_disp], g->fg_gc, x, 0, x, 8);
2286 for (i=0; axis->label[i]; i++) {
2288 layout = gtk_widget_create_pango_layout(g->drawing_area,
2290 pango_layout_get_pixel_size(layout, &w, &h);
2291 gdk_draw_layout(axis->pixmap[not_disp], g->fg_gc,
2292 axis->s.width - w - 50, 15+h+15 + i*(h+3),
2294 g_object_unref(G_OBJECT(layout));
2298 static void axis_pixmaps_switch (struct axis *axis)
2300 axis->displayed = 1 ^ axis->displayed;
2303 static void axis_pixmap_display (struct axis *axis)
2305 gdk_draw_pixmap (axis->drawing_area->window, axis->g->fg_gc,
2306 axis->pixmap[axis->displayed], 0, 0, axis->p.x, axis->p.y,
2307 axis->p.width, axis->p.height);
2310 static void axis_compute_ticks (struct axis *axis, double x0, double xmax, int dir)
2312 int i, j, ii, jj, ms;
2313 double zoom, x, steps[3]={ 0.1, 0.5 };
2314 int dim, check_needed, diminished;
2315 double majthresh[2]={2.0, 3.0};
2317 debug((DBS_FENTRY | DBS_AXES_TICKS)) puts ("axis_compute_ticks()");
2318 debug(DBS_AXES_TICKS)
2319 printf ("x0=%f xmax=%f dir=%s\n", x0,xmax, dir?"VERTICAL":"HORIZONTAL");
2321 zoom = axis_zoom_get (axis, dir);
2323 for (i=-9; i<=12; i++) {
2324 if (x / pow (10, i) < 1)
2328 ms = (int )(x / pow (10, i));
2338 axis->major = steps[j] * pow (10, i);
2340 debug(DBS_AXES_TICKS) printf ("zoom=%.1f, x=%f -> i=%d -> ms=%d -> j=%d ->"
2341 " axis->major=%f\n", zoom, x, i, ms, j, axis->major);
2343 /* let's compute minor ticks */
2346 axis_ticks_down (&ii, &jj);
2347 axis->minor = steps[jj] * pow (10, ii);
2348 /* we don't want minors if they would be less than 10 pixels apart */
2349 if (axis->minor*zoom < 10) {
2350 debug(DBS_AXES_TICKS) printf ("refusing axis->minor of %f: "
2351 "axis->minor*zoom == %f\n", axis->minor, axis->minor*zoom);
2355 check_needed = TRUE;
2357 while (check_needed) {
2358 check_needed = FALSE;
2359 dim = get_label_dim (axis, dir, xmax);
2360 debug(DBS_AXES_TICKS) printf ("axis->major==%.1f, axis->minor==%.1f =>"
2361 " axis->major*zoom/dim==%f, axis->minor*zoom/dim==%f\n",
2362 axis->major, axis->minor, axis->major*zoom/dim,
2363 axis->minor*zoom/dim);
2365 /* corrections: if majors are less than majthresh[dir] times label
2366 * dimension apart, we need to use bigger ones */
2367 if (axis->major*zoom / dim < majthresh[dir]) {
2368 axis_ticks_up (&ii, &jj);
2369 axis->minor = axis->major;
2370 axis_ticks_up (&i, &j);
2371 axis->major = steps[j] * pow (10, i);
2372 check_needed = TRUE;
2373 debug(DBS_AXES_TICKS) printf ("axis->major enlarged to %.1f\n",
2376 /* if minor ticks are bigger than majthresh[dir] times label dimension,
2377 * we could promote them to majors as well */
2378 if (axis->minor*zoom / dim > majthresh[dir] && !diminished) {
2379 axis_ticks_down (&i, &j);
2380 axis->major = axis->minor;
2381 axis_ticks_down (&ii, &jj);
2382 axis->minor = steps[jj] * pow (10, ii);
2383 check_needed = TRUE;
2386 debug(DBS_AXES_TICKS) printf ("axis->minor diminished to %.1f\n",
2389 if (axis->minor*zoom < 10) {
2390 debug(DBS_AXES_TICKS) printf ("refusing axis->minor of %f: "
2391 "axis->minor*zoom == %f\n", axis->minor, axis->minor*zoom);
2397 debug(DBS_AXES_TICKS) printf ("corrected: axis->major == %.1f -> "
2398 "axis->minor == %.1f\n", axis->major, axis->minor);
2401 static void axis_ticks_up (int *i, int *j)
2410 static void axis_ticks_down (int *i, int *j)
2419 static int get_label_dim (struct axis *axis, int dir, double label)
2424 PangoLayout *layout;
2426 /* First, let's compute how many digits to the right of radix
2427 * we need to print */
2428 y = axis->major - floor (axis->major);
2429 for (rdigits=0; rdigits<=6; rdigits++) {
2435 g_snprintf (str, sizeof(str), "%.*f", rdigits, label);
2437 case AXIS_HORIZONTAL:
2438 layout = gtk_widget_create_pango_layout(axis->g->drawing_area,
2440 pango_layout_get_pixel_size(layout, &dim, NULL);
2441 g_object_unref(G_OBJECT(layout));
2444 layout = gtk_widget_create_pango_layout(axis->g->drawing_area,
2446 pango_layout_get_pixel_size(layout, NULL, &dim);
2447 g_object_unref(G_OBJECT(layout));
2450 puts ("initialize axis: an axis must be either horizontal or vertical");
2456 static double axis_zoom_get (struct axis *axis, int dir)
2459 case AXIS_HORIZONTAL:
2460 return axis->g->zoom.x;
2462 return axis->g->zoom.y;
2468 static void graph_select_segment (struct graph *g, int x, int y)
2470 struct element_list *list;
2474 debug(DBS_FENTRY) puts ("graph_select_segment()");
2477 y = g->geom.height-1 - (y - g->geom.y);
2479 set_busy_cursor (g->drawing_area->window);
2481 for (list=g->elists; list; list=list->next)
2482 for (e=list->elements; e->type != ELMT_NONE; e++) {
2487 if (line_detect_collision (e, x, y)) {
2488 num = e->parent->num;
2491 if (arc_detect_collision (e, x, y)) {
2492 num = e->parent->num;
2502 cf_goto_frame(&cfile, num);
2504 unset_busy_cursor (g->drawing_area->window);
2507 static int line_detect_collision (struct element *e, int x, int y)
2509 int xx1, yy1, xx2, yy2;
2511 if (e->p.line.dim.x1 < e->p.line.dim.x2) {
2512 xx1 = (int )rint (e->p.line.dim.x1);
2513 xx2 = (int )rint (e->p.line.dim.x2);
2515 xx1 = (int )rint (e->p.line.dim.x2);
2516 xx2 = (int )rint (e->p.line.dim.x1);
2518 if (e->p.line.dim.y1 < e->p.line.dim.y2) {
2519 yy1 = (int )rint (e->p.line.dim.y1);
2520 yy2 = (int )rint (e->p.line.dim.y2);
2522 yy1 = (int )rint (e->p.line.dim.y2);
2523 yy2 = (int )rint (e->p.line.dim.y1);
2526 printf ("line: (%d,%d)->(%d,%d), clicked: (%d,%d)\n", xx1, yy1, xx2, yy2, x, y);
2528 if ((xx1==x && xx2==x && yy1<=y && y<=yy2)||(yy1==y && yy2==y && xx1<=x && x<=xx2))
2534 static int arc_detect_collision (struct element *e, int x, int y)
2536 int xx1, yy1, xx2, yy2;
2538 xx1 = (int )rint (e->p.arc.dim.x);
2539 xx2 = (int )rint (e->p.arc.dim.x + e->p.arc.dim.width);
2540 yy1 = (int )rint (e->p.arc.dim.y - e->p.arc.dim.height);
2541 yy2 = (int )rint (e->p.arc.dim.y);
2543 printf ("arc: (%d,%d)->(%d,%d), clicked: (%d,%d)\n", xx1, yy1, xx2, yy2, x, y);
2545 if (xx1<=x && x<=xx2 && yy1<=y && y<=yy2)
2551 static void cross_xor (struct graph *g, int x, int y)
2553 if (x > g->wp.x && x < g->wp.x+g->wp.width &&
2554 y >= g->wp.y && y < g->wp.y+g->wp.height) {
2555 gdk_draw_line (g->drawing_area->window, xor_gc, g->wp.x,
2556 y, g->wp.x + g->wp.width, y);
2557 gdk_draw_line (g->drawing_area->window, xor_gc, x,
2558 g->wp.y, x, g->wp.y + g->wp.height);
2562 static void cross_draw (struct graph *g, int x, int y)
2564 cross_xor (g, x, y);
2567 g->cross.erase_needed = 1;
2570 static void cross_erase (struct graph *g)
2572 cross_xor (g, g->cross.x, g->cross.y);
2573 g->cross.erase_needed = 0;
2576 static void magnify_create (struct graph *g, int x, int y)
2579 struct element_list *list, *new_list;
2580 struct ipoint pos, offsetpos;
2583 mg = g->magnify.g = (struct graph * )g_malloc (sizeof (struct graph));
2584 memcpy ((void * )mg, (void * )g, sizeof (struct graph));
2586 mg->toplevel = dlg_window_new("tcp graph magnify");
2587 mg->drawing_area = mg->toplevel;
2588 gtk_window_set_default_size(GTK_WINDOW(mg->toplevel), g->magnify.width, g->magnify.height);
2589 gtk_widget_set_events (mg->drawing_area, GDK_EXPOSURE_MASK
2590 /* | GDK_ENTER_NOTIFY_MASK */
2591 /* | GDK_ALL_EVENTS_MASK */
2596 mg->wp.width = g->magnify.width;
2597 mg->wp.height = g->magnify.height;
2598 mg->geom.width = (int )rint (g->geom.width * g->magnify.zoom.x);
2599 mg->geom.height = (int )rint (g->geom.height * g->magnify.zoom.y);
2600 mg->zoom.x = (mg->geom.width - 1) / g->bounds.width;
2601 mg->zoom.y = (mg->geom.height- 1) / g->bounds.height;
2603 /* in order to keep original element lists intact we need our own */
2604 graph_element_lists_initialize (mg);
2605 list = g->elists->next;
2606 new_list = mg->elists;
2607 for ( ; list; list=list->next) {
2609 (struct element_list * )g_malloc (sizeof (struct element_list));
2610 new_list = new_list->next;
2611 new_list->next = NULL;
2612 new_list->elements = NULL;
2614 graph_element_lists_make (mg);
2616 gdk_window_get_position (GTK_WIDGET (g->toplevel)->window, &pos.x, &pos.y);
2617 g->magnify.x = pos.x + x - g->magnify.width/2;
2618 g->magnify.y = pos.y + y - g->magnify.height/2;
2619 offsetpos.x = g->magnify.x + g->magnify.offset.x;
2620 offsetpos.x = offsetpos.x >= 0 ? offsetpos.x : 0;
2621 offsetpos.y = g->magnify.y + g->magnify.offset.y;
2622 offsetpos.y = offsetpos.y >= 0 ? offsetpos.y : 0;
2623 gtk_window_set_position (GTK_WINDOW(mg->drawing_area), GTK_WIN_POS_NONE);
2624 magnify_get_geom (g, x, y);
2626 gtk_widget_show (mg->drawing_area);
2628 /* we need to wait for the first expose event before we start drawing */
2629 while (!gdk_events_pending ());
2631 e = gdk_event_get ();
2633 if (e->any.type == GDK_EXPOSE) {
2641 mg->pixmap[0] = mg->pixmap[1] = NULL;
2642 graph_pixmaps_create (mg);
2644 g->magnify.active = 1;
2647 static void magnify_move (struct graph *g, int x, int y)
2649 struct ipoint pos, offsetpos;
2651 gdk_window_get_position (GTK_WIDGET (g->toplevel)->window, &pos.x, &pos.y);
2652 g->magnify.x = pos.x + x - g->magnify.width/2;
2653 g->magnify.y = pos.y + y - g->magnify.height/2;
2654 offsetpos.x = g->magnify.x + g->magnify.offset.x;
2655 offsetpos.x = offsetpos.x >= 0 ? offsetpos.x : 0;
2656 offsetpos.y = g->magnify.y + g->magnify.offset.y;
2657 offsetpos.y = offsetpos.y >= 0 ? offsetpos.y : 0;
2658 magnify_get_geom (g, x, y);
2662 static void magnify_destroy (struct graph *g)
2664 struct element_list *list;
2665 struct graph *mg = g->magnify.g;
2667 window_destroy (GTK_WIDGET (mg->drawing_area));
2668 gdk_pixmap_unref (mg->pixmap[0]);
2669 gdk_pixmap_unref (mg->pixmap[1]);
2670 for (list=mg->elists; list; list=list->next)
2671 g_free (list->elements);
2674 while (mg->elists->next) {
2675 list = mg->elists->next->next;
2676 g_free (mg->elists->next);
2677 mg->elists->next = list;
2680 g_free (g->magnify.g);
2681 g->magnify.active = 0;
2684 static void magnify_get_geom (struct graph *g, int x, int y)
2688 gdk_window_get_position (GTK_WIDGET (g->toplevel)->window, &posx, &posy);
2690 g->magnify.g->geom.x = g->geom.x;
2691 g->magnify.g->geom.y = g->geom.y;
2693 g->magnify.g->geom.x -=
2694 (int )rint ((g->magnify.g->geom.width - g->geom.width) *
2695 ((x-g->geom.x)/(double )g->geom.width));
2696 g->magnify.g->geom.y -=
2697 (int )rint ((g->magnify.g->geom.height - g->geom.height) *
2698 ((y-g->geom.y)/(double )g->geom.height));
2700 /* we have coords of origin of graph relative to origin of g->toplevel.
2701 * now we need them to relate to origin of magnify window */
2702 g->magnify.g->geom.x -= (g->magnify.x - posx);
2703 g->magnify.g->geom.y -= (g->magnify.y - posy);
2706 static void magnify_draw (struct graph *g)
2708 int not_disp = 1 ^ g->magnify.g->displayed;
2710 graph_pixmap_draw (g->magnify.g);
2711 /* graph pixmap is almost ready, just add border */
2712 gdk_draw_line (g->magnify.g->pixmap[not_disp], g->fg_gc, 0, 0,
2713 g->magnify.width - 1, 0);
2714 gdk_draw_line (g->magnify.g->pixmap[not_disp], g->fg_gc,
2715 g->magnify.width - 1, 0, g->magnify.width - 1, g->magnify.height);
2716 gdk_draw_line (g->magnify.g->pixmap[not_disp], g->fg_gc, 0, 0,
2717 0, g->magnify.height - 1);
2718 gdk_draw_line (g->magnify.g->pixmap[not_disp], g->fg_gc, 0,
2719 g->magnify.height - 1, g->magnify.width - 1, g->magnify.height - 1);
2721 graph_pixmaps_switch (g->magnify.g);
2722 graph_pixmap_display (g->magnify.g);
2726 static gboolean configure_event (GtkWidget *widget, GdkEventConfigure *event, gpointer user_data _U_)
2728 struct graph *g = (struct graph *) g_object_get_data(G_OBJECT(widget), "graph");
2732 int cur_g_width, cur_g_height;
2733 int cur_wp_width, cur_wp_height;
2735 debug(DBS_FENTRY) puts ("configure_event()");
2737 cur_wp_width = g->wp.width;
2738 cur_wp_height = g->wp.height;
2739 g->wp.width = event->width - g->y_axis->p.width - RMARGIN_WIDTH;
2740 g->wp.height = event->height - g->x_axis->p.height - g->wp.y;
2741 g->x_axis->s.width = g->wp.width;
2742 g->x_axis->p.width = g->wp.width + RMARGIN_WIDTH;
2743 g->y_axis->p.height = g->wp.height + g->wp.y;
2744 g->y_axis->s.height = g->wp.height;
2745 g->x_axis->p.y = g->y_axis->p.height;
2746 zoom.x = (double )g->wp.width / cur_wp_width;
2747 zoom.y = (double )g->wp.height / cur_wp_height;
2748 cur_g_width = g->geom.width;
2749 cur_g_height = g->geom.height;
2750 g->geom.width = (int )rint (g->geom.width * zoom.x);
2751 g->geom.height = (int )rint (g->geom.height * zoom.y);
2752 g->zoom.x = (double )(g->geom.width - 1) / g->bounds.width;
2753 g->zoom.y = (double )(g->geom.height -1) / g->bounds.height;
2754 /* g->zoom.initial.x = g->zoom.x; */
2755 /* g->zoom.initial.y = g->zoom.y; */
2757 g->geom.x = (int) (g->wp.x - (double )g->geom.width/cur_g_width *
2758 (g->wp.x - g->geom.x));
2759 g->geom.y = (int) (g->wp.y - (double )g->geom.height/cur_g_height *
2760 (g->wp.y - g->geom.y));
2762 printf ("configure: graph: (%d,%d), (%d,%d); viewport: (%d,%d), (%d,%d); "
2763 "zooms: (%f,%f)\n", g->geom.x, g->geom.y, g->geom.width,
2764 g->geom.height, g->wp.x, g->wp.y, g->wp.width, g->wp.height,
2765 g->zoom.x, g->zoom.y);
2768 update_zoom_spins (g);
2769 graph_element_lists_make (g);
2770 graph_pixmaps_create (g);
2771 graph_title_pixmap_create (g);
2772 axis_pixmaps_create (g->y_axis);
2773 axis_pixmaps_create (g->x_axis);
2774 /* we don't do actual drawing here; we leave it to expose handler */
2775 graph_pixmap_draw (g);
2776 graph_pixmaps_switch (g);
2777 graph_title_pixmap_draw (g);
2778 h_axis_pixmap_draw (g->x_axis);
2779 axis_pixmaps_switch (g->x_axis);
2780 v_axis_pixmap_draw (g->y_axis);
2781 axis_pixmaps_switch (g->y_axis);
2785 static gboolean expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data _U_)
2787 struct graph *g = (struct graph *) g_object_get_data(G_OBJECT(widget), "graph");
2789 debug(DBS_FENTRY) puts ("expose_event()");
2794 /* lower left corner */
2795 gdk_draw_rectangle (g->drawing_area->window, g->bg_gc, TRUE, 0,
2796 g->wp.y + g->wp.height, g->y_axis->p.width, g->x_axis->p.height);
2798 gdk_draw_rectangle (g->drawing_area->window, g->bg_gc, TRUE,
2799 g->wp.x + g->wp.width, g->wp.y, RMARGIN_WIDTH, g->wp.height);
2801 graph_pixmap_display (g);
2802 graph_title_pixmap_display (g);
2803 axis_pixmap_display (g->x_axis);
2804 axis_pixmap_display (g->y_axis);
2809 static void do_zoom_mouse (struct graph *g, GdkEventButton *event)
2811 int cur_width = g->geom.width, cur_height = g->geom.height;
2812 struct { double x, y; } factor;
2814 if (g->zoom.flags & ZOOM_OUT) {
2815 if (g->zoom.flags & ZOOM_HLOCK)
2818 factor.x = 1 / g->zoom.step_x;
2819 if (g->zoom.flags & ZOOM_VLOCK)
2822 factor.y = 1 / g->zoom.step_y;
2824 if (g->zoom.flags & ZOOM_HLOCK)
2827 factor.x = g->zoom.step_x;
2828 if (g->zoom.flags & ZOOM_VLOCK)
2831 factor.y = g->zoom.step_y;
2834 g->geom.width = (int )rint (g->geom.width * factor.x);
2835 g->geom.height = (int )rint (g->geom.height * factor.y);
2836 if (g->geom.width < g->wp.width)
2837 g->geom.width = g->wp.width;
2838 if (g->geom.height < g->wp.height)
2839 g->geom.height = g->wp.height;
2840 g->zoom.x = (g->geom.width - 1) / g->bounds.width;
2841 g->zoom.y = (g->geom.height- 1) / g->bounds.height;
2843 g->geom.x -= (int )rint ((g->geom.width - cur_width) *
2844 ((event->x-g->geom.x)/(double )cur_width));
2845 g->geom.y -= (int )rint ((g->geom.height - cur_height) *
2846 ((event->y-g->geom.y)/(double )cur_height));
2848 if (g->geom.x > g->wp.x)
2849 g->geom.x = g->wp.x;
2850 if (g->geom.y > g->wp.y)
2851 g->geom.y = g->wp.y;
2852 if (g->wp.x + g->wp.width > g->geom.x + g->geom.width)
2853 g->geom.x = g->wp.width + g->wp.x - g->geom.width;
2854 if (g->wp.y + g->wp.height > g->geom.y + g->geom.height)
2855 g->geom.y = g->wp.height + g->wp.y - g->geom.height;
2857 printf ("button press: graph: (%d,%d), (%d,%d); viewport: (%d,%d), "
2858 "(%d,%d); zooms: (%f,%f)\n", g->geom.x, g->geom.y,
2859 g->geom.width, g->geom.height, g->wp.x, g->wp.y, g->wp.width,
2860 g->wp.height, g->zoom.x, g->zoom.y);
2862 graph_element_lists_make (g);
2863 g->cross.erase_needed = 0;
2865 axis_display (g->y_axis);
2866 axis_display (g->x_axis);
2867 update_zoom_spins (g);
2869 cross_draw (g, (int) event->x, (int) event->y);
2872 static void do_zoom_keyboard (struct graph *g)
2874 int cur_width = g->geom.width, cur_height = g->geom.height;
2875 struct { double x, y; } factor;
2876 int pointer_x, pointer_y;
2878 gdk_window_get_pointer (g->drawing_area->window, &pointer_x, &pointer_y, 0);
2880 if (g->zoom.flags & ZOOM_OUT) {
2881 if (g->zoom.flags & ZOOM_HLOCK)
2884 factor.x = 1 / g->zoom.step_x;
2885 if (g->zoom.flags & ZOOM_VLOCK)
2888 factor.y = 1 / g->zoom.step_y;
2890 if (g->zoom.flags & ZOOM_HLOCK)
2893 factor.x = g->zoom.step_x;
2894 if (g->zoom.flags & ZOOM_VLOCK)
2897 factor.y = g->zoom.step_y;
2900 g->geom.width = (int )rint (g->geom.width * factor.x);
2901 g->geom.height = (int )rint (g->geom.height * factor.y);
2902 if (g->geom.width < g->wp.width)
2903 g->geom.width = g->wp.width;
2904 if (g->geom.height < g->wp.height)
2905 g->geom.height = g->wp.height;
2906 g->zoom.x = (g->geom.width - 1) / g->bounds.width;
2907 g->zoom.y = (g->geom.height- 1) / g->bounds.height;
2909 g->geom.x -= (int )rint ((g->geom.width - cur_width) *
2910 ((pointer_x - g->geom.x)/(double )cur_width));
2911 g->geom.y -= (int )rint ((g->geom.height - cur_height) *
2912 ((pointer_y - g->geom.y)/(double )cur_height));
2914 if (g->geom.x > g->wp.x)
2915 g->geom.x = g->wp.x;
2916 if (g->geom.y > g->wp.y)
2917 g->geom.y = g->wp.y;
2918 if (g->wp.x + g->wp.width > g->geom.x + g->geom.width)
2919 g->geom.x = g->wp.width + g->wp.x - g->geom.width;
2920 if (g->wp.y + g->wp.height > g->geom.y + g->geom.height)
2921 g->geom.y = g->wp.height + g->wp.y - g->geom.height;
2923 printf ("key press: graph: (%d,%d), (%d,%d); viewport: (%d,%d), "
2924 "(%d,%d); zooms: (%f,%f)\n", g->geom.x, g->geom.y,
2925 g->geom.width, g->geom.height, g->wp.x, g->wp.y, g->wp.width,
2926 g->wp.height, g->zoom.x, g->zoom.y);
2929 graph_element_lists_make (g);
2930 g->cross.erase_needed = 0;
2932 axis_display (g->y_axis);
2933 axis_display (g->x_axis);
2934 update_zoom_spins (g);
2936 cross_draw (g, pointer_x, pointer_y);
2939 static void do_zoom_in_keyboard (struct graph *g)
2941 gtk_toggle_button_set_active (g->zoom.widget.in_toggle, TRUE);
2942 do_zoom_keyboard (g);
2945 static void do_zoom_out_keyboard (struct graph *g)
2947 gtk_toggle_button_set_active (g->zoom.widget.out_toggle, TRUE);
2948 do_zoom_keyboard (g);
2949 gtk_toggle_button_set_active (g->zoom.widget.in_toggle, TRUE);
2952 static void do_select_segment (struct graph *g)
2954 int pointer_x, pointer_y;
2956 gdk_window_get_pointer (g->drawing_area->window, &pointer_x, &pointer_y, 0);
2957 graph_select_segment (g, pointer_x, pointer_y);
2960 static void do_rtt_graph (struct graph *g)
2962 gtk_toggle_button_set_active (g->gt.graph_rtt, TRUE);
2965 static void do_throughput_graph (struct graph *g)
2967 gtk_toggle_button_set_active (g->gt.graph_tput, TRUE);
2970 static void do_ts_graph_stevens (struct graph *g)
2972 gtk_toggle_button_set_active (g->gt.graph_tseqstevens, TRUE);
2975 static void do_ts_graph_tcptrace (struct graph *g)
2977 gtk_toggle_button_set_active (g->gt.graph_tseqttrace, TRUE);
2980 static void do_magnify_create (struct graph *g)
2982 int pointer_x, pointer_y;
2984 gdk_window_get_pointer (g->drawing_area->window, &pointer_x, &pointer_y, 0);
2986 magnify_create (g, (int )rint (pointer_x), (int )rint (pointer_y));
2989 static void do_key_motion (struct graph *g)
2991 if (g->geom.x > g->wp.x)
2992 g->geom.x = g->wp.x;
2993 if (g->geom.y > g->wp.y)
2994 g->geom.y = g->wp.y;
2995 if (g->wp.x + g->wp.width > g->geom.x + g->geom.width)
2996 g->geom.x = g->wp.width + g->wp.x - g->geom.width;
2997 if (g->wp.y + g->wp.height > g->geom.y + g->geom.height)
2998 g->geom.y = g->wp.height + g->wp.y - g->geom.height;
2999 g->cross.erase_needed = 0;
3001 axis_display (g->y_axis);
3002 axis_display (g->x_axis);
3003 if (g->cross.draw) {
3004 int pointer_x, pointer_y;
3005 gdk_window_get_pointer (g->drawing_area->window, &pointer_x, &pointer_y, 0);
3006 cross_draw (g, pointer_x, pointer_y);
3010 static void do_key_motion_up (struct graph *g, int step)
3016 static void do_key_motion_down (struct graph *g, int step)
3022 static void do_key_motion_left (struct graph *g, int step)
3028 static void do_key_motion_right (struct graph *g, int step)
3034 static gboolean button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data _U_)
3036 struct graph *g = (struct graph *) g_object_get_data(G_OBJECT(widget), "graph");
3038 debug(DBS_FENTRY) puts ("button_press_event()");
3040 if (event->button == MOUSE_BUTTON_RIGHT) {
3041 if (event->state & GDK_CONTROL_MASK) {
3042 magnify_create (g, (int )rint (event->x), (int )rint (event->y));
3044 g->grab.x = (int )rint (event->x) - g->geom.x;
3045 g->grab.y = (int )rint (event->y) - g->geom.y;
3046 g->grab.grabbed = TRUE;
3048 #ifdef ORIGINAL_WIN32_BUTTONS
3049 /* Windows mouse control: */
3050 /* [<ctrl>-left] - select packet */
3051 /* [left] - zoom in */
3052 /* [<shift>-left] - zoom out */
3053 } else if (event->button == MOUSE_BUTTON_LEFT) {
3054 if (event->state & GDK_CONTROL_MASK) {
3055 graph_select_segment (g, (int)event->x, (int)event->y);
3057 #else /* !ORIGINAL_WIN32_BUTTONS */
3058 } else if (event->button == MOUSE_BUTTON_MIDDLE) {
3060 do_zoom_mouse(g, event);
3061 #ifndef ORIGINAL_WIN32_BUTTONS
3062 } else if (event->button == MOUSE_BUTTON_LEFT) {
3063 graph_select_segment (g, (int )event->x, (int )event->y);
3064 #else /* ORIGINAL_WIN32_BUTTONS*/
3071 static gboolean motion_notify_event (GtkWidget *widget, GdkEventMotion *event, gpointer user_data _U_)
3073 struct graph *g = (struct graph *) g_object_get_data(G_OBJECT(widget), "graph");
3075 GdkModifierType state;
3077 /* debug(DBS_FENTRY) puts ("motion_notify_event()"); */
3080 gdk_window_get_pointer (event->window, &x, &y, &state);
3084 state = event->state;
3087 /* Testing just (state & GDK_BUTTON1_MASK) is not enough since when button1
3088 * is pressed while pointer is in motion, we will receive one more motion
3089 * notify *before* we get the button press. This last motion notify works
3090 * with stale grab coordinates */
3091 if (state & GDK_BUTTON3_MASK) {
3092 if (g->grab.grabbed) {
3093 g->geom.x = x-g->grab.x;
3094 g->geom.y = y-g->grab.y;
3096 if (g->geom.x > g->wp.x)
3097 g->geom.x = g->wp.x;
3098 if (g->geom.y > g->wp.y)
3099 g->geom.y = g->wp.y;
3100 if (g->wp.x + g->wp.width > g->geom.x + g->geom.width)
3101 g->geom.x = g->wp.width + g->wp.x - g->geom.width;
3102 if (g->wp.y + g->wp.height > g->geom.y + g->geom.height)
3103 g->geom.y = g->wp.height + g->wp.y - g->geom.height;
3104 g->cross.erase_needed = 0;
3106 axis_display (g->y_axis);
3107 axis_display (g->x_axis);
3109 cross_draw (g, x, y);
3110 } else if (g->magnify.active)
3111 magnify_move (g, x, y);
3112 } else if (state & GDK_BUTTON1_MASK) {
3113 graph_select_segment (g, x, y);
3114 if (g->cross.erase_needed)
3117 cross_draw (g, x, y);
3119 if (g->cross.erase_needed)
3122 cross_draw (g, x, y);
3128 static gboolean button_release_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data _U_)
3130 struct graph *g = (struct graph *) g_object_get_data(G_OBJECT(widget), "graph");
3132 debug(DBS_FENTRY) puts ("button_release_event()");
3134 if (event->button == MOUSE_BUTTON_RIGHT)
3135 g->grab.grabbed = FALSE;
3137 if (g->magnify.active)
3138 magnify_destroy (g);
3142 static gboolean key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data _U_)
3144 struct graph *g = (struct graph *) g_object_get_data(G_OBJECT(widget), "graph");
3147 debug(DBS_FENTRY) puts ("key_press_event()");
3149 if((event->state & GDK_CONTROL_MASK) && (event->state & GDK_SHIFT_MASK))
3151 else if (event->state & GDK_CONTROL_MASK)
3153 else if (event->state & GDK_SHIFT_MASK)
3158 switch (event->keyval) {
3160 toggle_crosshairs (g);
3163 toggle_time_origin (g);
3166 toggle_seq_origin (g);
3170 restore_initial_graph_view (g);
3174 do_zoom_in_keyboard (g);
3178 do_zoom_out_keyboard (g);
3181 do_magnify_create (g);
3184 do_select_segment (g);
3190 do_throughput_graph (g);
3193 do_ts_graph_stevens (g);
3196 do_ts_graph_tcptrace (g);
3199 do_key_motion_left (g, step);
3202 do_key_motion_up (g, step);
3205 do_key_motion_right (g, step);
3208 do_key_motion_down (g, step);
3211 callback_create_help (NULL, NULL);
3219 static gboolean key_release_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data _U_)
3221 struct graph *g = (struct graph *) g_object_get_data(G_OBJECT(widget), "graph");
3223 debug(DBS_FENTRY) puts ("key_release_event()");
3225 if (event->keyval == GDK_Shift_L || event->keyval == GDK_ISO_Prev_Group) {
3226 /* g->zoom.flags &= ~ZOOM_OUT; */
3227 gtk_toggle_button_set_active (g->zoom.widget.in_toggle, TRUE);
3232 static gboolean leave_notify_event (GtkWidget *widget, GdkEventCrossing *event _U_, gpointer user_data _U_)
3234 struct graph *g = (struct graph *) g_object_get_data(G_OBJECT(widget), "graph");
3236 if (g->cross.erase_needed)
3242 static gboolean enter_notify_event (GtkWidget *widget, GdkEventCrossing *event _U_, gpointer user_data _U_)
3244 struct graph *g = (struct graph *) g_object_get_data(G_OBJECT(widget), "graph");
3246 /* graph_pixmap_display (g); */
3247 if (g->cross.draw) {
3249 gdk_window_get_pointer (g->drawing_area->window, &x, &y, 0);
3250 cross_draw (g, x, y);
3255 static void toggle_crosshairs (struct graph *g)
3259 if (g->cross.draw) {
3261 gdk_window_get_pointer (g->drawing_area->window, &x, &y, 0);
3263 } else if (g->cross.erase_needed) {
3267 /* toggle buttons emit their "toggled" signals so don't bother doing
3268 * any real work here, it will be done in signal handlers */
3270 gtk_toggle_button_set_active (g->cross.on_toggle, TRUE);
3272 gtk_toggle_button_set_active (g->cross.off_toggle, TRUE);
3275 static void toggle_time_origin (struct graph *g)
3278 case GRAPH_TSEQ_STEVENS:
3279 tseq_stevens_toggle_time_origin (g);
3281 case GRAPH_TSEQ_TCPTRACE:
3282 tseq_tcptrace_toggle_time_origin (g);
3284 case GRAPH_THROUGHPUT:
3285 tput_toggle_time_origin (g);
3290 axis_display (g->x_axis);
3293 static void toggle_seq_origin (struct graph *g)
3296 case GRAPH_TSEQ_STEVENS:
3297 tseq_stevens_toggle_seq_origin (g);
3298 axis_display (g->y_axis);
3300 case GRAPH_TSEQ_TCPTRACE:
3301 tseq_tcptrace_toggle_seq_origin (g);
3302 axis_display (g->y_axis);
3305 rtt_toggle_seq_origin (g);
3306 axis_display (g->x_axis);
3313 static void restore_initial_graph_view (struct graph *g)
3315 g->geom.width = g->wp.width;
3316 g->geom.height = g->wp.height;
3317 g->geom.x = g->wp.x;
3318 g->geom.y = g->wp.y;
3319 graph_init_sequence (g);
3322 static int get_num_dsegs (struct graph *g)
3325 struct segment *tmp;
3327 for (tmp=g->segments, count=0; tmp; tmp=tmp->next) {
3328 if(compare_headers(&g->current->ip_src, &g->current->ip_dst,
3329 g->current->th_sport, g->current->th_dport,
3330 &tmp->ip_src, &tmp->ip_dst,
3331 tmp->th_sport, tmp->th_dport,
3332 COMPARE_CURR_DIR)) {
3339 static int get_num_acks (struct graph *g)
3342 struct segment *tmp;
3344 for (tmp=g->segments, count=0; tmp; tmp=tmp->next) {
3345 if(!compare_headers(&g->current->ip_src, &g->current->ip_dst,
3346 g->current->th_sport, g->current->th_dport,
3347 &tmp->ip_src, &tmp->ip_dst,
3348 tmp->th_sport, tmp->th_dport,
3349 COMPARE_CURR_DIR)) {
3357 * Stevens-style time-sequence grapH
3360 static void tseq_stevens_read_config (struct graph *g)
3362 debug(DBS_FENTRY) puts ("tseq_stevens_read_config()");
3364 g->s.tseq_stevens.seq_width = 4;
3365 g->s.tseq_stevens.seq_height = 4;
3366 g->s.tseq_stevens.flags = 0;
3368 g->title = (const char ** )g_malloc (2 * sizeof (char *));
3369 g->title[0] = "Time/Sequence Graph (Stevens)";
3371 g->y_axis->label = (const char ** )g_malloc (3 * sizeof (char * ));
3372 g->y_axis->label[0] = "number[B]";
3373 g->y_axis->label[1] = "Sequence";
3374 g->y_axis->label[2] = NULL;
3375 g->x_axis->label = (const char ** )g_malloc (2 * sizeof (char * ));
3376 g->x_axis->label[0] = "Time[s]";
3377 g->x_axis->label[1] = NULL;
3380 /* Used by both 'stevens' and 'tcptrace' */
3381 static void tseq_initialize (struct graph *g)
3383 debug(DBS_FENTRY) puts ("tseq_initialize()");
3384 tseq_get_bounds (g);
3390 case GRAPH_TSEQ_STEVENS:
3391 tseq_stevens_read_config(g);
3393 case GRAPH_TSEQ_TCPTRACE:
3394 tseq_tcptrace_read_config(g);
3400 /* Determine "bounds"
3401 * Essentially: look for lowest/highest time and seq in the list of segments
3402 * Note that for tcptrace the "(ack + window) sequence number" would normally be expected
3403 * to be the upper bound; However, just to be safe, include the data seg sequence numbers
3404 * in the comparison for tcptrace
3405 * (e.g. to handle the case of only data segments).
3408 /* ToDo: worry about handling cases such as trying to plot seq of just 1 frame */
3410 static void tseq_get_bounds (struct graph *g)
3412 struct segment *tmp;
3414 gboolean data_frame_seen=FALSE;
3415 double data_tim_low=0;
3416 double data_tim_high=0;
3417 guint32 data_seq_cur;
3418 guint32 data_seq_nxt;
3419 guint32 data_seq_low=0;
3420 guint32 data_seq_high=0;
3421 gboolean ack_frame_seen=FALSE;
3422 double ack_tim_low=0;
3423 double ack_tim_high=0;
3424 guint32 ack_seq_cur;
3425 guint32 ack_seq_low=0;
3426 guint32 win_seq_cur;
3427 guint32 win_seq_high=0;
3429 /* go thru all segments to determine "bounds" */
3430 for (tmp=g->segments; tmp; tmp=tmp->next) {
3431 if(compare_headers(&g->current->ip_src, &g->current->ip_dst,
3432 g->current->th_sport, g->current->th_dport,
3433 &tmp->ip_src, &tmp->ip_dst,
3434 tmp->th_sport, tmp->th_dport,
3435 COMPARE_CURR_DIR)) {
3438 tim = tmp->rel_secs + tmp->rel_usecs / 1000000.0;
3439 data_seq_cur = tmp->th_seq;
3440 data_seq_nxt = data_seq_cur + tmp->th_seglen;
3441 if (! data_frame_seen) {
3442 data_tim_low = data_tim_high = tim;
3443 data_seq_low = data_seq_cur;
3444 data_seq_high = data_seq_nxt;
3445 data_frame_seen = TRUE;
3447 if (tim < data_tim_low) data_tim_low = tim;
3448 if (tim > data_tim_high) data_tim_high = tim;
3449 if (data_seq_cur < data_seq_low) data_seq_low = data_seq_cur;
3450 if (data_seq_nxt > data_seq_high) data_seq_high = data_seq_nxt;
3452 else { /* ack seg */
3453 /* skip ack processing if no ACK (e.g. in RST) */
3454 if (TCP_ACK (tmp->th_flags)) {
3455 tim = tmp->rel_secs + tmp->rel_usecs / 1000000.0;
3456 ack_seq_cur = tmp->th_ack;
3457 win_seq_cur = ack_seq_cur + tmp->th_win;
3458 if (! ack_frame_seen) {
3459 ack_tim_low = ack_tim_high = tim;
3460 ack_seq_low = ack_seq_cur;
3461 win_seq_high = win_seq_cur;
3462 ack_frame_seen = TRUE;
3464 if (tim < ack_tim_low) ack_tim_low = tim;
3465 if (tim > ack_tim_high) ack_tim_high = tim;
3466 if (ack_seq_cur < ack_seq_low) ack_seq_low = ack_seq_cur;
3467 if (win_seq_cur > win_seq_high) win_seq_high = win_seq_cur;
3472 /* if 'stevens': use only data segments to determine bounds */
3473 /* if 'tcptrace': use both data and ack segments to determine bounds */
3475 case GRAPH_TSEQ_STEVENS:
3476 g->bounds.x0 = data_tim_low;
3477 g->bounds.width = data_tim_high - data_tim_low;
3478 g->bounds.y0 = data_seq_low;
3479 g->bounds.height = data_seq_high - data_seq_low;
3481 case GRAPH_TSEQ_TCPTRACE:
3482 /* If (ack_frame_seen == false) -> use 'data' segments.
3483 * Else If (data_frame_seen == false) -> use 'ack' segments.
3484 * Else -> use both data and ack segments.
3486 g->bounds.x0 = ((data_tim_low <= ack_tim_low && data_frame_seen) || (! ack_frame_seen)) ? data_tim_low : ack_tim_low;
3487 g->bounds.width = (((data_tim_high >= ack_tim_high && data_frame_seen) || (! ack_frame_seen)) ? data_tim_high : ack_tim_high) - g->bounds.x0;
3488 g->bounds.y0 = ((data_seq_low <= ack_seq_low && data_frame_seen) || (! ack_frame_seen)) ? data_seq_low : ack_seq_low;
3489 g->bounds.height = (((data_seq_high >= win_seq_high && data_frame_seen) || (! ack_frame_seen)) ? data_seq_high : win_seq_high) - g->bounds.y0;
3493 g->zoom.x = (g->geom.width - 1) / g->bounds.width;
3494 g->zoom.y = (g->geom.height -1) / g->bounds.height;
3498 static void tseq_stevens_make_elmtlist (struct graph *g)
3500 struct segment *tmp;
3501 struct element *elements, *e;
3502 double xx0 = g->bounds.x0, yy0 = g->bounds.y0;
3503 guint32 seq_base = (guint32) yy0;
3506 debug(DBS_FENTRY) puts ("tseq_stevens_make_elmtlist()");
3507 if (g->elists->elements == NULL) {
3508 int n = 1 + get_num_dsegs (g);
3509 e = elements = (struct element * )g_malloc (n*sizeof (struct element));
3511 e = elements = g->elists->elements;
3513 for (tmp=g->segments; tmp; tmp=tmp->next) {
3516 if(!compare_headers(&g->current->ip_src, &g->current->ip_dst,
3517 g->current->th_sport, g->current->th_dport,
3518 &tmp->ip_src, &tmp->ip_dst,
3519 tmp->th_sport, tmp->th_dport,
3520 COMPARE_CURR_DIR)) {
3524 seq_cur = tmp->th_seq - seq_base;
3525 secs = g->zoom.x * (tmp->rel_secs + tmp->rel_usecs / 1000000.0 - xx0);
3526 seqno = g->zoom.y * seq_cur;
3531 e->p.arc.dim.width = g->s.tseq_stevens.seq_width;
3532 e->p.arc.dim.height = g->s.tseq_stevens.seq_height;
3533 e->p.arc.dim.x = secs - g->s.tseq_stevens.seq_width/2.0;
3534 e->p.arc.dim.y = seqno + g->s.tseq_stevens.seq_height/2.0;
3535 e->p.arc.filled = TRUE;
3536 e->p.arc.angle1 = 0;
3537 e->p.arc.angle2 = 23040;
3540 e->type = ELMT_NONE;
3541 g->elists->elements = elements;
3544 static void tseq_stevens_toggle_seq_origin (struct graph *g)
3546 g->s.tseq_stevens.flags ^= SEQ_ORIGIN;
3548 if ((g->s.tseq_stevens.flags & SEQ_ORIGIN) == SEQ_ORIGIN_ZERO)
3549 g->y_axis->min = g->bounds.y0;
3550 else /* g->tseq_stevens.flags & SEQ_ORIGIN == SEQ_ORIGIN_ISN */
3554 static void tseq_stevens_toggle_time_origin (struct graph *g)
3556 g->s.tseq_stevens.flags ^= TIME_ORIGIN;
3558 if ((g->s.tseq_stevens.flags & TIME_ORIGIN) == TIME_ORIGIN_CAP)
3559 g->x_axis->min = g->bounds.x0;
3560 else /* g->tseq_stevens.flags & TIME_ORIGIN == TIME_ORIGIN_CONN */
3565 * tcptrace-style time-sequence graph
3568 static void tseq_tcptrace_read_config (struct graph *g)
3570 GdkColormap *colormap;
3573 g->s.tseq_tcptrace.flags = 0;
3574 g->s.tseq_tcptrace.gc_seq = gdk_gc_new (g->drawing_area->window);
3575 g->s.tseq_tcptrace.gc_ack[0] = gdk_gc_new (g->drawing_area->window);
3576 g->s.tseq_tcptrace.gc_ack[1] = gdk_gc_new (g->drawing_area->window);
3577 colormap = gdk_window_get_colormap (g->drawing_area->window);
3578 if (!gdk_color_parse ("black", &color)) {
3580 * XXX - do more than just warn.
3582 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
3583 "Could not parse color black.");
3585 if (!gdk_colormap_alloc_color (colormap, &color, FALSE, TRUE)) {
3587 * XXX - do more than just warn.
3589 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
3590 "Could not allocate color black.");
3592 gdk_gc_set_foreground (g->s.tseq_tcptrace.gc_seq, &color);
3593 if (!gdk_color_parse ("LightSlateGray", &color)) {
3595 * XXX - do more than just warn.
3597 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
3598 "Could not parse color LightSlateGray.");
3600 if (!gdk_colormap_alloc_color (colormap, &color, FALSE, TRUE)) {
3602 * XXX - do more than just warn.
3604 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
3605 "Could not allocate color LightSlateGray.");
3607 gdk_gc_set_foreground (g->s.tseq_tcptrace.gc_ack[0], &color);
3608 if (!gdk_color_parse ("LightGray", &color)) {
3610 * XXX - do more than just warn.
3612 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
3613 "Could not parse color LightGray.");
3615 if (!gdk_colormap_alloc_color (colormap, &color, FALSE, TRUE)) {
3617 * XXX - do more than just warn.
3619 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
3620 "Could not allocate color LightGray.");
3622 gdk_gc_set_foreground (g->s.tseq_tcptrace.gc_ack[1], &color);
3624 g->elists->next = (struct element_list * )
3625 g_malloc (sizeof (struct element_list));
3626 g->elists->next->next = NULL;
3627 g->elists->next->elements = NULL;
3629 g->title = (const char ** )g_malloc (2 * sizeof (char *));
3630 g->title[0] = "Time/Sequence Graph (tcptrace)";
3632 g->y_axis->label = (const char ** )g_malloc (3 * sizeof (char * ));
3633 g->y_axis->label[0] = "number[B]";
3634 g->y_axis->label[1] = "Sequence";
3635 g->y_axis->label[2] = NULL;
3636 g->x_axis->label = (const char ** )g_malloc (2 * sizeof (char * ));
3637 g->x_axis->label[0] = "Time[s]";
3638 g->x_axis->label[1] = NULL;
3641 static void tseq_tcptrace_make_elmtlist (struct graph *g)
3643 struct segment *tmp;
3644 struct element *elements0, *e0; /* list of elmts with prio 0 */
3645 struct element *elements1, *e1; /* list of elmts with prio 1 */
3647 double p_t = 0; /* ackno, window and time of previous segment */
3648 double p_ackno = 0, p_win = 0;
3649 gboolean ack_seen=FALSE;
3654 debug(DBS_FENTRY) puts ("tseq_tcptrace_make_elmtlist()");
3656 if (g->elists->elements == NULL) {
3657 int n = 1 + 4*get_num_acks(g);
3658 e0 = elements0 = (struct element * )g_malloc (n*sizeof (struct element));
3660 e0 = elements0 = g->elists->elements;
3662 if (g->elists->next->elements == NULL ) {
3663 int n = 1 + 3*get_num_dsegs(g);
3664 e1 = elements1 = (struct element * )g_malloc (n*sizeof (struct element));
3666 e1 = elements1 = g->elists->next->elements;
3670 seq_base = (guint32) yy0;
3672 for (tmp=g->segments; tmp; tmp=tmp->next) {
3676 secs = tmp->rel_secs + tmp->rel_usecs / 1000000.0;
3679 if(compare_headers(&g->current->ip_src, &g->current->ip_dst,
3680 g->current->th_sport, g->current->th_dport,
3681 &tmp->ip_src, &tmp->ip_dst,
3682 tmp->th_sport, tmp->th_dport,
3683 COMPARE_CURR_DIR)) {
3684 /* forward direction -> we need seqno and amount of data */
3687 seq_cur = tmp->th_seq - seq_base;
3688 if (TCP_SYN (tmp->th_flags) || TCP_FIN (tmp->th_flags))
3691 data = tmp->th_seglen;
3693 yy1 = g->zoom.y * (seq_cur);
3694 yy2 = g->zoom.y * (seq_cur + data);
3695 e1->type = ELMT_LINE;
3697 e1->gc = g->s.tseq_tcptrace.gc_seq;
3698 e1->p.line.dim.x1 = e1->p.line.dim.x2 = x;
3699 e1->p.line.dim.y1 = yy1;
3700 e1->p.line.dim.y2 = yy2;
3702 e1->type = ELMT_LINE;
3704 e1->gc = g->s.tseq_tcptrace.gc_seq;
3705 e1->p.line.dim.x1 = x - 1;
3706 e1->p.line.dim.x2 = x + 1;
3707 e1->p.line.dim.y1 = e1->p.line.dim.y2 = yy1;
3709 e1->type = ELMT_LINE;
3711 e1->gc = g->s.tseq_tcptrace.gc_seq;
3712 e1->p.line.dim.x1 = x + 1;
3713 e1->p.line.dim.x2 = x - 1;
3714 e1->p.line.dim.y1 = e1->p.line.dim.y2 = yy2;
3718 if (! TCP_ACK (tmp->th_flags))
3719 /* SYN's and RST's do not necessarily have ACK's*/
3721 /* backward direction -> we need ackno and window */
3722 seq_cur = tmp->th_ack - seq_base;
3723 ackno = seq_cur * g->zoom.y;
3724 win = tmp->th_win * g->zoom.y;
3727 if (ack_seen == TRUE) { /* don't plot the first ack */
3728 e0->type = ELMT_LINE;
3730 e0->gc = g->s.tseq_tcptrace.gc_ack[toggle];
3731 e0->p.line.dim.x1 = p_t;
3732 e0->p.line.dim.y1 = p_ackno;
3733 e0->p.line.dim.x2 = x;
3734 e0->p.line.dim.y2 = p_ackno;
3736 e0->type = ELMT_LINE;
3738 e0->gc = g->s.tseq_tcptrace.gc_ack[toggle];
3739 e0->p.line.dim.x1 = x;
3740 e0->p.line.dim.y1 = p_ackno;
3741 e0->p.line.dim.x2 = x;
3742 e0->p.line.dim.y2 = ackno!=p_ackno || ackno<4 ? ackno : ackno-4;
3745 e0->type = ELMT_LINE;
3747 e0->gc = g->s.tseq_tcptrace.gc_ack[toggle];
3748 e0->p.line.dim.x1 = p_t;
3749 e0->p.line.dim.y1 = p_win + p_ackno;
3750 e0->p.line.dim.x2 = x;
3751 e0->p.line.dim.y2 = p_win + p_ackno;
3753 e0->type = ELMT_LINE;
3755 e0->gc = g->s.tseq_tcptrace.gc_ack[toggle];
3756 e0->p.line.dim.x1 = x;
3757 e0->p.line.dim.y1 = p_win + p_ackno;
3758 e0->p.line.dim.x2 = x;
3759 e0->p.line.dim.y2 = win + ackno;
3769 e0->type = ELMT_NONE;
3770 e1->type = ELMT_NONE;
3771 g->elists->elements = elements0;
3772 g->elists->next->elements = elements1;
3775 static void tseq_tcptrace_toggle_seq_origin (struct graph *g)
3777 g->s.tseq_tcptrace.flags ^= SEQ_ORIGIN;
3779 if ((g->s.tseq_tcptrace.flags & SEQ_ORIGIN) == SEQ_ORIGIN_ZERO)
3780 g->y_axis->min = g->bounds.y0;
3781 else /* g->tseq_stevens.flags & SEQ_ORIGIN == SEQ_ORIGIN_ISN */
3785 static void tseq_tcptrace_toggle_time_origin (struct graph *g)
3787 g->s.tseq_tcptrace.flags ^= TIME_ORIGIN;
3789 if ((g->s.tseq_tcptrace.flags & TIME_ORIGIN) == TIME_ORIGIN_CAP)
3790 g->x_axis->min = g->bounds.x0;
3791 else /* g->tseq_stevens.flags & TIME_ORIGIN == TIME_ORIGIN_CONN */
3799 static void tput_make_elmtlist (struct graph *g)
3801 struct segment *tmp, *oldest;
3802 struct element *elements, *e;
3806 if (g->elists->elements == NULL) {
3807 int n = 1 + get_num_dsegs (g);
3808 e = elements = (struct element * )g_malloc (n*sizeof (struct element));
3810 e = elements = g->elists->elements;
3812 for (oldest=g->segments,tmp=g->segments->next,i=0; tmp; tmp=tmp->next,i++) {
3813 double time_val = tmp->rel_secs + tmp->rel_usecs/1000000.0;
3814 dtime = time_val - (oldest->rel_secs + oldest->rel_usecs/1000000.0);
3815 if (i>g->s.tput.nsegs) {
3816 sum -= oldest->th_seglen;
3817 oldest=oldest->next;
3819 sum += tmp->th_seglen;
3821 /* debug(DBS_TPUT_ELMTS) printf ("tput=%f\n", tput); */
3826 e->p.arc.dim.width = g->s.tput.width;
3827 e->p.arc.dim.height = g->s.tput.height;
3828 e->p.arc.dim.x = g->zoom.x*(time_val - g->bounds.x0) - g->s.tput.width/2.0;
3829 e->p.arc.dim.y = g->zoom.y*tput + g->s.tput.height/2.0;
3830 e->p.arc.filled = TRUE;
3831 e->p.arc.angle1 = 0;
3832 e->p.arc.angle2 = 23040;
3835 e->type = ELMT_NONE;
3836 g->elists->elements = elements;
3839 /* Purpose of <graph_type>_initialize functions:
3840 * - find maximum and minimum for both axes
3841 * - call setup routine for style struct */
3842 static void tput_initialize (struct graph *g)
3844 struct segment *tmp, *oldest, *last;
3846 double dtime, tput, tputmax=0;
3847 double t, t0, tmax = 0, yy0, ymax;
3849 debug(DBS_FENTRY) puts ("tput_initialize()");
3851 tput_read_config(g);
3853 for (last=g->segments; last->next; last=last->next);
3854 for (oldest=g->segments,tmp=g->segments->next,i=0; tmp; tmp=tmp->next,i++) {
3855 dtime = tmp->rel_secs + tmp->rel_usecs/1000000.0 -
3856 (oldest->rel_secs + oldest->rel_usecs/1000000.0);
3857 if (i>g->s.tput.nsegs) {
3858 sum -= oldest->th_seglen;
3859 oldest=oldest->next;
3861 sum += tmp->th_seglen;
3863 debug(DBS_TPUT_ELMTS) printf ("tput=%f\n", tput);
3866 t = tmp->rel_secs + tmp->rel_usecs / 1000000.0;
3871 t0 = g->segments->rel_secs + g->segments->rel_usecs / 1000000.0;
3877 g->bounds.width = tmax - t0;
3878 g->bounds.height = ymax - yy0;
3879 g->zoom.x = (g->geom.width - 1) / g->bounds.width;
3880 g->zoom.y = (g->geom.height -1) / g->bounds.height;
3883 static void tput_read_config (struct graph *g)
3885 debug(DBS_FENTRY) puts ("tput_read_config()");
3887 g->s.tput.width = 4;
3888 g->s.tput.height = 4;
3889 g->s.tput.nsegs = 20;
3891 g->title = (const char ** )g_malloc (2 * sizeof (char *));
3892 g->title[0] = "Throughput Graph";
3894 g->y_axis->label = (const char ** )g_malloc (3 * sizeof (char * ));
3895 g->y_axis->label[0] = "[B/s]";
3896 g->y_axis->label[1] = "Throughput";
3897 g->y_axis->label[2] = NULL;
3898 g->x_axis->label = (const char ** )g_malloc (2 * sizeof (char * ));
3899 g->x_axis->label[0] = "Time[s]";
3900 g->x_axis->label[1] = NULL;
3901 g->s.tput.flags = 0;
3904 static void tput_toggle_time_origin (struct graph *g)
3906 g->s.tput.flags ^= TIME_ORIGIN;
3908 if ((g->s.tput.flags & TIME_ORIGIN) == TIME_ORIGIN_CAP)
3909 g->x_axis->min = g->bounds.x0;
3910 else /* g->s.tput.flags & TIME_ORIGIN == TIME_ORIGIN_CONN */
3916 static void rtt_read_config (struct graph *g)
3918 debug(DBS_FENTRY) puts ("rtt_read_config()");
3921 g->s.rtt.height = 4;
3924 g->title = (const char ** )g_malloc (2 * sizeof (char *));
3925 g->title[0] = "Round Trip Time Graph";
3927 g->y_axis->label = (const char ** )g_malloc (3 * sizeof (char * ));
3928 g->y_axis->label[0] = "RTT [s]";
3929 g->y_axis->label[1] = NULL;
3930 g->x_axis->label = (const char ** )g_malloc (2 * sizeof (char * ));
3931 g->x_axis->label[0] = "Sequence Number[B]";
3932 g->x_axis->label[1] = NULL;
3935 static void rtt_initialize (struct graph *g)
3937 struct segment *tmp, *first=NULL;
3938 struct unack *unack = NULL, *u;
3940 double xx0, yy0, ymax;
3942 guint32 seq_base = 0;
3944 debug(DBS_FENTRY) puts ("rtt_initialize()");
3946 rtt_read_config (g);
3948 for (tmp=g->segments; tmp; tmp=tmp->next) {
3949 if(compare_headers(&g->current->ip_src, &g->current->ip_dst,
3950 g->current->th_sport, g->current->th_dport,
3951 &tmp->ip_src, &tmp->ip_dst,
3952 tmp->th_sport, tmp->th_dport,
3953 COMPARE_CURR_DIR)) {
3954 guint32 seqno = tmp->th_seq;
3961 if (tmp->th_seglen && !rtt_is_retrans (unack, seqno)) {
3962 double time_val = tmp->rel_secs + tmp->rel_usecs / 1000000.0;
3963 u = rtt_get_new_unack (time_val, seqno);
3965 rtt_put_unack_on_list (&unack, u);
3968 if (seqno + tmp->th_seglen > xmax)
3969 xmax = seqno + tmp->th_seglen;
3971 guint32 ackno = tmp->th_ack -seq_base;
3972 double time_val = tmp->rel_secs + tmp->rel_usecs / 1000000.0;
3975 for (u=unack; u; u=v)
3976 if (ackno > u->seqno) {
3977 double rtt = time_val - u->time;
3981 rtt_delete_unack_from_list (&unack, u);
3993 g->bounds.width = xmax;
3994 g->bounds.height = ymax - yy0;
3995 g->zoom.x = g->geom.width / g->bounds.width;
3996 g->zoom.y = g->geom.height / g->bounds.height;
3999 static int rtt_is_retrans (struct unack *list, unsigned int seqno)
4003 for (u=list; u; u=u->next)
4004 if (u->seqno== seqno)
4010 static struct unack *rtt_get_new_unack (double time_val, unsigned int seqno)
4014 u = (struct unack * )g_malloc (sizeof (struct unack));
4023 static void rtt_put_unack_on_list (struct unack **l, struct unack *new)
4025 struct unack *u, *list = *l;
4027 for (u=list; u; u=u->next)
4037 static void rtt_delete_unack_from_list (struct unack **l, struct unack *dead)
4039 struct unack *u, *list = *l;
4048 for (u=list; u; u=u->next)
4049 if (u->next == dead) {
4050 u->next = u->next->next;
4056 static void rtt_make_elmtlist (struct graph *g)
4058 struct segment *tmp;
4059 struct unack *unack = NULL, *u;
4060 struct element *elements, *e;
4061 guint32 seq_base = (guint32) g->bounds.x0;
4063 debug(DBS_FENTRY) puts ("rtt_make_elmtlist()");
4065 if (g->elists->elements == NULL) {
4066 int n = 1 + get_num_dsegs (g);
4067 e = elements = (struct element * )g_malloc (n*sizeof (struct element));
4069 e = elements = g->elists->elements;
4072 for (tmp=g->segments; tmp; tmp=tmp->next) {
4073 if(compare_headers(&g->current->ip_src, &g->current->ip_dst,
4074 g->current->th_sport, g->current->th_dport,
4075 &tmp->ip_src, &tmp->ip_dst,
4076 tmp->th_sport, tmp->th_dport,
4077 COMPARE_CURR_DIR)) {
4078 guint32 seqno = tmp->th_seq -seq_base;
4080 if (tmp->th_seglen && !rtt_is_retrans (unack, seqno)) {
4081 double time_val = tmp->rel_secs + tmp->rel_usecs / 1000000.0;
4082 u = rtt_get_new_unack (time_val, seqno);
4084 rtt_put_unack_on_list (&unack, u);
4087 guint32 ackno = tmp->th_ack -seq_base;
4088 double time_val = tmp->rel_secs + tmp->rel_usecs / 1000000.0;
4091 for (u=unack; u; u=v)
4092 if (ackno > u->seqno) {
4093 double rtt = time_val - u->time;
4098 e->p.arc.dim.width = g->s.rtt.width;
4099 e->p.arc.dim.height = g->s.rtt.height;
4100 e->p.arc.dim.x = g->zoom.x * u->seqno - g->s.rtt.width/2.0;
4101 e->p.arc.dim.y = g->zoom.y * rtt + g->s.rtt.height/2.0;
4102 e->p.arc.filled = TRUE;
4103 e->p.arc.angle1 = 0;
4104 e->p.arc.angle2 = 23040;
4108 rtt_delete_unack_from_list (&unack, u);
4113 e->type = ELMT_NONE;
4114 g->elists->elements = elements;
4117 static void rtt_toggle_seq_origin (struct graph *g)
4119 g->s.rtt.flags ^= SEQ_ORIGIN;
4121 if ((g->s.rtt.flags & SEQ_ORIGIN) == SEQ_ORIGIN_ZERO)
4122 g->x_axis->min = g->bounds.x0;
4127 #if defined(_WIN32) && !defined(__MINGW32__)
4128 /* replacement of Unix rint() for Windows */
4129 static int rint (double x)
4134 buf = _fcvt(x, 0, &dec, &sig);
4144 static gboolean tcp_graph_selected_packet_enabled(frame_data *current_frame, epan_dissect_t *edt, gpointer callback_data _U_)
4146 return current_frame != NULL ? (edt->pi.ipproto == IP_PROTO_TCP) : FALSE;
4151 register_tap_listener_tcp_graph(void)
4153 register_stat_menu_item("TCP Stream Graph/Time-Sequence Graph (Stevens)", REGISTER_STAT_GROUP_UNSORTED,
4154 tcp_graph_cb, tcp_graph_selected_packet_enabled, NULL, GINT_TO_POINTER(0));
4155 register_stat_menu_item("TCP Stream Graph/Time-Sequence Graph (tcptrace)", REGISTER_STAT_GROUP_UNSORTED,
4156 tcp_graph_cb, tcp_graph_selected_packet_enabled, NULL, GINT_TO_POINTER(1));
4157 register_stat_menu_item("TCP Stream Graph/Throughput Graph", REGISTER_STAT_GROUP_UNSORTED,
4158 tcp_graph_cb, tcp_graph_selected_packet_enabled, NULL, GINT_TO_POINTER(2));
4159 register_stat_menu_item("TCP Stream Graph/Round Trip Time Graph", REGISTER_STAT_GROUP_UNSORTED,
4160 tcp_graph_cb, tcp_graph_selected_packet_enabled, NULL, GINT_TO_POINTER(3));