diff options
Diffstat (limited to 'ui/gtk/tcp_graph.c')
-rw-r--r-- | ui/gtk/tcp_graph.c | 8346 |
1 files changed, 4180 insertions, 4166 deletions
diff --git a/ui/gtk/tcp_graph.c b/ui/gtk/tcp_graph.c index 363f713167..e688aad108 100644 --- a/ui/gtk/tcp_graph.c +++ b/ui/gtk/tcp_graph.c @@ -55,316 +55,323 @@ #include "ui/gtk/old-gtk-compat.h" -#define TCP_SYN(flags) ( flags & TH_SYN ) -#define TCP_ACK(flags) ( flags & TH_ACK ) -#define TCP_FIN(flags) ( flags & TH_FIN ) +#define TCP_SYN(flags) ( flags & TH_SYN ) +#define TCP_ACK(flags) ( flags & TH_ACK ) +#define TCP_FIN(flags) ( flags & TH_FIN ) -#define TXT_WIDTH 850 -#define TXT_HEIGHT 550 +#define TXT_WIDTH 850 +#define TXT_HEIGHT 550 /* for compare_headers() */ /* segment went the same direction as the currently selected one */ -#define COMPARE_CURR_DIR 0 -#define COMPARE_ANY_DIR 1 +#define COMPARE_CURR_DIR 0 +#define COMPARE_ANY_DIR 1 /* initialize_axis() */ -#define AXIS_HORIZONTAL 0 -#define AXIS_VERTICAL 1 +#define AXIS_HORIZONTAL 0 +#define AXIS_VERTICAL 1 #define WINDOW_TITLE_LENGTH 256 -#define MOUSE_BUTTON_LEFT 1 -#define MOUSE_BUTTON_MIDDLE 2 -#define MOUSE_BUTTON_RIGHT 3 +#define MOUSE_BUTTON_LEFT 1 +#define MOUSE_BUTTON_MIDDLE 2 +#define MOUSE_BUTTON_RIGHT 3 struct segment { - struct segment *next; - guint32 num; - guint32 rel_secs; - guint32 rel_usecs; - guint32 abs_secs; - guint32 abs_usecs; - - guint32 th_seq; - guint32 th_ack; - guint16 th_flags; - guint32 th_win; /* make it 32 bits so we can handle some scaling */ - guint32 th_seglen; - guint16 th_sport; - guint16 th_dport; - address ip_src; - address ip_dst; - - guint8 num_sack_ranges; - guint32 sack_left_edge[MAX_TCP_SACK_RANGES]; - guint32 sack_right_edge[MAX_TCP_SACK_RANGES]; + struct segment *next; + guint32 num; + guint32 rel_secs; + guint32 rel_usecs; + guint32 abs_secs; + guint32 abs_usecs; + + guint32 th_seq; + guint32 th_ack; + guint16 th_flags; + guint32 th_win; /* make it 32 bits so we can handle some scaling */ + guint32 th_seglen; + guint16 th_sport; + guint16 th_dport; + address ip_src; + address ip_dst; + + guint8 num_sack_ranges; + guint32 sack_left_edge[MAX_TCP_SACK_RANGES]; + guint32 sack_right_edge[MAX_TCP_SACK_RANGES]; }; struct rect { - double x, y, width, height; + double x, y, width, height; }; struct line { - double x1, y1, x2, y2; + double x1, y1, x2, y2; }; struct irect { - int x, y, width, height; + int x, y, width, height; }; struct ipoint { - int x, y; + int x, y; }; struct zoomfactor { - double x, y; + double x, y; }; typedef enum { - ELMT_NONE=0, - ELMT_RECT=1, - ELMT_LINE=2, - ELMT_ELLIPSE=3 + ELMT_NONE=0, + ELMT_RECT=1, + ELMT_LINE=2, + ELMT_ELLIPSE=3 } ElementType; struct rect_params { - struct rect dim; - gint filled; + struct rect dim; + gint filled; }; struct line_params { - struct line dim; + struct line dim; }; struct ellipse_params { - struct rect dim; + struct rect dim; }; struct element { - ElementType type; - GdkColor *elment_color_p; - struct segment *parent; - union { - struct ellipse_params ellipse; - struct rect_params rect; - struct line_params line; - } p; + ElementType type; + GdkColor *elment_color_p; + struct segment *parent; + union { + struct ellipse_params ellipse; + struct rect_params rect; + struct line_params line; + } p; }; struct element_list { - struct element_list *next; - struct element *elements; + struct element_list *next; + struct element *elements; }; struct axis { - struct graph *g; /* which graph we belong to */ - GtkWidget *drawing_area; + struct graph *g; /* which graph we belong to */ + GtkWidget *drawing_area; #if GTK_CHECK_VERSION(2,22,0) - cairo_surface_t *surface[2]; + cairo_surface_t *surface[2]; #else - GdkPixmap *pixmap[2]; + GdkPixmap *pixmap[2]; #endif - int displayed; -#define AXIS_ORIENTATION 1 << 0 - int flags; - /* dim and orig (relative to origin of window) of axis' pixmap */ - struct irect p; - /* dim and orig (relative to origin of axis' pixmap) of scale itself */ - struct irect s; - gdouble min, max; - gdouble major, minor; /* major and minor ticks */ - const char **label; + int displayed; +#define AXIS_ORIENTATION 1 << 0 + int flags; + /* dim and orig (relative to origin of window) of axis' pixmap */ + struct irect p; + /* dim and orig (relative to origin of axis' pixmap) of scale itself */ + struct irect s; + gdouble min, max; + gdouble major, minor; /* major and minor ticks */ + const char **label; }; -#define HAXIS_INIT_HEIGHT 70 -#define VAXIS_INIT_WIDTH 100 -#define TITLEBAR_HEIGHT 50 -#define RMARGIN_WIDTH 30 +#define HAXIS_INIT_HEIGHT 70 +#define VAXIS_INIT_WIDTH 100 +#define TITLEBAR_HEIGHT 50 +#define RMARGIN_WIDTH 30 struct style_tseq_tcptrace { - GdkColor seq_color; - GdkColor ack_color[2]; - GdkColor sack_color[2]; - int flags; + GdkColor seq_color; + GdkColor ack_color[2]; + GdkColor sack_color[2]; + int flags; }; struct style_tseq_stevens { - int seq_width; - int seq_height; - int flags; + int seq_width; + int seq_height; + int flags; }; struct style_tput { - int width, height; - int nsegs; - int flags; + int width, height; + int nsegs; + int flags; }; struct style_rtt { - int width, height; - int flags; + int width, height; + int flags; }; struct style_wscale { - int win_width; - int win_height; - int flags; + int win_width; + int win_height; + int flags; }; /* style flags */ -#define SEQ_ORIGIN 0x1 +#define SEQ_ORIGIN 0x1 /* show absolute sequence numbers (not differences from isn) */ -#define SEQ_ORIGIN_ZERO 0x1 -#define SEQ_ORIGIN_ISN 0x0 -#define TIME_ORIGIN 0x10 +#define SEQ_ORIGIN_ZERO 0x1 +#define SEQ_ORIGIN_ISN 0x0 +#define TIME_ORIGIN 0x10 /* show time from beginning of capture as opposed to time from beginning * of the connection */ -#define TIME_ORIGIN_CAP 0x10 -#define TIME_ORIGIN_CONN 0x0 +#define TIME_ORIGIN_CAP 0x10 +#define TIME_ORIGIN_CONN 0x0 /* this is used by rtt module only */ struct unack { - struct unack *next; - double time; - unsigned int seqno; + struct unack *next; + double time; + unsigned int seqno; }; struct cross { - int x, y; - int draw; /* indicates whether we should draw cross at all */ - int erase_needed; - GtkToggleButton *on_toggle; - GtkToggleButton *off_toggle; + int x, y; + int draw; /* indicates whether we should draw cross at all */ + int erase_needed; + GtkToggleButton *on_toggle; + GtkToggleButton *off_toggle; }; struct bounds { - double x0, y0, width, height; + double x0, y0, width, height; }; struct zoom { - double x, y; + double x, y; }; struct zooms { - double x, y; - double step_x, step_y; - struct zoom initial; -#define ZOOM_OUT (1 << 0) -#define ZOOM_HLOCK (1 << 1) -#define ZOOM_VLOCK (1 << 2) -#define ZOOM_STEPS_SAME (1 << 3) -#define ZOOM_STEPS_KEEP_RATIO (1 << 4) - int flags; - /* unfortunately, we need them both because gtk_toggle_button_set_active () - * with second argument FALSE doesn't do anything, somehow */ - struct { - GtkToggleButton *in_toggle; - GtkToggleButton *out_toggle; - GtkEntry *h_zoom; - GtkEntry *v_zoom; - GtkSpinButton *h_step; - GtkSpinButton *v_step; - } widget; + double x, y; + double step_x, step_y; + struct zoom initial; +#define ZOOM_OUT (1 << 0) +#define ZOOM_HLOCK (1 << 1) +#define ZOOM_VLOCK (1 << 2) +#define ZOOM_STEPS_SAME (1 << 3) +#define ZOOM_STEPS_KEEP_RATIO (1 << 4) + int flags; + /* unfortunately, we need them both because gtk_toggle_button_set_active() + * with second argument FALSE doesn't do anything, somehow */ + struct { + GtkToggleButton *in_toggle; + GtkToggleButton *out_toggle; + GtkEntry *h_zoom; + GtkEntry *v_zoom; + GtkSpinButton *h_step; + GtkSpinButton *v_step; + } widget; }; struct grab { - int grabbed; - int x, y; + int grabbed; + int x, y; }; struct magnify { - int active; - int x, y; - struct ipoint offset; - int width, height; - struct zoom zoom; - struct graph *g; -#define MAGZOOMS_SAME (1U << 0) -#define MAGZOOMS_SAME_RATIO (1U << 1) -#define MAGZOOMS_IGNORE (1U << 31) - guint flags; - struct { - GtkSpinButton *h_zoom, *v_zoom; - } widget; + int active; + int x, y; + struct ipoint offset; + int width, height; + struct zoom zoom; + struct graph *g; +#define MAGZOOMS_SAME (1U << 0) +#define MAGZOOMS_SAME_RATIO (1U << 1) +#define MAGZOOMS_IGNORE (1U << 31) + guint flags; + struct { + GtkSpinButton *h_zoom, *v_zoom; + } widget; }; struct graph { -#define GRAPH_TSEQ_STEVENS 0 -#define GRAPH_TSEQ_TCPTRACE 1 -#define GRAPH_THROUGHPUT 2 -#define GRAPH_RTT 3 -#define GRAPH_WSCALE 4 - int type; -#define GRAPH_DESTROYED (1 << 0) -#define GRAPH_INIT_ON_TYPE_CHANGE (1 << 1) - int flags; - GtkWidget *toplevel; /* keypress handler needs this */ - GtkWidget *drawing_area; - GtkWidget *text; /* text widget for seg list - probably - * temporary - */ - PangoFontDescription *font; /* font used for annotations etc. */ +#define GRAPH_TSEQ_STEVENS 0 +#define GRAPH_TSEQ_TCPTRACE 1 +#define GRAPH_THROUGHPUT 2 +#define GRAPH_RTT 3 +#define GRAPH_WSCALE 4 + int type; +#define GRAPH_DESTROYED (1 << 0) +#define GRAPH_INIT_ON_TYPE_CHANGE (1 << 1) + int flags; + GtkWidget *toplevel; /* keypress handler needs this */ + GtkWidget *drawing_area; + GtkWidget *text; /* text widget for seg list - probably + * temporary + */ + PangoFontDescription *font; /* font used for annotations etc. */ #if GTK_CHECK_VERSION(2,22,0) - cairo_surface_t *title_surface; - cairo_surface_t *surface[2]; + cairo_surface_t *title_surface; + cairo_surface_t *surface[2]; #else - GdkPixmap *title_pixmap; - GdkPixmap *pixmap[2]; + GdkPixmap *title_pixmap; + GdkPixmap *pixmap[2]; #endif - int displayed; /* which of both pixmaps is on screen right now */ - struct { - GtkWidget *control_panel; - /* this belongs to style structs of graph types that make use of it */ - GtkToggleButton *time_orig_conn, *seq_orig_isn; - } gui; - const char **title; - /* Next 4 attribs describe the graph in natural units, before any scaling. - * For example, if we want to display graph of TCP conversation that - * started 112.309845 s after beginning of the capture and ran until - * 479.093582 s, 237019 B went through the connection (in one direction) - * starting with isn 31934022, then (bounds.x0, bounds.y0)=(112.309845, - * 31934022) and (bounds.width, bounds.height)=(366.783737, 237019). */ - struct bounds bounds; - /* dimensions and position of the graph, both expressed already in pixels. - * x and y give the position of upper left corner of the graph relative - * to origin of the graph window, size is basically bounds*zoom */ - struct irect geom; - /* viewport (=graph window area which is reserved for graph itself), its - * size and position relative to origin of the graph window */ - struct irect wp; - /* whether and where the graph has been 'grabbed' and may now be moved */ - struct grab grab; - /* If we need to display 237019 sequence numbers (=bytes) onto say 500 - * pixels, we have to scale the graph down by factor of 0.002109. This - * number would be zoom.y. Obviously, both directions have separate zooms.*/ - struct zooms zoom; - struct cross cross; - gboolean zoomrect_erase_needed; - struct magnify magnify; - struct axis *x_axis, *y_axis; - struct segment *segments; - - /* The stream this graph will show */ - address src_address; - guint16 src_port; - address dst_address; - guint16 dst_port; - - struct element_list *elists; /* element lists */ - union { - struct style_tseq_stevens tseq_stevens; - struct style_tseq_tcptrace tseq_tcptrace; - struct style_tput tput; - struct style_rtt rtt; - struct style_wscale wscale; - } s; - /* This allows keyboard to set the radio button */ - struct { - GtkToggleButton *graph_rtt, *graph_tput, *graph_tseqstevens, *graph_tseqttrace; - GtkToggleButton *graph_wscale; - } gt; + int displayed; /* which of both pixmaps is on screen right now */ + struct { + GtkWidget *control_panel; + /* this belongs to style structs of graph types that make use of it */ + GtkToggleButton *time_orig_conn, *seq_orig_isn; + } gui; + const char **title; + + /* Next 4 attribs describe the graph in natural units, before any scaling. + * For example, if we want to display graph of TCP conversation that + * started 112.309845 s after beginning of the capture and ran until + * 479.093582 s, 237019 B went through the connection (in one direction) + * starting with isn 31934022, then (bounds.x0, bounds.y0)=(112.309845, + * 31934022) and (bounds.width, bounds.height)=(366.783737, 237019). */ + struct bounds bounds; + + /* dimensions and position of the graph, both expressed already in pixels. + * x and y give the position of upper left corner of the graph relative + * to origin of the graph window, size is basically bounds*zoom */ + struct irect geom; + + /* viewport (=graph window area which is reserved for graph itself), its + * size and position relative to origin of the graph window */ + struct irect wp; + + /* whether and where the graph has been 'grabbed' and may now be moved */ + struct grab grab; + + /* If we need to display 237019 sequence numbers (=bytes) onto say 500 + * pixels, we have to scale the graph down by factor of 0.002109. This + * number would be zoom.y. Obviously, both directions have separate zooms.*/ + struct zooms zoom; + + struct cross cross; + gboolean zoomrect_erase_needed; + struct magnify magnify; + struct axis *x_axis, *y_axis; + struct segment *segments; + + /* The stream this graph will show */ + address src_address; + guint16 src_port; + address dst_address; + guint16 dst_port; + + struct element_list *elists; /* element lists */ + union { + struct style_tseq_stevens tseq_stevens; + struct style_tseq_tcptrace tseq_tcptrace; + struct style_tput tput; + struct style_rtt rtt; + struct style_wscale wscale; + } s; + /* This allows keyboard to set the radio button */ + struct { + GtkToggleButton *graph_rtt, *graph_tput, *graph_tseqstevens, *graph_tseqttrace; + GtkToggleButton *graph_wscale; + } gt; }; + #if !GTK_CHECK_VERSION(3,0,0) static GdkGC *xor_gc = NULL; #endif @@ -372,11 +379,11 @@ static int refnum=0; #define debug(section) if (debugging & section) /* print function entry points */ -#define DBS_FENTRY (1 << 0) -#define DBS_AXES_TICKS (1 << 1) -#define DBS_AXES_DRAWING (1 << 2) -#define DBS_GRAPH_DRAWING (1 << 3) -#define DBS_TPUT_ELMTS (1 << 4) +#define DBS_FENTRY (1 << 0) +#define DBS_AXES_TICKS (1 << 1) +#define DBS_AXES_DRAWING (1 << 2) +#define DBS_GRAPH_DRAWING (1 << 3) +#define DBS_TPUT_ELMTS (1 << 4) /*static int debugging = DBS_FENTRY;*/ static int debugging = 0; /*static int debugging = DBS_AXES_TICKS;*/ @@ -384,137 +391,137 @@ static int debugging = 0; /*static int debugging = DBS_GRAPH_DRAWING;*/ /*static int debugging = DBS_TPUT_ELMTS;*/ -static void create_gui (struct graph * ); +static void create_gui(struct graph * ); #if 0 -static void create_text_widget (struct graph * ); -static void display_text (struct graph * ); +static void create_text_widget(struct graph * ); +static void display_text(struct graph * ); #endif -static void create_drawing_area (struct graph * ); -static void control_panel_create (struct graph * ); -static GtkWidget *control_panel_create_zoom_group (struct graph * ); -static GtkWidget *control_panel_create_magnify_group (struct graph * ); -static GtkWidget *control_panel_create_cross_group (struct graph * ); -static GtkWidget *control_panel_create_zoomlock_group (struct graph * ); -static GtkWidget *control_panel_create_graph_type_group (struct graph * ); -static void control_panel_add_zoom_page (struct graph * , GtkWidget * ); -static void control_panel_add_magnify_page (struct graph * , GtkWidget * ); -static void control_panel_add_origin_page (struct graph * , GtkWidget * ); -static void control_panel_add_cross_page (struct graph * , GtkWidget * ); -static void control_panel_add_graph_type_page (struct graph * , GtkWidget * ); -static void callback_toplevel_destroy (GtkWidget * , gpointer ); +static void create_drawing_area(struct graph * ); +static void control_panel_create(struct graph * ); +static GtkWidget *control_panel_create_zoom_group(struct graph * ); +static GtkWidget *control_panel_create_magnify_group(struct graph * ); +static GtkWidget *control_panel_create_cross_group(struct graph * ); +static GtkWidget *control_panel_create_zoomlock_group(struct graph * ); +static GtkWidget *control_panel_create_graph_type_group(struct graph * ); +static void control_panel_add_zoom_page(struct graph * , GtkWidget * ); +static void control_panel_add_magnify_page(struct graph * , GtkWidget * ); +static void control_panel_add_origin_page(struct graph * , GtkWidget * ); +static void control_panel_add_cross_page(struct graph * , GtkWidget * ); +static void control_panel_add_graph_type_page(struct graph * , GtkWidget * ); +static void callback_toplevel_destroy(GtkWidget * , gpointer ); static gboolean callback_delete_event(GtkWidget * , GdkEvent * , gpointer); -static void callback_close (GtkWidget * , gpointer ); -static void callback_time_origin (GtkWidget * , gpointer ); -static void callback_seq_origin (GtkWidget * , gpointer ); -static void callback_zoomlock_h (GtkWidget * , gpointer ); -static void callback_zoomlock_v (GtkWidget * , gpointer ); -static void callback_zoom_inout (GtkWidget * , gpointer ); -static void callback_zoom_step (GtkWidget * , gpointer ); -static void callback_zoom_flags (GtkWidget * , gpointer ); -static void callback_cross_on_off (GtkWidget * , gpointer ); -static void callback_mag_width (GtkWidget * , gpointer ); -static void callback_mag_height (GtkWidget * , gpointer ); -static void callback_mag_x (GtkWidget * , gpointer ); -static void callback_mag_y (GtkWidget * , gpointer ); -static void callback_mag_zoom (GtkWidget * , gpointer ); -static void callback_mag_flags (GtkWidget * , gpointer ); -static void callback_graph_type (GtkWidget * , gpointer ); -static void callback_graph_init_on_typechg (GtkWidget * , gpointer ); -static void callback_create_help (GtkWidget * , gpointer ); -static void get_mouse_position (GtkWidget *, int *pointer_x, int *pointer_y, GdkModifierType *mask); -static void update_zoom_spins (struct graph * ); -static struct tcpheader *select_tcpip_session (capture_file *, struct segment * ); -static int compare_headers (address *saddr1, address *daddr1, guint16 sport1, guint16 dport1, const address *saddr2, const address *daddr2, guint16 sport2, guint16 dport2, int dir); -static int get_num_dsegs (struct graph * ); -static int get_num_acks (struct graph *, int * ); -static void graph_type_dependent_initialize (struct graph * ); -static struct graph *graph_new (void); -static void graph_destroy (struct graph * ); -static void graph_initialize_values (struct graph * ); -static void graph_init_sequence (struct graph * ); -static void draw_element_line (struct graph * , struct element * , cairo_t *cr, GdkColor *new_color); -static void draw_element_ellipse (struct graph * , struct element * , cairo_t *cr); -static void graph_display (struct graph * ); -static void graph_pixmaps_create (struct graph * ); -static void graph_pixmaps_switch (struct graph * ); -static void graph_pixmap_draw (struct graph * ); -static void graph_pixmap_display (struct graph * ); -static void graph_element_lists_make (struct graph * ); -static void graph_element_lists_free (struct graph * ); -static void graph_element_lists_initialize (struct graph * ); -static void graph_title_pixmap_create (struct graph * ); -static void graph_title_pixmap_draw (struct graph * ); -static void graph_title_pixmap_display (struct graph * ); -static void graph_segment_list_get (struct graph *, gboolean stream_known ); -static void graph_segment_list_free (struct graph * ); -static void graph_select_segment (struct graph * , int , int ); -static int line_detect_collision (struct element * , int , int ); -static int ellipse_detect_collision (struct element * , int , int ); -static void axis_pixmaps_create (struct axis * ); -static void axis_pixmaps_switch (struct axis * ); -static void axis_display (struct axis * ); -static void v_axis_pixmap_draw (struct axis * ); -static void h_axis_pixmap_draw (struct axis * ); -static void axis_pixmap_display (struct axis * ); -static void axis_compute_ticks (struct axis * , double , double , int ); -static double axis_zoom_get (struct axis * , int ); -static void axis_ticks_up (int * , int * ); -static void axis_ticks_down (int * , int * ); -static void axis_destroy (struct axis * ); -static int get_label_dim (struct axis * , int , double ); -static void toggle_crosshairs (struct graph *g); -static void toggle_time_origin (struct graph * ); -static void toggle_seq_origin (struct graph * ); -static void restore_initial_graph_view (struct graph *g); -static void cross_draw (struct graph * , int , int ); -static void cross_erase (struct graph * ); -static void zoomrect_draw (struct graph * , int , int ); -static void zoomrect_erase (struct graph * ); -static void magnify_move (struct graph * , int , int ); -static void magnify_create (struct graph * , int , int ); -static void magnify_destroy (struct graph * ); -static void magnify_draw (struct graph * ); -static void magnify_get_geom (struct graph * , int , int ); -static gboolean configure_event (GtkWidget * , GdkEventConfigure * , gpointer ); +static void callback_close(GtkWidget * , gpointer ); +static void callback_time_origin(GtkWidget * , gpointer ); +static void callback_seq_origin(GtkWidget * , gpointer ); +static void callback_zoomlock_h(GtkWidget * , gpointer ); +static void callback_zoomlock_v(GtkWidget * , gpointer ); +static void callback_zoom_inout(GtkWidget * , gpointer ); +static void callback_zoom_step(GtkWidget * , gpointer ); +static void callback_zoom_flags(GtkWidget * , gpointer ); +static void callback_cross_on_off(GtkWidget * , gpointer ); +static void callback_mag_width(GtkWidget * , gpointer ); +static void callback_mag_height(GtkWidget * , gpointer ); +static void callback_mag_x(GtkWidget * , gpointer ); +static void callback_mag_y(GtkWidget * , gpointer ); +static void callback_mag_zoom(GtkWidget * , gpointer ); +static void callback_mag_flags(GtkWidget * , gpointer ); +static void callback_graph_type(GtkWidget * , gpointer ); +static void callback_graph_init_on_typechg(GtkWidget * , gpointer ); +static void callback_create_help(GtkWidget * , gpointer ); +static void get_mouse_position(GtkWidget *, int *pointer_x, int *pointer_y, GdkModifierType *mask); +static void update_zoom_spins(struct graph * ); +static struct tcpheader *select_tcpip_session(capture_file *, struct segment * ); +static int compare_headers(address *saddr1, address *daddr1, guint16 sport1, guint16 dport1, const address *saddr2, const address *daddr2, guint16 sport2, guint16 dport2, int dir); +static int get_num_dsegs(struct graph * ); +static int get_num_acks(struct graph *, int * ); +static void graph_type_dependent_initialize(struct graph * ); +static struct graph *graph_new(void); +static void graph_destroy(struct graph * ); +static void graph_initialize_values(struct graph * ); +static void graph_init_sequence(struct graph * ); +static void draw_element_line(struct graph * , struct element * , cairo_t *cr, GdkColor *new_color); +static void draw_element_ellipse(struct graph * , struct element * , cairo_t *cr); +static void graph_display(struct graph * ); +static void graph_pixmaps_create(struct graph * ); +static void graph_pixmaps_switch(struct graph * ); +static void graph_pixmap_draw(struct graph * ); +static void graph_pixmap_display(struct graph * ); +static void graph_element_lists_make(struct graph * ); +static void graph_element_lists_free(struct graph * ); +static void graph_element_lists_initialize(struct graph * ); +static void graph_title_pixmap_create(struct graph * ); +static void graph_title_pixmap_draw(struct graph * ); +static void graph_title_pixmap_display(struct graph * ); +static void graph_segment_list_get(struct graph *, gboolean stream_known ); +static void graph_segment_list_free(struct graph * ); +static void graph_select_segment(struct graph * , int , int ); +static int line_detect_collision(struct element * , int , int ); +static int ellipse_detect_collision(struct element * , int , int ); +static void axis_pixmaps_create(struct axis * ); +static void axis_pixmaps_switch(struct axis * ); +static void axis_display(struct axis * ); +static void v_axis_pixmap_draw(struct axis * ); +static void h_axis_pixmap_draw(struct axis * ); +static void axis_pixmap_display(struct axis * ); +static void axis_compute_ticks(struct axis * , double , double , int ); +static double axis_zoom_get(struct axis * , int ); +static void axis_ticks_up(int * , int * ); +static void axis_ticks_down(int * , int * ); +static void axis_destroy(struct axis * ); +static int get_label_dim(struct axis * , int , double ); +static void toggle_crosshairs(struct graph *g); +static void toggle_time_origin(struct graph * ); +static void toggle_seq_origin(struct graph * ); +static void restore_initial_graph_view(struct graph *g); +static void cross_draw(struct graph * , int , int ); +static void cross_erase(struct graph * ); +static void zoomrect_draw(struct graph * , int , int ); +static void zoomrect_erase(struct graph * ); +static void magnify_move(struct graph * , int , int ); +static void magnify_create(struct graph * , int , int ); +static void magnify_destroy(struct graph * ); +static void magnify_draw(struct graph * ); +static void magnify_get_geom(struct graph * , int , int ); +static gboolean configure_event(GtkWidget * , GdkEventConfigure * , gpointer ); #if GTK_CHECK_VERSION(3,0,0) static gboolean draw_event(GtkWidget *widget, cairo_t *cr, gpointer user_data); #else -static gboolean expose_event (GtkWidget * , GdkEventExpose * , gpointer ); +static gboolean expose_event(GtkWidget * , GdkEventExpose * , gpointer ); #endif -static gboolean button_press_event (GtkWidget * , GdkEventButton * , gpointer ); -static gboolean button_release_event (GtkWidget * , GdkEventButton * , gpointer ); -static gboolean motion_notify_event (GtkWidget * , GdkEventMotion * , gpointer ); -static gboolean leave_notify_event (GtkWidget * , GdkEventCrossing * , gpointer ); -static gboolean enter_notify_event (GtkWidget * , GdkEventCrossing * , gpointer ); -static gboolean key_press_event (GtkWidget * , GdkEventKey * , gpointer ); -static gboolean key_release_event (GtkWidget * , GdkEventKey * , gpointer ); -static void tseq_initialize (struct graph * ); -static void tseq_get_bounds (struct graph * ); -static void tseq_stevens_read_config (struct graph * ); -static void tseq_stevens_make_elmtlist (struct graph * ); -static void tseq_stevens_toggle_seq_origin (struct graph * ); -static void tseq_stevens_toggle_time_origin (struct graph * ); -static void tseq_tcptrace_read_config (struct graph * ); -static void tseq_tcptrace_make_elmtlist (struct graph * ); -static void tseq_tcptrace_toggle_seq_origin (struct graph * ); -static void tseq_tcptrace_toggle_time_origin (struct graph * ); -static void tput_initialize (struct graph * ); -static void tput_read_config (struct graph * ); -static void tput_make_elmtlist (struct graph * ); -static void tput_toggle_time_origin (struct graph * ); -static void rtt_read_config (struct graph * ); -static void rtt_initialize (struct graph * ); -static int rtt_is_retrans (struct unack * , unsigned int ); -static struct unack *rtt_get_new_unack (double , unsigned int ); -static void rtt_put_unack_on_list (struct unack ** , struct unack * ); -static void rtt_delete_unack_from_list (struct unack ** , struct unack * ); -static void rtt_make_elmtlist (struct graph * ); -static void rtt_toggle_seq_origin (struct graph * ); +static gboolean button_press_event(GtkWidget * , GdkEventButton * , gpointer ); +static gboolean button_release_event(GtkWidget * , GdkEventButton * , gpointer ); +static gboolean motion_notify_event(GtkWidget * , GdkEventMotion * , gpointer ); +static gboolean leave_notify_event(GtkWidget * , GdkEventCrossing * , gpointer ); +static gboolean enter_notify_event(GtkWidget * , GdkEventCrossing * , gpointer ); +static gboolean key_press_event(GtkWidget * , GdkEventKey * , gpointer ); +static gboolean key_release_event(GtkWidget * , GdkEventKey * , gpointer ); +static void tseq_initialize(struct graph * ); +static void tseq_get_bounds(struct graph * ); +static void tseq_stevens_read_config(struct graph * ); +static void tseq_stevens_make_elmtlist(struct graph * ); +static void tseq_stevens_toggle_seq_origin(struct graph * ); +static void tseq_stevens_toggle_time_origin(struct graph * ); +static void tseq_tcptrace_read_config(struct graph * ); +static void tseq_tcptrace_make_elmtlist(struct graph * ); +static void tseq_tcptrace_toggle_seq_origin(struct graph * ); +static void tseq_tcptrace_toggle_time_origin(struct graph * ); +static void tput_initialize(struct graph * ); +static void tput_read_config(struct graph * ); +static void tput_make_elmtlist(struct graph * ); +static void tput_toggle_time_origin(struct graph * ); +static void rtt_read_config(struct graph * ); +static void rtt_initialize(struct graph * ); +static int rtt_is_retrans(struct unack * , unsigned int ); +static struct unack *rtt_get_new_unack(double , unsigned int ); +static void rtt_put_unack_on_list(struct unack ** , struct unack * ); +static void rtt_delete_unack_from_list(struct unack ** , struct unack * ); +static void rtt_make_elmtlist(struct graph * ); +static void rtt_toggle_seq_origin(struct graph * ); static void wscale_initialize(struct graph *); static void wscale_read_config(struct graph *); static void wscale_make_elmtlist(struct graph *); #if defined(_WIN32) && !defined(__MINGW32__) -static int rint (double ); /* compiler template for Windows */ +static int rint(double ); /* compiler template for Windows */ #endif /* This should arguably be part of the graph, but in practice you can @@ -529,513 +536,514 @@ static struct irect zoomrect; /* #define ORIGINAL_WIN32_BUTTONS 1 */ /* XXX - what about OS X? */ +/* XXX: Needs work to ensire that the columns line up properly in both Gtk2 & Gtk3 */ +/* What is the proper way to do this ?? */ static char helptext[] = - "Here's what you can do:\n" - "\n" + "Here's what you can do:\n" + "\n" #ifdef ORIGINAL_WIN32_BUTTONS - " <Ctrl>-Left Mouse Button selects segment under cursor in Wireshark's packet list\n" - "\n" - " Left Mouse Button zooms in (towards area under mouse pointer)\n" - " <Shift>-Left Mouse Button zooms out\n" - "\n" - " Right Mouse Button moves the graph (if zoomed in)\n" - " <Ctrl>-Right Mouse Button displays a portion of graph under cursor magnified\n" + " <Ctrl>-Left Mouse Button selects segment under cursor in Wireshark's packet list\n" + "\n" + " Left Mouse Button zooms in (towards area under mouse pointer)\n" + " <Shift>-Left Mouse Button zooms out\n" + "\n" + " Right Mouse Button moves the graph (if zoomed in)\n" + " <Ctrl>-Right Mouse Button displays a portion of graph under cursor magnified\n" #else /* !ORIGINAL_WIN32_BUTTONS */ - " Left Mouse Button selects segment under cursor in Wireshark's packet list\n" - " can also drag to zoom in on a rectangular region\n" - "\n" - " Middle Mouse Button zooms in (towards area under cursor)\n" - " <Shift>-Middle Mouse Button zooms out\n" - "\n" - " Right Mouse Button moves the graph (if zoomed in)\n" - " <Ctrl>-Right Mouse Button displays a portion of graph under cursor magnified\n" + " Left Mouse Button selects segment under cursor in Wireshark's packet list\n" + " can also drag to zoom in on a rectangular region\n" + "\n" + " Middle Mouse Button zooms in (towards area under cursor)\n" + " <Shift>-Middle Mouse Button zooms out\n" + "\n" + " Right Mouse Button moves the graph (if zoomed in)\n" + " <Ctrl>-Right Mouse Button displays a portion of graph under cursor magnified\n" #endif - "\n" - "\n" - " '1' display Round Trip Time Graph\n" - " '2' display Throughput Graph\n" - " '3' display Time/Sequence Graph (Stevens)\n" - " '4' display Time/Sequence Graph (tcptrace)\n" - " '5' display Window Scaling Graph\n" - "\n" - " <Space bar> toggles crosshairs on/off\n" - "\n" - " 'i' or '+' zoom in (towards area under mouse pointer)\n" - " 'o' or '-' zoom out\n" - " 'r' or <Home> restore graph to initial state (zoom out max)\n" - " 's' toggles relative/absolute sequence numbers\n" - " 't' toggles time origin\n" - " 'g' go to frame under cursor in Wireshark's packet list (if possible)\n" - "\n" - " <Left> move view left by 100 pixels (if zoomed in)\n" - " <Right> move view right 100 pixels (if zoomed in)\n" - " <Up> move view up by 100 pixels (if zoomed in)\n" - " <Down> move view down by 100 pixels (if zoomed in)\n" - "\n" - " <Shift><Left> move view left by 10 pixels (if zoomed in)\n" - " <Shift><Right> move view right 10 pixels (if zoomed in)\n" - " <Shift><Up> move view up by 10 pixels (if zoomed in)\n" - " <Shift><Down> move view down by 10 pixels (if zoomed in)\n" - "\n" - " <Ctrl><Left> move view left by 1 pixel (if zoomed in)\n" - " <Ctrl><Right> move view right 1 pixel (if zoomed in)\n" - " <Ctrl><Up> move view up by 1 pixel (if zoomed in)\n" - " <Ctrl><Down> move view down by 1 pixel (if zoomed in)\n" + "\n" + "\n" + " '1' display Round Trip Time Graph\n" + " '2' display Throughput Graph\n" + " '3' display Time/Sequence Graph (Stevens)\n" + " '4' display Time/Sequence Graph (tcptrace)\n" + " '5' display Window Scaling Graph\n" + "\n" + " <Space bar> toggles crosshairs on/off\n" + "\n" + " 'i' or '+' zoom in (towards area under mouse pointer)\n" + " 'o' or '-' zoom out\n" + " 'r' or <Home> restore graph to initial state (zoom out max)\n" + " 's' toggles relative/absolute sequence numbers\n" + " 't' toggles time origin\n" + " 'g' go to frame under cursor in Wireshark's packet list (if possible)\n" + "\n" + " <Left> move view left by 100 pixels (if zoomed in)\n" + " <Right> move view right 100 pixels (if zoomed in)\n" + " <Up> move view up by 100 pixels (if zoomed in)\n" + " <Down> move view down by 100 pixels (if zoomed in)\n" + "\n" + " <Shift><Left> move view left by 10 pixels (if zoomed in)\n" + " <Shift><Right> move view right 10 pixels (if zoomed in)\n" + " <Shift><Up> move view up by 10 pixels (if zoomed in)\n" + " <Shift><Down> move view down by 10 pixels (if zoomed in)\n" + "\n" + " <Ctrl><Left> move view left by 1 pixel (if zoomed in)\n" + " <Ctrl><Right> move view right 1 pixel (if zoomed in)\n" + " <Ctrl><Up> move view up by 1 pixel (if zoomed in)\n" + " <Ctrl><Down> move view down by 1 pixel (if zoomed in)\n" ; #if 0 -static void debug_coord (struct graph *g, const char *c) +static void debug_coord(struct graph *g, const char *c) { - static guint count = 0; + static guint count = 0; - count++; - printf("%u: %s\n", count, c); - printf("%u: g->geom.width %d\n", count, g->geom.width); - printf("%u: g->geom.height %d\n", count, g->geom.height); - printf("%u: g->geom.x %d\n", count, g->geom.x); - printf("%u: g->geom.y %d\n", count, g->geom.y); + count++; + printf("%u: %s\n", count, c); + printf("%u: g->geom.width %d\n", count, g->geom.width); + printf("%u: g->geom.height %d\n", count, g->geom.height); + printf("%u: g->geom.x %d\n", count, g->geom.x); + printf("%u: g->geom.y %d\n", count, g->geom.y); - printf("%u: g->wp.width %d\n", count, g->wp.width); - printf("%u: g->wp.height %d\n", count, g->wp.height); - printf("%u: g->wp.x %d\n", count, g->wp.x); - printf("%u: g->wp.y %d\n", count, g->wp.y); - printf("---------------\n"); + printf("%u: g->wp.width %d\n", count, g->wp.width); + printf("%u: g->wp.height %d\n", count, g->wp.height); + printf("%u: g->wp.x %d\n", count, g->wp.x); + printf("%u: g->wp.y %d\n", count, g->wp.y); + printf("---------------\n"); } #endif static void set_busy_cursor(GdkWindow *w) { - GdkCursor* cursor; + GdkCursor *cursor; - cursor = gdk_cursor_new(GDK_WATCH); - gdk_window_set_cursor(w, cursor); - gdk_flush(); + cursor = gdk_cursor_new(GDK_WATCH); + gdk_window_set_cursor(w, cursor); + gdk_flush(); #if GTK_CHECK_VERSION(3,0,0) - g_object_unref(cursor); + g_object_unref(cursor); #else - gdk_cursor_unref(cursor); + gdk_cursor_unref(cursor); #endif } static void unset_busy_cursor(GdkWindow *w, gboolean cross) { - GdkCursor* cursor; + GdkCursor *cursor; - if(cross){ - cursor = gdk_cursor_new(GDK_CROSSHAIR); - gdk_window_set_cursor(w, cursor); - gdk_flush(); + if (cross) { + cursor = gdk_cursor_new(GDK_CROSSHAIR); + gdk_window_set_cursor(w, cursor); + gdk_flush(); #if GTK_CHECK_VERSION(3,0,0) - g_object_unref(cursor); + g_object_unref(cursor); #else - gdk_cursor_unref(cursor); + gdk_cursor_unref(cursor); #endif - }else{ - gdk_window_set_cursor(w, NULL); - gdk_flush(); - } + } else { + gdk_window_set_cursor(w, NULL); + gdk_flush(); + } } -void tcp_graph_cb (GtkAction *action, gpointer user_data _U_) +void tcp_graph_cb(GtkAction *action, gpointer user_data _U_) { - struct segment current; - struct graph *g; - const gchar *name; - guint graph_type; + struct segment current; + struct graph *g; + const gchar *name; + guint graph_type; - name = gtk_action_get_name (action); - if(strcmp(name, "/StatisticsMenu/TCPStreamGraphMenu/Time-Sequence-Graph-Stevens") == 0){ - graph_type = GRAPH_TSEQ_STEVENS; - }else if(strcmp(name, "/StatisticsMenu/TCPStreamGraphMenu/Time-Sequence-Graph-tcptrace") == 0){ - graph_type = GRAPH_TSEQ_TCPTRACE; - }else if(strcmp(name, "/StatisticsMenu/TCPStreamGraphMenu/Throughput-Graph") == 0){ - graph_type = GRAPH_THROUGHPUT; - }else if(strcmp(name, "/StatisticsMenu/TCPStreamGraphMenu/RTT-Graph") == 0){ - graph_type = GRAPH_RTT; - }else if(strcmp(name, "/StatisticsMenu/TCPStreamGraphMenu/Window-Scaling-Graph") == 0){ - graph_type = GRAPH_WSCALE; - }else{ - return; - } + name = gtk_action_get_name(action); + if (strcmp(name, "/StatisticsMenu/TCPStreamGraphMenu/Time-Sequence-Graph-Stevens") == 0) { + graph_type = GRAPH_TSEQ_STEVENS; + } else if (strcmp(name, "/StatisticsMenu/TCPStreamGraphMenu/Time-Sequence-Graph-tcptrace") == 0) { + graph_type = GRAPH_TSEQ_TCPTRACE; + } else if (strcmp(name, "/StatisticsMenu/TCPStreamGraphMenu/Throughput-Graph") == 0) { + graph_type = GRAPH_THROUGHPUT; + } else if (strcmp(name, "/StatisticsMenu/TCPStreamGraphMenu/RTT-Graph") == 0) { + graph_type = GRAPH_RTT; + } else if (strcmp(name, "/StatisticsMenu/TCPStreamGraphMenu/Window-Scaling-Graph") == 0) { + graph_type = GRAPH_WSCALE; + } else { + return; + } - debug(DBS_FENTRY) puts ("tcp_graph_cb()"); + debug(DBS_FENTRY) puts("tcp_graph_cb()"); - if (!select_tcpip_session (&cfile, ¤t)) { - return; - } + if (!select_tcpip_session(&cfile, ¤t)) { + return; + } - if (! (g = graph_new())) - return; + if (! (g = graph_new())) + return; - refnum++; - graph_initialize_values (g); + refnum++; + graph_initialize_values(g); - g->type = graph_type; + g->type = graph_type; - graph_segment_list_get(g, FALSE); - create_gui(g); - /* display_text(g); */ - graph_init_sequence(g); + graph_segment_list_get(g, FALSE); + create_gui(g); + /* display_text(g); */ + graph_init_sequence(g); } void tcp_graph_known_stream_launch(address *src_address, guint16 src_port, address *dst_address, guint16 dst_port) { - struct graph *g; + struct graph *g; - if (!(g = graph_new())) { - return; - } + if (!(g = graph_new())) { + return; + } - refnum++; - graph_initialize_values(g); + refnum++; + graph_initialize_values(g); - /* Can set stream info for graph now */ - COPY_ADDRESS(&g->src_address, src_address); - g->src_port = src_port; - COPY_ADDRESS(&g->dst_address, dst_address); - g->dst_port = dst_port; + /* Can set stream info for graph now */ + COPY_ADDRESS(&g->src_address, src_address); + g->src_port = src_port; + COPY_ADDRESS(&g->dst_address, dst_address); + g->dst_port = dst_port; - /* This graph type is arguably the most useful, so start there */ - g->type = GRAPH_TSEQ_TCPTRACE; + /* This graph type is arguably the most useful, so start there */ + g->type = GRAPH_TSEQ_TCPTRACE; - /* Get our list of segments from the packet list */ - graph_segment_list_get(g, TRUE); + /* Get our list of segments from the packet list */ + graph_segment_list_get(g, TRUE); - create_gui(g); - graph_init_sequence(g); + create_gui(g); + graph_init_sequence(g); } -static void create_gui (struct graph *g) +static void create_gui(struct graph *g) { - /* ToDo: Ensure that drawing area window doesn't - * (completely) cover the contraol_panel window. - */ - debug(DBS_FENTRY) puts ("create_gui()"); - /* create_text_widget(g); */ - control_panel_create (g); - create_drawing_area(g); + /* ToDo: Ensure that drawing area window doesn't + * (completely) cover the contraol_panel window. + */ + debug(DBS_FENTRY) puts("create_gui()"); + /* create_text_widget(g); */ + control_panel_create(g); + create_drawing_area(g); } -static void create_drawing_area (struct graph *g) +static void create_drawing_area(struct graph *g) { #if GTK_CHECK_VERSION(3,0,0) - GtkStyleContext *context; + GtkStyleContext *context; #else - GdkColormap *colormap; - GdkColor color; + GdkColormap *colormap; + GdkColor color; #endif - char *display_name; - char window_title[WINDOW_TITLE_LENGTH]; - GtkAllocation widget_alloc; + char *display_name; + char window_title[WINDOW_TITLE_LENGTH]; + GtkAllocation widget_alloc; #if 0 - /* Prep. to include the controls in the graph window */ - GtkWidget *frame; - GtkWidget *vbox; - GtkWidget *hbox; + /* Prep. to include the controls in the graph window */ + GtkWidget *frame; + GtkWidget *vbox; + GtkWidget *hbox; #endif - debug(DBS_FENTRY) puts ("create_drawing_area()"); - - /* Set title of window with file + conversation details */ - display_name = cf_get_display_name(&cfile); - g_snprintf (window_title, WINDOW_TITLE_LENGTH, "TCP Graph %d: %s %s:%d -> %s:%d", - refnum, - display_name, - ep_address_to_str(&g->src_address), - g->src_port, - ep_address_to_str(&g->dst_address), - g->dst_port - ); - g_free(display_name); - g->toplevel = dlg_window_new ("Tcp Graph"); - gtk_window_set_title(GTK_WINDOW(g->toplevel), window_title); - gtk_widget_set_name (g->toplevel, "Test Graph"); - - /* Create the drawing area */ - g->drawing_area = gtk_drawing_area_new (); - g->x_axis->drawing_area = g->y_axis->drawing_area = g->drawing_area; - gtk_widget_set_size_request (g->drawing_area, - g->wp.width + g->wp.x + RMARGIN_WIDTH, - g->wp.height + g->wp.y + g->x_axis->s.height); - gtk_widget_show (g->drawing_area); + debug(DBS_FENTRY) puts("create_drawing_area()"); + + /* Set title of window with file + conversation details */ + display_name = cf_get_display_name(&cfile); + g_snprintf(window_title, WINDOW_TITLE_LENGTH, "TCP Graph %d: %s %s:%d -> %s:%d", + refnum, + display_name, + ep_address_to_str(&g->src_address), + g->src_port, + ep_address_to_str(&g->dst_address), + g->dst_port + ); + g_free(display_name); + g->toplevel = dlg_window_new("Tcp Graph"); + gtk_window_set_title(GTK_WINDOW(g->toplevel), window_title); + gtk_widget_set_name(g->toplevel, "Test Graph"); + + /* Create the drawing area */ + g->drawing_area = gtk_drawing_area_new(); + g->x_axis->drawing_area = g->y_axis->drawing_area = g->drawing_area; + gtk_widget_set_size_request(g->drawing_area, + g->wp.width + g->wp.x + RMARGIN_WIDTH, + g->wp.height + g->wp.y + g->x_axis->s.height); + gtk_widget_show(g->drawing_area); #if GTK_CHECK_VERSION(3,0,0) - g_signal_connect(g->drawing_area, "draw", G_CALLBACK(draw_event), g); + g_signal_connect(g->drawing_area, "draw", G_CALLBACK(draw_event), g); #else - g_signal_connect(g->drawing_area, "expose_event", G_CALLBACK(expose_event), g); + g_signal_connect(g->drawing_area, "expose_event", G_CALLBACK(expose_event), g); #endif - /* this has to be done later, after the widget has been shown */ - /* - g_signal_connect(g->drawing_area,"configure_event", G_CALLBACK(configure_event), g); - */ - - g_signal_connect(g->drawing_area, "button_press_event", - G_CALLBACK(button_press_event), g); - g_signal_connect(g->drawing_area, "button_release_event", - G_CALLBACK(button_release_event), g); - g_signal_connect(g->drawing_area, "motion_notify_event", - G_CALLBACK(motion_notify_event), g); - g_signal_connect(g->drawing_area, "leave_notify_event", - G_CALLBACK(leave_notify_event), g); - g_signal_connect(g->drawing_area, "enter_notify_event", - G_CALLBACK(enter_notify_event), g); - g_signal_connect(g->toplevel, "destroy", G_CALLBACK(callback_toplevel_destroy), g); - /* why doesn't drawing area send key_press_signals? */ - g_signal_connect(g->toplevel, "key_press_event", G_CALLBACK(key_press_event), g); - g_signal_connect(g->toplevel, "key_release_event", G_CALLBACK(key_release_event), - g); - gtk_widget_set_events(g->toplevel, GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK); - - gtk_widget_set_events (g->drawing_area, - GDK_EXPOSURE_MASK - | GDK_LEAVE_NOTIFY_MASK - | GDK_ENTER_NOTIFY_MASK - | GDK_BUTTON_PRESS_MASK - | GDK_BUTTON_RELEASE_MASK - | GDK_POINTER_MOTION_MASK - | GDK_POINTER_MOTION_HINT_MASK); + /* this has to be done later, after the widget has been shown */ + /* + g_signal_connect(g->drawing_area, "configure_event", G_CALLBACK(configure_event), g); + */ + + g_signal_connect(g->drawing_area, "button_press_event", + G_CALLBACK(button_press_event), g); + g_signal_connect(g->drawing_area, "button_release_event", + G_CALLBACK(button_release_event), g); + g_signal_connect(g->drawing_area, "motion_notify_event", + G_CALLBACK(motion_notify_event), g); + g_signal_connect(g->drawing_area, "leave_notify_event", + G_CALLBACK(leave_notify_event), g); + g_signal_connect(g->drawing_area, "enter_notify_event", + G_CALLBACK(enter_notify_event), g); + g_signal_connect(g->toplevel, "destroy", G_CALLBACK(callback_toplevel_destroy), g); + /* why doesn't drawing area send key_press_signals? */ + g_signal_connect(g->toplevel, "key_press_event", G_CALLBACK(key_press_event), g); + g_signal_connect(g->toplevel, "key_release_event", G_CALLBACK(key_release_event), + g); + gtk_widget_set_events(g->toplevel, GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK); + + gtk_widget_set_events(g->drawing_area, + GDK_EXPOSURE_MASK + | GDK_LEAVE_NOTIFY_MASK + | GDK_ENTER_NOTIFY_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_POINTER_MOTION_MASK + | GDK_POINTER_MOTION_HINT_MASK); #if 0 - /* Prep. to include the controls in the graph window */ + /* Prep. to include the controls in the graph window */ - vbox = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE); - gtk_container_add (GTK_CONTAINER (g->toplevel), vbox); - gtk_container_set_border_width (GTK_CONTAINER (g->toplevel), 5); - gtk_widget_show (vbox); + vbox = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE); + gtk_container_add(GTK_CONTAINER(g->toplevel), vbox); + gtk_container_set_border_width(GTK_CONTAINER(g->toplevel), 5); + gtk_widget_show(vbox); - frame = gtk_frame_new (NULL); - gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); - gtk_container_add (GTK_CONTAINER (frame), g->drawing_area); - gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0); - gtk_widget_show (frame); + frame = gtk_frame_new(NULL); + gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN); + gtk_container_add(GTK_CONTAINER(frame), g->drawing_area); + gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0); + gtk_widget_show(frame); - /*gtk_box_pack_start (GTK_BOX (vbox), g->gui.control_panel, FALSE, FALSE, 0);*/ + /*gtk_box_pack_start(GTK_BOX(vbox), g->gui.control_panel, FALSE, FALSE, 0);*/ - hbox=ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5); - gtk_container_set_border_width(GTK_CONTAINER(hbox), 3); - gtk_box_set_child_packing(GTK_BOX(vbox), hbox, FALSE, FALSE, 0, GTK_PACK_START); - gtk_widget_show(hbox); + hbox = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5); + gtk_container_set_border_width(GTK_CONTAINER(hbox), 3); + gtk_box_set_child_packing(GTK_BOX(vbox), hbox, FALSE, FALSE, 0, GTK_PACK_START); + gtk_widget_show(hbox); - create_ctrl_area(g, hbox); + create_ctrl_area(g, hbox); #endif - gtk_container_add (GTK_CONTAINER (g->toplevel), g->drawing_area); - gtk_widget_show (g->toplevel); + gtk_container_add(GTK_CONTAINER(g->toplevel), g->drawing_area); + gtk_widget_show(g->toplevel); - /* in case we didn't get what we asked for */ - gtk_widget_get_allocation(GTK_WIDGET (g->drawing_area), &widget_alloc); - g->wp.width = widget_alloc.width - g->wp.x - RMARGIN_WIDTH; - g->wp.height = widget_alloc.height - g->wp.y - g->x_axis->s.height; + /* in case we didn't get what we asked for */ + gtk_widget_get_allocation(GTK_WIDGET(g->drawing_area), &widget_alloc); + g->wp.width = widget_alloc.width - g->wp.x - RMARGIN_WIDTH; + g->wp.height = widget_alloc.height - g->wp.y - g->x_axis->s.height; #if GTK_CHECK_VERSION(3,0,0) - context = gtk_widget_get_style_context (g->drawing_area); - gtk_style_context_get (context, GTK_STATE_FLAG_NORMAL, - GTK_STYLE_PROPERTY_FONT, &g->font, - NULL); + context = gtk_widget_get_style_context(g->drawing_area); + gtk_style_context_get(context, GTK_STATE_FLAG_NORMAL, + GTK_STYLE_PROPERTY_FONT, &g->font, + NULL); #else - g->font = gtk_widget_get_style(g->drawing_area)->font_desc; - - colormap = gtk_widget_get_colormap(GTK_WIDGET(g->drawing_area)); - if (!xor_gc) { - xor_gc = gdk_gc_new (gtk_widget_get_window(g->drawing_area)); - gdk_gc_set_function (xor_gc, GDK_XOR); - if (!gdk_color_parse ("gray15", &color)) { - /* - * XXX - do more than just warn. - */ - simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK, - "Could not parse color gray15."); - } - if (!gdk_colormap_alloc_color (colormap, &color, FALSE, TRUE)) { - /* - * XXX - do more than just warn. - */ - simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK, - "Could not allocate color gray15."); - } - gdk_gc_set_foreground (xor_gc, &color); - } - - /* this is probably quite an ugly way to get rid of the first configure - * event - * immediately after gtk_widget_show (window) drawing_area gets a configure - * event which is handled during the next return to gtk_main which is - * probably the gdk_gc_new() call. configure handler calls - * graph_element_lists_make() which is not good because the graph struct is - * not fully set up yet - namely we're not sure about actual geometry - * and we don't have the GC's at all. so we just postpone installation - * of configure handler until we're ready to deal with it. - * - * !!! NEMLLO BY TO BYT NA KONCI graph_init_sequence()? !!! - * - */ + g->font = gtk_widget_get_style(g->drawing_area)->font_desc; + + colormap = gtk_widget_get_colormap(GTK_WIDGET(g->drawing_area)); + if (!xor_gc) { + xor_gc = gdk_gc_new(gtk_widget_get_window(g->drawing_area)); + gdk_gc_set_function(xor_gc, GDK_XOR); + if (!gdk_color_parse("gray15", &color)) { + /* + * XXX - do more than just warn. + */ + simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK, + "Could not parse color gray15."); + } + if (!gdk_colormap_alloc_color(colormap, &color, FALSE, TRUE)) { + /* + * XXX - do more than just warn. + */ + simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK, + "Could not allocate color gray15."); + } + gdk_gc_set_foreground(xor_gc, &color); + } + + /* this is probably quite an ugly way to get rid of the first configure + * event + * immediately after gtk_widget_show(window) drawing_area gets a configure + * event which is handled during the next return to gtk_main which is + * probably the gdk_gc_new() call. configure handler calls + * graph_element_lists_make() which is not good because the graph struct is + * not fully set up yet - namely we're not sure about actual geometry + * and we don't have the GC's at all. so we just postpone installation + * of configure handler until we're ready to deal with it. + * + * !!! NEMLLO BY TO BYT NA KONCI graph_init_sequence()? !!! + * + */ #endif - g_signal_connect(g->drawing_area, "configure_event", G_CALLBACK(configure_event), - g); + g_signal_connect(g->drawing_area, "configure_event", G_CALLBACK(configure_event), + g); - /* puts ("exiting create_drawing_area()"); */ + /* puts("exiting create_drawing_area()"); */ } -static void callback_toplevel_destroy (GtkWidget *widget _U_, gpointer data) +static void callback_toplevel_destroy(GtkWidget *widget _U_, gpointer data) { - struct graph *g = (struct graph * )data; + struct graph *g = (struct graph *)data; - if (!(g->flags & GRAPH_DESTROYED)) { - g->flags |= GRAPH_DESTROYED; - graph_destroy ((struct graph * )data); - } + if (!(g->flags & GRAPH_DESTROYED)) { + g->flags |= GRAPH_DESTROYED; + graph_destroy((struct graph *)data); + } } -static void control_panel_create (struct graph *g) +static void control_panel_create(struct graph *g) { - GtkWidget *toplevel, *notebook; - GtkWidget *top_vb; - GtkWidget *help_bt, *close_bt, *bbox; - char window_title[WINDOW_TITLE_LENGTH]; + GtkWidget *toplevel, *notebook; + GtkWidget *top_vb; + GtkWidget *help_bt, *close_bt, *bbox; + char window_title[WINDOW_TITLE_LENGTH]; - debug(DBS_FENTRY) puts ("control_panel_create()"); + debug(DBS_FENTRY) puts("control_panel_create()"); - notebook = gtk_notebook_new (); - control_panel_add_zoom_page (g, notebook); - control_panel_add_magnify_page (g, notebook); - control_panel_add_origin_page (g, notebook); - control_panel_add_cross_page (g, notebook); - control_panel_add_graph_type_page (g, notebook); + notebook = gtk_notebook_new(); + control_panel_add_zoom_page(g, notebook); + control_panel_add_magnify_page(g, notebook); + control_panel_add_origin_page(g, notebook); + control_panel_add_cross_page(g, notebook); + control_panel_add_graph_type_page(g, notebook); - g_snprintf (window_title, WINDOW_TITLE_LENGTH, - "Graph %d - Control - Wireshark", refnum); - toplevel = dlg_window_new ("tcp-graph-control"); - gtk_window_set_title(GTK_WINDOW(toplevel), window_title); + g_snprintf(window_title, WINDOW_TITLE_LENGTH, + "Graph %d - Control - Wireshark", refnum); + toplevel = dlg_window_new("tcp-graph-control"); + gtk_window_set_title(GTK_WINDOW(toplevel), window_title); - gtk_window_set_resizable(GTK_WINDOW(toplevel), FALSE); /* XXX: Acceptable ? */ + gtk_window_set_resizable(GTK_WINDOW(toplevel), FALSE); /* XXX: Acceptable ? */ - top_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE); - gtk_container_add(GTK_CONTAINER(toplevel), top_vb); + top_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE); + gtk_container_add(GTK_CONTAINER(toplevel), top_vb); - gtk_box_pack_start(GTK_BOX(top_vb), notebook, FALSE, FALSE, 5); + gtk_box_pack_start(GTK_BOX(top_vb), notebook, FALSE, FALSE, 5); - /* Button row. */ - bbox = dlg_button_row_new(GTK_STOCK_HELP, GTK_STOCK_CLOSE, NULL); + /* Button row. */ + bbox = dlg_button_row_new(GTK_STOCK_HELP, GTK_STOCK_CLOSE, NULL); gtk_box_pack_start(GTK_BOX(top_vb), bbox, FALSE, FALSE, 5); - help_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP); - g_signal_connect(help_bt, "clicked", G_CALLBACK(callback_create_help), g); + help_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP); + g_signal_connect(help_bt, "clicked", G_CALLBACK(callback_create_help), g); - close_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE); - window_set_cancel_button(toplevel, close_bt, NULL); - g_signal_connect(close_bt, "clicked", G_CALLBACK(callback_close), g); + close_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE); + window_set_cancel_button(toplevel, close_bt, NULL); + g_signal_connect(close_bt, "clicked", G_CALLBACK(callback_close), g); - g_signal_connect(toplevel, "delete_event", G_CALLBACK(callback_delete_event), g); - g_signal_connect(toplevel, "destroy", G_CALLBACK(callback_toplevel_destroy), g); + g_signal_connect(toplevel, "delete_event", G_CALLBACK(callback_delete_event), g); + g_signal_connect(toplevel, "destroy", G_CALLBACK(callback_toplevel_destroy), g); - gtk_widget_show_all (toplevel); - window_present(toplevel); + gtk_widget_show_all(toplevel); + window_present(toplevel); - g->gui.control_panel = toplevel; + g->gui.control_panel = toplevel; } -static void control_panel_add_zoom_page (struct graph *g, GtkWidget *n) +static void control_panel_add_zoom_page(struct graph *g, GtkWidget *n) { - GtkWidget *zoom_frame; - GtkWidget *zoom_lock_frame; - GtkWidget *label; - GtkWidget *box; + GtkWidget *zoom_frame; + GtkWidget *zoom_lock_frame; + GtkWidget *label; + GtkWidget *box; - zoom_frame = control_panel_create_zoom_group (g); - gtk_container_set_border_width (GTK_CONTAINER (zoom_frame), 5); - zoom_lock_frame = control_panel_create_zoomlock_group (g); - gtk_container_set_border_width (GTK_CONTAINER (zoom_lock_frame), 5); - box = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE); - gtk_box_pack_start (GTK_BOX (box), zoom_frame, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (box), zoom_lock_frame, TRUE, TRUE, 0); - gtk_widget_show (box); - label = gtk_label_new ("Zoom"); - gtk_notebook_append_page (GTK_NOTEBOOK (n), box, label); + zoom_frame = control_panel_create_zoom_group(g); + gtk_container_set_border_width(GTK_CONTAINER(zoom_frame), 5); + zoom_lock_frame = control_panel_create_zoomlock_group(g); + gtk_container_set_border_width(GTK_CONTAINER(zoom_lock_frame), 5); + box = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE); + gtk_box_pack_start(GTK_BOX(box), zoom_frame, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(box), zoom_lock_frame, TRUE, TRUE, 0); + gtk_widget_show(box); + label = gtk_label_new("Zoom"); + gtk_notebook_append_page(GTK_NOTEBOOK(n), box, label); } -static void control_panel_add_magnify_page (struct graph *g, GtkWidget *n) +static void control_panel_add_magnify_page(struct graph *g, GtkWidget *n) { - GtkWidget *mag_frame, *label; + GtkWidget *mag_frame, *label; - mag_frame = control_panel_create_magnify_group (g); - gtk_container_set_border_width (GTK_CONTAINER (mag_frame), 5); - label = gtk_label_new ("Magnify"); - gtk_notebook_append_page (GTK_NOTEBOOK (n), mag_frame, label); + mag_frame = control_panel_create_magnify_group(g); + gtk_container_set_border_width(GTK_CONTAINER(mag_frame), 5); + label = gtk_label_new("Magnify"); + gtk_notebook_append_page(GTK_NOTEBOOK(n), mag_frame, label); } -static void control_panel_add_origin_page (struct graph *g, GtkWidget *n) +static void control_panel_add_origin_page(struct graph *g, GtkWidget *n) { - GtkWidget *time_orig_cap, *time_orig_conn, *time_orig_box, *time_orig_frame; - GtkWidget *seq_orig_isn, *seq_orig_zero, *seq_orig_box, *seq_orig_frame; - GtkWidget *box, *label; + GtkWidget *time_orig_cap, *time_orig_conn, *time_orig_box, *time_orig_frame; + GtkWidget *seq_orig_isn, *seq_orig_zero, *seq_orig_box, *seq_orig_frame; + GtkWidget *box, *label; - /* time origin box */ - time_orig_cap = - gtk_radio_button_new_with_label (NULL, "beginning of capture"); - time_orig_conn = gtk_radio_button_new_with_label ( - gtk_radio_button_get_group (GTK_RADIO_BUTTON (time_orig_cap)), - "beginning of this TCP connection"); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (time_orig_conn), TRUE); - time_orig_box = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE); - gtk_box_pack_start (GTK_BOX (time_orig_box), time_orig_conn, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (time_orig_box), time_orig_cap, TRUE, TRUE, 0); - time_orig_frame = gtk_frame_new ("Time origin"); - gtk_container_set_border_width (GTK_CONTAINER (time_orig_frame), 5); - gtk_container_add (GTK_CONTAINER (time_orig_frame), time_orig_box); + /* time origin box */ + time_orig_cap = gtk_radio_button_new_with_label(NULL, "beginning of capture"); + time_orig_conn = gtk_radio_button_new_with_label( + gtk_radio_button_get_group(GTK_RADIO_BUTTON(time_orig_cap)), + "beginning of this TCP connection"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(time_orig_conn), TRUE); + time_orig_box = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE); + gtk_box_pack_start(GTK_BOX(time_orig_box), time_orig_conn, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(time_orig_box), time_orig_cap, TRUE, TRUE, 0); + time_orig_frame = gtk_frame_new("Time origin"); + gtk_container_set_border_width(GTK_CONTAINER(time_orig_frame), 5); + gtk_container_add(GTK_CONTAINER(time_orig_frame), time_orig_box); - /* sequence number origin group */ - seq_orig_isn = - gtk_radio_button_new_with_label (NULL, "initial sequence number"); - seq_orig_zero = gtk_radio_button_new_with_label (gtk_radio_button_get_group ( - GTK_RADIO_BUTTON (seq_orig_isn)), "0 (=absolute)"); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (seq_orig_isn), TRUE); - seq_orig_box = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE); - gtk_box_pack_start (GTK_BOX (seq_orig_box), seq_orig_isn, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (seq_orig_box), seq_orig_zero, TRUE, TRUE, 0); - seq_orig_frame = gtk_frame_new ("Sequence number origin"); - gtk_container_set_border_width (GTK_CONTAINER (seq_orig_frame), 5); - gtk_container_add (GTK_CONTAINER (seq_orig_frame), seq_orig_box); + /* sequence number origin group */ + seq_orig_isn = gtk_radio_button_new_with_label(NULL, "initial sequence number"); + seq_orig_zero = gtk_radio_button_new_with_label( + gtk_radio_button_get_group(GTK_RADIO_BUTTON(seq_orig_isn)), + "0 (=absolute)"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(seq_orig_isn), TRUE); + seq_orig_box = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE); + gtk_box_pack_start(GTK_BOX(seq_orig_box), seq_orig_isn, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(seq_orig_box), seq_orig_zero, TRUE, TRUE, 0); + seq_orig_frame = gtk_frame_new("Sequence number origin"); + gtk_container_set_border_width(GTK_CONTAINER(seq_orig_frame), 5); + gtk_container_add(GTK_CONTAINER(seq_orig_frame), seq_orig_box); - g->gui.time_orig_conn = (GtkToggleButton * )time_orig_conn; - g->gui.seq_orig_isn = (GtkToggleButton * )seq_orig_isn; + g->gui.time_orig_conn = (GtkToggleButton * )time_orig_conn; + g->gui.seq_orig_isn = (GtkToggleButton * )seq_orig_isn; - g_signal_connect(time_orig_conn, "toggled", G_CALLBACK(callback_time_origin), g); - g_signal_connect(seq_orig_isn, "toggled", G_CALLBACK(callback_seq_origin), g); + g_signal_connect(time_orig_conn, "toggled", G_CALLBACK(callback_time_origin), g); + g_signal_connect(seq_orig_isn, "toggled", G_CALLBACK(callback_seq_origin), g); - box = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE); - gtk_container_set_border_width (GTK_CONTAINER (box), 5); - gtk_box_pack_start (GTK_BOX (box), time_orig_frame, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (box), seq_orig_frame, TRUE, TRUE, 0); - gtk_widget_show (box); - label = gtk_label_new ("Origin"); - gtk_notebook_append_page (GTK_NOTEBOOK (n), box, label); + box = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE); + gtk_container_set_border_width(GTK_CONTAINER(box), 5); + gtk_box_pack_start(GTK_BOX(box), time_orig_frame, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(box), seq_orig_frame, TRUE, TRUE, 0); + gtk_widget_show(box); + label = gtk_label_new("Origin"); + gtk_notebook_append_page(GTK_NOTEBOOK(n), box, label); } static void control_panel_add_cross_page (struct graph *g, GtkWidget *n) { - GtkWidget *cross_frame, *label; + GtkWidget *cross_frame, *label; - cross_frame = control_panel_create_cross_group (g); - gtk_container_set_border_width (GTK_CONTAINER (cross_frame), 5); - label = gtk_label_new ("Cross"); - gtk_notebook_append_page (GTK_NOTEBOOK (n), cross_frame, label); + cross_frame = control_panel_create_cross_group(g); + gtk_container_set_border_width(GTK_CONTAINER(cross_frame), 5); + label = gtk_label_new("Cross"); + gtk_notebook_append_page(GTK_NOTEBOOK(n), cross_frame, label); } -static void control_panel_add_graph_type_page (struct graph *g, GtkWidget *n) +static void control_panel_add_graph_type_page(struct graph *g, GtkWidget *n) { - GtkWidget *frame, *label; + GtkWidget *frame, *label; - frame = control_panel_create_graph_type_group (g); - gtk_container_set_border_width (GTK_CONTAINER (frame), 5); - label = gtk_label_new ("Graph type"); - gtk_notebook_append_page (GTK_NOTEBOOK (n), frame, label); + frame = control_panel_create_graph_type_group(g); + gtk_container_set_border_width(GTK_CONTAINER(frame), 5); + label = gtk_label_new("Graph type"); + gtk_notebook_append_page(GTK_NOTEBOOK(n), frame, label); } /* Treat this as a cancel, by calling "callback_close()" */ @@ -1043,930 +1051,931 @@ static gboolean callback_delete_event(GtkWidget *widget _U_, GdkEvent *event _U_, gpointer data) { - callback_close(NULL, data); - return FALSE; + callback_close(NULL, data); + return FALSE; } -static void callback_close (GtkWidget *widget _U_, gpointer data) +static void callback_close(GtkWidget *widget _U_, gpointer data) { - struct graph *g = (struct graph * )data; + struct graph *g = (struct graph * )data; - if (!(g->flags & GRAPH_DESTROYED)) { - g->flags |= GRAPH_DESTROYED; - graph_destroy ((struct graph * )data); - } + if (!(g->flags & GRAPH_DESTROYED)) { + g->flags |= GRAPH_DESTROYED; + graph_destroy((struct graph * )data); + } } static void callback_create_help(GtkWidget *widget _U_, gpointer data _U_) { - GtkWidget *toplevel, *vbox, *text, *scroll, *bbox, *close_bt; - GtkTextBuffer *buf; + GtkWidget *toplevel, *vbox, *text, *scroll, *bbox, *close_bt; + GtkTextBuffer *buf; - toplevel = dlg_window_new ("Help for TCP graphing"); - gtk_window_set_default_size(GTK_WINDOW(toplevel), 500, 400); + toplevel = dlg_window_new("Help for TCP graphing"); + gtk_window_set_default_size(GTK_WINDOW(toplevel), 500, 400); - vbox = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE); - gtk_container_set_border_width(GTK_CONTAINER(vbox), 12); - gtk_container_add (GTK_CONTAINER (toplevel), vbox); + vbox = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 12); + gtk_container_add(GTK_CONTAINER(toplevel), vbox); - scroll = scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll), - GTK_SHADOW_IN); - gtk_box_pack_start (GTK_BOX (vbox), scroll, TRUE, TRUE, 0); - text = gtk_text_view_new(); - gtk_text_view_set_editable(GTK_TEXT_VIEW(text), FALSE); - buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)); - gtk_text_buffer_set_text(buf, helptext, -1); - gtk_container_add (GTK_CONTAINER (scroll), text); + scroll = scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll), + GTK_SHADOW_IN); + gtk_box_pack_start(GTK_BOX(vbox), scroll, TRUE, TRUE, 0); + text = gtk_text_view_new(); + gtk_text_view_set_editable(GTK_TEXT_VIEW(text), FALSE); + buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)); + gtk_text_buffer_set_text(buf, helptext, -1); + gtk_container_add(GTK_CONTAINER(scroll), text); - /* Button row. */ - bbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL); - gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0); - gtk_widget_show(bbox); + /* Button row. */ + bbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL); + gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0); + gtk_widget_show(bbox); - close_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE); - window_set_cancel_button(toplevel, close_bt, window_cancel_button_cb); + close_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE); + window_set_cancel_button(toplevel, close_bt, window_cancel_button_cb); - g_signal_connect(toplevel, "delete_event", G_CALLBACK(window_delete_event_cb), NULL); + g_signal_connect(toplevel, "delete_event", G_CALLBACK(window_delete_event_cb), NULL); - gtk_widget_show_all (toplevel); - window_present(toplevel); + gtk_widget_show_all(toplevel); + window_present(toplevel); } static void get_mouse_position(GtkWidget *widget, int *pointer_x, int *pointer_y, GdkModifierType *mask) { #if GTK_CHECK_VERSION(3,0,0) - gdk_window_get_device_position (gtk_widget_get_window(widget), - gdk_device_manager_get_client_pointer( - gdk_display_get_device_manager( - gtk_widget_get_display(GTK_WIDGET(widget)))), - pointer_x, pointer_y, mask); + gdk_window_get_device_position(gtk_widget_get_window(widget), + gdk_device_manager_get_client_pointer( + gdk_display_get_device_manager( + gtk_widget_get_display(GTK_WIDGET(widget)))), + pointer_x, pointer_y, mask); #else - gdk_window_get_pointer (gtk_widget_get_window(widget), pointer_x, pointer_y, mask); + gdk_window_get_pointer(gtk_widget_get_window(widget), pointer_x, pointer_y, mask); #endif } -static void callback_time_origin (GtkWidget *toggle _U_, gpointer data) -{ - toggle_time_origin ((struct graph * )data); -} - -static void callback_seq_origin (GtkWidget *toggle _U_, gpointer data) -{ - toggle_seq_origin ((struct graph * )data); -} - -static GtkWidget *control_panel_create_zoom_group (struct graph *g) +static void callback_time_origin(GtkWidget *toggle _U_, gpointer data) +{ + toggle_time_origin((struct graph * )data); +} + +static void callback_seq_origin(GtkWidget *toggle _U_, gpointer data) +{ + toggle_seq_origin((struct graph * )data); +} + +static GtkWidget *control_panel_create_zoom_group(struct graph *g) { - GtkWidget *zoom_in, *zoom_out, *zoom_box, *zoom_frame; - GtkAdjustment *zoom_h_adj, *zoom_v_adj; - GtkWidget *zoom_inout_box, *zoom_h_step_label, *zoom_h_step; - GtkWidget *zoom_v_step_label, *zoom_v_step; - GtkWidget *zoom_separator1, *zoom_separator2, *zoom_step_grid, *zoom_grid; - GtkWidget *zoom_ratio_toggle, *zoom_same_toggle; - GtkWidget *zoom_h_entry, *zoom_v_entry; - GtkWidget *zoom_h_label, *zoom_v_label; - - zoom_in = gtk_radio_button_new_with_label (NULL, "in"); - zoom_out = gtk_radio_button_new_with_label ( - gtk_radio_button_get_group (GTK_RADIO_BUTTON (zoom_in)), "out"); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (zoom_in), TRUE); - zoom_inout_box = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0, FALSE); - gtk_box_pack_start (GTK_BOX (zoom_inout_box), zoom_in, FALSE, FALSE, 10); - gtk_box_pack_start (GTK_BOX (zoom_inout_box), zoom_out, FALSE, FALSE, 0); + GtkWidget *zoom_in, *zoom_out, *zoom_box, *zoom_frame; + GtkAdjustment *zoom_h_adj, *zoom_v_adj; + GtkWidget *zoom_inout_box, *zoom_h_step_label, *zoom_h_step; + GtkWidget *zoom_v_step_label, *zoom_v_step; + GtkWidget *zoom_separator1, *zoom_separator2, *zoom_step_grid, *zoom_grid; + GtkWidget *zoom_ratio_toggle, *zoom_same_toggle; + GtkWidget *zoom_h_entry, *zoom_v_entry; + GtkWidget *zoom_h_label, *zoom_v_label; - zoom_separator1 = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); + zoom_in = gtk_radio_button_new_with_label(NULL, "in"); + zoom_out = gtk_radio_button_new_with_label( + gtk_radio_button_get_group(GTK_RADIO_BUTTON(zoom_in)), "out"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(zoom_in), TRUE); + zoom_inout_box = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0, FALSE); + gtk_box_pack_start(GTK_BOX(zoom_inout_box), zoom_in, FALSE, FALSE, 10); + gtk_box_pack_start(GTK_BOX(zoom_inout_box), zoom_out, FALSE, FALSE, 0); - zoom_h_entry = gtk_entry_new (); - gtk_entry_set_text (GTK_ENTRY (zoom_h_entry), "1.000"); - gtk_editable_set_editable (GTK_EDITABLE (zoom_h_entry), FALSE); - zoom_h_label = gtk_label_new ("Horizontal:"); + zoom_separator1 = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL); - zoom_v_entry = gtk_entry_new (); - gtk_entry_set_text (GTK_ENTRY (zoom_v_entry), "1.000"); - gtk_editable_set_editable (GTK_EDITABLE (zoom_v_entry), FALSE); - zoom_v_label = gtk_label_new ("Vertical:"); - - g->zoom.widget.h_zoom = (GtkEntry * )zoom_h_entry; - g->zoom.widget.v_zoom = (GtkEntry * )zoom_v_entry; - - zoom_grid = ws_gtk_grid_new(); - ws_gtk_grid_attach_extended(GTK_GRID(zoom_grid), zoom_h_label, 0, 0, 1, 1, - GTK_FILL|GTK_EXPAND, 0, 5, 0); - ws_gtk_grid_attach_extended(GTK_GRID(zoom_grid), zoom_h_entry, 1, 0, 1, 1, - GTK_FILL|GTK_EXPAND, 0, 5, 0); - ws_gtk_grid_attach_extended(GTK_GRID(zoom_grid), zoom_v_label, 0, 1, 1, 1, - GTK_FILL|GTK_EXPAND, 0, 5, 0); - ws_gtk_grid_attach_extended(GTK_GRID(zoom_grid), zoom_v_entry, 1, 1, 1, 1, - GTK_FILL|GTK_EXPAND, 0, 5, 0); - - zoom_separator2 = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); - - zoom_h_adj = (GtkAdjustment * )gtk_adjustment_new ((gfloat)1.2, 1.0, 5, (gfloat)0.1, 1, 0); - zoom_h_step = gtk_spin_button_new (zoom_h_adj, 0, 1); - gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (zoom_h_step), TRUE); - zoom_h_step_label = gtk_label_new ("Horizontal step:"); - - zoom_v_adj = (GtkAdjustment * )gtk_adjustment_new ((gfloat)1.2, 1.0, 5, (gfloat)0.1, 1, 0); - zoom_v_step = gtk_spin_button_new (zoom_v_adj, 0, 1); - gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (zoom_v_step), TRUE); - zoom_v_step_label = gtk_label_new ("Vertical step:"); - - g->zoom.widget.h_step = (GtkSpinButton * )zoom_h_step; - g->zoom.widget.v_step = (GtkSpinButton * )zoom_v_step; - - zoom_same_toggle = gtk_check_button_new_with_label("Keep them the same"); - zoom_ratio_toggle = gtk_check_button_new_with_label("Preserve their ratio"); - g_object_set_data(G_OBJECT(zoom_same_toggle), "flag", (gpointer)ZOOM_STEPS_SAME); - g_object_set_data(G_OBJECT(zoom_ratio_toggle), "flag", - (gpointer)ZOOM_STEPS_KEEP_RATIO); - g_signal_connect(zoom_same_toggle, "clicked", G_CALLBACK(callback_zoom_flags), g); - g_signal_connect(zoom_ratio_toggle, "clicked", G_CALLBACK(callback_zoom_flags), g); - - zoom_step_grid = ws_gtk_grid_new(); - ws_gtk_grid_attach_extended(GTK_GRID(zoom_step_grid), zoom_h_step_label, 0, 0, 1, 1, - GTK_FILL|GTK_EXPAND, 0, 5, 0); - ws_gtk_grid_attach_extended(GTK_GRID(zoom_step_grid), zoom_h_step, 1, 0, 1, 1, - GTK_FILL|GTK_EXPAND, 0, 5, 0); - ws_gtk_grid_attach_extended(GTK_GRID(zoom_step_grid), zoom_v_step_label, 0, 1, 1, 1, - GTK_FILL|GTK_EXPAND, 0, 5, 0); - ws_gtk_grid_attach_extended(GTK_GRID(zoom_step_grid), zoom_v_step, 1, 1, 1, 1, - GTK_FILL|GTK_EXPAND, 0, 5, 0); - ws_gtk_grid_attach_extended(GTK_GRID(zoom_step_grid), zoom_same_toggle, 0, 2, 2, 1, - GTK_FILL|GTK_EXPAND, 0, 5, 0); - ws_gtk_grid_attach_extended(GTK_GRID(zoom_step_grid), zoom_ratio_toggle, 0, 3, 2, 1, - GTK_FILL|GTK_EXPAND, 0, 5, 0); - - zoom_box = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE); - gtk_box_pack_start (GTK_BOX (zoom_box), zoom_inout_box, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (zoom_box), zoom_separator1, TRUE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(zoom_box), zoom_grid, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (zoom_box), zoom_separator2, TRUE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(zoom_box), zoom_step_grid, TRUE, TRUE, 0); - zoom_frame = gtk_frame_new ("Zoom"); - gtk_container_add (GTK_CONTAINER (zoom_frame), zoom_box); - - g_object_set_data(G_OBJECT(zoom_h_step), "direction", GINT_TO_POINTER(0)); - g_object_set_data(G_OBJECT(zoom_v_step), "direction", GINT_TO_POINTER(1)); - - g_signal_connect(zoom_in, "toggled", G_CALLBACK(callback_zoom_inout), g); - g_signal_connect(zoom_h_step, "changed", G_CALLBACK(callback_zoom_step), g); - g_signal_connect(zoom_v_step, "changed", G_CALLBACK(callback_zoom_step), g); - - g->zoom.widget.in_toggle = (GtkToggleButton * )zoom_in; - g->zoom.widget.out_toggle = (GtkToggleButton * )zoom_out; - return zoom_frame; -} - -static void callback_zoom_inout (GtkWidget *toggle, gpointer data) -{ - struct graph *g = (struct graph * )data; - - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (toggle))) - g->zoom.flags &= ~ZOOM_OUT; - else - g->zoom.flags |= ZOOM_OUT; -} - -static void callback_zoom_step (GtkWidget *spin, gpointer data) -{ - struct graph *g = (struct graph * )data; - double value; - int direction; - double *zoom_this, *zoom_other; - GtkSpinButton *widget_this, *widget_other; - double old_this; - - direction = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(spin), "direction")); - value = gtk_spin_button_get_value (GTK_SPIN_BUTTON (spin)); - - if (direction) { - zoom_this = &g->zoom.step_y; - zoom_other = &g->zoom.step_x; - widget_this = g->zoom.widget.v_step; - widget_other = g->zoom.widget.h_step; - } else { - zoom_this = &g->zoom.step_x; - zoom_other = &g->zoom.step_y; - widget_this = g->zoom.widget.h_step; - widget_other = g->zoom.widget.v_step; - } - - old_this = *zoom_this; - *zoom_this = value; - if (g->zoom.flags & ZOOM_STEPS_SAME) { - *zoom_other = value; - gtk_spin_button_set_value (widget_other, (gfloat) *zoom_other); - } else if (g->zoom.flags & ZOOM_STEPS_KEEP_RATIO) { - double old_other = *zoom_other; - *zoom_other *= value / old_this; - if (*zoom_other < 1.0) { - *zoom_other = 1.0; - *zoom_this = old_this * 1.0 / old_other; - gtk_spin_button_set_value (widget_this, (gfloat) *zoom_this); - } else if (*zoom_other > 5.0) { - *zoom_other = 5.0; - *zoom_this = old_this * 5.0 / old_other; - gtk_spin_button_set_value (widget_this, (gfloat) *zoom_this); - } - gtk_spin_button_set_value (widget_other, (gfloat) *zoom_other); - } -} - -static void callback_zoom_flags (GtkWidget *toggle, gpointer data) -{ - struct graph *g = (struct graph * )data; - int flag = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(toggle), "flag")); - - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (toggle))) - g->zoom.flags |= flag; - else - g->zoom.flags &= ~flag; -} - -static void update_zoom_spins (struct graph *g) -{ - char s[32]; - - g_snprintf (s, sizeof(s), "%.3f", g->zoom.x / g->zoom.initial.x); - gtk_entry_set_text (g->zoom.widget.h_zoom, s); - g_snprintf (s, sizeof(s), "%.3f", g->zoom.y / g->zoom.initial.y); - gtk_entry_set_text (g->zoom.widget.v_zoom, s); -} - -static GtkWidget *control_panel_create_magnify_group (struct graph *g) -{ - GtkWidget *mag_width_label, *mag_width; - GtkWidget *mag_height_label, *mag_height; - GtkWidget *mag_x_label, *mag_x; - GtkWidget *mag_y_label, *mag_y; - GtkWidget *mag_wh_grid, *mag_zoom_frame, *mag_zoom_grid; - GtkWidget *mag_h_zoom_label, *mag_h_zoom; - GtkWidget *mag_v_zoom_label, *mag_v_zoom; - GtkWidget *mag_zoom_same, *mag_zoom_ratio; - GtkAdjustment *mag_width_adj, *mag_height_adj, *mag_x_adj, *mag_y_adj; - GtkAdjustment *mag_h_zoom_adj, *mag_v_zoom_adj; - GtkWidget *mag_box, *mag_frame; - - mag_width_label = gtk_label_new ("Width:"); - mag_width_adj = (GtkAdjustment * )gtk_adjustment_new (250,100,600,1,10,0); - mag_width = gtk_spin_button_new (mag_width_adj, 0, 0); - - mag_height_label = gtk_label_new ("Height:"); - mag_height_adj = (GtkAdjustment * )gtk_adjustment_new (250,100,600,1,10,0); - mag_height = gtk_spin_button_new (mag_height_adj, 0, 0); - - mag_x_label = gtk_label_new ("X:"); - mag_x_adj = (GtkAdjustment * )gtk_adjustment_new (0,-1000,1000,1,10,0); - mag_x = gtk_spin_button_new (mag_x_adj, 0, 0); - - mag_y_label = gtk_label_new ("Y:"); - mag_y_adj = (GtkAdjustment * )gtk_adjustment_new (0,-1000,1000,1,10,0); - mag_y = gtk_spin_button_new (mag_y_adj, 0, 0); - - mag_wh_grid = ws_gtk_grid_new(); - ws_gtk_grid_attach_extended(GTK_GRID(mag_wh_grid), mag_width_label, 0, 0, 1, 1, - GTK_FILL|GTK_EXPAND, 0, 5, 0); - ws_gtk_grid_attach_extended(GTK_GRID(mag_wh_grid), mag_width, 1, 0, 1, 1, - GTK_FILL|GTK_EXPAND, 0, 5, 0); - ws_gtk_grid_attach_extended(GTK_GRID(mag_wh_grid), mag_height_label, 0, 1, 1, 1, - GTK_FILL|GTK_EXPAND, 0, 5, 0); - ws_gtk_grid_attach_extended(GTK_GRID(mag_wh_grid), mag_height, 1, 1, 1, 1, - GTK_FILL|GTK_EXPAND, 0, 5, 0); - ws_gtk_grid_attach_extended(GTK_GRID(mag_wh_grid), mag_x_label, 0, 2, 1, 1, - GTK_FILL|GTK_EXPAND, 0, 5, 0); - ws_gtk_grid_attach_extended(GTK_GRID(mag_wh_grid), mag_x, 1, 2, 1, 1, - GTK_FILL|GTK_EXPAND, 0, 5, 0); - ws_gtk_grid_attach_extended(GTK_GRID(mag_wh_grid), mag_y_label, 0, 3, 1, 1, - GTK_FILL|GTK_EXPAND, 0, 5, 0); - ws_gtk_grid_attach_extended(GTK_GRID(mag_wh_grid), mag_y, 1, 3, 1, 1, - GTK_FILL|GTK_EXPAND, 0, 5, 0); - - mag_h_zoom_label = gtk_label_new ("Horizontal:"); - mag_h_zoom_adj = (GtkAdjustment *)gtk_adjustment_new(10.0, 1.0, 25.0, (gfloat)0.1, 1, 0); - mag_h_zoom = gtk_spin_button_new (mag_h_zoom_adj, 0, 1); - - mag_v_zoom_label = gtk_label_new ("Vertical:"); - mag_v_zoom_adj = (GtkAdjustment *)gtk_adjustment_new(10.0, 1.0, 25.0, (gfloat)0.1, 1, 0); - mag_v_zoom = gtk_spin_button_new (mag_v_zoom_adj, 0, 1); - - mag_zoom_same = gtk_check_button_new_with_label ("Keep them the same"); - mag_zoom_ratio = gtk_check_button_new_with_label("Preserve their ratio"); - - mag_zoom_grid = ws_gtk_grid_new(); - ws_gtk_grid_attach_extended(GTK_GRID(mag_zoom_grid), mag_h_zoom_label, 0, 0, 1, 1, - GTK_FILL|GTK_EXPAND, 0, 0, 0); - ws_gtk_grid_attach_extended(GTK_GRID(mag_zoom_grid), mag_h_zoom, 1, 0, 1, 1, - GTK_FILL|GTK_EXPAND, 0, 0, 0); - ws_gtk_grid_attach_extended(GTK_GRID(mag_zoom_grid), mag_v_zoom_label, 0, 1 , 1, 1, - GTK_FILL|GTK_EXPAND, 0, 0, 0); - ws_gtk_grid_attach_extended(GTK_GRID(mag_zoom_grid), mag_v_zoom, 1, 1, 1, 1, - GTK_FILL|GTK_EXPAND, 0, 0, 0); - ws_gtk_grid_attach_extended(GTK_GRID(mag_zoom_grid), mag_zoom_same, 0, 2, 2, 1, - GTK_FILL|GTK_EXPAND, 0, 0, 0); - ws_gtk_grid_attach_extended(GTK_GRID(mag_zoom_grid), mag_zoom_ratio, 0, 3, 2, 1, - GTK_FILL|GTK_EXPAND, 0, 0, 0); - - mag_zoom_frame = gtk_frame_new ("Magnify zoom"); - gtk_container_add(GTK_CONTAINER(mag_zoom_frame), mag_zoom_grid); - gtk_container_set_border_width (GTK_CONTAINER (mag_zoom_frame), 3); - - mag_box = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE); - gtk_box_pack_start(GTK_BOX(mag_box), mag_wh_grid, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (mag_box), mag_zoom_frame, TRUE, TRUE, 0); - mag_frame = gtk_frame_new ("Magnify"); - gtk_container_add (GTK_CONTAINER (mag_frame), mag_box); - - g->magnify.widget.h_zoom = (GtkSpinButton * )mag_h_zoom; - g->magnify.widget.v_zoom = (GtkSpinButton * )mag_v_zoom; - g_object_set_data(G_OBJECT(mag_h_zoom), "direction", GINT_TO_POINTER(0)); - g_object_set_data(G_OBJECT(mag_v_zoom), "direction", GINT_TO_POINTER(1)); - g_object_set_data(G_OBJECT(mag_zoom_same), "flag", (gpointer)MAGZOOMS_SAME); - g_object_set_data(G_OBJECT(mag_zoom_ratio), "flag", (gpointer)MAGZOOMS_SAME_RATIO); - - g_signal_connect(mag_width, "changed", G_CALLBACK(callback_mag_width), g); - g_signal_connect(mag_height, "changed", G_CALLBACK(callback_mag_height), g); - g_signal_connect(mag_x, "changed", G_CALLBACK(callback_mag_x), g); - g_signal_connect(mag_y, "changed", G_CALLBACK(callback_mag_y), g); - g_signal_connect(mag_h_zoom, "changed", G_CALLBACK(callback_mag_zoom), g); - g_signal_connect(mag_v_zoom, "changed", G_CALLBACK(callback_mag_zoom), g); - g_signal_connect(mag_zoom_same, "clicked", G_CALLBACK(callback_mag_flags), g); - g_signal_connect(mag_zoom_ratio, "clicked", G_CALLBACK(callback_mag_flags), g); - - return mag_frame; -} - -static void callback_mag_width (GtkWidget *spin, gpointer data) -{ - struct graph *g = (struct graph * )data; - - g->magnify.width = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(spin)); -} - -static void callback_mag_height (GtkWidget *spin, gpointer data) -{ - struct graph *g = (struct graph * )data; - - g->magnify.height = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin)); -} - -static void callback_mag_x (GtkWidget *spin, gpointer data) -{ - struct graph *g = (struct graph * )data; - - g->magnify.offset.x=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin)); -} - -static void callback_mag_y (GtkWidget *spin, gpointer data) -{ - struct graph *g = (struct graph * )data; - - g->magnify.offset.y=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin)); -} - -static void callback_mag_zoom (GtkWidget *spin, gpointer data) -{ - struct graph *g = (struct graph * )data; - double value; - int direction; - double *zoom_this, *zoom_other; - GtkSpinButton *widget_this, *widget_other; - double old_this; - - if (g->magnify.flags & MAGZOOMS_IGNORE) { - printf ("refusing callback for %s zoom widget.\n", (GtkSpinButton * )spin==g->magnify.widget.h_zoom ? "horizontal" : "vertical"); - g->magnify.flags &= ~MAGZOOMS_IGNORE; - return; - } - direction = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(spin), "direction")); - value = gtk_spin_button_get_value (GTK_SPIN_BUTTON (spin)); + zoom_h_entry = gtk_entry_new(); + gtk_entry_set_text(GTK_ENTRY(zoom_h_entry), "1.000"); + gtk_editable_set_editable(GTK_EDITABLE(zoom_h_entry), FALSE); + zoom_h_label = gtk_label_new("Horizontal:"); - if (direction) { - zoom_this = &g->magnify.zoom.y; - zoom_other = &g->magnify.zoom.x; - widget_this = g->magnify.widget.v_zoom; - widget_other = g->magnify.widget.h_zoom; - } else { - zoom_this = &g->magnify.zoom.x; - zoom_other = &g->magnify.zoom.y; - widget_this = g->magnify.widget.h_zoom; - widget_other = g->magnify.widget.v_zoom; - } + zoom_v_entry = gtk_entry_new(); + gtk_entry_set_text(GTK_ENTRY(zoom_v_entry), "1.000"); + gtk_editable_set_editable(GTK_EDITABLE(zoom_v_entry), FALSE); + zoom_v_label = gtk_label_new("Vertical:"); + + g->zoom.widget.h_zoom = (GtkEntry * )zoom_h_entry; + g->zoom.widget.v_zoom = (GtkEntry * )zoom_v_entry; + + zoom_grid = ws_gtk_grid_new(); + ws_gtk_grid_attach_extended(GTK_GRID(zoom_grid), zoom_h_label, 0, 0, 1, 1, + GTK_FILL|GTK_EXPAND, 0, 5, 0); + ws_gtk_grid_attach_extended(GTK_GRID(zoom_grid), zoom_h_entry, 1, 0, 1, 1, + GTK_FILL|GTK_EXPAND, 0, 5, 0); + ws_gtk_grid_attach_extended(GTK_GRID(zoom_grid), zoom_v_label, 0, 1, 1, 1, + GTK_FILL|GTK_EXPAND, 0, 5, 0); + ws_gtk_grid_attach_extended(GTK_GRID(zoom_grid), zoom_v_entry, 1, 1, 1, 1, + GTK_FILL|GTK_EXPAND, 0, 5, 0); + + zoom_separator2 = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL); + + zoom_h_adj = (GtkAdjustment * )gtk_adjustment_new((gfloat)1.2, 1.0, 5, (gfloat)0.1, 1, 0); + zoom_h_step = gtk_spin_button_new(zoom_h_adj, 0, 1); + gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(zoom_h_step), TRUE); + zoom_h_step_label = gtk_label_new("Horizontal step:"); + + zoom_v_adj = (GtkAdjustment * )gtk_adjustment_new((gfloat)1.2, 1.0, 5, (gfloat)0.1, 1, 0); + zoom_v_step = gtk_spin_button_new(zoom_v_adj, 0, 1); + gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(zoom_v_step), TRUE); + zoom_v_step_label = gtk_label_new("Vertical step:"); + + g->zoom.widget.h_step = (GtkSpinButton * )zoom_h_step; + g->zoom.widget.v_step = (GtkSpinButton * )zoom_v_step; + + zoom_same_toggle = gtk_check_button_new_with_label("Keep them the same"); + zoom_ratio_toggle = gtk_check_button_new_with_label("Preserve their ratio"); + g_object_set_data(G_OBJECT(zoom_same_toggle), "flag", (gpointer)ZOOM_STEPS_SAME); + g_object_set_data(G_OBJECT(zoom_ratio_toggle), "flag", + (gpointer)ZOOM_STEPS_KEEP_RATIO); + g_signal_connect(zoom_same_toggle, "clicked", G_CALLBACK(callback_zoom_flags), g); + g_signal_connect(zoom_ratio_toggle, "clicked", G_CALLBACK(callback_zoom_flags), g); + + zoom_step_grid = ws_gtk_grid_new(); + ws_gtk_grid_attach_extended(GTK_GRID(zoom_step_grid), zoom_h_step_label, 0, 0, 1, 1, + GTK_FILL|GTK_EXPAND, 0, 5, 0); + ws_gtk_grid_attach_extended(GTK_GRID(zoom_step_grid), zoom_h_step, 1, 0, 1, 1, + GTK_FILL|GTK_EXPAND, 0, 5, 0); + ws_gtk_grid_attach_extended(GTK_GRID(zoom_step_grid), zoom_v_step_label, 0, 1, 1, 1, + GTK_FILL|GTK_EXPAND, 0, 5, 0); + ws_gtk_grid_attach_extended(GTK_GRID(zoom_step_grid), zoom_v_step, 1, 1, 1, 1, + GTK_FILL|GTK_EXPAND, 0, 5, 0); + ws_gtk_grid_attach_extended(GTK_GRID(zoom_step_grid), zoom_same_toggle, 0, 2, 2, 1, + GTK_FILL|GTK_EXPAND, 0, 5, 0); + ws_gtk_grid_attach_extended(GTK_GRID(zoom_step_grid), zoom_ratio_toggle, 0, 3, 2, 1, + GTK_FILL|GTK_EXPAND, 0, 5, 0); + + zoom_box = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE); + gtk_box_pack_start(GTK_BOX(zoom_box), zoom_inout_box, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(zoom_box), zoom_separator1, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(zoom_box), zoom_grid, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(zoom_box), zoom_separator2, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(zoom_box), zoom_step_grid, TRUE, TRUE, 0); + zoom_frame = gtk_frame_new("Zoom"); + gtk_container_add(GTK_CONTAINER(zoom_frame), zoom_box); + + g_object_set_data(G_OBJECT(zoom_h_step), "direction", GINT_TO_POINTER(0)); + g_object_set_data(G_OBJECT(zoom_v_step), "direction", GINT_TO_POINTER(1)); + + g_signal_connect(zoom_in, "toggled", G_CALLBACK(callback_zoom_inout), g); + g_signal_connect(zoom_h_step, "changed", G_CALLBACK(callback_zoom_step), g); + g_signal_connect(zoom_v_step, "changed", G_CALLBACK(callback_zoom_step), g); + + g->zoom.widget.in_toggle = (GtkToggleButton * )zoom_in; + g->zoom.widget.out_toggle = (GtkToggleButton * )zoom_out; + return zoom_frame; +} + +static void callback_zoom_inout(GtkWidget *toggle, gpointer data) +{ + struct graph *g = (struct graph * )data; + + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle))) + g->zoom.flags &= ~ZOOM_OUT; + else + g->zoom.flags |= ZOOM_OUT; +} + +static void callback_zoom_step(GtkWidget *spin, gpointer data) +{ + struct graph *g = (struct graph * )data; + double value; + int direction; + double *zoom_this, *zoom_other; + GtkSpinButton *widget_this, *widget_other; + double old_this; + + direction = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(spin), "direction")); + value = gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)); + + if (direction) { + zoom_this = &g->zoom.step_y; + zoom_other = &g->zoom.step_x; + widget_this = g->zoom.widget.v_step; + widget_other = g->zoom.widget.h_step; + } else { + zoom_this = &g->zoom.step_x; + zoom_other = &g->zoom.step_y; + widget_this = g->zoom.widget.h_step; + widget_other = g->zoom.widget.v_step; + } + + old_this = *zoom_this; + *zoom_this = value; + if (g->zoom.flags & ZOOM_STEPS_SAME) { + *zoom_other = value; + gtk_spin_button_set_value(widget_other, (gfloat) *zoom_other); + } else if (g->zoom.flags & ZOOM_STEPS_KEEP_RATIO) { + double old_other = *zoom_other; + *zoom_other *= value / old_this; + if (*zoom_other < 1.0) { + *zoom_other = 1.0; + *zoom_this = old_this * 1.0 / old_other; + gtk_spin_button_set_value(widget_this, (gfloat) *zoom_this); + } else if (*zoom_other > 5.0) { + *zoom_other = 5.0; + *zoom_this = old_this * 5.0 / old_other; + gtk_spin_button_set_value(widget_this, (gfloat) *zoom_this); + } + gtk_spin_button_set_value(widget_other, (gfloat) *zoom_other); + } +} + +static void callback_zoom_flags(GtkWidget *toggle, gpointer data) +{ + struct graph *g = (struct graph * )data; + int flag = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(toggle), "flag")); + + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle))) + g->zoom.flags |= flag; + else + g->zoom.flags &= ~flag; +} + +static void update_zoom_spins(struct graph *g) +{ + char s[32]; + + g_snprintf(s, sizeof(s), "%.3f", g->zoom.x / g->zoom.initial.x); + gtk_entry_set_text(g->zoom.widget.h_zoom, s); + g_snprintf(s, sizeof(s), "%.3f", g->zoom.y / g->zoom.initial.y); + gtk_entry_set_text(g->zoom.widget.v_zoom, s); +} + +static GtkWidget *control_panel_create_magnify_group(struct graph *g) +{ + GtkWidget *mag_width_label, *mag_width; + GtkWidget *mag_height_label, *mag_height; + GtkWidget *mag_x_label, *mag_x; + GtkWidget *mag_y_label, *mag_y; + GtkWidget *mag_wh_grid, *mag_zoom_frame, *mag_zoom_grid; + GtkWidget *mag_h_zoom_label, *mag_h_zoom; + GtkWidget *mag_v_zoom_label, *mag_v_zoom; + GtkWidget *mag_zoom_same, *mag_zoom_ratio; + GtkAdjustment *mag_width_adj, *mag_height_adj, *mag_x_adj, *mag_y_adj; + GtkAdjustment *mag_h_zoom_adj, *mag_v_zoom_adj; + GtkWidget *mag_box, *mag_frame; + + mag_width_label = gtk_label_new("Width:"); + mag_width_adj = (GtkAdjustment * )gtk_adjustment_new(250, 100, 600, 1, 10, 0); + mag_width = gtk_spin_button_new(mag_width_adj, 0, 0); + + mag_height_label = gtk_label_new("Height:"); + mag_height_adj = (GtkAdjustment * )gtk_adjustment_new(250, 100, 600, 1, 10, 0); + mag_height = gtk_spin_button_new(mag_height_adj, 0, 0); + + mag_x_label = gtk_label_new("X:"); + mag_x_adj = (GtkAdjustment * )gtk_adjustment_new(0, -1000, 1000, 1, 10, 0); + mag_x = gtk_spin_button_new(mag_x_adj, 0, 0); + + mag_y_label = gtk_label_new("Y:"); + mag_y_adj = (GtkAdjustment * )gtk_adjustment_new(0, -1000, 1000, 1, 10, 0); + mag_y = gtk_spin_button_new(mag_y_adj, 0, 0); + + mag_wh_grid = ws_gtk_grid_new(); + ws_gtk_grid_attach_extended(GTK_GRID(mag_wh_grid), mag_width_label, 0, 0, 1, 1, + GTK_FILL|GTK_EXPAND, 0, 5, 0); + ws_gtk_grid_attach_extended(GTK_GRID(mag_wh_grid), mag_width, 1, 0, 1, 1, + GTK_FILL|GTK_EXPAND, 0, 5, 0); + ws_gtk_grid_attach_extended(GTK_GRID(mag_wh_grid), mag_height_label, 0, 1, 1, 1, + GTK_FILL|GTK_EXPAND, 0, 5, 0); + ws_gtk_grid_attach_extended(GTK_GRID(mag_wh_grid), mag_height, 1, 1, 1, 1, + GTK_FILL|GTK_EXPAND, 0, 5, 0); + ws_gtk_grid_attach_extended(GTK_GRID(mag_wh_grid), mag_x_label, 0, 2, 1, 1, + GTK_FILL|GTK_EXPAND, 0, 5, 0); + ws_gtk_grid_attach_extended(GTK_GRID(mag_wh_grid), mag_x, 1, 2, 1, 1, + GTK_FILL|GTK_EXPAND, 0, 5, 0); + ws_gtk_grid_attach_extended(GTK_GRID(mag_wh_grid), mag_y_label, 0, 3, 1, 1, + GTK_FILL|GTK_EXPAND, 0, 5, 0); + ws_gtk_grid_attach_extended(GTK_GRID(mag_wh_grid), mag_y, 1, 3, 1, 1, + GTK_FILL|GTK_EXPAND, 0, 5, 0); + + mag_h_zoom_label = gtk_label_new("Horizontal:"); + mag_h_zoom_adj = (GtkAdjustment *)gtk_adjustment_new(10.0, 1.0, 25.0, (gfloat)0.1, 1, 0); + mag_h_zoom = gtk_spin_button_new(mag_h_zoom_adj, 0, 1); + + mag_v_zoom_label = gtk_label_new("Vertical:"); + mag_v_zoom_adj = (GtkAdjustment *)gtk_adjustment_new(10.0, 1.0, 25.0, (gfloat)0.1, 1, 0); + mag_v_zoom = gtk_spin_button_new(mag_v_zoom_adj, 0, 1); + + mag_zoom_same = gtk_check_button_new_with_label("Keep them the same"); + mag_zoom_ratio = gtk_check_button_new_with_label("Preserve their ratio"); + + mag_zoom_grid = ws_gtk_grid_new(); + ws_gtk_grid_attach_extended(GTK_GRID(mag_zoom_grid), mag_h_zoom_label, 0, 0, 1, 1, + GTK_FILL|GTK_EXPAND, 0, 0, 0); + ws_gtk_grid_attach_extended(GTK_GRID(mag_zoom_grid), mag_h_zoom, 1, 0, 1, 1, + GTK_FILL|GTK_EXPAND, 0, 0, 0); + ws_gtk_grid_attach_extended(GTK_GRID(mag_zoom_grid), mag_v_zoom_label, 0, 1 , 1, 1, + GTK_FILL|GTK_EXPAND, 0, 0, 0); + ws_gtk_grid_attach_extended(GTK_GRID(mag_zoom_grid), mag_v_zoom, 1, 1, 1, 1, + GTK_FILL|GTK_EXPAND, 0, 0, 0); + ws_gtk_grid_attach_extended(GTK_GRID(mag_zoom_grid), mag_zoom_same, 0, 2, 2, 1, + GTK_FILL|GTK_EXPAND, 0, 0, 0); + ws_gtk_grid_attach_extended(GTK_GRID(mag_zoom_grid), mag_zoom_ratio, 0, 3, 2, 1, + GTK_FILL|GTK_EXPAND, 0, 0, 0); + + mag_zoom_frame = gtk_frame_new("Magnify zoom"); + gtk_container_add(GTK_CONTAINER(mag_zoom_frame), mag_zoom_grid); + gtk_container_set_border_width(GTK_CONTAINER(mag_zoom_frame), 3); + + mag_box = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE); + gtk_box_pack_start(GTK_BOX(mag_box), mag_wh_grid, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(mag_box), mag_zoom_frame, TRUE, TRUE, 0); + mag_frame = gtk_frame_new("Magnify"); + gtk_container_add(GTK_CONTAINER(mag_frame), mag_box); + + g->magnify.widget.h_zoom = (GtkSpinButton * )mag_h_zoom; + g->magnify.widget.v_zoom = (GtkSpinButton * )mag_v_zoom; + g_object_set_data(G_OBJECT(mag_h_zoom), "direction", GINT_TO_POINTER(0)); + g_object_set_data(G_OBJECT(mag_v_zoom), "direction", GINT_TO_POINTER(1)); + g_object_set_data(G_OBJECT(mag_zoom_same), "flag", (gpointer)MAGZOOMS_SAME); + g_object_set_data(G_OBJECT(mag_zoom_ratio), "flag", (gpointer)MAGZOOMS_SAME_RATIO); + + g_signal_connect(mag_width, "changed", G_CALLBACK(callback_mag_width), g); + g_signal_connect(mag_height, "changed", G_CALLBACK(callback_mag_height), g); + g_signal_connect(mag_x, "changed", G_CALLBACK(callback_mag_x), g); + g_signal_connect(mag_y, "changed", G_CALLBACK(callback_mag_y), g); + g_signal_connect(mag_h_zoom, "changed", G_CALLBACK(callback_mag_zoom), g); + g_signal_connect(mag_v_zoom, "changed", G_CALLBACK(callback_mag_zoom), g); + g_signal_connect(mag_zoom_same, "clicked", G_CALLBACK(callback_mag_flags), g); + g_signal_connect(mag_zoom_ratio, "clicked", G_CALLBACK(callback_mag_flags), g); + + return mag_frame; +} + +static void callback_mag_width(GtkWidget *spin, gpointer data) +{ + struct graph *g = (struct graph * )data; + + g->magnify.width = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin)); +} + +static void callback_mag_height(GtkWidget *spin, gpointer data) +{ + struct graph *g = (struct graph * )data; + + g->magnify.height = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin)); +} + +static void callback_mag_x(GtkWidget *spin, gpointer data) +{ + struct graph *g = (struct graph * )data; + + g->magnify.offset.x = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin)); +} + +static void callback_mag_y(GtkWidget *spin, gpointer data) +{ + struct graph *g = (struct graph * )data; + + g->magnify.offset.y = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin)); +} + +static void callback_mag_zoom(GtkWidget *spin, gpointer data) +{ + struct graph *g = (struct graph * )data; + double value; + int direction; + double *zoom_this, *zoom_other; + GtkSpinButton *widget_this, *widget_other; + double old_this; + + if (g->magnify.flags & MAGZOOMS_IGNORE) { + printf("refusing callback for %s zoom widget.\n", + ((GtkSpinButton * )spin == g->magnify.widget.h_zoom) ? "horizontal" : "vertical"); + g->magnify.flags &= ~MAGZOOMS_IGNORE; + return; + } + direction = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(spin), "direction")); + value = gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)); - old_this = *zoom_this; - *zoom_this = value; - if (g->magnify.flags & MAGZOOMS_SAME) { - *zoom_other = value; - /* g->magnify.flags |= MAGZOOMS_IGNORE; */ - gtk_spin_button_set_value (widget_other, (gfloat) *zoom_other); - } else if (g->magnify.flags & MAGZOOMS_SAME_RATIO) { - double old_other = *zoom_other; - *zoom_other *= value / old_this; - if (*zoom_other < 1.0) { - *zoom_other = 1.0; - *zoom_this = old_this * 1.0 / old_other; - /* g->magnify.flags |= MAGZOOMS_IGNORE; */ - gtk_spin_button_set_value (widget_this, (gfloat) *zoom_this); - } else if (*zoom_other > 25.0) { - *zoom_other = 25.0; - *zoom_this = old_this * 25.0 / old_other; - /* g->magnify.flags |= MAGZOOMS_IGNORE; */ - gtk_spin_button_set_value (widget_this, (gfloat) *zoom_this); - } - /* g->magnify.flags |= MAGZOOMS_IGNORE; */ - gtk_spin_button_set_value (widget_other, (gfloat) *zoom_other); - } + if (direction) { + zoom_this = &g->magnify.zoom.y; + zoom_other = &g->magnify.zoom.x; + widget_this = g->magnify.widget.v_zoom; + widget_other = g->magnify.widget.h_zoom; + } else { + zoom_this = &g->magnify.zoom.x; + zoom_other = &g->magnify.zoom.y; + widget_this = g->magnify.widget.h_zoom; + widget_other = g->magnify.widget.v_zoom; + } + + old_this = *zoom_this; + *zoom_this = value; + if (g->magnify.flags & MAGZOOMS_SAME) { + *zoom_other = value; + /* g->magnify.flags |= MAGZOOMS_IGNORE; */ + gtk_spin_button_set_value(widget_other, (gfloat) *zoom_other); + } else if (g->magnify.flags & MAGZOOMS_SAME_RATIO) { + double old_other = *zoom_other; + *zoom_other *= value / old_this; + if (*zoom_other < 1.0) { + *zoom_other = 1.0; + *zoom_this = old_this * 1.0 / old_other; + /* g->magnify.flags |= MAGZOOMS_IGNORE; */ + gtk_spin_button_set_value(widget_this, (gfloat) *zoom_this); + } else if (*zoom_other > 25.0) { + *zoom_other = 25.0; + *zoom_this = old_this * 25.0 / old_other; + /* g->magnify.flags |= MAGZOOMS_IGNORE; */ + gtk_spin_button_set_value(widget_this, (gfloat) *zoom_this); + } + /* g->magnify.flags |= MAGZOOMS_IGNORE; */ + gtk_spin_button_set_value(widget_other, (gfloat) *zoom_other); + } } -static void callback_mag_flags (GtkWidget *toggle, gpointer data) +static void callback_mag_flags(GtkWidget *toggle, gpointer data) { - struct graph *g = (struct graph * )data; - int flag = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(toggle), "flag")); + struct graph *g = (struct graph * )data; + int flag = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(toggle), "flag")); - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (toggle))) - g->magnify.flags |= flag; - else - g->magnify.flags &= ~flag; + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle))) + g->magnify.flags |= flag; + else + g->magnify.flags &= ~flag; } -static GtkWidget *control_panel_create_zoomlock_group (struct graph *g) +static GtkWidget *control_panel_create_zoomlock_group(struct graph *g) { - GtkWidget *zoom_lock_h, *zoom_lock_v, *zoom_lock_none, *zoom_lock_box; - GtkWidget *zoom_lock_frame; + GtkWidget *zoom_lock_h, *zoom_lock_v, *zoom_lock_none, *zoom_lock_box; + GtkWidget *zoom_lock_frame; - zoom_lock_none = gtk_radio_button_new_with_label (NULL, "none"); - zoom_lock_h = gtk_radio_button_new_with_label ( - gtk_radio_button_get_group (GTK_RADIO_BUTTON (zoom_lock_none)), - "horizontal"); - zoom_lock_v = gtk_radio_button_new_with_label ( - gtk_radio_button_get_group (GTK_RADIO_BUTTON (zoom_lock_none)), - "vertical"); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (zoom_lock_none), TRUE); - zoom_lock_box = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0, FALSE); - gtk_box_pack_start(GTK_BOX(zoom_lock_box), zoom_lock_none, - TRUE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(zoom_lock_box), zoom_lock_h, TRUE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(zoom_lock_box), zoom_lock_v, TRUE, TRUE, 0); - zoom_lock_frame = gtk_frame_new ("Zoom lock:"); - gtk_container_add (GTK_CONTAINER (zoom_lock_frame), zoom_lock_box); - - g_signal_connect(zoom_lock_h, "toggled", G_CALLBACK(callback_zoomlock_h), g); - g_signal_connect(zoom_lock_v, "toggled", G_CALLBACK(callback_zoomlock_v), g); - - return zoom_lock_frame; -} - -static void callback_zoomlock_h (GtkWidget *toggle, gpointer data) -{ - struct graph *g = (struct graph * )data; - - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (toggle))) - g->zoom.flags |= ZOOM_HLOCK; - else - g->zoom.flags &= ~ZOOM_HLOCK; -} - -static void callback_zoomlock_v (GtkWidget *toggle, gpointer data) -{ - struct graph *g = (struct graph * )data; - - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (toggle))) - g->zoom.flags |= ZOOM_VLOCK; - else - g->zoom.flags &= ~ZOOM_VLOCK; -} - -static GtkWidget *control_panel_create_cross_group (struct graph *g) -{ - GtkWidget *on, *off, *box, *frame, *vbox, *label; - - label = gtk_label_new ("Crosshairs:"); - off = gtk_radio_button_new_with_label (NULL, "off"); - on = gtk_radio_button_new_with_label ( - gtk_radio_button_get_group (GTK_RADIO_BUTTON (off)), "on"); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (off), TRUE); - box = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0, FALSE); - gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 10); - gtk_box_pack_start (GTK_BOX (box), off, FALSE, FALSE, 10); - gtk_box_pack_start (GTK_BOX (box), on, FALSE, FALSE, 0); - vbox = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE); - gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, FALSE, 15); - /* frame = gtk_frame_new ("Cross:"); */ - frame = gtk_frame_new (NULL); - gtk_container_add (GTK_CONTAINER (frame), vbox); - - g_signal_connect(on, "toggled", G_CALLBACK(callback_cross_on_off), g); - - g->cross.on_toggle = (GtkToggleButton * )on; - g->cross.off_toggle = (GtkToggleButton * )off; - - return frame; -} -static void callback_cross_on_off (GtkWidget *toggle, gpointer data) -{ - struct graph *g = (struct graph * )data; - - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (toggle))) { - int x, y; - g->cross.draw = TRUE; - get_mouse_position(g->drawing_area, &x, &y, 0); - cross_draw (g, x, y); - } else { - g->cross.draw = FALSE; - if (g->cross.erase_needed) { - cross_erase (g); - } - } -} - -static GtkWidget *control_panel_create_graph_type_group (struct graph *g) -{ - GtkWidget *graph_tseqttrace, *graph_tseqstevens; - GtkWidget *graph_tput, *graph_rtt, *graph_sep, *graph_init, *graph_box; - GtkWidget *graph_frame; - GtkWidget *graph_wscale; - - graph_tput = gtk_radio_button_new_with_label (NULL, "Throughput"); - graph_tseqttrace = gtk_radio_button_new_with_label ( - gtk_radio_button_get_group (GTK_RADIO_BUTTON (graph_tput)), - "Time/Sequence (tcptrace-style)"); - graph_tseqstevens = gtk_radio_button_new_with_label ( - gtk_radio_button_get_group (GTK_RADIO_BUTTON (graph_tput)), - "Time/Sequence (Stevens'-style)"); - graph_rtt = gtk_radio_button_new_with_label ( - gtk_radio_button_get_group (GTK_RADIO_BUTTON (graph_tput)), - "Round-trip Time"); - graph_wscale = gtk_radio_button_new_with_label ( - gtk_radio_button_get_group (GTK_RADIO_BUTTON (graph_tput)), - "Window Scaling"); - - switch (g->type) { - case GRAPH_TSEQ_STEVENS: - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(graph_tseqstevens),TRUE); - break; - case GRAPH_TSEQ_TCPTRACE: - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(graph_tseqttrace),TRUE); - break; - case GRAPH_THROUGHPUT: - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(graph_tput), TRUE); - break; - case GRAPH_RTT: - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(graph_rtt), TRUE); - break; - case GRAPH_WSCALE: - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(graph_wscale), TRUE); - break; - } - graph_init = gtk_check_button_new_with_label ("Init on change"); - graph_sep = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); - graph_box = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE); - gtk_box_pack_start (GTK_BOX (graph_box), graph_rtt, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (graph_box), graph_tput, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (graph_box), graph_tseqstevens, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (graph_box), graph_tseqttrace, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (graph_box), graph_wscale, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (graph_box), graph_sep, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (graph_box), graph_init, TRUE, TRUE, 0); - graph_frame = gtk_frame_new ("Graph type:"); - gtk_container_add (GTK_CONTAINER (graph_frame), graph_box); - - g_object_set_data(G_OBJECT(graph_tseqstevens), "new-graph-type", - GINT_TO_POINTER(GRAPH_TSEQ_STEVENS)); - g_object_set_data(G_OBJECT(graph_tseqttrace), "new-graph-type", - GINT_TO_POINTER(GRAPH_TSEQ_TCPTRACE)); - g_object_set_data(G_OBJECT(graph_tput), "new-graph-type", - GINT_TO_POINTER(GRAPH_THROUGHPUT)); - g_object_set_data(G_OBJECT(graph_rtt), "new-graph-type", - GINT_TO_POINTER(GRAPH_RTT)); - g_object_set_data(G_OBJECT(graph_wscale), "new-graph-type", - GINT_TO_POINTER(GRAPH_WSCALE)); - - g->gt.graph_wscale = (GtkToggleButton *)graph_wscale; - g->gt.graph_rtt = (GtkToggleButton * )graph_rtt; - g->gt.graph_tput = (GtkToggleButton * )graph_tput; - g->gt.graph_tseqstevens = (GtkToggleButton * )graph_tseqstevens; - g->gt.graph_tseqttrace = (GtkToggleButton * )graph_tseqttrace; - - g_signal_connect(graph_tseqttrace, "toggled", G_CALLBACK(callback_graph_type), g); - g_signal_connect(graph_tseqstevens, "toggled", G_CALLBACK(callback_graph_type), g); - g_signal_connect(graph_tput, "toggled", G_CALLBACK(callback_graph_type), g); - g_signal_connect(graph_rtt, "toggled", G_CALLBACK(callback_graph_type), g); - g_signal_connect(graph_wscale, "toggled", G_CALLBACK(callback_graph_type), g); - g_signal_connect(graph_init, "toggled", G_CALLBACK(callback_graph_init_on_typechg), g); - - return graph_frame; -} - -static void callback_graph_type (GtkWidget *toggle, gpointer data) -{ - int old_type, new_type; - struct graph *g = (struct graph * )data; - - new_type = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(toggle),"new-graph-type")); - - if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (toggle))) - return; - - old_type = g->type; - g->type = new_type; - - graph_element_lists_free (g); - graph_element_lists_initialize (g); - - if (old_type == GRAPH_THROUGHPUT || new_type == GRAPH_THROUGHPUT) { - /* throughput graph uses differently constructed segment list so we - * need to recreate it */ - graph_segment_list_free (g); - graph_segment_list_get (g, TRUE); - } - - if (g->flags & GRAPH_INIT_ON_TYPE_CHANGE) { - g->geom.width = g->wp.width; - g->geom.height = g->wp.height; - g->geom.x = g->wp.x; - g->geom.y = g->wp.y; - } - g->x_axis->min = g->y_axis->min = 0; - gtk_toggle_button_set_active (g->gui.time_orig_conn, TRUE); - gtk_toggle_button_set_active (g->gui.seq_orig_isn, TRUE); - graph_init_sequence (g); -} - -static void callback_graph_init_on_typechg (GtkWidget *toggle _U_, gpointer data) -{ - ((struct graph * )data)->flags ^= GRAPH_INIT_ON_TYPE_CHANGE; -} - -static struct graph *graph_new (void) -{ - struct graph *g; - - g = (struct graph * )g_malloc0 (sizeof (struct graph)); - graph_element_lists_initialize (g); - - g->x_axis = (struct axis * )g_malloc0 (sizeof (struct axis)); - g->y_axis = (struct axis * )g_malloc0 (sizeof (struct axis)); - g->x_axis->g = g; - g->x_axis->flags = 0; - g->x_axis->flags |= AXIS_ORIENTATION; - g->x_axis->s.x = g->x_axis->s.y = 0; - g->x_axis->s.height = HAXIS_INIT_HEIGHT; - g->x_axis->p.x = VAXIS_INIT_WIDTH; - g->x_axis->p.height = HAXIS_INIT_HEIGHT; - g->y_axis->g = g; - g->y_axis->flags = 0; - g->y_axis->flags &= ~AXIS_ORIENTATION; - g->y_axis->p.x = g->y_axis->p.y = 0; - g->y_axis->p.width = VAXIS_INIT_WIDTH; - g->y_axis->s.x = 0; - g->y_axis->s.y = TITLEBAR_HEIGHT; - g->y_axis->s.width = VAXIS_INIT_WIDTH; - - return g; -} - -static void graph_initialize_values (struct graph *g) -{ - g->geom.width = g->wp.width = 750; - g->geom.height = g->wp.height = 550; - g->geom.x = g->wp.x = VAXIS_INIT_WIDTH; - g->geom.y = g->wp.y = TITLEBAR_HEIGHT; - g->flags = 0; - /* g->zoom.x = g->zoom.y = 1.0; */ - g->zoom.step_x = g->zoom.step_y = 1.2; - g->zoom.flags = 0; - g->cross.draw = g->cross.erase_needed = FALSE; - g->zoomrect_erase_needed = FALSE; - g->grab.grabbed = 0; - g->magnify.active = 0; - g->magnify.offset.x = g->magnify.offset.y = 0; - g->magnify.width = g->magnify.height = 250; - g->magnify.zoom.x = g->magnify.zoom.y = 10.0; - g->magnify.flags = 0; -} - -static void graph_init_sequence (struct graph *g) -{ - debug(DBS_FENTRY) puts ("graph_init_sequence()"); - - graph_type_dependent_initialize (g); - g->zoom.initial.x = g->zoom.x; - g->zoom.initial.y = g->zoom.y; - graph_element_lists_make (g); - g->x_axis->s.width = g->wp.width; - g->x_axis->p.width = g->x_axis->s.width + RMARGIN_WIDTH; - g->x_axis->p.y = TITLEBAR_HEIGHT + g->wp.height; - g->x_axis->s.height = g->x_axis->p.height = HAXIS_INIT_HEIGHT; - g->y_axis->s.height = g->wp.height; - g->y_axis->p.height = g->wp.height + TITLEBAR_HEIGHT; - graph_pixmaps_create (g); - axis_pixmaps_create (g->y_axis); - axis_pixmaps_create (g->x_axis); - graph_title_pixmap_create (g); - graph_title_pixmap_draw (g); - graph_title_pixmap_display (g); - graph_display (g); - axis_display (g->y_axis); - axis_display (g->x_axis); -} - -static void graph_type_dependent_initialize (struct graph *g) -{ - switch (g->type) { - case GRAPH_TSEQ_STEVENS: - case GRAPH_TSEQ_TCPTRACE: - tseq_initialize (g); - break; - case GRAPH_THROUGHPUT: - tput_initialize (g); - break; - case GRAPH_RTT: - rtt_initialize (g); - break; - case GRAPH_WSCALE: - wscale_initialize (g); - break; - default: - break; - } -} - -static void graph_destroy (struct graph *g) -{ - debug(DBS_FENTRY) puts ("graph_destroy()"); - - axis_destroy (g->x_axis); - axis_destroy (g->y_axis); - /* window_destroy (g->drawing_area); */ - window_destroy (g->gui.control_panel); - window_destroy (g->toplevel); - /* window_destroy (g->text); */ + zoom_lock_none = gtk_radio_button_new_with_label(NULL, "none"); + zoom_lock_h = gtk_radio_button_new_with_label( + gtk_radio_button_get_group(GTK_RADIO_BUTTON(zoom_lock_none)), + "horizontal"); + zoom_lock_v = gtk_radio_button_new_with_label( + gtk_radio_button_get_group(GTK_RADIO_BUTTON(zoom_lock_none)), + "vertical"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(zoom_lock_none), TRUE); + zoom_lock_box = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0, FALSE); + gtk_box_pack_start(GTK_BOX(zoom_lock_box), zoom_lock_none, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(zoom_lock_box), zoom_lock_h, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(zoom_lock_box), zoom_lock_v, TRUE, TRUE, 0); + zoom_lock_frame = gtk_frame_new("Zoom lock:"); + gtk_container_add(GTK_CONTAINER(zoom_lock_frame), zoom_lock_box); + + g_signal_connect(zoom_lock_h, "toggled", G_CALLBACK(callback_zoomlock_h), g); + g_signal_connect(zoom_lock_v, "toggled", G_CALLBACK(callback_zoomlock_v), g); + + return zoom_lock_frame; +} + +static void callback_zoomlock_h(GtkWidget *toggle, gpointer data) +{ + struct graph *g = (struct graph * )data; + + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle))) + g->zoom.flags |= ZOOM_HLOCK; + else + g->zoom.flags &= ~ZOOM_HLOCK; +} + +static void callback_zoomlock_v(GtkWidget *toggle, gpointer data) +{ + struct graph *g = (struct graph * )data; + + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle))) + g->zoom.flags |= ZOOM_VLOCK; + else + g->zoom.flags &= ~ZOOM_VLOCK; +} + +static GtkWidget *control_panel_create_cross_group(struct graph *g) +{ + GtkWidget *on, *off, *box, *frame, *vbox, *label; + + label = gtk_label_new("Crosshairs:"); + off = gtk_radio_button_new_with_label(NULL, "off"); + on = gtk_radio_button_new_with_label( + gtk_radio_button_get_group(GTK_RADIO_BUTTON(off)), "on"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(off), TRUE); + box = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0, FALSE); + gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 10); + gtk_box_pack_start(GTK_BOX(box), off, FALSE, FALSE, 10); + gtk_box_pack_start(GTK_BOX(box), on, FALSE, FALSE, 0); + vbox = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE); + gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 15); + /* frame = gtk_frame_new("Cross:"); */ + frame = gtk_frame_new(NULL); + gtk_container_add(GTK_CONTAINER(frame), vbox); + + g_signal_connect(on, "toggled", G_CALLBACK(callback_cross_on_off), g); + + g->cross.on_toggle = (GtkToggleButton * )on; + g->cross.off_toggle = (GtkToggleButton * )off; + + return frame; +} +static void callback_cross_on_off(GtkWidget *toggle, gpointer data) +{ + struct graph *g = (struct graph * )data; + + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle))) { + int x, y; + g->cross.draw = TRUE; + get_mouse_position(g->drawing_area, &x, &y, 0); + cross_draw(g, x, y); + } else { + g->cross.draw = FALSE; + if (g->cross.erase_needed) { + cross_erase(g); + } + } +} + +static GtkWidget *control_panel_create_graph_type_group(struct graph *g) +{ + GtkWidget *graph_tseqttrace, *graph_tseqstevens; + GtkWidget *graph_tput, *graph_rtt, *graph_sep, *graph_init, *graph_box; + GtkWidget *graph_frame; + GtkWidget *graph_wscale; + + graph_tput = gtk_radio_button_new_with_label(NULL, "Throughput"); + graph_tseqttrace = gtk_radio_button_new_with_label( + gtk_radio_button_get_group(GTK_RADIO_BUTTON(graph_tput)), + "Time/Sequence (tcptrace-style)"); + graph_tseqstevens = gtk_radio_button_new_with_label( + gtk_radio_button_get_group(GTK_RADIO_BUTTON(graph_tput)), + "Time/Sequence (Stevens'-style)"); + graph_rtt = gtk_radio_button_new_with_label( + gtk_radio_button_get_group(GTK_RADIO_BUTTON(graph_tput)), + "Round-trip Time"); + graph_wscale = gtk_radio_button_new_with_label( + gtk_radio_button_get_group(GTK_RADIO_BUTTON(graph_tput)), + "Window Scaling"); + + switch (g->type) { + case GRAPH_TSEQ_STEVENS: + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(graph_tseqstevens), TRUE); + break; + case GRAPH_TSEQ_TCPTRACE: + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(graph_tseqttrace), TRUE); + break; + case GRAPH_THROUGHPUT: + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(graph_tput), TRUE); + break; + case GRAPH_RTT: + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(graph_rtt), TRUE); + break; + case GRAPH_WSCALE: + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(graph_wscale), TRUE); + break; + } + graph_init = gtk_check_button_new_with_label("Init on change"); + graph_sep = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL); + graph_box = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE); + gtk_box_pack_start(GTK_BOX(graph_box), graph_rtt, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(graph_box), graph_tput, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(graph_box), graph_tseqstevens, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(graph_box), graph_tseqttrace, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(graph_box), graph_wscale, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(graph_box), graph_sep, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(graph_box), graph_init, TRUE, TRUE, 0); + graph_frame = gtk_frame_new("Graph type:"); + gtk_container_add(GTK_CONTAINER(graph_frame), graph_box); + + g_object_set_data(G_OBJECT(graph_tseqstevens), "new-graph-type", + GINT_TO_POINTER(GRAPH_TSEQ_STEVENS)); + g_object_set_data(G_OBJECT(graph_tseqttrace), "new-graph-type", + GINT_TO_POINTER(GRAPH_TSEQ_TCPTRACE)); + g_object_set_data(G_OBJECT(graph_tput), "new-graph-type", + GINT_TO_POINTER(GRAPH_THROUGHPUT)); + g_object_set_data(G_OBJECT(graph_rtt), "new-graph-type", + GINT_TO_POINTER(GRAPH_RTT)); + g_object_set_data(G_OBJECT(graph_wscale), "new-graph-type", + GINT_TO_POINTER(GRAPH_WSCALE)); + + g->gt.graph_wscale = (GtkToggleButton * )graph_wscale; + g->gt.graph_rtt = (GtkToggleButton * )graph_rtt; + g->gt.graph_tput = (GtkToggleButton * )graph_tput; + g->gt.graph_tseqstevens = (GtkToggleButton * )graph_tseqstevens; + g->gt.graph_tseqttrace = (GtkToggleButton * )graph_tseqttrace; + + g_signal_connect(graph_tseqttrace, "toggled", G_CALLBACK(callback_graph_type), g); + g_signal_connect(graph_tseqstevens, "toggled", G_CALLBACK(callback_graph_type), g); + g_signal_connect(graph_tput, "toggled", G_CALLBACK(callback_graph_type), g); + g_signal_connect(graph_rtt, "toggled", G_CALLBACK(callback_graph_type), g); + g_signal_connect(graph_wscale, "toggled", G_CALLBACK(callback_graph_type), g); + g_signal_connect(graph_init, "toggled", G_CALLBACK(callback_graph_init_on_typechg), g); + + return graph_frame; +} + +static void callback_graph_type(GtkWidget *toggle, gpointer data) +{ + int old_type, new_type; + struct graph *g = (struct graph * )data; + + new_type = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(toggle), "new-graph-type")); + + if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle))) + return; + + old_type = g->type; + g->type = new_type; + + graph_element_lists_free(g); + graph_element_lists_initialize(g); + + if ((old_type == GRAPH_THROUGHPUT) || (new_type == GRAPH_THROUGHPUT)) { + /* throughput graph uses differently constructed segment list so we + * need to recreate it */ + graph_segment_list_free(g); + graph_segment_list_get(g, TRUE); + } + + if (g->flags & GRAPH_INIT_ON_TYPE_CHANGE) { + g->geom.width = g->wp.width; + g->geom.height = g->wp.height; + g->geom.x = g->wp.x; + g->geom.y = g->wp.y; + } + g->x_axis->min = g->y_axis->min = 0; + gtk_toggle_button_set_active(g->gui.time_orig_conn, TRUE); + gtk_toggle_button_set_active(g->gui.seq_orig_isn, TRUE); + graph_init_sequence(g); +} + +static void callback_graph_init_on_typechg(GtkWidget *toggle _U_, gpointer data) +{ + ((struct graph * )data)->flags ^= GRAPH_INIT_ON_TYPE_CHANGE; +} + +static struct graph *graph_new(void) +{ + struct graph *g; + + g = (struct graph * )g_malloc0(sizeof(struct graph)); + graph_element_lists_initialize(g); + + g->x_axis = (struct axis * )g_malloc0(sizeof(struct axis)); + g->y_axis = (struct axis * )g_malloc0(sizeof(struct axis)); + g->x_axis->g = g; + g->x_axis->flags = 0; + g->x_axis->flags |= AXIS_ORIENTATION; + g->x_axis->s.x = g->x_axis->s.y = 0; + g->x_axis->s.height = HAXIS_INIT_HEIGHT; + g->x_axis->p.x = VAXIS_INIT_WIDTH; + g->x_axis->p.height = HAXIS_INIT_HEIGHT; + g->y_axis->g = g; + g->y_axis->flags = 0; + g->y_axis->flags &= ~AXIS_ORIENTATION; + g->y_axis->p.x = g->y_axis->p.y = 0; + g->y_axis->p.width = VAXIS_INIT_WIDTH; + g->y_axis->s.x = 0; + g->y_axis->s.y = TITLEBAR_HEIGHT; + g->y_axis->s.width = VAXIS_INIT_WIDTH; + + return g; +} + +static void graph_initialize_values(struct graph *g) +{ + g->geom.width = g->wp.width = 750; + g->geom.height = g->wp.height = 550; + g->geom.x = g->wp.x = VAXIS_INIT_WIDTH; + g->geom.y = g->wp.y = TITLEBAR_HEIGHT; + g->flags = 0; + /* g->zoom.x = g->zoom.y = 1.0; */ + g->zoom.step_x = g->zoom.step_y = 1.2; + g->zoom.flags = 0; + g->cross.draw = g->cross.erase_needed = FALSE; + g->zoomrect_erase_needed = FALSE; + g->grab.grabbed = 0; + g->magnify.active = 0; + g->magnify.offset.x = g->magnify.offset.y = 0; + g->magnify.width = g->magnify.height = 250; + g->magnify.zoom.x = g->magnify.zoom.y = 10.0; + g->magnify.flags = 0; +} + +static void graph_init_sequence(struct graph *g) +{ + debug(DBS_FENTRY) puts("graph_init_sequence()"); + + graph_type_dependent_initialize(g); + g->zoom.initial.x = g->zoom.x; + g->zoom.initial.y = g->zoom.y; + graph_element_lists_make(g); + g->x_axis->s.width = g->wp.width; + g->x_axis->p.width = g->x_axis->s.width + RMARGIN_WIDTH; + g->x_axis->p.y = TITLEBAR_HEIGHT + g->wp.height; + g->x_axis->s.height = g->x_axis->p.height = HAXIS_INIT_HEIGHT; + g->y_axis->s.height = g->wp.height; + g->y_axis->p.height = g->wp.height + TITLEBAR_HEIGHT; + graph_pixmaps_create(g); + axis_pixmaps_create(g->y_axis); + axis_pixmaps_create(g->x_axis); + graph_title_pixmap_create(g); + graph_title_pixmap_draw(g); + graph_title_pixmap_display(g); + graph_display(g); + axis_display(g->y_axis); + axis_display(g->x_axis); +} + +static void graph_type_dependent_initialize(struct graph *g) +{ + switch (g->type) { + case GRAPH_TSEQ_STEVENS: + case GRAPH_TSEQ_TCPTRACE: + tseq_initialize(g); + break; + case GRAPH_THROUGHPUT: + tput_initialize(g); + break; + case GRAPH_RTT: + rtt_initialize(g); + break; + case GRAPH_WSCALE: + wscale_initialize(g); + break; + default: + break; + } +} + +static void graph_destroy(struct graph *g) +{ + debug(DBS_FENTRY) puts("graph_destroy()"); + + axis_destroy(g->x_axis); + axis_destroy(g->y_axis); + /* window_destroy(g->drawing_area); */ + window_destroy(g->gui.control_panel); + window_destroy(g->toplevel); + /* window_destroy(g->text); */ #if GTK_CHECK_VERSION(2,22,0) - if(g->title_surface){ - cairo_surface_destroy (g->title_surface); - } - if(g->surface[0]){ - cairo_surface_destroy (g->surface[0]); - } - if(g->surface[1]){ - cairo_surface_destroy (g->surface[1]); - } + if (g->title_surface) { + cairo_surface_destroy(g->title_surface); + } + if (g->surface[0]) { + cairo_surface_destroy(g->surface[0]); + } + if (g->surface[1]) { + cairo_surface_destroy(g->surface[1]); + } #else - g_object_unref (g->pixmap[0]); - g_object_unref (g->pixmap[1]); + g_object_unref(g->pixmap[0]); + g_object_unref(g->pixmap[1]); #endif /* GTK_CHECK_VERSION(2,22,0) */ - g_free (g->x_axis); - g_free (g->y_axis); - g_free ( (gpointer) (g->title) ); - graph_segment_list_free (g); - graph_element_lists_free (g); + g_free(g->x_axis); + g_free(g->y_axis); + g_free((gpointer )(g->title)); + graph_segment_list_free(g); + graph_element_lists_free(g); - g_free (g); + g_free(g); } typedef struct _tcp_scan_t { - struct segment *current; - int direction; - struct graph *g; - struct segment *last; + struct segment *current; + int direction; + struct graph *g; + struct segment *last; } tcp_scan_t; static int tapall_tcpip_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip) { - tcp_scan_t *ts=(tcp_scan_t *)pct; - struct graph *g = ts->g; - const struct tcpheader *tcphdr = (const struct tcpheader *)vip; - - if (compare_headers(&g->src_address, &g->dst_address, - g->src_port, g->dst_port, - &tcphdr->ip_src, &tcphdr->ip_dst, - tcphdr->th_sport, tcphdr->th_dport, - ts->direction)) { - - struct segment *segment = g_malloc(sizeof (struct segment)); - segment->next = NULL; - segment->num = pinfo->fd->num; - segment->rel_secs = (guint32) pinfo->fd->rel_ts.secs; - segment->rel_usecs = pinfo->fd->rel_ts.nsecs/1000; - segment->abs_secs = (guint32) pinfo->fd->abs_ts.secs; - segment->abs_usecs = pinfo->fd->abs_ts.nsecs/1000; - segment->th_seq=tcphdr->th_seq; - segment->th_ack=tcphdr->th_ack; - segment->th_win=tcphdr->th_win; - segment->th_flags=tcphdr->th_flags; - segment->th_sport=tcphdr->th_sport; - segment->th_dport=tcphdr->th_dport; - segment->th_seglen=tcphdr->th_seglen; - COPY_ADDRESS(&segment->ip_src, &tcphdr->ip_src); - COPY_ADDRESS(&segment->ip_dst, &tcphdr->ip_dst); - - segment->num_sack_ranges = MIN(MAX_TCP_SACK_RANGES, tcphdr->num_sack_ranges); - if (segment->num_sack_ranges > 0) { - /* Copy entries in the order they happen */ - memcpy(&segment->sack_left_edge, &tcphdr->sack_left_edge, sizeof(segment->sack_left_edge)); - memcpy(&segment->sack_right_edge, &tcphdr->sack_right_edge, sizeof(segment->sack_right_edge)); - } - - if (ts->g->segments) { - ts->last->next = segment; - } else { - ts->g->segments = segment; - } - ts->last = segment; - } - - return 0; + tcp_scan_t *ts = (tcp_scan_t *)pct; + struct graph *g = ts->g; + const struct tcpheader *tcphdr = (const struct tcpheader *)vip; + + if (compare_headers(&g->src_address, &g->dst_address, + g->src_port, g->dst_port, + &tcphdr->ip_src, &tcphdr->ip_dst, + tcphdr->th_sport, tcphdr->th_dport, + ts->direction)) + { + struct segment *segment = g_malloc(sizeof(struct segment)); + segment->next = NULL; + segment->num = pinfo->fd->num; + segment->rel_secs = (guint32)pinfo->fd->rel_ts.secs; + segment->rel_usecs = pinfo->fd->rel_ts.nsecs/1000; + segment->abs_secs = (guint32)pinfo->fd->abs_ts.secs; + segment->abs_usecs = pinfo->fd->abs_ts.nsecs/1000; + segment->th_seq = tcphdr->th_seq; + segment->th_ack = tcphdr->th_ack; + segment->th_win = tcphdr->th_win; + segment->th_flags = tcphdr->th_flags; + segment->th_sport = tcphdr->th_sport; + segment->th_dport = tcphdr->th_dport; + segment->th_seglen = tcphdr->th_seglen; + COPY_ADDRESS(&segment->ip_src, &tcphdr->ip_src); + COPY_ADDRESS(&segment->ip_dst, &tcphdr->ip_dst); + + segment->num_sack_ranges = MIN(MAX_TCP_SACK_RANGES, tcphdr->num_sack_ranges); + if (segment->num_sack_ranges > 0) { + /* Copy entries in the order they happen */ + memcpy(&segment->sack_left_edge, &tcphdr->sack_left_edge, sizeof(segment->sack_left_edge)); + memcpy(&segment->sack_right_edge, &tcphdr->sack_right_edge, sizeof(segment->sack_right_edge)); + } + + if (ts->g->segments) { + ts->last->next = segment; + } else { + ts->g->segments = segment; + } + ts->last = segment; + } + + return 0; } /* here we collect all the external data we will ever need */ -static void graph_segment_list_get (struct graph *g, gboolean stream_known) -{ - struct segment current; - GString *error_string; - tcp_scan_t ts; - - debug(DBS_FENTRY) puts ("graph_segment_list_get()"); - - if (!stream_known) { - select_tcpip_session (&cfile, ¤t); - if (g->type == GRAPH_THROUGHPUT) - ts.direction = COMPARE_CURR_DIR; - else - ts.direction = COMPARE_ANY_DIR; - - /* Remember stream info in graph */ - COPY_ADDRESS(&g->src_address, ¤t.ip_src); - g->src_port = current.th_sport; - COPY_ADDRESS(&g->dst_address, ¤t.ip_dst); - g->dst_port = current.th_dport; - } - - /* rescan all the packets and pick up all interesting tcp headers. - * we only filter for TCP here for speed and do the actual compare - * in the tap listener - */ - ts.current=¤t; - ts.g=g; - ts.last=NULL; - error_string=register_tap_listener("tcp", &ts, "tcp", 0, NULL, tapall_tcpip_packet, NULL); - if(error_string){ - fprintf(stderr, "wireshark: Couldn't register tcp_graph tap: %s\n", - error_string->str); - g_string_free(error_string, TRUE); - exit(1); - } - cf_retap_packets(&cfile); - remove_tap_listener(&ts); +static void graph_segment_list_get(struct graph *g, gboolean stream_known) +{ + struct segment current; + GString *error_string; + tcp_scan_t ts; + + debug(DBS_FENTRY) puts("graph_segment_list_get()"); + + if (!stream_known) { + select_tcpip_session(&cfile, ¤t); + if (g->type == GRAPH_THROUGHPUT) + ts.direction = COMPARE_CURR_DIR; + else + ts.direction = COMPARE_ANY_DIR; + + /* Remember stream info in graph */ + COPY_ADDRESS(&g->src_address, ¤t.ip_src); + g->src_port = current.th_sport; + COPY_ADDRESS(&g->dst_address, ¤t.ip_dst); + g->dst_port = current.th_dport; + } + + /* rescan all the packets and pick up all interesting tcp headers. + * we only filter for TCP here for speed and do the actual compare + * in the tap listener + */ + ts.current = ¤t; + ts.g = g; + ts.last = NULL; + error_string = register_tap_listener("tcp", &ts, "tcp", 0, NULL, tapall_tcpip_packet, NULL); + if (error_string) { + fprintf(stderr, "wireshark: Couldn't register tcp_graph tap: %s\n", + error_string->str); + g_string_free(error_string, TRUE); + exit(1); /* XXX: fix this */ + } + cf_retap_packets(&cfile); + remove_tap_listener(&ts); } typedef struct _th_t { - int num_hdrs; - #define MAX_SUPPORTED_TCP_HEADERS 8 - struct tcpheader *tcphdrs[MAX_SUPPORTED_TCP_HEADERS]; + int num_hdrs; + #define MAX_SUPPORTED_TCP_HEADERS 8 + struct tcpheader *tcphdrs[MAX_SUPPORTED_TCP_HEADERS]; } th_t; static int tap_tcpip_packet(void *pct, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *vip) { - int n; - gboolean is_unique = TRUE; - th_t *th=pct; - const struct tcpheader *header = (const struct tcpheader *)vip; + int n; + gboolean is_unique = TRUE; + th_t *th = pct; + const struct tcpheader *header = (const struct tcpheader *)vip; - /* Check new header details against any/all stored ones */ - for (n=0; n < th->num_hdrs; n++) { - struct tcpheader *stored = th->tcphdrs[n]; + /* Check new header details against any/all stored ones */ + for (n=0; n < th->num_hdrs; n++) { + struct tcpheader *stored = th->tcphdrs[n]; - if (compare_headers(&stored->ip_src, &stored->ip_dst, - stored->th_sport, stored->th_dport, - &header->ip_src, &header->ip_dst, - header->th_sport, stored->th_dport, - COMPARE_CURR_DIR)) { - is_unique = FALSE; - break; - } - } + if (compare_headers(&stored->ip_src, &stored->ip_dst, + stored->th_sport, stored->th_dport, + &header->ip_src, &header->ip_dst, + header->th_sport, stored->th_dport, + COMPARE_CURR_DIR)) + { + is_unique = FALSE; + break; + } + } - /* Add address if unique and have space for it */ - if (is_unique && (th->num_hdrs < MAX_SUPPORTED_TCP_HEADERS)) { - /* Need to take a deep copy of the tap struct, it may not be valid - to read after this function returns? */ - th->tcphdrs[th->num_hdrs] = g_malloc(sizeof(struct tcpheader)); - *(th->tcphdrs[th->num_hdrs]) = *header; - COPY_ADDRESS(&th->tcphdrs[th->num_hdrs]->ip_src, &header->ip_src); - COPY_ADDRESS(&th->tcphdrs[th->num_hdrs]->ip_dst, &header->ip_dst); + /* Add address if unique and have space for it */ + if (is_unique && (th->num_hdrs < MAX_SUPPORTED_TCP_HEADERS)) { + /* Need to take a deep copy of the tap struct, it may not be valid + to read after this function returns? */ + th->tcphdrs[th->num_hdrs] = g_malloc(sizeof(struct tcpheader)); + *(th->tcphdrs[th->num_hdrs]) = *header; + COPY_ADDRESS(&th->tcphdrs[th->num_hdrs]->ip_src, &header->ip_src); + COPY_ADDRESS(&th->tcphdrs[th->num_hdrs]->ip_dst, &header->ip_dst); - th->num_hdrs++; - } + th->num_hdrs++; + } - return 0; + return 0; } @@ -1975,1313 +1984,1310 @@ tap_tcpip_packet(void *pct, packet_info *pinfo _U_, epan_dissect_t *edt _U_, con * then present the user with a dialog where the user can select WHICH tcp * session to graph. */ -static struct tcpheader *select_tcpip_session (capture_file *cf, struct segment *hdrs) -{ - frame_data *fdata; - epan_dissect_t edt; - dfilter_t *sfcode; - GString *error_string; - th_t th = {0, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}}; - - fdata = cf->current_frame; - - /* no real filter yet */ - if (!dfilter_compile("tcp", &sfcode)) { - simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", dfilter_error_msg); - return NULL; - } - - /* dissect the current frame */ - if (!cf_read_frame(cf, fdata)) - return NULL; /* error reading the frame */ - - - error_string=register_tap_listener("tcp", &th, NULL, 0, NULL, tap_tcpip_packet, NULL); - if(error_string){ - fprintf(stderr, "wireshark: Couldn't register tcp_graph tap: %s\n", - error_string->str); - g_string_free(error_string, TRUE); - exit(1); - } - - epan_dissect_init(&edt, TRUE, FALSE); - epan_dissect_prime_dfilter(&edt, sfcode); - epan_dissect_run_with_taps(&edt, &cf->phdr, cf->pd, fdata, NULL); - epan_dissect_cleanup(&edt); - remove_tap_listener(&th); - - if(th.num_hdrs==0){ - /* This "shouldn't happen", as our menu items shouldn't - * even be enabled if the selected packet isn't a TCP - * segment, as tcp_graph_selected_packet_enabled() is used - * to determine whether to enable any of our menu items. */ - simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, - "Selected packet isn't a TCP segment"); - return NULL; - } - /* XXX fix this later, we should show a dialog allowing the user - to select which session he wants here - */ - if(th.num_hdrs>1){ - /* can only handle a single tcp layer yet */ - simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, - "The selected packet has more than one TCP unique conversation " - "in it."); - return NULL; - } - - /* For now, still always choose the first/only one */ - hdrs->num = fdata->num; - hdrs->rel_secs = (guint32) fdata->rel_ts.secs; - hdrs->rel_usecs = fdata->rel_ts.nsecs/1000; - hdrs->abs_secs = (guint32) fdata->abs_ts.secs; - hdrs->abs_usecs = fdata->abs_ts.nsecs/1000; - hdrs->th_seq=th.tcphdrs[0]->th_seq; - hdrs->th_ack=th.tcphdrs[0]->th_ack; - hdrs->th_win=th.tcphdrs[0]->th_win; - hdrs->th_flags=th.tcphdrs[0]->th_flags; - hdrs->th_sport=th.tcphdrs[0]->th_sport; - hdrs->th_dport=th.tcphdrs[0]->th_dport; - hdrs->th_seglen=th.tcphdrs[0]->th_seglen; - COPY_ADDRESS(&hdrs->ip_src, &th.tcphdrs[0]->ip_src); - COPY_ADDRESS(&hdrs->ip_dst, &th.tcphdrs[0]->ip_dst); - return th.tcphdrs[0]; - -} - -static int compare_headers (address *saddr1, address *daddr1, guint16 sport1, guint16 dport1, const address *saddr2, const address *daddr2, guint16 sport2, guint16 dport2, int dir) -{ - int dir1, dir2; - - dir1 = ((!(CMP_ADDRESS(saddr1, saddr2))) && - (!(CMP_ADDRESS(daddr1, daddr2))) && - (sport1==sport2) && - (dport1==dport2)); - - if(dir==COMPARE_CURR_DIR){ - return dir1; - } else { - dir2 = ((!(CMP_ADDRESS(saddr1, daddr2))) && - (!(CMP_ADDRESS(daddr1, saddr2))) && - (sport1==dport2) && - (dport1==sport2)); - return dir1 || dir2; - } -} - -static void graph_segment_list_free (struct graph *g) -{ - struct segment *segment; - - while (g->segments) { - segment = g->segments->next; - g_free (g->segments); - g->segments = segment; - } - g->segments = NULL; -} - -static void graph_element_lists_initialize (struct graph *g) -{ - g->elists = (struct element_list *)g_malloc0 (sizeof (struct element_list)); -} - -static void graph_element_lists_make (struct graph *g) -{ - debug(DBS_FENTRY) puts ("graph_element_lists_make()"); - - switch (g->type) { - case GRAPH_TSEQ_STEVENS: - tseq_stevens_make_elmtlist (g); - break; - case GRAPH_TSEQ_TCPTRACE: - tseq_tcptrace_make_elmtlist (g); - break; - case GRAPH_THROUGHPUT: - tput_make_elmtlist (g); - break; - case GRAPH_RTT: - rtt_make_elmtlist (g); - break; - case GRAPH_WSCALE: - wscale_make_elmtlist (g); - break; - default: - printf ("graph_element_lists_make: unknown graph type: %d\n", g->type); - break; - } -} - -static void graph_element_lists_free (struct graph *g) -{ - struct element_list *list, *next_list; - - for (list=g->elists; list; list=next_list) { - g_free (list->elements); - next_list = list->next; - g_free (list); - } - g->elists = NULL; /* just to make debugging easier */ -} +static struct tcpheader *select_tcpip_session(capture_file *cf, struct segment *hdrs) +{ + frame_data *fdata; + epan_dissect_t edt; + dfilter_t *sfcode; + GString *error_string; + th_t th = {0, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}}; + + fdata = cf->current_frame; + + /* no real filter yet */ + if (!dfilter_compile("tcp", &sfcode)) { + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", dfilter_error_msg); + return NULL; + } + + /* dissect the current frame */ + if (!cf_read_frame(cf, fdata)) + return NULL; /* error reading the frame */ + + + error_string=register_tap_listener("tcp", &th, NULL, 0, NULL, tap_tcpip_packet, NULL); + if (error_string) { + fprintf(stderr, "wireshark: Couldn't register tcp_graph tap: %s\n", + error_string->str); + g_string_free(error_string, TRUE); + exit(1); + } + + epan_dissect_init(&edt, TRUE, FALSE); + epan_dissect_prime_dfilter(&edt, sfcode); + epan_dissect_run_with_taps(&edt, &cf->phdr, cf->pd, fdata, NULL); + epan_dissect_cleanup(&edt); + remove_tap_listener(&th); + + if (th.num_hdrs == 0) { + /* This "shouldn't happen", as our menu items shouldn't + * even be enabled if the selected packet isn't a TCP + * segment, as tcp_graph_selected_packet_enabled() is used + * to determine whether to enable any of our menu items. */ + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, + "Selected packet isn't a TCP segment"); + return NULL; + } + /* XXX fix this later, we should show a dialog allowing the user + to select which session he wants here + */ + if (th.num_hdrs > 1) { + /* can only handle a single tcp layer yet */ + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, + "The selected packet has more than one TCP unique conversation " + "in it."); + return NULL; + } + + /* For now, still always choose the first/only one */ + hdrs->num = fdata->num; + hdrs->rel_secs = (guint32) fdata->rel_ts.secs; + hdrs->rel_usecs = fdata->rel_ts.nsecs/1000; + hdrs->abs_secs = (guint32) fdata->abs_ts.secs; + hdrs->abs_usecs = fdata->abs_ts.nsecs/1000; + hdrs->th_seq = th.tcphdrs[0]->th_seq; + hdrs->th_ack = th.tcphdrs[0]->th_ack; + hdrs->th_win = th.tcphdrs[0]->th_win; + hdrs->th_flags = th.tcphdrs[0]->th_flags; + hdrs->th_sport = th.tcphdrs[0]->th_sport; + hdrs->th_dport = th.tcphdrs[0]->th_dport; + hdrs->th_seglen = th.tcphdrs[0]->th_seglen; + COPY_ADDRESS(&hdrs->ip_src, &th.tcphdrs[0]->ip_src); + COPY_ADDRESS(&hdrs->ip_dst, &th.tcphdrs[0]->ip_dst); + return th.tcphdrs[0]; + +} + +static int compare_headers(address *saddr1, address *daddr1, guint16 sport1, guint16 dport1, const address *saddr2, const address *daddr2, guint16 sport2, guint16 dport2, int dir) +{ + int dir1, dir2; + + dir1 = ((!(CMP_ADDRESS(saddr1, saddr2))) && + (!(CMP_ADDRESS(daddr1, daddr2))) && + (sport1==sport2) && + (dport1==dport2)); + + if (dir == COMPARE_CURR_DIR) { + return dir1; + } else { + dir2 = ((!(CMP_ADDRESS(saddr1, daddr2))) && + (!(CMP_ADDRESS(daddr1, saddr2))) && + (sport1 == dport2) && + (dport1 == sport2)); + return dir1 || dir2; + } +} + +static void graph_segment_list_free(struct graph *g) +{ + struct segment *segment; + + while (g->segments) { + segment = g->segments->next; + g_free(g->segments); + g->segments = segment; + } + g->segments = NULL; +} + +static void graph_element_lists_initialize(struct graph *g) +{ + g->elists = (struct element_list *)g_malloc0(sizeof(struct element_list)); +} + +static void graph_element_lists_make(struct graph *g) +{ + debug(DBS_FENTRY) puts("graph_element_lists_make()"); + + switch (g->type) { + case GRAPH_TSEQ_STEVENS: + tseq_stevens_make_elmtlist(g); + break; + case GRAPH_TSEQ_TCPTRACE: + tseq_tcptrace_make_elmtlist(g); + break; + case GRAPH_THROUGHPUT: + tput_make_elmtlist(g); + break; + case GRAPH_RTT: + rtt_make_elmtlist(g); + break; + case GRAPH_WSCALE: + wscale_make_elmtlist(g); + break; + default: + printf("graph_element_lists_make: unknown graph type: %d\n", g->type); + break; + } +} + +static void graph_element_lists_free(struct graph *g) +{ + struct element_list *list, *next_list; + + for (list=g->elists; list; list=next_list) { + g_free(list->elements); + next_list = list->next; + g_free(list); + } + g->elists = NULL; /* just to make debugging easier */ +} -static void graph_title_pixmap_create (struct graph *g) +static void graph_title_pixmap_create(struct graph *g) { #if GTK_CHECK_VERSION(2,22,0) - if(g->title_surface){ - cairo_surface_destroy (g->title_surface); - g->title_surface = NULL; - } + if (g->title_surface) { + cairo_surface_destroy(g->title_surface); + g->title_surface = NULL; + } - g->title_surface = gdk_window_create_similar_surface (gtk_widget_get_window(g->drawing_area), - CAIRO_CONTENT_COLOR, - g->x_axis->p.width, - g->wp.y); + g->title_surface = gdk_window_create_similar_surface(gtk_widget_get_window(g->drawing_area), + CAIRO_CONTENT_COLOR, + g->x_axis->p.width, + g->wp.y); #else - if (g->title_pixmap) - g_object_unref (g->title_pixmap); + if (g->title_pixmap) + g_object_unref(g->title_pixmap); - g->title_pixmap = gdk_pixmap_new (gtk_widget_get_window(g->drawing_area), - g->x_axis->p.width, g->wp.y, -1); + g->title_pixmap = gdk_pixmap_new(gtk_widget_get_window(g->drawing_area), + g->x_axis->p.width, g->wp.y, -1); #endif } -static void graph_title_pixmap_draw (struct graph *g) +static void graph_title_pixmap_draw(struct graph *g) { - int i; - cairo_t *cr; + int i; + cairo_t *cr; #if GTK_CHECK_VERSION(2,22,0) - cr = cairo_create (g->title_surface); + cr = cairo_create(g->title_surface); #else - cr = gdk_cairo_create (g->title_pixmap); + cr = gdk_cairo_create(g->title_pixmap); #endif - cairo_set_source_rgb (cr, 1, 1, 1); /* set fill color */ - cairo_rectangle (cr, 0, 0, g->x_axis->p.width, g->wp.y); - cairo_fill (cr); - cairo_set_source_rgb (cr, 0, 0, 0); /* set text color */ + cairo_set_source_rgb(cr, 1, 1, 1); /* set fill color */ + cairo_rectangle(cr, 0, 0, g->x_axis->p.width, g->wp.y); + cairo_fill(cr); + cairo_set_source_rgb(cr, 0, 0, 0); /* set text color */ - for (i=0; g->title[i]; i++) { - gint w, h; - PangoLayout *layout; - layout = gtk_widget_create_pango_layout(g->drawing_area, - g->title[i]); - pango_layout_get_pixel_size(layout, &w, &h); - cairo_move_to (cr, g->wp.width/2 - w/2, 20 + i*(h+3)); - pango_cairo_show_layout (cr, layout); - g_object_unref(G_OBJECT(layout)); - } - cairo_destroy (cr); + for (i=0; g->title[i]; i++) { + gint w, h; + PangoLayout *layout; + layout = gtk_widget_create_pango_layout(g->drawing_area, + g->title[i]); + pango_layout_get_pixel_size(layout, &w, &h); + cairo_move_to(cr, g->wp.width/2 - w/2, 20 + i*(h+3)); + pango_cairo_show_layout(cr, layout); + g_object_unref(G_OBJECT(layout)); + } + cairo_destroy(cr); } -static void graph_title_pixmap_display (struct graph *g) +static void graph_title_pixmap_display(struct graph *g) { - cairo_t *cr; + cairo_t *cr; - cr = gdk_cairo_create (gtk_widget_get_window(g->drawing_area)); + cr = gdk_cairo_create(gtk_widget_get_window(g->drawing_area)); #if GTK_CHECK_VERSION(2,22,0) - cairo_set_source_surface (cr, g->title_surface, g->wp.x, 0); + cairo_set_source_surface(cr, g->title_surface, g->wp.x, 0); #else - gdk_cairo_set_source_pixmap (cr, g->title_pixmap, g->wp.x, 0); + gdk_cairo_set_source_pixmap(cr, g->title_pixmap, g->wp.x, 0); #endif - cairo_rectangle (cr, g->wp.x, 0, g->x_axis->p.width, g->wp.y); - cairo_fill (cr); - cairo_destroy (cr); + cairo_rectangle(cr, g->wp.x, 0, g->x_axis->p.width, g->wp.y); + cairo_fill(cr); + cairo_destroy(cr); } -static void graph_pixmaps_create (struct graph *g) +static void graph_pixmaps_create(struct graph *g) { - debug(DBS_FENTRY) puts ("graph_pixmaps_create()"); + debug(DBS_FENTRY) puts("graph_pixmaps_create()"); #if GTK_CHECK_VERSION(2,22,0) - if(g->surface[0]){ - cairo_surface_destroy (g->surface[0]); - g->surface[0] = NULL; - } - - if(g->surface[1]){ - cairo_surface_destroy (g->surface[1]); - g->surface[1] = NULL; - } - - g->surface[0] = gdk_window_create_similar_surface (gtk_widget_get_window(g->drawing_area), - CAIRO_CONTENT_COLOR, - g->wp.width, - g->wp.height); - - g->surface[1] = gdk_window_create_similar_surface (gtk_widget_get_window(g->drawing_area), - CAIRO_CONTENT_COLOR, - g->wp.width, - g->wp.height); - - g->displayed = 0; + if (g->surface[0]) { + cairo_surface_destroy(g->surface[0]); + g->surface[0] = NULL; + } + + if (g->surface[1]) { + cairo_surface_destroy(g->surface[1]); + g->surface[1] = NULL; + } + + g->surface[0] = gdk_window_create_similar_surface(gtk_widget_get_window(g->drawing_area), + CAIRO_CONTENT_COLOR, + g->wp.width, + g->wp.height); + + g->surface[1] = gdk_window_create_similar_surface(gtk_widget_get_window(g->drawing_area), + CAIRO_CONTENT_COLOR, + g->wp.width, + g->wp.height); + + g->displayed = 0; #else - if (g->pixmap[0]) - g_object_unref (g->pixmap[0]); - if (g->pixmap[1]) - g_object_unref (g->pixmap[1]); + if (g->pixmap[0]) + g_object_unref(g->pixmap[0]); + if (g->pixmap[1]) + g_object_unref(g->pixmap[1]); - g->pixmap[0] = gdk_pixmap_new (gtk_widget_get_window(g->drawing_area), - g->wp.width, g->wp.height, -1); - g->pixmap[1] = gdk_pixmap_new (gtk_widget_get_window(g->drawing_area), - g->wp.width, g->wp.height, -1); + g->pixmap[0] = gdk_pixmap_new(gtk_widget_get_window(g->drawing_area), + g->wp.width, g->wp.height, -1); + g->pixmap[1] = gdk_pixmap_new(gtk_widget_get_window(g->drawing_area), + g->wp.width, g->wp.height, -1); - g->displayed = 0; + g->displayed = 0; #endif /* GTK_CHECK_VERSION(2,22,0) */ } -static void graph_display (struct graph *g) +static void graph_display(struct graph *g) { - set_busy_cursor (gtk_widget_get_window(g->drawing_area)); - graph_pixmap_draw (g); - unset_busy_cursor (gtk_widget_get_window(g->drawing_area), g->cross.draw); - graph_pixmaps_switch (g); - graph_pixmap_display (g); + set_busy_cursor(gtk_widget_get_window(g->drawing_area)); + graph_pixmap_draw(g); + unset_busy_cursor(gtk_widget_get_window(g->drawing_area), g->cross.draw); + graph_pixmaps_switch(g); + graph_pixmap_display(g); } -static void graph_pixmap_display (struct graph *g) +static void graph_pixmap_display(struct graph *g) { - cairo_t *cr; + cairo_t *cr; - cr = gdk_cairo_create (gtk_widget_get_window(g->drawing_area)); + cr = gdk_cairo_create(gtk_widget_get_window(g->drawing_area)); #if GTK_CHECK_VERSION(2,22,0) - cairo_set_source_surface (cr, g->surface[g->displayed], g->wp.x, g->wp.y); + cairo_set_source_surface(cr, g->surface[g->displayed], g->wp.x, g->wp.y); #else - gdk_cairo_set_source_pixmap (cr, g->pixmap[g->displayed], g->wp.x, g->wp.y); + gdk_cairo_set_source_pixmap(cr, g->pixmap[g->displayed], g->wp.x, g->wp.y); #endif /* GTK_CHECK_VERSION(2,22,0) */ - cairo_rectangle (cr, g->wp.x, g->wp.y, g->wp.width, g->wp.height); - cairo_fill (cr); - cairo_destroy (cr); - if (g->cross.erase_needed) { - cross_erase(g); - } + cairo_rectangle(cr, g->wp.x, g->wp.y, g->wp.width, g->wp.height); + cairo_fill(cr); + cairo_destroy(cr); + if (g->cross.erase_needed) { + cross_erase(g); + } } -static void graph_pixmaps_switch (struct graph *g) +static void graph_pixmaps_switch(struct graph *g) { - g->displayed = 1 ^ g->displayed; + g->displayed = 1 ^ g->displayed; } -static void graph_pixmap_draw (struct graph *g) +static void graph_pixmap_draw(struct graph *g) { - struct element_list *list; - struct element *e; - int not_disp; - cairo_t *cr; - GdkColor *current_line_color = NULL; - GdkColor *color_to_set = NULL; - gboolean line_stroked = TRUE; + struct element_list *list; + struct element *e; + int not_disp; + cairo_t *cr; + GdkColor *current_line_color = NULL; + GdkColor *color_to_set = NULL; + gboolean line_stroked = TRUE; - debug(DBS_FENTRY) puts ("graph_pixmap_draw()"); - not_disp = 1 ^ g->displayed; + debug(DBS_FENTRY) puts("graph_pixmap_draw()"); + not_disp = 1 ^ g->displayed; #if GTK_CHECK_VERSION(2,22,0) - cr = cairo_create (g->surface[not_disp]); + cr = cairo_create(g->surface[not_disp]); #else - cr = gdk_cairo_create (g->pixmap[not_disp]); + cr = gdk_cairo_create(g->pixmap[not_disp]); #endif /* GTK_CHECK_VERSION(2,22,0) */ - cairo_set_source_rgb (cr, 1, 1, 1); - cairo_rectangle (cr, 0, 0, g->wp.width, g->wp.height); - cairo_fill (cr); - - /* Want line width 1 for all elements */ - cairo_set_line_width (cr, 1.0); - - for (list=g->elists; list; list=list->next) - for (e=list->elements; e->type != ELMT_NONE; e++) { - switch (e->type) { - case ELMT_RECT: - current_line_color = NULL; - break; - - case ELMT_LINE: - /* Work out if we need to change colour */ - if (current_line_color == e->elment_color_p) { - /* No change needed */ - color_to_set = NULL; - } - else { - /* Changing colour */ - current_line_color = color_to_set = e->elment_color_p; - } - - /* Draw the line */ - draw_element_line (g, e, cr, color_to_set); - line_stroked = FALSE; - break; - - case ELMT_ELLIPSE: - if (!line_stroked) { - cairo_stroke(cr); - line_stroked = TRUE; - } - draw_element_ellipse (g, e, cr); - break; - - default: - break; - } - } - - /* Make sure any remaining lines get drawn */ - if (!line_stroked) - cairo_stroke (cr); - - cairo_destroy (cr); -} - -static void draw_element_line (struct graph *g, struct element *e, cairo_t *cr, - GdkColor *new_color) -{ - int xx1, xx2, yy1, yy2; - - debug(DBS_GRAPH_DRAWING) printf ("line element: (%.2f,%.2f)->(%.2f,%.2f), " - "seg %d ... ", e->p.line.dim.x1, e->p.line.dim.y1, - e->p.line.dim.x2, e->p.line.dim.y2, e->parent->num); - - /* Set our new colour (if changed) */ - if (new_color != NULL) { - /* First draw any previous lines with old colour */ - cairo_stroke(cr); - gdk_cairo_set_source_color(cr, new_color); - } - - xx1 = (int )rint (e->p.line.dim.x1 + g->geom.x - g->wp.x); - xx2 = (int )rint (e->p.line.dim.x2 + g->geom.x - g->wp.x); - yy1 = (int )rint ((g->geom.height-1-e->p.line.dim.y1) + g->geom.y-g->wp.y); - yy2 = (int )rint ((g->geom.height-1-e->p.line.dim.y2) + g->geom.y-g->wp.y); - - /* If line completely out of the area, we won't show it */ - if ((xx1<0 && xx2<0) || (xx1>=g->wp.width && xx2>=g->wp.width) || - (yy1<0 && yy2<0) || (yy1>=g->wp.height && yy2>=g->wp.height)) { - debug(DBS_GRAPH_DRAWING) printf (" refusing: (%d,%d)->(%d,%d)\n", - xx1, yy1, xx2, yy2); - return; - } - - /* If one end of the line is out of bounds, don't worry. Cairo will - clip the line to the outside of g->wp at the correct angle! */ - - debug(DBS_GRAPH_DRAWING) printf ("line: (%d,%d)->(%d,%d)\n", xx1, yy1, xx2,yy2); - - g_assert(e->elment_color_p!=NULL); - - cairo_move_to(cr, xx1+0.5, yy1+0.5); - cairo_line_to(cr, xx2+0.5, yy2+0.5); -} - -static void draw_element_ellipse (struct graph *g, struct element *e, cairo_t *cr) + cairo_set_source_rgb(cr, 1, 1, 1); + cairo_rectangle(cr, 0, 0, g->wp.width, g->wp.height); + cairo_fill(cr); + + /* Want line width 1 for all elements */ + cairo_set_line_width(cr, 1.0); + + for (list=g->elists; list; list=list->next) { + for (e=list->elements; e->type != ELMT_NONE; e++) { + switch (e->type) { + case ELMT_RECT: + current_line_color = NULL; + break; + + case ELMT_LINE: + /* Work out if we need to change colour */ + if (current_line_color == e->elment_color_p) { + /* No change needed */ + color_to_set = NULL; + } + else { + /* Changing colour */ + current_line_color = color_to_set = e->elment_color_p; + } + + /* Draw the line */ + draw_element_line(g, e, cr, color_to_set); + line_stroked = FALSE; + break; + + case ELMT_ELLIPSE: + if (!line_stroked) { + cairo_stroke(cr); + line_stroked = TRUE; + } + draw_element_ellipse(g, e, cr); + break; + + default: + break; + } + } + } + + /* Make sure any remaining lines get drawn */ + if (!line_stroked) + cairo_stroke(cr); + + cairo_destroy(cr); +} + +static void draw_element_line(struct graph *g, struct element *e, cairo_t *cr, + GdkColor *new_color) +{ + int xx1, xx2, yy1, yy2; + + debug(DBS_GRAPH_DRAWING) printf("line element: (%.2f,%.2f)->(%.2f,%.2f), " + "seg %d ... ", e->p.line.dim.x1, e->p.line.dim.y1, + e->p.line.dim.x2, e->p.line.dim.y2, e->parent->num); + + /* Set our new colour (if changed) */ + if (new_color != NULL) { + /* First draw any previous lines with old colour */ + cairo_stroke(cr); + gdk_cairo_set_source_color(cr, new_color); + } + + xx1 = (int )rint(e->p.line.dim.x1 + g->geom.x - g->wp.x); + xx2 = (int )rint(e->p.line.dim.x2 + g->geom.x - g->wp.x); + yy1 = (int )rint((g->geom.height-1-e->p.line.dim.y1) + g->geom.y-g->wp.y); + yy2 = (int )rint((g->geom.height-1-e->p.line.dim.y2) + g->geom.y-g->wp.y); + + /* If line completely out of the area, we won't show it */ + if (((xx1 < 0) && (xx2 < 0)) || ((xx1 >= g->wp.width) && (xx2 >= g->wp.width)) || + ((yy1 < 0) && (yy2 < 0)) || ((yy1 >= g->wp.height) && (yy2 >= g->wp.height))) { + debug(DBS_GRAPH_DRAWING) printf(" refusing: (%d,%d)->(%d,%d)\n", + xx1, yy1, xx2, yy2); + return; + } + + /* If one end of the line is out of bounds, don't worry. Cairo will + clip the line to the outside of g->wp at the correct angle! */ + + debug(DBS_GRAPH_DRAWING) printf("line: (%d,%d)->(%d,%d)\n", xx1, yy1, xx2, yy2); + + g_assert(e->elment_color_p!=NULL); + + cairo_move_to(cr, xx1+0.5, yy1+0.5); + cairo_line_to(cr, xx2+0.5, yy2+0.5); +} + +static void draw_element_ellipse(struct graph *g, struct element *e, cairo_t *cr) +{ + gdouble w = e->p.ellipse.dim.width; + gdouble h = e->p.ellipse.dim.height; + gdouble x = e->p.ellipse.dim.x + g->geom.x - g->wp.x; + gdouble y = g->geom.height-1 - e->p.ellipse.dim.y + g->geom.y - g->wp.y; + + debug(DBS_GRAPH_DRAWING) printf("ellipse: (x, y) -> (w, h): (%f, %f) -> (%f, %f)\n", x, y, w, h); + + cairo_save(cr); + cairo_set_source_rgb(cr, 0, 0, 0); + cairo_translate(cr, x + w / 2., y + h / 2.); + cairo_scale(cr, w / 2., h / 2.); + cairo_arc(cr, 0., 0., 1., 0., 2 * G_PI); + cairo_fill(cr); + cairo_restore(cr); +} + +static void axis_pixmaps_create(struct axis *axis) { - gdouble w = e->p.ellipse.dim.width; - gdouble h = e->p.ellipse.dim.height; - gdouble x = e->p.ellipse.dim.x + g->geom.x - g->wp.x; - gdouble y = g->geom.height-1 - e->p.ellipse.dim.y + g->geom.y - g->wp.y; - - debug(DBS_GRAPH_DRAWING) printf ("ellipse: (x, y) -> (w, h): (%f, %f) -> (%f, %f)\n", x, y, w, h); - - cairo_save(cr); - cairo_set_source_rgb(cr, 0, 0, 0); - cairo_translate (cr, x + w / 2., y + h / 2.); - cairo_scale (cr, w / 2., h / 2.); - cairo_arc (cr, 0., 0., 1., 0., 2 * G_PI); - cairo_fill(cr); - cairo_restore(cr); -} - -static void axis_pixmaps_create (struct axis *axis) -{ - debug(DBS_FENTRY) puts ("axis_pixmaps_create()"); + debug(DBS_FENTRY) puts("axis_pixmaps_create()"); #if GTK_CHECK_VERSION(2,22,0) - if(axis->surface[0]){ - cairo_surface_destroy (axis->surface[0]); - axis->surface[0] = NULL; - } - if(axis->surface[1]){ - cairo_surface_destroy (axis->surface[1]); - axis->surface[1] = NULL; - } - axis->surface[0] = gdk_window_create_similar_surface (gtk_widget_get_window(axis->drawing_area), - CAIRO_CONTENT_COLOR, - axis->p.width, - axis->p.height); - - axis->surface[1] = gdk_window_create_similar_surface (gtk_widget_get_window(axis->drawing_area), - CAIRO_CONTENT_COLOR, - axis->p.width, - axis->p.height); - - axis->displayed = 0; + if (axis->surface[0]) { + cairo_surface_destroy(axis->surface[0]); + axis->surface[0] = NULL; + } + if (axis->surface[1]) { + cairo_surface_destroy(axis->surface[1]); + axis->surface[1] = NULL; + } + axis->surface[0] = gdk_window_create_similar_surface(gtk_widget_get_window(axis->drawing_area), + CAIRO_CONTENT_COLOR, + axis->p.width, + axis->p.height); + + axis->surface[1] = gdk_window_create_similar_surface(gtk_widget_get_window(axis->drawing_area), + CAIRO_CONTENT_COLOR, + axis->p.width, + axis->p.height); + + axis->displayed = 0; #else - if (axis->pixmap[0]) - g_object_unref (axis->pixmap[0]); - if (axis->pixmap[1]) - g_object_unref (axis->pixmap[1]); + if (axis->pixmap[0]) + g_object_unref(axis->pixmap[0]); + if (axis->pixmap[1]) + g_object_unref(axis->pixmap[1]); - axis->pixmap[0] = gdk_pixmap_new (gtk_widget_get_window(axis->drawing_area), - axis->p.width, axis->p.height, -1); - axis->pixmap[1] = gdk_pixmap_new (gtk_widget_get_window(axis->drawing_area), - axis->p.width, axis->p.height, -1); + axis->pixmap[0] = gdk_pixmap_new(gtk_widget_get_window(axis->drawing_area), + axis->p.width, axis->p.height, -1); + axis->pixmap[1] = gdk_pixmap_new(gtk_widget_get_window(axis->drawing_area), + axis->p.width, axis->p.height, -1); - axis->displayed = 0; + axis->displayed = 0; #endif } -static void axis_destroy (struct axis *axis) +static void axis_destroy(struct axis *axis) { #if GTK_CHECK_VERSION(2,22,0) - if(axis->surface[0]){ - cairo_surface_destroy (axis->surface[0]); - axis->surface[0] = NULL; - } - if(axis->surface[1]){ - cairo_surface_destroy (axis->surface[1]); - axis->surface[1] = NULL; - } + if (axis->surface[0]) { + cairo_surface_destroy(axis->surface[0]); + axis->surface[0] = NULL; + } + if (axis->surface[1]) { + cairo_surface_destroy(axis->surface[1]); + axis->surface[1] = NULL; + } #else - g_object_unref (axis->pixmap[0]); - g_object_unref (axis->pixmap[1]); + g_object_unref(axis->pixmap[0]); + g_object_unref(axis->pixmap[1]); #endif - g_free ( (gpointer) (axis->label) ); + g_free( (gpointer) (axis->label) ); } -static void axis_display (struct axis *axis) +static void axis_display(struct axis *axis) { - if (axis->flags & AXIS_ORIENTATION) - h_axis_pixmap_draw (axis); - else - v_axis_pixmap_draw (axis); - axis_pixmaps_switch (axis); - axis_pixmap_display (axis); + if (axis->flags & AXIS_ORIENTATION) + h_axis_pixmap_draw(axis); + else + v_axis_pixmap_draw(axis); + axis_pixmaps_switch(axis); + axis_pixmap_display(axis); } -static void v_axis_pixmap_draw (struct axis *axis) +static void v_axis_pixmap_draw(struct axis *axis) { - struct graph *g = axis->g; - int i; - double major_tick; - int not_disp, rdigits, offset, imin, imax; - double bottom, top, j, fl, corr; - PangoLayout *layout; - cairo_t *cr; + struct graph *g = axis->g; + int i; + double major_tick; + int not_disp, rdigits, offset, imin, imax; + double bottom, top, j, fl, corr; + PangoLayout *layout; + cairo_t *cr; - debug(DBS_FENTRY) puts ("v_axis_pixmap_draw()"); - bottom = (g->geom.height - (g->wp.height + g->wp.y + (-g->geom.y))) / - (double )g->geom.height * g->bounds.height; - bottom += axis->min; - top = (g->geom.height - (g->wp.y + (-g->geom.y))) / - (double )g->geom.height * g->bounds.height; - top += axis->min; - axis_compute_ticks (axis, bottom, top, AXIS_VERTICAL); + debug(DBS_FENTRY) puts("v_axis_pixmap_draw()"); + bottom = (g->geom.height - (g->wp.height + g->wp.y + (-g->geom.y))) / + (double )g->geom.height * g->bounds.height; + bottom += axis->min; + top = (g->geom.height - (g->wp.y + (-g->geom.y))) / + (double )g->geom.height * g->bounds.height; + top += axis->min; + axis_compute_ticks(axis, bottom, top, AXIS_VERTICAL); - j = axis->major - floor (axis->major); - for (rdigits=0; rdigits<=6; rdigits++) { - j *= 10; - if (j<=0.000001) - break; - j = j - floor (j); - } + j = axis->major - floor(axis->major); + for (rdigits=0; rdigits <= 6; rdigits++) { + j *= 10; + if (j <= 0.000001) + break; + j = j - floor(j); + } - not_disp = 1 ^ axis->displayed; + not_disp = 1 ^ axis->displayed; #if GTK_CHECK_VERSION(2,22,0) - cr = cairo_create (axis->surface[not_disp]); + cr = cairo_create(axis->surface[not_disp]); #else - cr = gdk_cairo_create (axis->pixmap[not_disp]); + cr = gdk_cairo_create(axis->pixmap[not_disp]); #endif - cairo_set_source_rgb (cr, 1, 1, 1); - cairo_rectangle (cr, 0, 0, axis->p.width, axis->p.height); - cairo_fill (cr); - - /* axis */ - cairo_set_source_rgb (cr, 0, 0, 0); - cairo_set_line_width (cr, 1.0); - cairo_move_to(cr, axis->p.width - 1.5, (axis->p.height-axis->s.height)/2.0); - cairo_line_to(cr, axis->s.width - 1.5, axis->p.height); - - offset = g->wp.y + (-g->geom.y); - fl = floor (axis->min / axis->major) * axis->major; - corr = rint ((axis->min - fl) * g->zoom.y); - - /* major ticks */ - major_tick = axis->major * g->zoom.y; - imin = (int) ((g->geom.height - offset + corr - g->wp.height) / major_tick + 1); - imax = (int) ((g->geom.height - offset + corr) / major_tick); - for (i=imin; i <= imax; i++) { - gint w, h; - char desc[32]; - int y = (int) (g->geom.height-1 - (int )rint (i * major_tick) - - offset + corr + axis->s.y); - - debug(DBS_AXES_DRAWING) printf("%f @ %d\n", - i*axis->major + fl, y); - if (y < 0 || y > axis->p.height) - continue; - - cairo_move_to(cr, axis->p.width - 15, y+0.5); - cairo_line_to(cr, axis->s.width - 1, y+0.5); - - g_snprintf (desc, sizeof(desc), "%.*f", rdigits, i*axis->major + fl); - layout = gtk_widget_create_pango_layout (g->drawing_area, desc); - pango_layout_get_pixel_size (layout, &w, &h); - cairo_move_to (cr, axis->s.width-14-4-w, y - h/2); - pango_cairo_show_layout (cr, layout); - g_object_unref (G_OBJECT(layout)); - } - /* minor ticks */ - if (axis->minor) { - double minor_tick = axis->minor * g->zoom.y; - imin = (int) ((g->geom.height - offset + corr - g->wp.height)/minor_tick + 1); - imax = (int) ((g->geom.height - offset + corr) / minor_tick); - for (i=imin; i <= imax; i++) { - int y = (int) (g->geom.height-1 - (int )rint (i*minor_tick) - - offset + corr + axis->s.y); - - debug (DBS_AXES_DRAWING) printf ("%f @ %d\n", i*axis->minor+fl, y); - if (y > 0 && y < axis->p.height) { - cairo_move_to(cr, axis->s.width - 8, y+0.5); - cairo_line_to(cr, axis->s.width - 1, y+0.5); - } - } - } - for (i=0; axis->label[i]; i++) { - gint w, h; - layout = gtk_widget_create_pango_layout(g->drawing_area, - axis->label[i]); - pango_layout_get_pixel_size(layout, &w, &h); - cairo_move_to (cr, (axis->p.width - w)/2, TITLEBAR_HEIGHT-10 - i*(h+3) - h); - pango_cairo_show_layout (cr, layout); - g_object_unref(G_OBJECT(layout)); - } - cairo_stroke (cr); - cairo_destroy (cr); -} - -static void h_axis_pixmap_draw (struct axis *axis) -{ - struct graph *g = axis->g; - int i; - double major_tick, minor_tick; - int not_disp, rdigits, offset, imin, imax; - double left, right, j, fl, corr; - PangoLayout *layout; - cairo_t *cr; - - debug(DBS_FENTRY) puts ("h_axis_pixmap_draw()"); - left = (g->wp.x-g->geom.x) / - (double )g->geom.width * g->bounds.width; - left += axis->min; - right = (g->wp.x-g->geom.x+g->wp.width) / - (double )g->geom.width * g->bounds.width; - right += axis->min; - axis_compute_ticks (axis, left, right, AXIS_HORIZONTAL); - - j = axis->major - floor (axis->major); - for (rdigits=0; rdigits<=6; rdigits++) { - j *= 10; - if (j<=0.000001) - break; - j = j - floor (j); - } - - not_disp = 1 ^ axis->displayed; + cairo_set_source_rgb(cr, 1, 1, 1); + cairo_rectangle(cr, 0, 0, axis->p.width, axis->p.height); + cairo_fill(cr); + + /* axis */ + cairo_set_source_rgb(cr, 0, 0, 0); + cairo_set_line_width(cr, 1.0); + cairo_move_to(cr, axis->p.width - 1.5, (axis->p.height-axis->s.height)/2.0); + cairo_line_to(cr, axis->s.width - 1.5, axis->p.height); + + offset = g->wp.y + (-g->geom.y); + fl = floor(axis->min / axis->major) * axis->major; + corr = rint((axis->min - fl) * g->zoom.y); + + /* major ticks */ + major_tick = axis->major * g->zoom.y; + imin = (int) ((g->geom.height - offset + corr - g->wp.height) / major_tick + 1); + imax = (int) ((g->geom.height - offset + corr) / major_tick); + for (i=imin; i <= imax; i++) { + gint w, h; + char desc[32]; + int y = (int) (g->geom.height - 1 - (int )rint(i * major_tick) - + offset + corr + axis->s.y); + + debug(DBS_AXES_DRAWING) printf("%f @ %d\n", + (i * axis->major) + fl, y); + if ((y < 0) || (y > axis->p.height)) + continue; + + cairo_move_to(cr, axis->p.width - 15, y + 0.5); + cairo_line_to(cr, axis->s.width - 1, y + 0.5); + + g_snprintf(desc, sizeof(desc), "%.*f", rdigits, i*axis->major + fl); + layout = gtk_widget_create_pango_layout(g->drawing_area, desc); + pango_layout_get_pixel_size(layout, &w, &h); + cairo_move_to(cr, axis->s.width-14-4-w, y - h/2); + pango_cairo_show_layout(cr, layout); + g_object_unref(G_OBJECT(layout)); + } + /* minor ticks */ + if (axis->minor) { + double minor_tick = axis->minor * g->zoom.y; + imin = (int) ((g->geom.height - offset + corr - g->wp.height)/minor_tick + 1); + imax = (int) ((g->geom.height - offset + corr) / minor_tick); + for (i=imin; i <= imax; i++) { + int y = (int) (g->geom.height-1 - (int )rint (i*minor_tick) - + offset + corr + axis->s.y); + + debug(DBS_AXES_DRAWING) printf("%f @ %d\n", i*axis->minor+fl, y); + if ((y > 0) && (y < axis->p.height)) { + cairo_move_to(cr, axis->s.width - 8, y+0.5); + cairo_line_to(cr, axis->s.width - 1, y+0.5); + } + } + } + for (i=0; axis->label[i]; i++) { + gint w, h; + layout = gtk_widget_create_pango_layout(g->drawing_area, + axis->label[i]); + pango_layout_get_pixel_size(layout, &w, &h); + cairo_move_to(cr,(axis->p.width - w)/2, TITLEBAR_HEIGHT-10 - i*(h+3) - h); + pango_cairo_show_layout(cr, layout); + g_object_unref(G_OBJECT(layout)); + } + cairo_stroke(cr); + cairo_destroy(cr); +} + +static void h_axis_pixmap_draw(struct axis *axis) +{ + struct graph *g = axis->g; + int i; + double major_tick, minor_tick; + int not_disp, rdigits, offset, imin, imax; + double left, right, j, fl, corr; + PangoLayout *layout; + cairo_t *cr; + + debug(DBS_FENTRY) puts("h_axis_pixmap_draw()"); + left = (g->wp.x-g->geom.x) / (double )g->geom.width * g->bounds.width; + left += axis->min; + right = (g->wp.x - g->geom.x + g->wp.width) / (double )g->geom.width * g->bounds.width; + right += axis->min; + axis_compute_ticks(axis, left, right, AXIS_HORIZONTAL); + + j = axis->major - floor(axis->major); + for (rdigits=0; rdigits <= 6; rdigits++) { + j *= 10; + if (j <= 0.000001) + break; + j = j - floor(j); + } + + not_disp = 1 ^ axis->displayed; #if GTK_CHECK_VERSION(2,22,0) - cr = cairo_create (axis->surface[not_disp]); + cr = cairo_create(axis->surface[not_disp]); #else - cr = gdk_cairo_create (axis->pixmap[not_disp]); + cr = gdk_cairo_create(axis->pixmap[not_disp]); #endif - cairo_set_source_rgb (cr, 1, 1, 1); - cairo_rectangle (cr, 0, 0, axis->p.width, axis->p.height); - cairo_fill (cr); - - /* axis */ - cairo_set_source_rgb (cr, 0, 0, 0); - cairo_set_line_width (cr, 1.0); - cairo_move_to(cr, 0, 0.5); - cairo_line_to(cr, axis->s.width + (axis->p.width-axis->s.width)/2.0, 0.5); - - offset = g->wp.x - g->geom.x; - - fl = floor (axis->min / axis->major) * axis->major; - corr = rint ((axis->min - fl) * g->zoom.x); - - /* major ticks */ - major_tick = axis->major*g->zoom.x; - imin = (int) ((offset + corr) / major_tick + 1); - imax = (int) ((offset + corr + axis->s.width) / major_tick); - for (i=imin; i <= imax; i++) { - char desc[32]; - int w, h; - int x = (int ) (rint (i * major_tick) - offset - corr); - - /* printf ("%f @ %d\n", i*axis->major + fl, x); */ - if (x < 0 || x > axis->s.width) - continue; - cairo_move_to(cr, x+0.5, 0); - cairo_line_to(cr, x+0.5, 15); - - g_snprintf (desc, sizeof(desc), "%.*f", rdigits, i*axis->major + fl); - layout = gtk_widget_create_pango_layout(g->drawing_area, desc); - pango_layout_get_pixel_size(layout, &w, &h); - cairo_move_to (cr, x - w/2, 15+4); - pango_cairo_show_layout (cr, layout); - g_object_unref(G_OBJECT(layout)); - } - if (axis->minor > 0) { - /* minor ticks */ - minor_tick = axis->minor*g->zoom.x; - imin = (int) ((offset + corr) / minor_tick + 1); - imax = (int) ((offset + corr + g->wp.width) / minor_tick); - for (i=imin; i <= imax; i++) { - int x = (int) (rint (i * minor_tick) - offset - corr); - if (x > 0 && x < axis->s.width){ - cairo_move_to(cr, x+0.5, 0); - cairo_line_to(cr, x+0.5, 8); - } - } - } - for (i=0; axis->label[i]; i++) { - gint w, h; - layout = gtk_widget_create_pango_layout(g->drawing_area, - axis->label[i]); - pango_layout_get_pixel_size(layout, &w, &h); - cairo_move_to (cr, axis->s.width - w - 50, 15+h+15 + i*(h+3)); - pango_cairo_show_layout (cr, layout); - g_object_unref(G_OBJECT(layout)); - } - cairo_stroke (cr); - cairo_destroy (cr); -} - -static void axis_pixmaps_switch (struct axis *axis) -{ - axis->displayed = 1 ^ axis->displayed; -} - -static void axis_pixmap_display (struct axis *axis) -{ - cairo_t *cr; - - cr = gdk_cairo_create (gtk_widget_get_window(axis->drawing_area)); + cairo_set_source_rgb(cr, 1, 1, 1); + cairo_rectangle(cr, 0, 0, axis->p.width, axis->p.height); + cairo_fill(cr); + + /* axis */ + cairo_set_source_rgb(cr, 0, 0, 0); + cairo_set_line_width(cr, 1.0); + cairo_move_to(cr, 0, 0.5); + cairo_line_to(cr, axis->s.width + (axis->p.width-axis->s.width)/2.0, 0.5); + + offset = g->wp.x - g->geom.x; + + fl = floor(axis->min / axis->major) * axis->major; + corr = rint((axis->min - fl) * g->zoom.x); + + /* major ticks */ + major_tick = axis->major*g->zoom.x; + imin = (int) ((offset + corr) / major_tick + 1); + imax = (int) ((offset + corr + axis->s.width) / major_tick); + for (i=imin; i <= imax; i++) { + char desc[32]; + int w, h; + int x = (int ) (rint(i * major_tick) - offset - corr); + + /* printf("%f @ %d\n", i*axis->major + fl, x); */ + if ((x < 0) || (x > axis->s.width)) + continue; + cairo_move_to(cr, x+0.5, 0); + cairo_line_to(cr, x+0.5, 15); + + g_snprintf(desc, sizeof(desc), "%.*f", rdigits, i*axis->major + fl); + layout = gtk_widget_create_pango_layout(g->drawing_area, desc); + pango_layout_get_pixel_size(layout, &w, &h); + cairo_move_to(cr, x - w/2, 15+4); + pango_cairo_show_layout(cr, layout); + g_object_unref(G_OBJECT(layout)); + } + if (axis->minor > 0) { + /* minor ticks */ + minor_tick = axis->minor*g->zoom.x; + imin = (int) ((offset + corr) / minor_tick + 1); + imax = (int) ((offset + corr + g->wp.width) / minor_tick); + for (i=imin; i <= imax; i++) { + int x = (int) (rint(i * minor_tick) - offset - corr); + if ((x > 0) && (x < axis->s.width)) { + cairo_move_to(cr, x+0.5, 0); + cairo_line_to(cr, x+0.5, 8); + } + } + } + for (i=0; axis->label[i]; i++) { + gint w, h; + layout = gtk_widget_create_pango_layout(g->drawing_area, + axis->label[i]); + pango_layout_get_pixel_size(layout, &w, &h); + cairo_move_to(cr, axis->s.width - w - 50, 15+h+15 + i*(h+3)); + pango_cairo_show_layout(cr, layout); + g_object_unref(G_OBJECT(layout)); + } + cairo_stroke(cr); + cairo_destroy(cr); +} + +static void axis_pixmaps_switch(struct axis *axis) +{ + axis->displayed = 1 ^ axis->displayed; +} + +static void axis_pixmap_display(struct axis *axis) +{ + cairo_t *cr; + + cr = gdk_cairo_create(gtk_widget_get_window(axis->drawing_area)); #if GTK_CHECK_VERSION(2,22,0) - cairo_set_source_surface (cr, axis->surface[axis->displayed], axis->p.x, axis->p.y); + cairo_set_source_surface(cr, axis->surface[axis->displayed], axis->p.x, axis->p.y); #else - gdk_cairo_set_source_pixmap (cr, axis->pixmap[axis->displayed], axis->p.x, axis->p.y); + gdk_cairo_set_source_pixmap(cr, axis->pixmap[axis->displayed], axis->p.x, axis->p.y); #endif - cairo_rectangle (cr, axis->p.x, axis->p.y, axis->p.width, axis->p.height); - cairo_fill (cr); - cairo_destroy (cr); - -} - -static void axis_compute_ticks (struct axis *axis, double x0, double xmax, int dir) -{ - int i, j, ii, jj, ms; - double zoom, x, steps[3]={ 0.1, 0.5 }; - int dim, check_needed, diminished; - double majthresh[2]={2.0, 3.0}; - - debug((DBS_FENTRY | DBS_AXES_TICKS)) puts ("axis_compute_ticks()"); - debug(DBS_AXES_TICKS) - printf ("x0=%f xmax=%f dir=%s\n", x0,xmax, dir?"VERTICAL":"HORIZONTAL"); - - zoom = axis_zoom_get (axis, dir); - x = xmax-x0; - for (i=-9; i<=12; i++) { - if (x / pow (10, i) < 1) - break; - } - --i; - ms = (int )(x / pow (10, i)); - - if (ms > 5) { - j = 0; - ++i; - } else if (ms > 2) - j = 1; - else - j = 0; - - axis->major = steps[j] * pow (10, i); - - debug(DBS_AXES_TICKS) printf ("zoom=%.1f, x=%f -> i=%d -> ms=%d -> j=%d ->" - " axis->major=%f\n", zoom, x, i, ms, j, axis->major); - - /* let's compute minor ticks */ - jj = j; - ii = i; - axis_ticks_down (&ii, &jj); - axis->minor = steps[jj] * pow (10, ii); - /* we don't want minors if they would be less than 10 pixels apart */ - if (axis->minor*zoom < 10) { - debug(DBS_AXES_TICKS) printf ("refusing axis->minor of %f: " - "axis->minor*zoom == %f\n", axis->minor, axis->minor*zoom); - axis->minor = 0; - } - - check_needed = TRUE; - diminished = FALSE; - while (check_needed) { - check_needed = FALSE; - dim = get_label_dim (axis, dir, xmax); - debug(DBS_AXES_TICKS) printf ("axis->major==%.1f, axis->minor==%.1f =>" - " axis->major*zoom/dim==%f, axis->minor*zoom/dim==%f\n", - axis->major, axis->minor, axis->major*zoom/dim, - axis->minor*zoom/dim); - - /* corrections: if majors are less than majthresh[dir] times label - * dimension apart, we need to use bigger ones */ - if (axis->major*zoom / dim < majthresh[dir]) { - axis_ticks_up (&ii, &jj); - axis->minor = axis->major; - axis_ticks_up (&i, &j); - axis->major = steps[j] * pow (10, i); - check_needed = TRUE; - debug(DBS_AXES_TICKS) printf ("axis->major enlarged to %.1f\n", - axis->major); - } - /* if minor ticks are bigger than majthresh[dir] times label dimension, - * we could promote them to majors as well */ - if (axis->minor*zoom / dim > majthresh[dir] && !diminished) { - axis_ticks_down (&i, &j); - axis->major = axis->minor; - axis_ticks_down (&ii, &jj); - axis->minor = steps[jj] * pow (10, ii); - check_needed = TRUE; - diminished = TRUE; - - debug(DBS_AXES_TICKS) printf ("axis->minor diminished to %.1f\n", - axis->minor); - - if (axis->minor*zoom < 10) { - debug(DBS_AXES_TICKS) printf ("refusing axis->minor of %f: " - "axis->minor*zoom == %f\n", axis->minor, axis->minor*zoom); - axis->minor = 0; - } - } - } - - debug(DBS_AXES_TICKS) printf ("corrected: axis->major == %.1f -> " - "axis->minor == %.1f\n", axis->major, axis->minor); -} - -static void axis_ticks_up (int *i, int *j) -{ - (*j)++; - if (*j>1) { - (*i)++; - *j=0; - } -} - -static void axis_ticks_down (int *i, int *j) -{ - (*j)--; - if (*j<0) { - (*i)--; - *j=1; - } -} - -static int get_label_dim (struct axis *axis, int dir, double label) -{ - double y; - char str[32]; - int rdigits, dim; - PangoLayout *layout; - - /* First, let's compute how many digits to the right of radix - * we need to print */ - y = axis->major - floor (axis->major); - for (rdigits=0; rdigits<=6; rdigits++) { - y *= 10; - if (y<=0.000001) - break; - y = y - floor (y); - } - g_snprintf (str, sizeof(str), "%.*f", rdigits, label); - switch (dir) { - case AXIS_HORIZONTAL: - layout = gtk_widget_create_pango_layout(axis->g->drawing_area, - str); - pango_layout_get_pixel_size(layout, &dim, NULL); - g_object_unref(G_OBJECT(layout)); - break; - case AXIS_VERTICAL: - layout = gtk_widget_create_pango_layout(axis->g->drawing_area, - str); - pango_layout_get_pixel_size(layout, NULL, &dim); - g_object_unref(G_OBJECT(layout)); - break; - default: - puts ("initialize axis: an axis must be either horizontal or vertical"); - return -1; - } - return dim; -} - -static double axis_zoom_get (struct axis *axis, int dir) -{ - switch (dir) { - case AXIS_HORIZONTAL: - return axis->g->zoom.x; - case AXIS_VERTICAL: - return axis->g->zoom.y; - default: - return -1; - } -} - -static void graph_select_segment (struct graph *g, int x, int y) -{ - struct element_list *list; - struct element *e; - guint num = 0; - - debug(DBS_FENTRY) puts ("graph_select_segment()"); - - x -= g->geom.x; - y = g->geom.height-1 - (y - g->geom.y); - - set_busy_cursor (gtk_widget_get_window(g->drawing_area)); - - for (list=g->elists; list; list=list->next) - for (e=list->elements; e->type != ELMT_NONE; e++) { - switch (e->type) { - case ELMT_RECT: - break; - case ELMT_LINE: - if (line_detect_collision (e, x, y)) { - num = e->parent->num; - } - break; - case ELMT_ELLIPSE: - if (ellipse_detect_collision (e, x, y)) { - num = e->parent->num; - } - break; - default: - break; - } - } - - - if (num) { - cf_goto_frame(&cfile, num); - } - unset_busy_cursor (gtk_widget_get_window(g->drawing_area), g->cross.draw); -} - -static int line_detect_collision (struct element *e, int x, int y) -{ - int xx1, yy1, xx2, yy2; - - if (e->p.line.dim.x1 < e->p.line.dim.x2) { - xx1 = (int )rint (e->p.line.dim.x1); - xx2 = (int )rint (e->p.line.dim.x2); - } else { - xx1 = (int )rint (e->p.line.dim.x2); - xx2 = (int )rint (e->p.line.dim.x1); - } - if (e->p.line.dim.y1 < e->p.line.dim.y2) { - yy1 = (int )rint (e->p.line.dim.y1); - yy2 = (int )rint (e->p.line.dim.y2); - } else { - yy1 = (int )rint (e->p.line.dim.y2); - yy2 = (int )rint (e->p.line.dim.y1); - } - /* - printf ("line: (%d,%d)->(%d,%d), clicked: (%d,%d)\n", xx1, yy1, xx2, yy2, x, y); - */ - if ((xx1==x && xx2==x && yy1<=y && y<=yy2)||(yy1==y && yy2==y && xx1<=x && x<=xx2)) - return TRUE; - else - return FALSE; -} - -static int ellipse_detect_collision (struct element *e, int x, int y) -{ - int xx1, yy1, xx2, yy2; - - xx1 = (int )rint (e->p.ellipse.dim.x); - xx2 = (int )rint (e->p.ellipse.dim.x + e->p.ellipse.dim.width); - yy1 = (int )rint (e->p.ellipse.dim.y - e->p.ellipse.dim.height); - yy2 = (int )rint (e->p.ellipse.dim.y); - /* - printf ("ellipse: (%d,%d)->(%d,%d), clicked: (%d,%d)\n", xx1, yy1, xx2, yy2, x, y); - */ - if (xx1<=x && x<=xx2 && yy1<=y && y<=yy2) - return TRUE; - else - return FALSE; + cairo_rectangle(cr, axis->p.x, axis->p.y, axis->p.width, axis->p.height); + cairo_fill(cr); + cairo_destroy(cr); + +} + +static void axis_compute_ticks(struct axis *axis, double x0, double xmax, int dir) +{ + int i, j, ii, jj, ms; + double zoom, x, steps[3] = { 0.1, 0.5 }; + int dim, check_needed, diminished; + double majthresh[2] = {2.0, 3.0}; + + debug((DBS_FENTRY | DBS_AXES_TICKS)) puts("axis_compute_ticks()"); + debug(DBS_AXES_TICKS) + printf("x0=%f xmax=%f dir=%s\n", x0,xmax, dir?"VERTICAL":"HORIZONTAL"); + + zoom = axis_zoom_get(axis, dir); + x = xmax-x0; + for (i=-9; i <= 12; i++) { + if (x / pow(10, i) < 1) + break; + } + --i; + ms = (int )(x / pow(10, i)); + + if (ms > 5) { + j = 0; + ++i; + } else if (ms > 2) + j = 1; + else + j = 0; + + axis->major = steps[j] * pow(10, i); + + debug(DBS_AXES_TICKS) printf("zoom=%.1f, x=%f -> i=%d -> ms=%d -> j=%d ->" + " axis->major=%f\n", zoom, x, i, ms, j, axis->major); + + /* let's compute minor ticks */ + jj = j; + ii = i; + axis_ticks_down(&ii, &jj); + axis->minor = steps[jj] * pow(10, ii); + /* we don't want minors if they would be less than 10 pixels apart */ + if (axis->minor*zoom < 10) { + debug(DBS_AXES_TICKS) printf("refusing axis->minor of %f: " + "axis->minor*zoom == %f\n", axis->minor, axis->minor*zoom); + axis->minor = 0; + } + + check_needed = TRUE; + diminished = FALSE; + while (check_needed) { + check_needed = FALSE; + dim = get_label_dim(axis, dir, xmax); + debug(DBS_AXES_TICKS) printf("axis->major==%.1f, axis->minor==%.1f =>" + " axis->major*zoom/dim==%f, axis->minor*zoom/dim==%f\n", + axis->major, axis->minor, axis->major*zoom/dim, + axis->minor*zoom/dim); + + /* corrections: if majors are less than majthresh[dir] times label + * dimension apart, we need to use bigger ones */ + if (axis->major*zoom / dim < majthresh[dir]) { + axis_ticks_up(&ii, &jj); + axis->minor = axis->major; + axis_ticks_up(&i, &j); + axis->major = steps[j] * pow(10, i); + check_needed = TRUE; + debug(DBS_AXES_TICKS) printf("axis->major enlarged to %.1f\n", + axis->major); + } + /* if minor ticks are bigger than majthresh[dir] times label dimension, + * we could promote them to majors as well */ + if (((axis->minor * zoom / dim) > majthresh[dir]) && !diminished) { + axis_ticks_down(&i, &j); + axis->major = axis->minor; + axis_ticks_down(&ii, &jj); + axis->minor = steps[jj] * pow(10, ii); + check_needed = TRUE; + diminished = TRUE; + + debug(DBS_AXES_TICKS) printf("axis->minor diminished to %.1f\n", + axis->minor); + + if (axis->minor*zoom < 10) { + debug(DBS_AXES_TICKS) printf("refusing axis->minor of %f:" + " axis->minor*zoom == %f\n", + axis->minor, axis->minor*zoom); + axis->minor = 0; + } + } + } + + debug(DBS_AXES_TICKS) printf("corrected: axis->major == %.1f ->" + " axis->minor == %.1f\n", axis->major, axis->minor); +} + +static void axis_ticks_up(int *i, int *j) +{ + (*j)++; + if (*j > 1) { + (*i)++; + *j = 0; + } +} + +static void axis_ticks_down(int *i, int *j) +{ + (*j)--; + if (*j < 0) { + (*i)--; + *j = 1; + } +} + +static int get_label_dim(struct axis *axis, int dir, double label) +{ + double y; + char str[32]; + int rdigits, dim; + PangoLayout *layout; + + /* First, let's compute how many digits to the right of radix + * we need to print */ + y = axis->major - floor(axis->major); + for (rdigits=0; rdigits <= 6; rdigits++) { + y *= 10; + if (y <= 0.000001) + break; + y = y - floor(y); + } + g_snprintf(str, sizeof(str), "%.*f", rdigits, label); + switch (dir) { + case AXIS_HORIZONTAL: + layout = gtk_widget_create_pango_layout(axis->g->drawing_area, str); + pango_layout_get_pixel_size(layout, &dim, NULL); + g_object_unref(G_OBJECT(layout)); + break; + case AXIS_VERTICAL: + layout = gtk_widget_create_pango_layout(axis->g->drawing_area, + str); + pango_layout_get_pixel_size(layout, NULL, &dim); + g_object_unref(G_OBJECT(layout)); + break; + default: + puts("initialize axis: an axis must be either horizontal or vertical"); + return -1; + } + return dim; +} + +static double axis_zoom_get(struct axis *axis, int dir) +{ + switch (dir) { + case AXIS_HORIZONTAL: + return axis->g->zoom.x; + case AXIS_VERTICAL: + return axis->g->zoom.y; + default: + return -1; + } +} + +static void graph_select_segment(struct graph *g, int x, int y) +{ + struct element_list *list; + struct element *e; + guint num = 0; + + debug(DBS_FENTRY) puts("graph_select_segment()"); + + x -= g->geom.x; + y = g->geom.height-1 - (y - g->geom.y); + + set_busy_cursor(gtk_widget_get_window(g->drawing_area)); + + for (list=g->elists; list; list=list->next) { + for (e=list->elements; e->type != ELMT_NONE; e++) { + switch (e->type) { + case ELMT_RECT: + break; + case ELMT_LINE: + if (line_detect_collision(e, x, y)) { + num = e->parent->num; + } + break; + case ELMT_ELLIPSE: + if (ellipse_detect_collision(e, x, y)) { + num = e->parent->num; + } + break; + default: + break; + } + } + } + + if (num) { + cf_goto_frame(&cfile, num); + } + unset_busy_cursor(gtk_widget_get_window(g->drawing_area), g->cross.draw); +} + +static int line_detect_collision(struct element *e, int x, int y) +{ + int xx1, yy1, xx2, yy2; + + if (e->p.line.dim.x1 < e->p.line.dim.x2) { + xx1 = (int )rint(e->p.line.dim.x1); + xx2 = (int )rint(e->p.line.dim.x2); + } else { + xx1 = (int )rint(e->p.line.dim.x2); + xx2 = (int )rint(e->p.line.dim.x1); + } + if (e->p.line.dim.y1 < e->p.line.dim.y2) { + yy1 = (int )rint(e->p.line.dim.y1); + yy2 = (int )rint(e->p.line.dim.y2); + } else { + yy1 = (int )rint(e->p.line.dim.y2); + yy2 = (int )rint(e->p.line.dim.y1); + } + /* + printf("line: (%d,%d)->(%d,%d), clicked: (%d,%d)\n", xx1, yy1, xx2, yy2, x, y); + */ + if (((xx1 == x) && (xx2 == x) && (yy1 <= y) && (y <= yy2)) || + ((yy1 == y) && (yy2 == y) && (xx1 <= x) && (x <= xx2))) + return TRUE; + else + return FALSE; +} + +static int ellipse_detect_collision(struct element *e, int x, int y) +{ + int xx1, yy1, xx2, yy2; + + xx1 = (int )rint(e->p.ellipse.dim.x); + xx2 = (int )rint(e->p.ellipse.dim.x + e->p.ellipse.dim.width); + yy1 = (int )rint(e->p.ellipse.dim.y - e->p.ellipse.dim.height); + yy2 = (int )rint(e->p.ellipse.dim.y); + /* + printf("ellipse: (%d,%d)->(%d,%d), clicked: (%d,%d)\n", xx1, yy1, xx2, yy2, x, y); + */ + if ((xx1 <= x) && (x <= xx2) && (yy1 <= y) && (y <= yy2)) + return TRUE; + else + return FALSE; } -static void cross_draw (struct graph *g, int x, int y) +static void cross_draw(struct graph *g, int x, int y) { - /* Shouldn't draw twice onto the same position if haven't erased in the - meantime! */ - if (g->cross.erase_needed && (g->cross.x == x) && (g->cross.y == y)) { - return; - } + /* Shouldn't draw twice onto the same position if haven't erased in the + meantime! */ + if (g->cross.erase_needed && (g->cross.x == x) && (g->cross.y == y)) { + return; + } + + /* Draw the cross */ + if ((x > g->wp.x + 0.5) && (x < g->wp.x+g->wp.width) && + (y > g->wp.y) && (y < g->wp.y+g->wp.height)) { + + cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(g->drawing_area)); + gdk_cairo_set_source_color(cr, &g->s.tseq_tcptrace.seq_color); + cairo_set_line_width(cr, 1.0); + + /* Horizonal line */ + cairo_move_to(cr, g->wp.x, y); + cairo_line_to(cr, g->wp.x + g->wp.width, y); + + /* Vertical line */ + cairo_move_to(cr, x, g->wp.y); + cairo_line_to(cr, x, g->wp.y + g->wp.height); + cairo_stroke(cr); + cairo_destroy(cr); + } + + g->cross.x = x; + g->cross.y = y; + g->cross.erase_needed = TRUE; +} + +static void zoomrect_draw(struct graph *g, int x, int y) +{ + if ((x > g->wp.x + 0.5) && (x < g->wp.x+g->wp.width) && + (y > g->wp.y) && (y < g->wp.y+g->wp.height)) { + + cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(g->drawing_area)); + gdk_cairo_set_source_color(cr, &g->s.tseq_tcptrace.seq_color); + cairo_set_line_width(cr, 1.0); + + /* Do outline of rect */ + cairo_rectangle(cr, zoomrect.x, zoomrect.y, x-zoomrect.x, y-zoomrect.y); + cairo_stroke(cr); + cairo_destroy(cr); + } + + g->zoomrect_erase_needed = TRUE; +} + +static void zoomrect_erase(struct graph *g) +{ + /* Just redraw what is in the pixmap buffer */ + graph_pixmap_display(g); + g->zoomrect_erase_needed = FALSE; +} + +static void cross_erase(struct graph *g) +{ + int x = g->cross.x; + int y = g->cross.y; + + g->cross.erase_needed = FALSE; + + if ((x > g->wp.x) && (x < g->wp.x+g->wp.width) && + (y >= g->wp.y) && (y < g->wp.y+g->wp.height)) { + + /* Just redraw what is in the pixmap buffer */ + graph_pixmap_display(g); + } +} + +static void magnify_move(struct graph *g, int x, int y) +{ + struct ipoint pos, offsetpos; + + get_mouse_position(g->toplevel, &pos.x, &pos.y, NULL); + g->magnify.x = pos.x + x - g->magnify.width/2; + g->magnify.y = pos.y + y - g->magnify.height/2; + offsetpos.x = g->magnify.x + g->magnify.offset.x; + offsetpos.x = offsetpos.x >= 0 ? offsetpos.x : 0; + offsetpos.y = g->magnify.y + g->magnify.offset.y; + offsetpos.y = offsetpos.y >= 0 ? offsetpos.y : 0; + magnify_get_geom(g, x, y); + magnify_draw(g); +} + +static void magnify_create(struct graph *g, int x, int y) +{ + struct graph *mg; + struct ipoint pos, offsetpos; + GdkEvent *e = NULL; + struct element_list *list, *new_list; + + mg = g->magnify.g = (struct graph * )g_malloc(sizeof(struct graph)); + memcpy((void * )mg, (void * )g, sizeof(struct graph)); - /* Draw the cross */ - if (x > g->wp.x+0.5 && x < g->wp.x+g->wp.width && - y > g->wp.y && y < g->wp.y+g->wp.height) { + mg->toplevel = dlg_window_new("tcp graph magnify"); + mg->drawing_area = mg->toplevel; + gtk_window_set_default_size(GTK_WINDOW(mg->toplevel), g->magnify.width, g->magnify.height); + gtk_widget_set_events(mg->drawing_area, GDK_EXPOSURE_MASK + /* | GDK_ENTER_NOTIFY_MASK */ + /* | GDK_ALL_EVENTS_MASK */ + ); + + mg->wp.x = 0; + mg->wp.y = 0; + mg->wp.width = g->magnify.width; + mg->wp.height = g->magnify.height; + mg->geom.width = (int )rint(g->geom.width * g->magnify.zoom.x); + mg->geom.height = (int )rint(g->geom.height * g->magnify.zoom.y); + mg->zoom.x = (mg->geom.width - 1) / g->bounds.width; + mg->zoom.y = (mg->geom.height- 1) / g->bounds.height; + + /* in order to keep original element lists intact we need our own */ + graph_element_lists_initialize(mg); + list = g->elists->next; + new_list = mg->elists; + for ( ; list; list=list->next) { + new_list->next = (struct element_list * )g_malloc(sizeof(struct element_list)); + new_list = new_list->next; + new_list->next = NULL; + new_list->elements = NULL; + } + graph_element_lists_make(mg); - cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(g->drawing_area)); - gdk_cairo_set_source_color(cr, &g->s.tseq_tcptrace.seq_color); - cairo_set_line_width(cr, 1.0); - - /* Horizonal line */ - cairo_move_to(cr, g->wp.x, y); - cairo_line_to(cr, g->wp.x + g->wp.width, y); - - /* Vertical line */ - cairo_move_to(cr, x, g->wp.y); - cairo_line_to(cr, x, g->wp.y + g->wp.height); - cairo_stroke(cr); - cairo_destroy(cr); - } - - g->cross.x = x; - g->cross.y = y; - g->cross.erase_needed = TRUE; -} - -static void zoomrect_draw (struct graph *g, int x, int y) -{ - if (x > g->wp.x+0.5 && x < g->wp.x+g->wp.width && - y > g->wp.y && y < g->wp.y+g->wp.height) { - - cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(g->drawing_area)); - gdk_cairo_set_source_color(cr, &g->s.tseq_tcptrace.seq_color); - cairo_set_line_width(cr, 1.0); - - /* Do outline of rect */ - cairo_rectangle(cr, zoomrect.x, zoomrect.y, x-zoomrect.x, y-zoomrect.y); - cairo_stroke(cr); - cairo_destroy(cr); - } - - g->zoomrect_erase_needed = TRUE; -} - -static void zoomrect_erase (struct graph *g) -{ - /* Just redraw what is in the pixmap buffer */ - graph_pixmap_display(g); - g->zoomrect_erase_needed = FALSE; -} - -static void cross_erase (struct graph *g) -{ - int x = g->cross.x; - int y = g->cross.y; - - g->cross.erase_needed = FALSE; - - if (x > g->wp.x && x < g->wp.x+g->wp.width && - y >= g->wp.y && y < g->wp.y+g->wp.height) { - - /* Just redraw what is in the pixmap buffer */ - graph_pixmap_display(g); - } -} - -static void magnify_move (struct graph *g, int x, int y) -{ - struct ipoint pos, offsetpos; - - get_mouse_position(g->toplevel, &pos.x, &pos.y, NULL); - g->magnify.x = pos.x + x - g->magnify.width/2; - g->magnify.y = pos.y + y - g->magnify.height/2; - offsetpos.x = g->magnify.x + g->magnify.offset.x; - offsetpos.x = offsetpos.x >= 0 ? offsetpos.x : 0; - offsetpos.y = g->magnify.y + g->magnify.offset.y; - offsetpos.y = offsetpos.y >= 0 ? offsetpos.y : 0; - magnify_get_geom (g, x, y); - magnify_draw (g); -} - -static void magnify_create (struct graph *g, int x, int y) -{ - struct graph *mg; - struct element_list *list, *new_list; - struct ipoint pos, offsetpos; - GdkEvent *e=NULL; - - mg = g->magnify.g = (struct graph * )g_malloc (sizeof (struct graph)); - memcpy ((void * )mg, (void * )g, sizeof (struct graph)); - - mg->toplevel = dlg_window_new("tcp graph magnify"); - mg->drawing_area = mg->toplevel; - gtk_window_set_default_size(GTK_WINDOW(mg->toplevel), g->magnify.width, g->magnify.height); - gtk_widget_set_events (mg->drawing_area, GDK_EXPOSURE_MASK - /* | GDK_ENTER_NOTIFY_MASK */ - /* | GDK_ALL_EVENTS_MASK */ - ); - - mg->wp.x = 0; - mg->wp.y = 0; - mg->wp.width = g->magnify.width; - mg->wp.height = g->magnify.height; - mg->geom.width = (int )rint (g->geom.width * g->magnify.zoom.x); - mg->geom.height = (int )rint (g->geom.height * g->magnify.zoom.y); - mg->zoom.x = (mg->geom.width - 1) / g->bounds.width; - mg->zoom.y = (mg->geom.height- 1) / g->bounds.height; - - /* in order to keep original element lists intact we need our own */ - graph_element_lists_initialize (mg); - list = g->elists->next; - new_list = mg->elists; - for ( ; list; list=list->next) { - new_list->next = - (struct element_list * )g_malloc (sizeof (struct element_list)); - new_list = new_list->next; - new_list->next = NULL; - new_list->elements = NULL; - } - graph_element_lists_make (mg); - - get_mouse_position(g->toplevel, &pos.x, &pos.y, NULL); - g->magnify.x = pos.x + x - g->magnify.width/2; - g->magnify.y = pos.y + y - g->magnify.height/2; - offsetpos.x = g->magnify.x + g->magnify.offset.x; - offsetpos.x = offsetpos.x >= 0 ? offsetpos.x : 0; - offsetpos.y = g->magnify.y + g->magnify.offset.y; - offsetpos.y = offsetpos.y >= 0 ? offsetpos.y : 0; - gtk_window_set_position (GTK_WINDOW(mg->drawing_area), GTK_WIN_POS_NONE); - magnify_get_geom (g, x, y); - - gtk_widget_show (mg->drawing_area); - - /* we need to wait for the first expose event before we start drawing */ - while (!gdk_events_pending ()); - do { - e = gdk_event_get (); - if (e) { - if (e->any.type == GDK_EXPOSE) { - gdk_event_free (e); - break; - } - gdk_event_free (e); - } - } while (e); + get_mouse_position(g->toplevel, &pos.x, &pos.y, NULL); + g->magnify.x = pos.x + x - g->magnify.width/2; + g->magnify.y = pos.y + y - g->magnify.height/2; + offsetpos.x = g->magnify.x + g->magnify.offset.x; + offsetpos.x = offsetpos.x >= 0 ? offsetpos.x : 0; + offsetpos.y = g->magnify.y + g->magnify.offset.y; + offsetpos.y = offsetpos.y >= 0 ? offsetpos.y : 0; + gtk_window_set_position(GTK_WINDOW(mg->drawing_area), GTK_WIN_POS_NONE); + magnify_get_geom(g, x, y); + + gtk_widget_show(mg->drawing_area); + + /* we need to wait for the first expose event before we start drawing */ + while (!gdk_events_pending()); + do { + e = gdk_event_get(); + if (e) { + if (e->any.type == GDK_EXPOSE) { + gdk_event_free(e); + break; + } + gdk_event_free(e); + } + } while (e); #if GTK_CHECK_VERSION(2,22,0) - mg->surface[0] = mg->surface[1] = NULL; + mg->surface[0] = mg->surface[1] = NULL; #else - mg->pixmap[0] = mg->pixmap[1] = NULL; + mg->pixmap[0] = mg->pixmap[1] = NULL; #endif /* GTK_CHECK_VERSION(2,22,0) */ - graph_pixmaps_create (mg); - magnify_draw (g); - g->magnify.active = 1; + graph_pixmaps_create(mg); + magnify_draw(g); + g->magnify.active = 1; } -static void magnify_destroy (struct graph *g) +static void magnify_destroy(struct graph *g) { - struct element_list *list; - struct graph *mg = g->magnify.g; + struct element_list *list; + struct graph *mg = g->magnify.g; - window_destroy (GTK_WIDGET (mg->drawing_area)); + window_destroy(GTK_WIDGET(mg->drawing_area)); #if GTK_CHECK_VERSION(2,22,0) - if(mg->surface[0]){ - cairo_surface_destroy (mg->surface[0]); - } - if(mg->surface[1]){ - cairo_surface_destroy (mg->surface[1]); - } + if (mg->surface[0]) { + cairo_surface_destroy(mg->surface[0]); + } + if (mg->surface[1]) { + cairo_surface_destroy(mg->surface[1]); + } #else - g_object_unref (mg->pixmap[0]); - g_object_unref (mg->pixmap[1]); + g_object_unref(mg->pixmap[0]); + g_object_unref(mg->pixmap[1]); #endif /* GTK_CHECK_VERSION(2,22,0) */ - for (list=mg->elists; list; list=list->next) - g_free (list->elements); + for (list=mg->elists; list; list=list->next) + g_free(list->elements); - if (mg->elists) { - while (mg->elists->next) { - list = mg->elists->next->next; - g_free (mg->elists->next); - mg->elists->next = list; - } - } - g_free (g->magnify.g); - g->magnify.active = 0; + if (mg->elists) { + while (mg->elists->next) { + list = mg->elists->next->next; + g_free(mg->elists->next); + mg->elists->next = list; + } + } + g_free(g->magnify.g); + g->magnify.active = 0; } -static void magnify_get_geom (struct graph *g, int x, int y) +static void magnify_get_geom(struct graph *g, int x, int y) { - int posx, posy; + int posx, posy; - get_mouse_position(g->toplevel, &posx, &posy, NULL); + get_mouse_position(g->toplevel, &posx, &posy, NULL); - g->magnify.g->geom.x = g->geom.x; - g->magnify.g->geom.y = g->geom.y; + g->magnify.g->geom.x = g->geom.x; + g->magnify.g->geom.y = g->geom.y; - g->magnify.g->geom.x -= - (int )rint ((g->magnify.g->geom.width - g->geom.width) * - ((x-g->geom.x)/(double )g->geom.width)); - g->magnify.g->geom.y -= - (int )rint ((g->magnify.g->geom.height - g->geom.height) * - ((y-g->geom.y)/(double )g->geom.height)); + g->magnify.g->geom.x -= (int )rint((g->magnify.g->geom.width - g->geom.width) * + ((x-g->geom.x)/(double )g->geom.width)); + g->magnify.g->geom.y -= (int )rint((g->magnify.g->geom.height - g->geom.height) * + ((y-g->geom.y)/(double )g->geom.height)); - /* we have coords of origin of graph relative to origin of g->toplevel. - * now we need them to relate to origin of magnify window */ - g->magnify.g->geom.x -= (g->magnify.x - posx); - g->magnify.g->geom.y -= (g->magnify.y - posy); + /* we have coords of origin of graph relative to origin of g->toplevel. + * now we need them to relate to origin of magnify window */ + g->magnify.g->geom.x -= (g->magnify.x - posx); + g->magnify.g->geom.y -= (g->magnify.y - posy); } -static void magnify_draw (struct graph *g) +static void magnify_draw(struct graph *g) { - cairo_t *cr; - int not_disp = 1 ^ g->magnify.g->displayed; + cairo_t *cr; + int not_disp = 1 ^ g->magnify.g->displayed; - graph_pixmap_draw (g->magnify.g); - /* graph pixmap is almost ready, just add border */ + graph_pixmap_draw(g->magnify.g); + /* graph pixmap is almost ready, just add border */ #if GTK_CHECK_VERSION(2,22,0) - cr = cairo_create (g->magnify.g->surface[not_disp]); + cr = cairo_create(g->magnify.g->surface[not_disp]); #else - cr = gdk_cairo_create (g->magnify.g->pixmap[not_disp]); + cr = gdk_cairo_create(g->magnify.g->pixmap[not_disp]); #endif /* GTK_CHECK_VERSION(2,22,0) */ - cairo_set_line_width (cr, 1.0); - cairo_move_to(cr, 0, 0); - cairo_line_to(cr, g->magnify.width - 1, 0); - cairo_stroke(cr); - - cairo_move_to(cr, g->magnify.width - 1, 0); - cairo_line_to(cr, g->magnify.width - 1, g->magnify.height); - cairo_stroke(cr); - - cairo_move_to(cr, 0, 0); - cairo_line_to(cr, 0,g->magnify.height - 1); - cairo_stroke(cr); - - cairo_move_to(cr, 0, g->magnify.height - 1); - cairo_line_to(cr, g->magnify.width - 1, g->magnify.height - 1); - cairo_stroke(cr); - cairo_destroy(cr); - - graph_pixmaps_switch (g->magnify.g); - graph_pixmap_display (g->magnify.g); - -} - -static gboolean configure_event (GtkWidget *widget _U_, GdkEventConfigure *event, gpointer user_data) -{ - struct graph *g = user_data; - struct { - double x, y; - } zoom; - int cur_g_width, cur_g_height; - int cur_wp_width, cur_wp_height; - - debug(DBS_FENTRY) puts ("configure_event()"); - - cur_wp_width = g->wp.width; - cur_wp_height = g->wp.height; - g->wp.width = event->width - g->y_axis->p.width - RMARGIN_WIDTH; - g->wp.height = event->height - g->x_axis->p.height - g->wp.y; - g->x_axis->s.width = g->wp.width; - g->x_axis->p.width = g->wp.width + RMARGIN_WIDTH; - g->y_axis->p.height = g->wp.height + g->wp.y; - g->y_axis->s.height = g->wp.height; - g->x_axis->p.y = g->y_axis->p.height; - zoom.x = (double )g->wp.width / cur_wp_width; - zoom.y = (double )g->wp.height / cur_wp_height; - cur_g_width = g->geom.width; - cur_g_height = g->geom.height; - g->geom.width = (int )rint (g->geom.width * zoom.x); - g->geom.height = (int )rint (g->geom.height * zoom.y); - g->zoom.x = (double )(g->geom.width - 1) / g->bounds.width; - g->zoom.y = (double )(g->geom.height -1) / g->bounds.height; - /* g->zoom.initial.x = g->zoom.x; */ - /* g->zoom.initial.y = g->zoom.y; */ - - g->geom.x = (int) (g->wp.x - (double )g->geom.width/cur_g_width * - (g->wp.x - g->geom.x)); - g->geom.y = (int) (g->wp.y - (double )g->geom.height/cur_g_height * - (g->wp.y - g->geom.y)); + cairo_set_line_width(cr, 1.0); + cairo_move_to(cr, 0, 0); + cairo_line_to(cr, g->magnify.width - 1, 0); + cairo_stroke(cr); + + cairo_move_to(cr, g->magnify.width - 1, 0); + cairo_line_to(cr, g->magnify.width - 1, g->magnify.height); + cairo_stroke(cr); + + cairo_move_to(cr, 0, 0); + cairo_line_to(cr, 0, g->magnify.height - 1); + cairo_stroke(cr); + + cairo_move_to(cr, 0, g->magnify.height - 1); + cairo_line_to(cr, g->magnify.width - 1, g->magnify.height - 1); + cairo_stroke(cr); + cairo_destroy(cr); + + graph_pixmaps_switch(g->magnify.g); + graph_pixmap_display(g->magnify.g); + +} + +static gboolean configure_event(GtkWidget *widget _U_, GdkEventConfigure *event, gpointer user_data) +{ + struct graph *g = user_data; + struct { + double x, y; + } zoom; + int cur_g_width, cur_g_height; + int cur_wp_width, cur_wp_height; + + debug(DBS_FENTRY) puts("configure_event()"); + + cur_wp_width = g->wp.width; + cur_wp_height = g->wp.height; + g->wp.width = event->width - g->y_axis->p.width - RMARGIN_WIDTH; + g->wp.height = event->height - g->x_axis->p.height - g->wp.y; + g->x_axis->s.width = g->wp.width; + g->x_axis->p.width = g->wp.width + RMARGIN_WIDTH; + g->y_axis->p.height = g->wp.height + g->wp.y; + g->y_axis->s.height = g->wp.height; + g->x_axis->p.y = g->y_axis->p.height; + zoom.x = (double )g->wp.width / cur_wp_width; + zoom.y = (double )g->wp.height / cur_wp_height; + cur_g_width = g->geom.width; + cur_g_height = g->geom.height; + g->geom.width = (int )rint(g->geom.width * zoom.x); + g->geom.height = (int )rint(g->geom.height * zoom.y); + g->zoom.x = (double )(g->geom.width - 1) / g->bounds.width; + g->zoom.y = (double )(g->geom.height -1) / g->bounds.height; + /* g->zoom.initial.x = g->zoom.x; */ + /* g->zoom.initial.y = g->zoom.y; */ + + g->geom.x = (int) (g->wp.x - (double )g->geom.width/cur_g_width * + (g->wp.x - g->geom.x)); + g->geom.y = (int) (g->wp.y - (double )g->geom.height/cur_g_height * + (g->wp.y - g->geom.y)); #if 0 - printf ("configure: graph: (%d,%d), (%d,%d); viewport: (%d,%d), (%d,%d); " - "zooms: (%f,%f)\n", g->geom.x, g->geom.y, g->geom.width, - g->geom.height, g->wp.x, g->wp.y, g->wp.width, g->wp.height, - g->zoom.x, g->zoom.y); + printf("configure: graph: (%d,%d), (%d,%d); viewport: (%d,%d), (%d,%d);" + " zooms: (%f,%f)\n", g->geom.x, g->geom.y, g->geom.width, + g->geom.height, g->wp.x, g->wp.y, g->wp.width, g->wp.height, + g->zoom.x, g->zoom.y); #endif - update_zoom_spins (g); - graph_element_lists_make (g); - graph_pixmaps_create (g); - graph_title_pixmap_create (g); - axis_pixmaps_create (g->y_axis); - axis_pixmaps_create (g->x_axis); - /* we don't do actual drawing here; we leave it to expose handler */ - graph_pixmap_draw (g); - graph_pixmaps_switch (g); - graph_title_pixmap_draw (g); - h_axis_pixmap_draw (g->x_axis); - axis_pixmaps_switch (g->x_axis); - v_axis_pixmap_draw (g->y_axis); - axis_pixmaps_switch (g->y_axis); - return TRUE; + update_zoom_spins(g); + graph_element_lists_make(g); + graph_pixmaps_create(g); + graph_title_pixmap_create(g); + axis_pixmaps_create(g->y_axis); + axis_pixmaps_create(g->x_axis); + /* we don't do actual drawing here; we leave it to expose handler */ + graph_pixmap_draw(g); + graph_pixmaps_switch(g); + graph_title_pixmap_draw(g); + h_axis_pixmap_draw(g->x_axis); + axis_pixmaps_switch(g->x_axis); + v_axis_pixmap_draw(g->y_axis); + axis_pixmaps_switch(g->y_axis); + return TRUE; } #if GTK_CHECK_VERSION(3,0,0) static gboolean draw_event(GtkWidget *widget _U_, cairo_t *cr, gpointer user_data) { - struct graph *g = user_data; + struct graph *g = user_data; - debug(DBS_FENTRY) puts ("draw_event()"); + debug(DBS_FENTRY) puts("draw_event()"); - /* lower left corner */ - cairo_set_source_rgb (cr, 1, 1, 1); - cairo_rectangle (cr, 0, g->wp.y + g->wp.height, g->y_axis->p.width, g->x_axis->p.height); - cairo_fill (cr); + /* lower left corner */ + cairo_set_source_rgb(cr, 1, 1, 1); + cairo_rectangle(cr, 0, g->wp.y + g->wp.height, g->y_axis->p.width, g->x_axis->p.height); + cairo_fill(cr); - /* right margin */ - cairo_rectangle (cr, g->wp.x + g->wp.width, g->wp.y, RMARGIN_WIDTH, g->wp.height); - cairo_fill (cr); + /* right margin */ + cairo_rectangle(cr, g->wp.x + g->wp.width, g->wp.y, RMARGIN_WIDTH, g->wp.height); + cairo_fill(cr); - /* Should these routines be copied here, or be given the cairo_t ?? */ - graph_pixmap_display (g); - graph_title_pixmap_display (g); - axis_pixmap_display (g->x_axis); - axis_pixmap_display (g->y_axis); + /* Should these routines be copied here, or be given the cairo_t ?? */ + graph_pixmap_display(g); + graph_title_pixmap_display(g); + axis_pixmap_display(g->x_axis); + axis_pixmap_display(g->y_axis); - return TRUE; + return TRUE; } #else -static gboolean expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data) +static gboolean expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer user_data) { - struct graph *g = user_data; - cairo_t *cr; + struct graph *g = user_data; + cairo_t *cr; - debug(DBS_FENTRY) puts ("expose_event()"); + debug(DBS_FENTRY) puts("expose_event()"); - if (event->count) - return TRUE; + if (event->count) + return TRUE; - /* lower left corner */ - cr = gdk_cairo_create (gtk_widget_get_window(widget)); - cairo_set_source_rgb (cr, 1, 1, 1); - cairo_rectangle (cr, 0, g->wp.y + g->wp.height, g->y_axis->p.width, g->x_axis->p.height); - cairo_fill (cr); - cairo_destroy(cr); - cr = NULL; + /* lower left corner */ + cr = gdk_cairo_create(gtk_widget_get_window(widget)); + cairo_set_source_rgb(cr, 1, 1, 1); + cairo_rectangle(cr, 0, g->wp.y + g->wp.height, g->y_axis->p.width, g->x_axis->p.height); + cairo_fill(cr); + cairo_destroy(cr); + cr = NULL; - /* right margin */ - cr = gdk_cairo_create (gtk_widget_get_window(widget)); - cairo_set_source_rgb (cr, 1, 1, 1); - cairo_rectangle (cr, g->wp.x + g->wp.width, g->wp.y, RMARGIN_WIDTH, g->wp.height); - cairo_fill (cr); - cairo_destroy(cr); - cr = NULL; + /* right margin */ + cr = gdk_cairo_create(gtk_widget_get_window(widget)); + cairo_set_source_rgb(cr, 1, 1, 1); + cairo_rectangle(cr, g->wp.x + g->wp.width, g->wp.y, RMARGIN_WIDTH, g->wp.height); + cairo_fill(cr); + cairo_destroy(cr); + cr = NULL; - graph_pixmap_display (g); - graph_title_pixmap_display (g); - axis_pixmap_display (g->x_axis); - axis_pixmap_display (g->y_axis); + graph_pixmap_display(g); + graph_title_pixmap_display(g); + axis_pixmap_display(g->x_axis); + axis_pixmap_display(g->y_axis); - return TRUE; + return TRUE; } #endif @@ -3291,727 +3297,727 @@ static void perform_zoom(struct graph *g, struct zoomfactor *zf, int origin_x, int origin_y, int redraw) { - int cur_width = g->geom.width, cur_height = g->geom.height; - - /* Multiply by x and y factors */ - g->geom.width = (int )rint (g->geom.width * zf->x); - g->geom.height = (int )rint (g->geom.height * zf->y); - - /* If already fully-zoomed out, don't waste time re-drawing */ - if ((g->geom.width <= g->wp.width) && - (g->geom.height <= g->wp.height)) { - return; - } - - if (g->geom.width < g->wp.width) { - g->geom.width = g->wp.width; - } - if (g->geom.height < g->wp.height) { - g->geom.height = g->wp.height; - } - - /* Divide to work out new zoom */ - g->zoom.x = (g->geom.width - 1) / g->bounds.width; - g->zoom.y = (g->geom.height- 1) / g->bounds.height; - - /* Move origin to keep mouse position at centre of view */ - g->geom.x -= (int)rint ((g->geom.width - cur_width) * - ((origin_x - g->geom.x)/(double )cur_width)); - g->geom.y -= (int)rint ((g->geom.height - cur_height) * - ((origin_y - g->geom.y)/(double )cur_height)); - - if (g->geom.x > g->wp.x) - g->geom.x = g->wp.x; - if (g->geom.y > g->wp.y) - g->geom.y = g->wp.y; - if (g->wp.x + g->wp.width > g->geom.x + g->geom.width) - g->geom.x = g->wp.width + g->wp.x - g->geom.width; - if (g->wp.y + g->wp.height > g->geom.y + g->geom.height) - g->geom.y = g->wp.height + g->wp.y - g->geom.height; - - if (redraw == ZOOM_NOREDRAW) - return; - - graph_element_lists_make(g); - g->cross.erase_needed = FALSE; - graph_display(g); - axis_display(g->y_axis); - axis_display(g->x_axis); - update_zoom_spins(g); - - if (g->cross.draw) { - g->cross.erase_needed = FALSE; - cross_draw(g, origin_x, origin_y); - } + int cur_width = g->geom.width, cur_height = g->geom.height; + + /* Multiply by x and y factors */ + g->geom.width = (int )rint(g->geom.width * zf->x); + g->geom.height = (int )rint(g->geom.height * zf->y); + + /* If already fully-zoomed out, don't waste time re-drawing */ + if ((g->geom.width <= g->wp.width) && + (g->geom.height <= g->wp.height)) { + return; + } + + if (g->geom.width < g->wp.width) { + g->geom.width = g->wp.width; + } + if (g->geom.height < g->wp.height) { + g->geom.height = g->wp.height; + } + + /* Divide to work out new zoom */ + g->zoom.x = (g->geom.width - 1) / g->bounds.width; + g->zoom.y = (g->geom.height- 1) / g->bounds.height; + + /* Move origin to keep mouse position at centre of view */ + g->geom.x -= (int)rint((g->geom.width - cur_width) * + ((origin_x - g->geom.x)/(double )cur_width)); + g->geom.y -= (int)rint((g->geom.height - cur_height) * + ((origin_y - g->geom.y)/(double )cur_height)); + + if (g->geom.x > g->wp.x) + g->geom.x = g->wp.x; + if (g->geom.y > g->wp.y) + g->geom.y = g->wp.y; + if (g->wp.x + g->wp.width > g->geom.x + g->geom.width) + g->geom.x = g->wp.width + g->wp.x - g->geom.width; + if (g->wp.y + g->wp.height > g->geom.y + g->geom.height) + g->geom.y = g->wp.height + g->wp.y - g->geom.height; + + if (redraw == ZOOM_NOREDRAW) + return; + + graph_element_lists_make(g); + g->cross.erase_needed = FALSE; + graph_display(g); + axis_display(g->y_axis); + axis_display(g->x_axis); + update_zoom_spins(g); + + if (g->cross.draw) { + g->cross.erase_needed = FALSE; + cross_draw(g, origin_x, origin_y); + } } static void get_zoomfactor(struct graph *g, struct zoomfactor *zf, double step_x, - double step_y) -{ - if (g->zoom.flags & ZOOM_OUT) { - /* - * If can't zoom out anymore don't waste time redrawing - * the whole graph! - */ - if ((g->geom.height <= g->wp.height) && - (g->geom.width <= g->wp.width)) { - zf->x = 1.0; - zf->y = 1.0; - return; - } - if (g->zoom.flags & ZOOM_HLOCK) - zf->x = 1.0; - else - zf->x = 1 / step_x; - if (g->zoom.flags & ZOOM_VLOCK) - zf->y = 1.0; - else - zf->y = 1 / step_y; - } else { - if (g->zoom.flags & ZOOM_HLOCK) - zf->x = 1.0; - else - zf->x = step_x; - if (g->zoom.flags & ZOOM_VLOCK) - zf->y = 1.0; - else - zf->y = step_y; - } + double step_y) +{ + if (g->zoom.flags & ZOOM_OUT) { + /* + * If can't zoom out anymore don't waste time redrawing + * the whole graph! + */ + if ((g->geom.height <= g->wp.height) && + (g->geom.width <= g->wp.width)) { + zf->x = 1.0; + zf->y = 1.0; + return; + } + if (g->zoom.flags & ZOOM_HLOCK) + zf->x = 1.0; + else + zf->x = 1 / step_x; + if (g->zoom.flags & ZOOM_VLOCK) + zf->y = 1.0; + else + zf->y = 1 / step_y; + } else { + if (g->zoom.flags & ZOOM_HLOCK) + zf->x = 1.0; + else + zf->x = step_x; + if (g->zoom.flags & ZOOM_VLOCK) + zf->y = 1.0; + else + zf->y = step_y; + } } static void do_zoom_rectangle(struct graph *g, struct irect lcl_zoomrect) { - int cur_width = g->wp.width, cur_height = g->wp.height; - struct irect geom1 = g->geom; - struct zoomfactor factor; - - /* Left hand too much to the right */ - if (lcl_zoomrect.x > g->wp.x + g->wp.width) - return; - /* Right hand not far enough */ - if (lcl_zoomrect.x + lcl_zoomrect.width < g->wp.x) - return; - /* Left hand too much to the left */ - if (lcl_zoomrect.x < g->wp.x) { - int dx = g->wp.x - lcl_zoomrect.x; - lcl_zoomrect.x += dx; - lcl_zoomrect.width -= dx; - } - /* Right hand too much to the right */ - if (lcl_zoomrect.x + lcl_zoomrect.width > g->wp.x + g->wp.width) { - int dx = lcl_zoomrect.width + lcl_zoomrect.x - g->wp.x - g->wp.width; - lcl_zoomrect.width -= dx; - } - - /* Top too low */ - if (lcl_zoomrect.y > g->wp.y + g->wp.height) - return; - /* Bottom too high */ - if (lcl_zoomrect.y + lcl_zoomrect.height < g->wp.y) - return; - /* Top too high */ - if (lcl_zoomrect.y < g->wp.y) { - int dy = g->wp.y - lcl_zoomrect.y; - lcl_zoomrect.y += dy; - lcl_zoomrect.height -= dy; - } - /* Bottom too low */ - if (lcl_zoomrect.y + lcl_zoomrect.height > g->wp.y + g->wp.height) { - int dy = lcl_zoomrect.height + lcl_zoomrect.y - g->wp.y - g->wp.height; - lcl_zoomrect.height -= dy; - } + int cur_width = g->wp.width, cur_height = g->wp.height; + struct irect geom1 = g->geom; + struct zoomfactor factor; + + /* Left hand too much to the right */ + if (lcl_zoomrect.x > g->wp.x + g->wp.width) + return; + /* Right hand not far enough */ + if (lcl_zoomrect.x + lcl_zoomrect.width < g->wp.x) + return; + /* Left hand too much to the left */ + if (lcl_zoomrect.x < g->wp.x) { + int dx = g->wp.x - lcl_zoomrect.x; + lcl_zoomrect.x += dx; + lcl_zoomrect.width -= dx; + } + /* Right hand too much to the right */ + if (lcl_zoomrect.x + lcl_zoomrect.width > g->wp.x + g->wp.width) { + int dx = lcl_zoomrect.width + lcl_zoomrect.x - g->wp.x - g->wp.width; + lcl_zoomrect.width -= dx; + } + + /* Top too low */ + if (lcl_zoomrect.y > g->wp.y + g->wp.height) + return; + /* Bottom too high */ + if (lcl_zoomrect.y + lcl_zoomrect.height < g->wp.y) + return; + /* Top too high */ + if (lcl_zoomrect.y < g->wp.y) { + int dy = g->wp.y - lcl_zoomrect.y; + lcl_zoomrect.y += dy; + lcl_zoomrect.height -= dy; + } + /* Bottom too low */ + if (lcl_zoomrect.y + lcl_zoomrect.height > g->wp.y + g->wp.height) { + int dy = lcl_zoomrect.height + lcl_zoomrect.y - g->wp.y - g->wp.height; + lcl_zoomrect.height -= dy; + } /* - printf("before:\n" - "\tgeom: (%d, %d)+(%d x %d)\n" + printf("before:\n" + "\tgeom: (%d, %d)+(%d x %d)\n" */ - get_zoomfactor(g, &factor, (double)cur_width / lcl_zoomrect.width, - (double)cur_height / lcl_zoomrect.height); + get_zoomfactor(g, &factor, (double)cur_width / lcl_zoomrect.width, + (double)cur_height / lcl_zoomrect.height); /* - printf("Zoomfactor: %f x %f\n", factor.x, factor.y); + printf("Zoomfactor: %f x %f\n", factor.x, factor.y); */ - perform_zoom(g, &factor, - lcl_zoomrect.x, lcl_zoomrect.y, - ZOOM_NOREDRAW); + perform_zoom(g, &factor, + lcl_zoomrect.x, lcl_zoomrect.y, + ZOOM_NOREDRAW); /* - printf("middle:\n" - "\tgeom: (%d, %d)+(%d x %d)\n" - "\twp: (%d, %d)+(%d x %d)\n" - "\tzoomrect: (%d, %d)+(%d x %d)\n", - g->geom.x, g->geom.y, - g->geom.width, g->geom.height, - g->wp.x, g->wp.y, g->wp.width, g->wp.height, - lcl_zoomrect.x, lcl_zoomrect.y, lcl_zoomrect.width, lcl_zoomrect.height); + printf("middle:\n" + "\tgeom: (%d, %d)+(%d x %d)\n" + "\twp: (%d, %d)+(%d x %d)\n" + "\tzoomrect: (%d, %d)+(%d x %d)\n", + g->geom.x, g->geom.y, + g->geom.width, g->geom.height, + g->wp.x, g->wp.y, g->wp.width, g->wp.height, + lcl_zoomrect.x, lcl_zoomrect.y, lcl_zoomrect.width, lcl_zoomrect.height); */ - g->geom.x = (int)(geom1.x * (1 + factor.x) - - lcl_zoomrect.x * factor.x - (geom1.x - g->wp.x)); - g->geom.y = (int)(geom1.y * (1 + factor.y) - - lcl_zoomrect.y * factor.y - (geom1.y - g->wp.y)); + g->geom.x = (int)(geom1.x * (1 + factor.x) - + lcl_zoomrect.x * factor.x - (geom1.x - g->wp.x)); + g->geom.y = (int)(geom1.y * (1 + factor.y) - + lcl_zoomrect.y * factor.y - (geom1.y - g->wp.y)); /* - printf("after:\n" - "\tgeom: (%d, %d)+(%d x %d)\n" - "\twp: (%d, %d)+(%d x %d)\n" - "\tzoomrect: (%d, %d)+(%d x %d)\n", - g->geom.x, g->geom.y, - g->geom.width, g->geom.height, - g->wp.x, g->wp.y, g->wp.width, g->wp.height, - lcl_zoomrect.x, lcl_zoomrect.y, lcl_zoomrect.width, lcl_zoomrect.height); + printf("after:\n" + "\tgeom: (%d, %d)+(%d x %d)\n" + "\twp: (%d, %d)+(%d x %d)\n" + "\tzoomrect: (%d, %d)+(%d x %d)\n", + g->geom.x, g->geom.y, + g->geom.width, g->geom.height, + g->wp.x, g->wp.y, g->wp.width, g->wp.height, + lcl_zoomrect.x, lcl_zoomrect.y, lcl_zoomrect.width, lcl_zoomrect.height); */ - graph_element_lists_make(g); - g->cross.erase_needed = FALSE; - graph_display(g); - axis_display(g->y_axis); - axis_display(g->x_axis); - update_zoom_spins(g); + graph_element_lists_make(g); + g->cross.erase_needed = FALSE; + graph_display(g); + axis_display(g->y_axis); + axis_display(g->x_axis); + update_zoom_spins(g); } -static void do_zoom_mouse (struct graph *g, GdkEventButton *event) +static void do_zoom_mouse(struct graph *g, GdkEventButton *event) { - struct zoomfactor factor; + struct zoomfactor factor; - get_zoomfactor(g, &factor, g->zoom.step_x, g->zoom.step_y); - perform_zoom(g, &factor, (int)event->x, (int)event->y, ZOOM_REDRAW); + get_zoomfactor(g, &factor, g->zoom.step_x, g->zoom.step_y); + perform_zoom(g, &factor, (int)event->x, (int)event->y, ZOOM_REDRAW); } -static void do_zoom_keyboard (struct graph *g) +static void do_zoom_keyboard(struct graph *g) { - int pointer_x, pointer_y; - struct zoomfactor factor; + int pointer_x, pointer_y; + struct zoomfactor factor; - get_mouse_position (g->drawing_area, &pointer_x, &pointer_y, NULL); - get_zoomfactor(g, &factor, g->zoom.step_x, g->zoom.step_y); - perform_zoom(g, &factor, pointer_x, pointer_y, ZOOM_REDRAW); + get_mouse_position(g->drawing_area, &pointer_x, &pointer_y, NULL); + get_zoomfactor(g, &factor, g->zoom.step_x, g->zoom.step_y); + perform_zoom(g, &factor, pointer_x, pointer_y, ZOOM_REDRAW); } -static void do_zoom_in_keyboard (struct graph *g) +static void do_zoom_in_keyboard(struct graph *g) { - gtk_toggle_button_set_active (g->zoom.widget.in_toggle, TRUE); - do_zoom_keyboard (g); + gtk_toggle_button_set_active(g->zoom.widget.in_toggle, TRUE); + do_zoom_keyboard(g); } -static void do_zoom_out_keyboard (struct graph *g) +static void do_zoom_out_keyboard(struct graph *g) { - gtk_toggle_button_set_active (g->zoom.widget.out_toggle, TRUE); - do_zoom_keyboard (g); - gtk_toggle_button_set_active (g->zoom.widget.in_toggle, TRUE); + gtk_toggle_button_set_active(g->zoom.widget.out_toggle, TRUE); + do_zoom_keyboard(g); + gtk_toggle_button_set_active(g->zoom.widget.in_toggle, TRUE); } -static void do_select_segment (struct graph *g) +static void do_select_segment(struct graph *g) { - int pointer_x, pointer_y; + int pointer_x, pointer_y; - get_mouse_position(g->drawing_area, &pointer_x, &pointer_y, NULL); - graph_select_segment (g, pointer_x, pointer_y); + get_mouse_position(g->drawing_area, &pointer_x, &pointer_y, NULL); + graph_select_segment(g, pointer_x, pointer_y); } -static void do_wscale_graph (struct graph *g) +static void do_wscale_graph(struct graph *g) { - gtk_toggle_button_set_active (g->gt.graph_wscale, TRUE); + gtk_toggle_button_set_active(g->gt.graph_wscale, TRUE); } -static void do_rtt_graph (struct graph *g) +static void do_rtt_graph(struct graph *g) { - gtk_toggle_button_set_active (g->gt.graph_rtt, TRUE); + gtk_toggle_button_set_active(g->gt.graph_rtt, TRUE); } -static void do_throughput_graph (struct graph *g) +static void do_throughput_graph(struct graph *g) { - gtk_toggle_button_set_active (g->gt.graph_tput, TRUE); + gtk_toggle_button_set_active(g->gt.graph_tput, TRUE); } -static void do_ts_graph_stevens (struct graph *g) +static void do_ts_graph_stevens(struct graph *g) { - gtk_toggle_button_set_active (g->gt.graph_tseqstevens, TRUE); + gtk_toggle_button_set_active(g->gt.graph_tseqstevens, TRUE); } -static void do_ts_graph_tcptrace (struct graph *g) +static void do_ts_graph_tcptrace(struct graph *g) { - gtk_toggle_button_set_active (g->gt.graph_tseqttrace, TRUE); + gtk_toggle_button_set_active(g->gt.graph_tseqttrace, TRUE); } -static void do_magnify_create (struct graph *g) +static void do_magnify_create(struct graph *g) { - int pointer_x, pointer_y; + int pointer_x, pointer_y; - get_mouse_position(g->drawing_area, &pointer_x, &pointer_y, NULL); - magnify_create (g, (int )rint (pointer_x), (int )rint (pointer_y)); + get_mouse_position(g->drawing_area, &pointer_x, &pointer_y, NULL); + magnify_create(g, (int )rint(pointer_x), (int )rint(pointer_y)); } -static void do_key_motion (struct graph *g) +static void do_key_motion(struct graph *g) { - if (g->geom.x > g->wp.x) - g->geom.x = g->wp.x; - if (g->geom.y > g->wp.y) - g->geom.y = g->wp.y; - if (g->wp.x + g->wp.width > g->geom.x + g->geom.width) - g->geom.x = g->wp.width + g->wp.x - g->geom.width; - if (g->wp.y + g->wp.height > g->geom.y + g->geom.height) - g->geom.y = g->wp.height + g->wp.y - g->geom.height; - g->cross.erase_needed = FALSE; - graph_display (g); - axis_display (g->y_axis); - axis_display (g->x_axis); - if (g->cross.draw) { - int pointer_x, pointer_y; + if (g->geom.x > g->wp.x) + g->geom.x = g->wp.x; + if (g->geom.y > g->wp.y) + g->geom.y = g->wp.y; + if (g->wp.x + g->wp.width > g->geom.x + g->geom.width) + g->geom.x = g->wp.width + g->wp.x - g->geom.width; + if (g->wp.y + g->wp.height > g->geom.y + g->geom.height) + g->geom.y = g->wp.height + g->wp.y - g->geom.height; + g->cross.erase_needed = FALSE; + graph_display(g); + axis_display(g->y_axis); + axis_display(g->x_axis); + if (g->cross.draw) { + int pointer_x, pointer_y; - get_mouse_position(g->drawing_area, &pointer_x, &pointer_y, NULL); - g->cross.erase_needed = FALSE; - cross_draw (g, pointer_x, pointer_y); - } + get_mouse_position(g->drawing_area, &pointer_x, &pointer_y, NULL); + g->cross.erase_needed = FALSE; + cross_draw(g, pointer_x, pointer_y); + } } -static void do_key_motion_up (struct graph *g, int step) +static void do_key_motion_up(struct graph *g, int step) { - g->geom.y += step; - do_key_motion (g); + g->geom.y += step; + do_key_motion(g); } -static void do_key_motion_down (struct graph *g, int step) +static void do_key_motion_down(struct graph *g, int step) { - g->geom.y -= step; - do_key_motion (g); + g->geom.y -= step; + do_key_motion(g); } -static void do_key_motion_left (struct graph *g, int step) +static void do_key_motion_left(struct graph *g, int step) { - g->geom.x += step; - do_key_motion (g); + g->geom.x += step; + do_key_motion(g); } -static void do_key_motion_right (struct graph *g, int step) +static void do_key_motion_right(struct graph *g, int step) { - g->geom.x -= step; - do_key_motion (g); + g->geom.x -= step; + do_key_motion(g); } -static gboolean button_press_event (GtkWidget *widget _U_, GdkEventButton *event, gpointer user_data) +static gboolean button_press_event(GtkWidget *widget _U_, GdkEventButton *event, gpointer user_data) { - struct graph *g = user_data; + struct graph *g = user_data; - debug(DBS_FENTRY) puts ("button_press_event()"); + debug(DBS_FENTRY) puts("button_press_event()"); - if (event->button == MOUSE_BUTTON_RIGHT) { - if (event->state & GDK_CONTROL_MASK) { - magnify_create (g, (int )rint (event->x), (int )rint (event->y)); - } else { - g->grab.x = (int )rint (event->x) - g->geom.x; - g->grab.y = (int )rint (event->y) - g->geom.y; - g->grab.grabbed = TRUE; - } + if (event->button == MOUSE_BUTTON_RIGHT) { + if (event->state & GDK_CONTROL_MASK) { + magnify_create(g, (int )rint(event->x), (int )rint(event->y)); + } else { + g->grab.x = (int )rint(event->x) - g->geom.x; + g->grab.y = (int )rint(event->y) - g->geom.y; + g->grab.grabbed = TRUE; + } #ifdef ORIGINAL_WIN32_BUTTONS - /* Windows mouse control: */ - /* [<ctrl>-left] - select packet */ - /* [left] - zoom in */ - /* [<shift>-left] - zoom out */ - } else if (event->button == MOUSE_BUTTON_LEFT) { - if (event->state & GDK_CONTROL_MASK) { - graph_select_segment (g, (int)event->x, (int)event->y); - } else { + /* Windows mouse control: */ + /* [<ctrl>-left] - select packet */ + /* [left] - zoom in */ + /* [<shift>-left] - zoom out */ + } else if (event->button == MOUSE_BUTTON_LEFT) { + if (event->state & GDK_CONTROL_MASK) { + graph_select_segment(g, (int)event->x, (int)event->y); + } else { #else /* !ORIGINAL_WIN32_BUTTONS */ - } else if (event->button == MOUSE_BUTTON_MIDDLE) { + } else if (event->button == MOUSE_BUTTON_MIDDLE) { #endif - /* Shift means we should zoom out */ - if (event->state & GDK_SHIFT_MASK) { - gtk_toggle_button_set_active (g->zoom.widget.out_toggle, TRUE); - } - else { - gtk_toggle_button_set_active (g->zoom.widget.in_toggle, TRUE); - } - do_zoom_mouse(g, event); + /* Shift means we should zoom out */ + if (event->state & GDK_SHIFT_MASK) { + gtk_toggle_button_set_active(g->zoom.widget.out_toggle, TRUE); + } + else { + gtk_toggle_button_set_active(g->zoom.widget.in_toggle, TRUE); + } + do_zoom_mouse(g, event); #ifndef ORIGINAL_WIN32_BUTTONS - } else if (event->button == MOUSE_BUTTON_LEFT) { - /* See if we're on an element that links to a frame */ - graph_select_segment (g, (int )event->x, (int )event->y); + } else if (event->button == MOUSE_BUTTON_LEFT) { + /* See if we're on an element that links to a frame */ + graph_select_segment(g, (int )event->x, (int )event->y); - /* Record the origin of the zoom rectangle */ - zoomrect.x = (int)event->x; - zoomrect.y = (int)event->y; + /* Record the origin of the zoom rectangle */ + zoomrect.x = (int)event->x; + zoomrect.y = (int)event->y; #else /* ORIGINAL_WIN32_BUTTONS*/ - } + } #endif - } - return TRUE; -} - -static gboolean motion_notify_event (GtkWidget *widget _U_, GdkEventMotion *event, gpointer user_data) -{ - struct graph *g = user_data; - int x, y; - GdkModifierType state; - - /* debug(DBS_FENTRY) puts ("motion_notify_event()"); */ - - if (event->is_hint) - get_mouse_position(g->drawing_area, &x, &y, &state); - else { - x = (int) event->x; - y = (int) event->y; - state = event->state; - } - - /* Testing just (state & GDK_BUTTON1_MASK) is not enough since when button1 - * is pressed while pointer is in motion, we will receive one more motion - * notify *before* we get the button press. This last motion notify works - * with stale grab coordinates */ - if (state & GDK_BUTTON3_MASK) { - if (g->grab.grabbed) { - g->geom.x = x-g->grab.x; - g->geom.y = y-g->grab.y; - - if (g->geom.x > g->wp.x) - g->geom.x = g->wp.x; - if (g->geom.y > g->wp.y) - g->geom.y = g->wp.y; - if (g->wp.x + g->wp.width > g->geom.x + g->geom.width) - g->geom.x = g->wp.width + g->wp.x - g->geom.width; - if (g->wp.y + g->wp.height > g->geom.y + g->geom.height) - g->geom.y = g->wp.height + g->wp.y - g->geom.height; - g->cross.erase_needed = FALSE; - graph_display (g); - axis_display (g->y_axis); - axis_display (g->x_axis); - if (g->cross.draw) { - cross_draw (g, x, y); - } - } else if (g->magnify.active) - magnify_move (g, x, y); - } else if (state & GDK_BUTTON1_MASK) { - - /* TODO: not sure we really want to jump to frames unless we release? */ - graph_select_segment (g, x, y); - - /* Update cross if necessary */ - if (g->cross.erase_needed) - cross_erase (g); - if (g->cross.draw) - cross_draw (g, x, y); - - /* Draw bounded box for zoomrect being chosen! */ - if (g->zoomrect_erase_needed) { - zoomrect_erase (g); - } - zoomrect_draw (g, x, y); - } else { - if (g->cross.erase_needed) - cross_erase (g); - if (g->cross.draw) { - cross_draw (g, x, y); - } - } - - return TRUE; -} - -static gboolean button_release_event (GtkWidget *widget _U_, GdkEventButton *event, gpointer user_data) -{ - struct graph *g = user_data; - - debug(DBS_FENTRY) puts ("button_release_event()"); - - if (event->button == MOUSE_BUTTON_RIGHT) - g->grab.grabbed = FALSE; - - if (event->button == MOUSE_BUTTON_LEFT) { - int xx1 = zoomrect.x; - int xx2 = (int)event->x; - int yy1 = zoomrect.y; - int yy2 = (int)event->y; - zoomrect.x = MIN(xx1, xx2); - zoomrect.width = abs(xx1 - xx2); - zoomrect.y = MIN(yy1, yy2); - zoomrect.height = abs(yy1 - yy2); - - /* Finish selecting a region to zoom in on. - Take care not to choose a too-small area (by accident?) */ - if (zoomrect.width > 3 && zoomrect.height > 3) { - int oldflags = g->zoom.flags; - - debug(DBS_GRAPH_DRAWING) printf("Zoom in from (%d, %d) - (%d, %d)\n", - zoomrect.x, zoomrect.y, - zoomrect.width, zoomrect.height); - - g->zoom.flags &= ~ZOOM_OUT; - do_zoom_rectangle(g, zoomrect); - g->zoom.flags = oldflags; - } - } - - if (g->magnify.active) - magnify_destroy (g); - return TRUE; -} - -static gboolean key_press_event (GtkWidget *widget _U_, GdkEventKey *event, gpointer user_data) -{ - struct graph *g = user_data; - int step; - - debug(DBS_FENTRY) puts ("key_press_event()"); - - if((event->state & GDK_CONTROL_MASK) && (event->state & GDK_SHIFT_MASK)) - step = 0; - else if (event->state & GDK_CONTROL_MASK) - step = 1; - else if (event->state & GDK_SHIFT_MASK) - step = 10; - else - step = 100; - - switch (event->keyval) { - case ' ': - toggle_crosshairs (g); - break; - case 't': - toggle_time_origin (g); - break; - case 's': - toggle_seq_origin (g); - break; - case 'r': - case GDK_Home: - restore_initial_graph_view (g); - break; - case 'i': - case '+': - do_zoom_in_keyboard (g); - break; - case 'o': - case '-': - do_zoom_out_keyboard (g); - break; - case 'm': - do_magnify_create (g); - break; - case 'g': - do_select_segment (g); - break; - case '1': - do_rtt_graph (g); - break; - case '2': - do_throughput_graph (g); - break; - case '3': - do_ts_graph_stevens (g); - break; - case '4': - do_ts_graph_tcptrace (g); - break; - case '5': - do_wscale_graph(g); - break; - case GDK_Left: - do_key_motion_left (g, step); - break; - case GDK_Up: - do_key_motion_up (g, step); - break; - case GDK_Right: - do_key_motion_right (g, step); - break; - case GDK_Down: - do_key_motion_down (g, step); - break; - case GDK_F1: - callback_create_help (NULL, NULL); - break; - default: - break; - } - - return TRUE; -} - -static gboolean key_release_event (GtkWidget *widget _U_, GdkEventKey *event, gpointer user_data) -{ - struct graph *g = user_data; - - debug(DBS_FENTRY) puts ("key_release_event()"); - - if (event->keyval == GDK_Shift_L || event->keyval == GDK_ISO_Prev_Group) { - /* g->zoom.flags &= ~ZOOM_OUT; */ - gtk_toggle_button_set_active (g->zoom.widget.in_toggle, TRUE); - } - return TRUE; -} - - -static gboolean leave_notify_event (GtkWidget *widget _U_, GdkEventCrossing *event _U_, gpointer user_data) -{ - struct graph *g = user_data; - - if (g->cross.erase_needed) - cross_erase (g); - - return TRUE; -} - -static gboolean enter_notify_event (GtkWidget *widget, GdkEventCrossing *event _U_, gpointer user_data) -{ - struct graph *g = user_data; - - graph_pixmap_display (g); - if (g->cross.draw) { - int x, y; - get_mouse_position(widget, &x, &y, NULL); - cross_draw (g, x, y); - } - return TRUE; -} - -static void toggle_crosshairs (struct graph *g) -{ - g->cross.draw ^= 1; - if (g->cross.draw) { - int x, y; - get_mouse_position(g->drawing_area, &x, &y, NULL); - cross_draw (g, x, y); - } else if (g->cross.erase_needed) { - cross_erase (g); - } - /* toggle buttons emit their "toggled" signals so don't bother doing - * any real work here, it will be done in signal handlers */ - if (g->cross.draw) - gtk_toggle_button_set_active (g->cross.on_toggle, TRUE); - else - gtk_toggle_button_set_active (g->cross.off_toggle, TRUE); -} - -static void toggle_time_origin (struct graph *g) -{ - switch (g->type) { - case GRAPH_TSEQ_STEVENS: - tseq_stevens_toggle_time_origin (g); - break; - case GRAPH_TSEQ_TCPTRACE: - tseq_tcptrace_toggle_time_origin (g); - break; - case GRAPH_THROUGHPUT: - tput_toggle_time_origin (g); - break; - default: - break; - } - axis_display (g->x_axis); -} - -static void toggle_seq_origin (struct graph *g) -{ - switch (g->type) { - case GRAPH_TSEQ_STEVENS: - tseq_stevens_toggle_seq_origin (g); - axis_display (g->y_axis); - break; - case GRAPH_TSEQ_TCPTRACE: - tseq_tcptrace_toggle_seq_origin (g); - axis_display (g->y_axis); - break; - case GRAPH_RTT: - rtt_toggle_seq_origin (g); - axis_display (g->x_axis); - break; - default: - break; - } + } + return TRUE; +} + +static gboolean motion_notify_event(GtkWidget *widget _U_, GdkEventMotion *event, gpointer user_data) +{ + struct graph *g = user_data; + int x, y; + GdkModifierType state; + + /* debug(DBS_FENTRY) puts("motion_notify_event()"); */ + + if (event->is_hint) + get_mouse_position(g->drawing_area, &x, &y, &state); + else { + x = (int) event->x; + y = (int) event->y; + state = event->state; + } + + /* Testing just (state & GDK_BUTTON1_MASK) is not enough since when button1 + * is pressed while pointer is in motion, we will receive one more motion + * notify *before* we get the button press. This last motion notify works + * with stale grab coordinates */ + if (state & GDK_BUTTON3_MASK) { + if (g->grab.grabbed) { + g->geom.x = x-g->grab.x; + g->geom.y = y-g->grab.y; + + if (g->geom.x > g->wp.x) + g->geom.x = g->wp.x; + if (g->geom.y > g->wp.y) + g->geom.y = g->wp.y; + if (g->wp.x + g->wp.width > g->geom.x + g->geom.width) + g->geom.x = g->wp.width + g->wp.x - g->geom.width; + if (g->wp.y + g->wp.height > g->geom.y + g->geom.height) + g->geom.y = g->wp.height + g->wp.y - g->geom.height; + g->cross.erase_needed = FALSE; + graph_display(g); + axis_display(g->y_axis); + axis_display(g->x_axis); + if (g->cross.draw) { + cross_draw(g, x, y); + } + } else if (g->magnify.active) + magnify_move(g, x, y); + } else if (state & GDK_BUTTON1_MASK) { + + /* TODO: not sure we really want to jump to frames unless we release? */ + graph_select_segment(g, x, y); + + /* Update cross if necessary */ + if (g->cross.erase_needed) + cross_erase(g); + if (g->cross.draw) + cross_draw(g, x, y); + + /* Draw bounded box for zoomrect being chosen! */ + if (g->zoomrect_erase_needed) { + zoomrect_erase(g); + } + zoomrect_draw(g, x, y); + } else { + if (g->cross.erase_needed) + cross_erase(g); + if (g->cross.draw) { + cross_draw(g, x, y); + } + } + + return TRUE; +} + +static gboolean button_release_event(GtkWidget *widget _U_, GdkEventButton *event, gpointer user_data) +{ + struct graph *g = user_data; + + debug(DBS_FENTRY) puts("button_release_event()"); + + if (event->button == MOUSE_BUTTON_RIGHT) + g->grab.grabbed = FALSE; + + if (event->button == MOUSE_BUTTON_LEFT) { + int xx1 = zoomrect.x; + int xx2 = (int)event->x; + int yy1 = zoomrect.y; + int yy2 = (int)event->y; + zoomrect.x = MIN(xx1, xx2); + zoomrect.width = abs(xx1 - xx2); + zoomrect.y = MIN(yy1, yy2); + zoomrect.height = abs(yy1 - yy2); + + /* Finish selecting a region to zoom in on. + Take care not to choose a too-small area (by accident?) */ + if ((zoomrect.width > 3) && (zoomrect.height > 3)) { + int oldflags = g->zoom.flags; + + debug(DBS_GRAPH_DRAWING) printf("Zoom in from (%d, %d) - (%d, %d)\n", + zoomrect.x, zoomrect.y, + zoomrect.width, zoomrect.height); + + g->zoom.flags &= ~ZOOM_OUT; + do_zoom_rectangle(g, zoomrect); + g->zoom.flags = oldflags; + } + } + + if (g->magnify.active) + magnify_destroy(g); + return TRUE; +} + +static gboolean key_press_event(GtkWidget *widget _U_, GdkEventKey *event, gpointer user_data) +{ + struct graph *g = user_data; + int step; + + debug(DBS_FENTRY) puts("key_press_event()"); + + if ((event->state & GDK_CONTROL_MASK) && (event->state & GDK_SHIFT_MASK)) + step = 0; + else if (event->state & GDK_CONTROL_MASK) + step = 1; + else if (event->state & GDK_SHIFT_MASK) + step = 10; + else + step = 100; + + switch (event->keyval) { + case ' ': + toggle_crosshairs(g); + break; + case 't': + toggle_time_origin(g); + break; + case 's': + toggle_seq_origin(g); + break; + case 'r': + case GDK_Home: + restore_initial_graph_view(g); + break; + case 'i': + case '+': + do_zoom_in_keyboard(g); + break; + case 'o': + case '-': + do_zoom_out_keyboard(g); + break; + case 'm': + do_magnify_create(g); + break; + case 'g': + do_select_segment(g); + break; + case '1': + do_rtt_graph(g); + break; + case '2': + do_throughput_graph(g); + break; + case '3': + do_ts_graph_stevens(g); + break; + case '4': + do_ts_graph_tcptrace(g); + break; + case '5': + do_wscale_graph(g); + break; + case GDK_Left: + do_key_motion_left(g, step); + break; + case GDK_Up: + do_key_motion_up(g, step); + break; + case GDK_Right: + do_key_motion_right(g, step); + break; + case GDK_Down: + do_key_motion_down(g, step); + break; + case GDK_F1: + callback_create_help(NULL, NULL); + break; + default: + break; + } + + return TRUE; +} + +static gboolean key_release_event(GtkWidget *widget _U_, GdkEventKey *event, gpointer user_data) +{ + struct graph *g = user_data; + + debug(DBS_FENTRY) puts("key_release_event()"); + + if ((event->keyval == GDK_Shift_L) || (event->keyval == GDK_ISO_Prev_Group)) { + /* g->zoom.flags &= ~ZOOM_OUT; */ + gtk_toggle_button_set_active(g->zoom.widget.in_toggle, TRUE); + } + return TRUE; +} + + +static gboolean leave_notify_event(GtkWidget *widget _U_, GdkEventCrossing *event _U_, gpointer user_data) +{ + struct graph *g = user_data; + + if (g->cross.erase_needed) + cross_erase(g); + + return TRUE; +} + +static gboolean enter_notify_event(GtkWidget *widget, GdkEventCrossing *event _U_, gpointer user_data) +{ + struct graph *g = user_data; + + graph_pixmap_display(g); + if (g->cross.draw) { + int x, y; + get_mouse_position(widget, &x, &y, NULL); + cross_draw(g, x, y); + } + return TRUE; +} + +static void toggle_crosshairs(struct graph *g) +{ + g->cross.draw ^= 1; + if (g->cross.draw) { + int x, y; + get_mouse_position(g->drawing_area, &x, &y, NULL); + cross_draw(g, x, y); + } else if (g->cross.erase_needed) { + cross_erase(g); + } + /* toggle buttons emit their "toggled" signals so don't bother doing + * any real work here, it will be done in signal handlers */ + if (g->cross.draw) + gtk_toggle_button_set_active(g->cross.on_toggle, TRUE); + else + gtk_toggle_button_set_active(g->cross.off_toggle, TRUE); +} + +static void toggle_time_origin(struct graph *g) +{ + switch (g->type) { + case GRAPH_TSEQ_STEVENS: + tseq_stevens_toggle_time_origin(g); + break; + case GRAPH_TSEQ_TCPTRACE: + tseq_tcptrace_toggle_time_origin(g); + break; + case GRAPH_THROUGHPUT: + tput_toggle_time_origin(g); + break; + default: + break; + } + axis_display(g->x_axis); +} + +static void toggle_seq_origin(struct graph *g) +{ + switch (g->type) { + case GRAPH_TSEQ_STEVENS: + tseq_stevens_toggle_seq_origin(g); + axis_display(g->y_axis); + break; + case GRAPH_TSEQ_TCPTRACE: + tseq_tcptrace_toggle_seq_origin(g); + axis_display(g->y_axis); + break; + case GRAPH_RTT: + rtt_toggle_seq_origin(g); + axis_display(g->x_axis); + break; + default: + break; + } } -static void restore_initial_graph_view (struct graph *g) +static void restore_initial_graph_view(struct graph *g) { - g->geom.width = g->wp.width; - g->geom.height = g->wp.height; - g->geom.x = g->wp.x; - g->geom.y = g->wp.y; - graph_init_sequence (g); + g->geom.width = g->wp.width; + g->geom.height = g->wp.height; + g->geom.x = g->wp.x; + g->geom.y = g->wp.y; + graph_init_sequence(g); - if (g->cross.draw) { - g->cross.erase_needed = FALSE; - } + if (g->cross.draw) { + g->cross.erase_needed = FALSE; + } } -static int get_num_dsegs (struct graph *g) +static int get_num_dsegs(struct graph *g) { - int count; - struct segment *tmp; + int count; + struct segment *tmp; - for (tmp=g->segments, count=0; tmp; tmp=tmp->next) { - if(compare_headers(&g->src_address, &g->dst_address, - g->src_port, g->dst_port, - &tmp->ip_src, &tmp->ip_dst, - tmp->th_sport, tmp->th_dport, - COMPARE_CURR_DIR)) { - count++; - } - } - return count; -} - -static int get_num_acks (struct graph *g, int *num_sack_ranges) -{ - int count; - struct segment *tmp; - - for (tmp=g->segments, count=0; tmp; tmp=tmp->next) { - if(!compare_headers(&g->src_address, &g->dst_address, - g->src_port, g->dst_port, - &tmp->ip_src, &tmp->ip_dst, - tmp->th_sport, tmp->th_dport, - COMPARE_CURR_DIR)) { - count++; - *num_sack_ranges += tmp->num_sack_ranges; - } - } - return count; + for (tmp=g->segments, count=0; tmp; tmp=tmp->next) { + if (compare_headers(&g->src_address, &g->dst_address, + g->src_port, g->dst_port, + &tmp->ip_src, &tmp->ip_dst, + tmp->th_sport, tmp->th_dport, + COMPARE_CURR_DIR)) { + count++; + } + } + return count; +} + +static int get_num_acks(struct graph *g, int *num_sack_ranges) +{ + int count; + struct segment *tmp; + + for (tmp = g->segments, count=0; tmp; tmp = tmp->next) { + if (!compare_headers(&g->src_address, &g->dst_address, + g->src_port, g->dst_port, + &tmp->ip_src, &tmp->ip_dst, + tmp->th_sport, tmp->th_dport, + COMPARE_CURR_DIR)) { + count++; + *num_sack_ranges += tmp->num_sack_ranges; + } + } + return count; } /* * Stevens-style time-sequence grapH */ -static void tseq_stevens_read_config (struct graph *g) +static void tseq_stevens_read_config(struct graph *g) { - debug(DBS_FENTRY) puts ("tseq_stevens_read_config()"); + debug(DBS_FENTRY) puts("tseq_stevens_read_config()"); - g->s.tseq_stevens.seq_width = 4; - g->s.tseq_stevens.seq_height = 4; - g->s.tseq_stevens.flags = 0; + g->s.tseq_stevens.seq_width = 4; + g->s.tseq_stevens.seq_height = 4; + g->s.tseq_stevens.flags = 0; - g->title = (const char ** )g_malloc (2 * sizeof (char *)); - g->title[0] = "Time/Sequence Graph (Stevens)"; - g->title[1] = NULL; - g->y_axis->label = (const char ** )g_malloc (3 * sizeof (char * )); - g->y_axis->label[0] = "number[B]"; - g->y_axis->label[1] = "Sequence"; - g->y_axis->label[2] = NULL; - g->x_axis->label = (const char ** )g_malloc (2 * sizeof (char * )); - g->x_axis->label[0] = "Time[s]"; - g->x_axis->label[1] = NULL; + g->title = (const char ** )g_malloc(2 * sizeof(char *)); + g->title[0] = "Time/Sequence Graph (Stevens)"; + g->title[1] = NULL; + g->y_axis->label = (const char ** )g_malloc(3 * sizeof(char * )); + g->y_axis->label[0] = "number[B]"; + g->y_axis->label[1] = "Sequence"; + g->y_axis->label[2] = NULL; + g->x_axis->label = (const char ** )g_malloc(2 * sizeof(char * )); + g->x_axis->label[0] = "Time[s]"; + g->x_axis->label[1] = NULL; } /* Used by both 'stevens' and 'tcptrace' */ -static void tseq_initialize (struct graph *g) +static void tseq_initialize(struct graph *g) { - debug(DBS_FENTRY) puts ("tseq_initialize()"); - tseq_get_bounds (g); + debug(DBS_FENTRY) puts("tseq_initialize()"); + tseq_get_bounds(g); - g->x_axis->min = 0; - g->y_axis->min = 0; + g->x_axis->min = 0; + g->y_axis->min = 0; - switch (g->type) { - case GRAPH_TSEQ_STEVENS: - tseq_stevens_read_config(g); - break; - case GRAPH_TSEQ_TCPTRACE: - tseq_tcptrace_read_config(g); - break; - } + switch (g->type) { + case GRAPH_TSEQ_STEVENS: + tseq_stevens_read_config(g); + break; + case GRAPH_TSEQ_TCPTRACE: + tseq_tcptrace_read_config(g); + break; + } } @@ -4025,897 +4031,905 @@ static void tseq_initialize (struct graph *g) /* ToDo: worry about handling cases such as trying to plot seq of just 1 frame */ -static void tseq_get_bounds (struct graph *g) -{ - struct segment *tmp; - double tim; - gboolean data_frame_seen=FALSE; - double data_tim_low=0; - double data_tim_high=0; - guint32 data_seq_cur; - guint32 data_seq_nxt; - guint32 data_seq_low=0; - guint32 data_seq_high=0; - gboolean ack_frame_seen=FALSE; - double ack_tim_low=0; - double ack_tim_high=0; - guint32 ack_seq_cur; - guint32 ack_seq_low=0; - guint32 win_seq_cur; - guint32 win_seq_high=0; - - /* go thru all segments to determine "bounds" */ - for (tmp=g->segments; tmp; tmp=tmp->next) { - if(compare_headers(&g->src_address, &g->dst_address, - g->src_port, g->dst_port, - &tmp->ip_src, &tmp->ip_dst, - tmp->th_sport, tmp->th_dport, - COMPARE_CURR_DIR)) { - - /* "data" seg */ - tim = tmp->rel_secs + tmp->rel_usecs / 1000000.0; - data_seq_cur = tmp->th_seq; - data_seq_nxt = data_seq_cur + tmp->th_seglen; - if (! data_frame_seen) { - data_tim_low = data_tim_high = tim; - data_seq_low = data_seq_cur; - data_seq_high = data_seq_nxt; - data_frame_seen = TRUE; - } - if (tim < data_tim_low) data_tim_low = tim; - if (tim > data_tim_high) data_tim_high = tim; - if (data_seq_cur < data_seq_low) data_seq_low = data_seq_cur; - if (data_seq_nxt > data_seq_high) data_seq_high = data_seq_nxt; - } - else { /* ack seg */ - /* skip ack processing if no ACK (e.g. in RST) */ - if (TCP_ACK (tmp->th_flags)) { - tim = tmp->rel_secs + tmp->rel_usecs / 1000000.0; - ack_seq_cur = tmp->th_ack; - win_seq_cur = ack_seq_cur + tmp->th_win; - if (! ack_frame_seen) { - ack_tim_low = ack_tim_high = tim; - ack_seq_low = ack_seq_cur; - win_seq_high = win_seq_cur; - ack_frame_seen = TRUE; - } - if (tim < ack_tim_low) ack_tim_low = tim; - if (tim > ack_tim_high) ack_tim_high = tim; - if (ack_seq_cur < ack_seq_low) ack_seq_low = ack_seq_cur; - if (win_seq_cur > win_seq_high) win_seq_high = win_seq_cur; - } - } - } - - /* if 'stevens': use only data segments to determine bounds */ - /* if 'tcptrace': use both data and ack segments to determine bounds */ - switch (g->type) { - case GRAPH_TSEQ_STEVENS: - g->bounds.x0 = data_tim_low; - g->bounds.width = data_tim_high - data_tim_low; - g->bounds.y0 = data_seq_low; - g->bounds.height = data_seq_high - data_seq_low; - break; - case GRAPH_TSEQ_TCPTRACE: - /* If (ack_frame_seen == false) -> use 'data' segments. - * Else If (data_frame_seen == false) -> use 'ack' segments. - * Else -> use both data and ack segments. - */ - g->bounds.x0 = ((data_tim_low <= ack_tim_low && data_frame_seen) || (! ack_frame_seen)) ? data_tim_low : ack_tim_low; - g->bounds.width = (((data_tim_high >= ack_tim_high && data_frame_seen) || (! ack_frame_seen)) ? data_tim_high : ack_tim_high) - g->bounds.x0; - g->bounds.y0 = ((data_seq_low <= ack_seq_low && data_frame_seen) || (! ack_frame_seen)) ? data_seq_low : ack_seq_low; - g->bounds.height = (((data_seq_high >= win_seq_high && data_frame_seen) || (! ack_frame_seen)) ? data_seq_high : win_seq_high) - g->bounds.y0; - break; - } - - g->zoom.x = (g->geom.width - 1) / g->bounds.width; - g->zoom.y = (g->geom.height -1) / g->bounds.height; -} - - -static void tseq_stevens_make_elmtlist (struct graph *g) -{ - struct segment *tmp; - struct element *elements, *e; - double xx0 = g->bounds.x0, yy0 = g->bounds.y0; - guint32 seq_base = (guint32) yy0; - guint32 seq_cur; - - debug(DBS_FENTRY) puts ("tseq_stevens_make_elmtlist()"); - if (g->elists->elements == NULL) { - int n = 1 + get_num_dsegs (g); - e = elements = (struct element * )g_malloc (n*sizeof (struct element)); - } else - e = elements = g->elists->elements; - - for (tmp=g->segments; tmp; tmp=tmp->next) { - double secs, seqno; - - if(!compare_headers(&g->src_address, &g->dst_address, - g->src_port, g->dst_port, - &tmp->ip_src, &tmp->ip_dst, - tmp->th_sport, tmp->th_dport, - COMPARE_CURR_DIR)) { - continue; - } - /* data seg */ - seq_cur = tmp->th_seq - seq_base; - secs = g->zoom.x * (tmp->rel_secs + tmp->rel_usecs / 1000000.0 - xx0); - seqno = g->zoom.y * seq_cur; - - e->type = ELMT_ELLIPSE; - e->parent = tmp; - e->p.ellipse.dim.width = g->s.tseq_stevens.seq_width; - e->p.ellipse.dim.height = g->s.tseq_stevens.seq_height; - e->p.ellipse.dim.x = secs - g->s.tseq_stevens.seq_width/2.0; - e->p.ellipse.dim.y = seqno + g->s.tseq_stevens.seq_height/2.0; - e++; - } - e->type = ELMT_NONE; - g->elists->elements = elements; -} - -static void tseq_stevens_toggle_seq_origin (struct graph *g) -{ - g->s.tseq_stevens.flags ^= SEQ_ORIGIN; - - if ((g->s.tseq_stevens.flags & SEQ_ORIGIN) == SEQ_ORIGIN_ZERO) - g->y_axis->min = g->bounds.y0; - else /* g->tseq_stevens.flags & SEQ_ORIGIN == SEQ_ORIGIN_ISN */ - g->y_axis->min = 0; -} - -static void tseq_stevens_toggle_time_origin (struct graph *g) -{ - g->s.tseq_stevens.flags ^= TIME_ORIGIN; - - if ((g->s.tseq_stevens.flags & TIME_ORIGIN) == TIME_ORIGIN_CAP) - g->x_axis->min = g->bounds.x0; - else /* g->tseq_stevens.flags & TIME_ORIGIN == TIME_ORIGIN_CONN */ - g->x_axis->min = 0; +static void tseq_get_bounds(struct graph *g) +{ + struct segment *tmp; + double tim; + gboolean data_frame_seen = FALSE; + double data_tim_low = 0; + double data_tim_high = 0; + guint32 data_seq_cur; + guint32 data_seq_nxt; + guint32 data_seq_low = 0; + guint32 data_seq_high = 0; + gboolean ack_frame_seen = FALSE; + double ack_tim_low = 0; + double ack_tim_high = 0; + guint32 ack_seq_cur; + guint32 ack_seq_low = 0; + guint32 win_seq_cur; + guint32 win_seq_high = 0; + + /* go thru all segments to determine "bounds" */ + for (tmp=g->segments; tmp; tmp=tmp->next) { + if (compare_headers(&g->src_address, &g->dst_address, + g->src_port, g->dst_port, + &tmp->ip_src, &tmp->ip_dst, + tmp->th_sport, tmp->th_dport, + COMPARE_CURR_DIR)) { + + /* "data" seg */ + tim = tmp->rel_secs + tmp->rel_usecs / 1000000.0; + data_seq_cur = tmp->th_seq; + data_seq_nxt = data_seq_cur + tmp->th_seglen; + if (! data_frame_seen) { + data_tim_low = data_tim_high = tim; + data_seq_low = data_seq_cur; + data_seq_high = data_seq_nxt; + data_frame_seen = TRUE; + } + if (tim < data_tim_low) data_tim_low = tim; + if (tim > data_tim_high) data_tim_high = tim; + if (data_seq_cur < data_seq_low) data_seq_low = data_seq_cur; + if (data_seq_nxt > data_seq_high) data_seq_high = data_seq_nxt; + } + else { /* ack seg */ + /* skip ack processing if no ACK (e.g. in RST) */ + if (TCP_ACK(tmp->th_flags)) { + tim = tmp->rel_secs + tmp->rel_usecs / 1000000.0; + ack_seq_cur = tmp->th_ack; + win_seq_cur = ack_seq_cur + tmp->th_win; + if (! ack_frame_seen) { + ack_tim_low = ack_tim_high = tim; + ack_seq_low = ack_seq_cur; + win_seq_high = win_seq_cur; + ack_frame_seen = TRUE; + } + if (tim < ack_tim_low) ack_tim_low = tim; + if (tim > ack_tim_high) ack_tim_high = tim; + if (ack_seq_cur < ack_seq_low) ack_seq_low = ack_seq_cur; + if (win_seq_cur > win_seq_high) win_seq_high = win_seq_cur; + } + } + } + + /* if 'stevens': use only data segments to determine bounds */ + /* if 'tcptrace': use both data and ack segments to determine bounds */ + switch (g->type) { + case GRAPH_TSEQ_STEVENS: + g->bounds.x0 = data_tim_low; + g->bounds.width = data_tim_high - data_tim_low; + g->bounds.y0 = data_seq_low; + g->bounds.height = data_seq_high - data_seq_low; + break; + case GRAPH_TSEQ_TCPTRACE: + /* If (ack_frame_seen == false) -> use 'data' segments. + * Else If (data_frame_seen == false) -> use 'ack' segments. + * Else -> use both data and ack segments. + */ + g->bounds.x0 = (((data_tim_low <= ack_tim_low) && data_frame_seen) || (! ack_frame_seen)) + ? data_tim_low : ack_tim_low; + g->bounds.width = ((((data_tim_high >= ack_tim_high) && data_frame_seen) || (! ack_frame_seen)) + ? data_tim_high : ack_tim_high) - g->bounds.x0; + g->bounds.y0 = (((data_seq_low <= ack_seq_low) && data_frame_seen) || (! ack_frame_seen)) + ? data_seq_low : ack_seq_low; + g->bounds.height = ((((data_seq_high >= win_seq_high) && data_frame_seen) || (! ack_frame_seen)) + ? data_seq_high : win_seq_high) - g->bounds.y0; + break; + } + + g->zoom.x = (g->geom.width - 1) / g->bounds.width; + g->zoom.y = (g->geom.height -1) / g->bounds.height; +} + + +static void tseq_stevens_make_elmtlist(struct graph *g) +{ + struct segment *tmp; + struct element *elements, *e; + double xx0 = g->bounds.x0, yy0 = g->bounds.y0; + guint32 seq_base = (guint32) yy0; + guint32 seq_cur; + + debug(DBS_FENTRY) puts("tseq_stevens_make_elmtlist()"); + if (g->elists->elements == NULL) { + int n = 1 + get_num_dsegs(g); + e = elements = (struct element * )g_malloc(n*sizeof(struct element)); + } else + e = elements = g->elists->elements; + + for (tmp = g->segments; tmp; tmp = tmp->next) { + double secs, seqno; + + if (!compare_headers(&g->src_address, &g->dst_address, + g->src_port, g->dst_port, + &tmp->ip_src, &tmp->ip_dst, + tmp->th_sport, tmp->th_dport, + COMPARE_CURR_DIR)) { + continue; + } + /* data seg */ + seq_cur = tmp->th_seq - seq_base; + secs = g->zoom.x * (tmp->rel_secs + tmp->rel_usecs / 1000000.0 - xx0); + seqno = g->zoom.y * seq_cur; + + e->type = ELMT_ELLIPSE; + e->parent = tmp; + e->p.ellipse.dim.width = g->s.tseq_stevens.seq_width; + e->p.ellipse.dim.height = g->s.tseq_stevens.seq_height; + e->p.ellipse.dim.x = secs - g->s.tseq_stevens.seq_width/2.0; + e->p.ellipse.dim.y = seqno + g->s.tseq_stevens.seq_height/2.0; + e++; + } + e->type = ELMT_NONE; + g->elists->elements = elements; +} + +static void tseq_stevens_toggle_seq_origin(struct graph *g) +{ + g->s.tseq_stevens.flags ^= SEQ_ORIGIN; + + if ((g->s.tseq_stevens.flags & SEQ_ORIGIN) == SEQ_ORIGIN_ZERO) + g->y_axis->min = g->bounds.y0; + else /* g->tseq_stevens.flags & SEQ_ORIGIN == SEQ_ORIGIN_ISN */ + g->y_axis->min = 0; +} + +static void tseq_stevens_toggle_time_origin(struct graph *g) +{ + g->s.tseq_stevens.flags ^= TIME_ORIGIN; + + if ((g->s.tseq_stevens.flags & TIME_ORIGIN) == TIME_ORIGIN_CAP) + g->x_axis->min = g->bounds.x0; + else /* g->tseq_stevens.flags & TIME_ORIGIN == TIME_ORIGIN_CONN */ + g->x_axis->min = 0; } /* * tcptrace-style time-sequence graph */ -static void tseq_tcptrace_read_config (struct graph *g) -{ - /* Black */ - g->s.tseq_tcptrace.seq_color.pixel=0; - g->s.tseq_tcptrace.seq_color.red=0; - g->s.tseq_tcptrace.seq_color.green=0; - g->s.tseq_tcptrace.seq_color.blue=0; - - /* LightSlateGray */ - g->s.tseq_tcptrace.ack_color[0].pixel=0; - g->s.tseq_tcptrace.ack_color[0].red=0x7777; - g->s.tseq_tcptrace.ack_color[0].green=0x8888; - g->s.tseq_tcptrace.ack_color[0].blue=0x9999; - - /* LightGray */ - g->s.tseq_tcptrace.ack_color[1].pixel=0; - g->s.tseq_tcptrace.ack_color[1].red=0xd3d3; - g->s.tseq_tcptrace.ack_color[1].green=0xd3d3; - g->s.tseq_tcptrace.ack_color[1].blue=0xd3d3; - - /* Light blue */ - g->s.tseq_tcptrace.sack_color[0].pixel=0; - g->s.tseq_tcptrace.sack_color[0].red=0x0; - g->s.tseq_tcptrace.sack_color[0].green=0x0; - g->s.tseq_tcptrace.sack_color[0].blue=0xffff; - - /* Darker blue */ - g->s.tseq_tcptrace.sack_color[1].pixel=0; - g->s.tseq_tcptrace.sack_color[1].red=0x0; - g->s.tseq_tcptrace.sack_color[1].green=0x0; - g->s.tseq_tcptrace.sack_color[1].blue=0x9888; - - g->s.tseq_tcptrace.flags = 0; - - /* Allocate first list, but not elements */ - g->elists->next = (struct element_list * ) - g_malloc (sizeof (struct element_list)); - g->elists->next->next = NULL; - g->elists->next->elements = NULL; - - g->title = (const char ** )g_malloc (2 * sizeof (char *)); - g->title[0] = "Time/Sequence Graph (tcptrace)"; - g->title[1] = NULL; - g->y_axis->label = (const char ** )g_malloc (3 * sizeof (char * )); - g->y_axis->label[0] = "number[B]"; - g->y_axis->label[1] = "Sequence"; - g->y_axis->label[2] = NULL; - g->x_axis->label = (const char ** )g_malloc (2 * sizeof (char * )); - g->x_axis->label[0] = "Time[s]"; - g->x_axis->label[1] = NULL; -} - -static void tseq_tcptrace_make_elmtlist (struct graph *g) -{ - struct segment *tmp; - struct element *elements0, *e0; /* list of elmts with prio 0 */ - struct element *elements1, *e1; /* list of elmts with prio 1 */ - double xx0, yy0; - double p_t = 0; /* ackno, window and time of previous segment */ - double p_ackno = 0, p_win = 0; - gboolean ack_seen=FALSE; - int toggle=0; - guint32 seq_base; - guint32 seq_cur; - int num_sack_ranges = 0; - - debug(DBS_FENTRY) puts ("tseq_tcptrace_make_elmtlist()"); - - if (g->elists->elements == NULL ) { - /* 3 elements per data segment */ - int n = 1 + 3*get_num_dsegs(g); - e0 = elements0 = (struct element * )g_malloc (n*sizeof (struct element)); - } else { - /* Existing array */ - e0 = elements0 = g->elists->elements; - } - - if (g->elists->next->elements == NULL) { - /* 4 elements per ACK, but only one for each SACK range */ - int n = 1 + 4*get_num_acks(g, &num_sack_ranges); - n += num_sack_ranges; - e1 = elements1 = (struct element * )g_malloc (n*sizeof (struct element)); - } else { - /* Existing array */ - e1 = elements1 = g->elists->next->elements; - } - - xx0 = g->bounds.x0; - yy0 = g->bounds.y0; - seq_base = (guint32) yy0; - - for (tmp=g->segments; tmp; tmp=tmp->next) { - double secs, data; - double x; - - secs = tmp->rel_secs + tmp->rel_usecs / 1000000.0; - x = secs - xx0; - x *= g->zoom.x; - if(compare_headers(&g->src_address, &g->dst_address, - g->src_port, g->dst_port, - &tmp->ip_src, &tmp->ip_dst, - tmp->th_sport, tmp->th_dport, - COMPARE_CURR_DIR)) { - /* forward direction (data) -> we need seqno and amount of data */ - double yy1, yy2; - - seq_cur = tmp->th_seq - seq_base; - if (TCP_SYN (tmp->th_flags) || TCP_FIN (tmp->th_flags)) - data = 1; - else - data = tmp->th_seglen; - - yy1 = g->zoom.y * (seq_cur); - yy2 = g->zoom.y * (seq_cur + data); - e0->type = ELMT_LINE; - e0->parent = tmp; - /* Set the drawing color */ - e0->elment_color_p = &g->s.tseq_tcptrace.seq_color; - e0->p.line.dim.x1 = e0->p.line.dim.x2 = x; - e0->p.line.dim.y1 = yy1; - e0->p.line.dim.y2 = yy2; - e0++; - e0->type = ELMT_LINE; - e0->parent = tmp; - /* Set the drawing color */ - e0->elment_color_p = &g->s.tseq_tcptrace.seq_color; - e0->p.line.dim.x1 = x - 1; - e0->p.line.dim.x2 = x + 1; - e0->p.line.dim.y1 = e0->p.line.dim.y2 = yy1; - e0++; - e0->type = ELMT_LINE; - e0->parent = tmp; - /* Set the drawing color */ - e0->elment_color_p = &g->s.tseq_tcptrace.seq_color; - e0->p.line.dim.x1 = x + 1; - e0->p.line.dim.x2 = x - 1; - e0->p.line.dim.y1 = e0->p.line.dim.y2 = yy2; - e0++; - } else { - double ackno, win; - if (! TCP_ACK (tmp->th_flags)) - /* SYN's and RST's do not necessarily have ACK's*/ - continue; - /* backward direction -> we need ackno and window */ - seq_cur = tmp->th_ack - seq_base; - ackno = seq_cur * g->zoom.y; - win = tmp->th_win * g->zoom.y; - - /* ack line */ - if (ack_seen == TRUE) { /* don't plot the first ack */ - - /* Horizonal: time of previous ACK to now (at new ACK) */ - e1->type = ELMT_LINE; - e1->parent = tmp; - /* Set the drawing color */ - e1->elment_color_p = &g->s.tseq_tcptrace.ack_color[toggle]; - e1->p.line.dim.x1 = p_t; - e1->p.line.dim.y1 = p_ackno; - e1->p.line.dim.x2 = x; - e1->p.line.dim.y2 = p_ackno; - e1++; - - /* Vertical: from previous ACKNO to current one (at current time) */ - e1->type = ELMT_LINE; - e1->parent = tmp; - /* Set the drawing color */ - e1->elment_color_p = &g->s.tseq_tcptrace.ack_color[toggle]; - e1->p.line.dim.x1 = x; - e1->p.line.dim.y1 = p_ackno; - e1->p.line.dim.x2 = x; - e1->p.line.dim.y2 = ackno!=p_ackno || ackno<4 ? ackno : ackno-4; - e1++; - - /* Horizontal: window line */ - e1->type = ELMT_LINE; - e1->parent = tmp; - /* Set the drawing color */ - e1->elment_color_p = &g->s.tseq_tcptrace.ack_color[toggle]; - e1->p.line.dim.x1 = p_t; - e1->p.line.dim.y1 = p_win + p_ackno; - e1->p.line.dim.x2 = x; - e1->p.line.dim.y2 = p_win + p_ackno; - e1++; - - /* Vertical: old window to new window */ - e1->type = ELMT_LINE; - e1->parent = tmp; - /* Set the drawing color */ - e1->elment_color_p = &g->s.tseq_tcptrace.ack_color[toggle]; - e1->p.line.dim.x1 = x; - e1->p.line.dim.y1 = p_win + p_ackno; - e1->p.line.dim.x2 = x; - e1->p.line.dim.y2 = win + ackno; - e1++; - - /* Toggle color to use for ACKs... */ - toggle = 1^toggle; - } - ack_seen = TRUE; - p_ackno = ackno; - p_win = win; - p_t = x; - - /* Now any SACK entries */ - if (tmp->num_sack_ranges) { - int n; - - for (n=0; n < tmp->num_sack_ranges; n++) { - double left_edge = (tmp->sack_left_edge[n] - seq_base) * g->zoom.y; - double right_edge = (tmp->sack_right_edge[n] - seq_base) * g->zoom.y; - - /* Vertical: just show range of SACK. - Have experimented with sorting ranges and showing in red regions - between SACKs, but when TCP is limited by option bytes and needs to - miss out ranges, this can be pretty confusing as we end up apparently - NACKing what has been received... */ - e1->type = ELMT_LINE; - e1->parent = tmp; - /* Set the drawing color. First range is significant, so use - separate colour */ - e1->elment_color_p = (n==0) ? &g->s.tseq_tcptrace.sack_color[0] : - &g->s.tseq_tcptrace.sack_color[1]; - e1->p.line.dim.x1 = x; - e1->p.line.dim.y1 = right_edge; - e1->p.line.dim.x2 = x; - e1->p.line.dim.y2 = left_edge; - e1++; - } - } - } - } - - /* Terminate both lists */ - e0->type = ELMT_NONE; - e1->type = ELMT_NONE; - - g->elists->elements = elements0; - g->elists->next->elements = elements1; - g->elists->next->next = NULL; -} - -static void tseq_tcptrace_toggle_seq_origin (struct graph *g) -{ - g->s.tseq_tcptrace.flags ^= SEQ_ORIGIN; - - if ((g->s.tseq_tcptrace.flags & SEQ_ORIGIN) == SEQ_ORIGIN_ZERO) - g->y_axis->min = g->bounds.y0; - else /* g->tseq_stevens.flags & SEQ_ORIGIN == SEQ_ORIGIN_ISN */ - g->y_axis->min = 0; -} - -static void tseq_tcptrace_toggle_time_origin (struct graph *g) -{ - g->s.tseq_tcptrace.flags ^= TIME_ORIGIN; - - if ((g->s.tseq_tcptrace.flags & TIME_ORIGIN) == TIME_ORIGIN_CAP) - g->x_axis->min = g->bounds.x0; - else /* g->tseq_stevens.flags & TIME_ORIGIN == TIME_ORIGIN_CONN */ - g->x_axis->min = 0; +static void tseq_tcptrace_read_config(struct graph *g) +{ + /* Black */ + g->s.tseq_tcptrace.seq_color.pixel = 0; + g->s.tseq_tcptrace.seq_color.red = 0; + g->s.tseq_tcptrace.seq_color.green = 0; + g->s.tseq_tcptrace.seq_color.blue = 0; + + /* LightSlateGray */ + g->s.tseq_tcptrace.ack_color[0].pixel = 0; + g->s.tseq_tcptrace.ack_color[0].red = 0x7777; + g->s.tseq_tcptrace.ack_color[0].green = 0x8888; + g->s.tseq_tcptrace.ack_color[0].blue = 0x9999; + + /* LightGray */ + g->s.tseq_tcptrace.ack_color[1].pixel = 0; + g->s.tseq_tcptrace.ack_color[1].red = 0xd3d3; + g->s.tseq_tcptrace.ack_color[1].green = 0xd3d3; + g->s.tseq_tcptrace.ack_color[1].blue = 0xd3d3; + + /* Light blue */ + g->s.tseq_tcptrace.sack_color[0].pixel = 0; + g->s.tseq_tcptrace.sack_color[0].red = 0x0; + g->s.tseq_tcptrace.sack_color[0].green = 0x0; + g->s.tseq_tcptrace.sack_color[0].blue = 0xffff; + + /* Darker blue */ + g->s.tseq_tcptrace.sack_color[1].pixel = 0; + g->s.tseq_tcptrace.sack_color[1].red = 0x0; + g->s.tseq_tcptrace.sack_color[1].green = 0x0; + g->s.tseq_tcptrace.sack_color[1].blue = 0x9888; + + g->s.tseq_tcptrace.flags = 0; + + /* Allocate first list, but not elements */ + g->elists->next = (struct element_list * ) + g_malloc(sizeof(struct element_list)); + g->elists->next->next = NULL; + g->elists->next->elements = NULL; + + g->title = (const char ** )g_malloc(2 * sizeof(char *)); + g->title[0] = "Time/Sequence Graph (tcptrace)"; + g->title[1] = NULL; + g->y_axis->label = (const char ** )g_malloc(3 * sizeof(char * )); + g->y_axis->label[0] = "number[B]"; + g->y_axis->label[1] = "Sequence"; + g->y_axis->label[2] = NULL; + g->x_axis->label = (const char ** )g_malloc(2 * sizeof(char * )); + g->x_axis->label[0] = "Time[s]"; + g->x_axis->label[1] = NULL; +} + +static void tseq_tcptrace_make_elmtlist(struct graph *g) +{ + struct segment *tmp; + struct element *elements0, *e0; /* list of elmts with prio 0 */ + struct element *elements1, *e1; /* list of elmts with prio 1 */ + double xx0, yy0; + double p_t = 0; /* ackno, window and time of previous segment */ + double p_ackno = 0, p_win = 0; + gboolean ack_seen = FALSE; + int toggle = 0; + guint32 seq_base; + guint32 seq_cur; + int num_sack_ranges = 0; + + debug(DBS_FENTRY) puts("tseq_tcptrace_make_elmtlist()"); + + if (g->elists->elements == NULL ) { + /* 3 elements per data segment */ + int n = 1 + 3*get_num_dsegs(g); + e0 = elements0 = (struct element * )g_malloc(n * sizeof(struct element)); + } else { + /* Existing array */ + e0 = elements0 = g->elists->elements; + } + + if (g->elists->next->elements == NULL) { + /* 4 elements per ACK, but only one for each SACK range */ + int n = 1 + 4*get_num_acks(g, &num_sack_ranges); + n += num_sack_ranges; + e1 = elements1 = (struct element * )g_malloc(n * sizeof(struct element)); + } else { + /* Existing array */ + e1 = elements1 = g->elists->next->elements; + } + + xx0 = g->bounds.x0; + yy0 = g->bounds.y0; + seq_base = (guint32) yy0; + + for (tmp = g->segments; tmp; tmp = tmp->next) { + double secs, data; + double x; + + secs = tmp->rel_secs + tmp->rel_usecs / 1000000.0; + x = secs - xx0; + x *= g->zoom.x; + if (compare_headers(&g->src_address, &g->dst_address, + g->src_port, g->dst_port, + &tmp->ip_src, &tmp->ip_dst, + tmp->th_sport, tmp->th_dport, + COMPARE_CURR_DIR)) { + /* forward direction (data) -> we need seqno and amount of data */ + double yy1, yy2; + + seq_cur = tmp->th_seq - seq_base; + if (TCP_SYN(tmp->th_flags) || TCP_FIN(tmp->th_flags)) + data = 1; + else + data = tmp->th_seglen; + + yy1 = g->zoom.y * (seq_cur); + yy2 = g->zoom.y * (seq_cur + data); + e0->type = ELMT_LINE; + e0->parent = tmp; + /* Set the drawing color */ + e0->elment_color_p = &g->s.tseq_tcptrace.seq_color; + e0->p.line.dim.x1 = e0->p.line.dim.x2 = x; + e0->p.line.dim.y1 = yy1; + e0->p.line.dim.y2 = yy2; + e0++; + e0->type = ELMT_LINE; + e0->parent = tmp; + /* Set the drawing color */ + e0->elment_color_p = &g->s.tseq_tcptrace.seq_color; + e0->p.line.dim.x1 = x - 1; + e0->p.line.dim.x2 = x + 1; + e0->p.line.dim.y1 = e0->p.line.dim.y2 = yy1; + e0++; + e0->type = ELMT_LINE; + e0->parent = tmp; + /* Set the drawing color */ + e0->elment_color_p = &g->s.tseq_tcptrace.seq_color; + e0->p.line.dim.x1 = x + 1; + e0->p.line.dim.x2 = x - 1; + e0->p.line.dim.y1 = e0->p.line.dim.y2 = yy2; + e0++; + } else { + double ackno, win; + if (! TCP_ACK(tmp->th_flags)) + /* SYN's and RST's do not necessarily have ACK's*/ + continue; + /* backward direction -> we need ackno and window */ + seq_cur = tmp->th_ack - seq_base; + ackno = seq_cur * g->zoom.y; + win = tmp->th_win * g->zoom.y; + + /* ack line */ + if (ack_seen == TRUE) { /* don't plot the first ack */ + + /* Horizonal: time of previous ACK to now (at new ACK) */ + e1->type = ELMT_LINE; + e1->parent = tmp; + /* Set the drawing color */ + e1->elment_color_p = &g->s.tseq_tcptrace.ack_color[toggle]; + e1->p.line.dim.x1 = p_t; + e1->p.line.dim.y1 = p_ackno; + e1->p.line.dim.x2 = x; + e1->p.line.dim.y2 = p_ackno; + e1++; + + /* Vertical: from previous ACKNO to current one (at current time) */ + e1->type = ELMT_LINE; + e1->parent = tmp; + /* Set the drawing color */ + e1->elment_color_p = &g->s.tseq_tcptrace.ack_color[toggle]; + e1->p.line.dim.x1 = x; + e1->p.line.dim.y1 = p_ackno; + e1->p.line.dim.x2 = x; + e1->p.line.dim.y2 = ((ackno != p_ackno) || (ackno < 4)) ? ackno : ackno - 4; + e1++; + + /* Horizontal: window line */ + e1->type = ELMT_LINE; + e1->parent = tmp; + /* Set the drawing color */ + e1->elment_color_p = &g->s.tseq_tcptrace.ack_color[toggle]; + e1->p.line.dim.x1 = p_t; + e1->p.line.dim.y1 = p_win + p_ackno; + e1->p.line.dim.x2 = x; + e1->p.line.dim.y2 = p_win + p_ackno; + e1++; + + /* Vertical: old window to new window */ + e1->type = ELMT_LINE; + e1->parent = tmp; + /* Set the drawing color */ + e1->elment_color_p = &g->s.tseq_tcptrace.ack_color[toggle]; + e1->p.line.dim.x1 = x; + e1->p.line.dim.y1 = p_win + p_ackno; + e1->p.line.dim.x2 = x; + e1->p.line.dim.y2 = win + ackno; + e1++; + + /* Toggle color to use for ACKs... */ + toggle = 1^toggle; + } + ack_seen = TRUE; + p_ackno = ackno; + p_win = win; + p_t = x; + + /* Now any SACK entries */ + if (tmp->num_sack_ranges) { + int n; + + for (n=0; n < tmp->num_sack_ranges; n++) { + double left_edge = (tmp->sack_left_edge[n] - seq_base) * g->zoom.y; + double right_edge = (tmp->sack_right_edge[n] - seq_base) * g->zoom.y; + + /* Vertical: just show range of SACK. + Have experimented with sorting ranges and showing in red regions + between SACKs, but when TCP is limited by option bytes and needs to + miss out ranges, this can be pretty confusing as we end up apparently + NACKing what has been received... */ + e1->type = ELMT_LINE; + e1->parent = tmp; + /* Set the drawing color. First range is significant, so use + separate colour */ + e1->elment_color_p = (n==0) ? &g->s.tseq_tcptrace.sack_color[0] : + &g->s.tseq_tcptrace.sack_color[1]; + e1->p.line.dim.x1 = x; + e1->p.line.dim.y1 = right_edge; + e1->p.line.dim.x2 = x; + e1->p.line.dim.y2 = left_edge; + e1++; + } + } + } + } + + /* Terminate both lists */ + e0->type = ELMT_NONE; + e1->type = ELMT_NONE; + + g->elists->elements = elements0; + g->elists->next->elements = elements1; + g->elists->next->next = NULL; +} + +static void tseq_tcptrace_toggle_seq_origin(struct graph *g) +{ + g->s.tseq_tcptrace.flags ^= SEQ_ORIGIN; + + if ((g->s.tseq_tcptrace.flags & SEQ_ORIGIN) == SEQ_ORIGIN_ZERO) + g->y_axis->min = g->bounds.y0; + else /* g->tseq_stevens.flags & SEQ_ORIGIN == SEQ_ORIGIN_ISN */ + g->y_axis->min = 0; +} + +static void tseq_tcptrace_toggle_time_origin(struct graph *g) +{ + g->s.tseq_tcptrace.flags ^= TIME_ORIGIN; + + if ((g->s.tseq_tcptrace.flags & TIME_ORIGIN) == TIME_ORIGIN_CAP) + g->x_axis->min = g->bounds.x0; + else /* g->tseq_stevens.flags & TIME_ORIGIN == TIME_ORIGIN_CONN */ + g->x_axis->min = 0; } /* * throughput graph */ -static void tput_make_elmtlist (struct graph *g) -{ - struct segment *tmp, *oldest; - struct element *elements, *e; - int i, sum=0; - double dtime, tput; - int num_sack_ranges; - - if (g->elists->elements == NULL) { - int n = 1 + get_num_dsegs (g) + get_num_acks (g, &num_sack_ranges); - e = elements = (struct element * )g_malloc (n*sizeof (struct element)); - } else - e = elements = g->elists->elements; - - for (oldest=g->segments,tmp=g->segments->next,i=0; tmp; tmp=tmp->next,i++) { - double time_val = tmp->rel_secs + tmp->rel_usecs/1000000.0; - dtime = time_val - (oldest->rel_secs + oldest->rel_usecs/1000000.0); - if (i>g->s.tput.nsegs) { - sum -= oldest->th_seglen; - oldest=oldest->next; - } - sum += tmp->th_seglen; - tput = sum / dtime; - /* debug(DBS_TPUT_ELMTS) printf ("tput=%f\n", tput); */ - - e->type = ELMT_ELLIPSE; - e->parent = tmp; - e->p.ellipse.dim.width = g->s.tput.width; - e->p.ellipse.dim.height = g->s.tput.height; - e->p.ellipse.dim.x = g->zoom.x*(time_val - g->bounds.x0) - g->s.tput.width/2.0; - e->p.ellipse.dim.y = g->zoom.y*tput + g->s.tput.height/2.0; - e++; - } - e->type = ELMT_NONE; - g->elists->elements = elements; +static void tput_make_elmtlist(struct graph *g) +{ + struct segment *tmp, *oldest; + struct element *elements, *e; + int i, sum = 0; + double dtime, tput; + int num_sack_ranges; + + if (g->elists->elements == NULL) { + int n = 1 + get_num_dsegs(g) + get_num_acks(g, &num_sack_ranges); + e = elements = (struct element * )g_malloc(n * sizeof(struct element)); + } else + e = elements = g->elists->elements; + + for (oldest=g->segments, tmp=g->segments->next, i=0; tmp; tmp=tmp->next, i++) { + double time_val = tmp->rel_secs + tmp->rel_usecs/1000000.0; + dtime = time_val - (oldest->rel_secs + oldest->rel_usecs/1000000.0); + if (i>g->s.tput.nsegs) { + sum -= oldest->th_seglen; + oldest = oldest->next; + } + sum += tmp->th_seglen; + tput = sum / dtime; + /* debug(DBS_TPUT_ELMTS) printf("tput=%f\n", tput); */ + + e->type = ELMT_ELLIPSE; + e->parent = tmp; + e->p.ellipse.dim.width = g->s.tput.width; + e->p.ellipse.dim.height = g->s.tput.height; + e->p.ellipse.dim.x = g->zoom.x*(time_val - g->bounds.x0) - g->s.tput.width/2.0; + e->p.ellipse.dim.y = g->zoom.y*tput + g->s.tput.height/2.0; + e++; + } + e->type = ELMT_NONE; + g->elists->elements = elements; } /* Purpose of <graph_type>_initialize functions: * - find maximum and minimum for both axes * - call setup routine for style struct */ -static void tput_initialize (struct graph *g) -{ - struct segment *tmp, *oldest, *last; - int i, sum=0; - double dtime, tput, tputmax=0; - double t, t0, tmax = 0, yy0, ymax; - - debug(DBS_FENTRY) puts ("tput_initialize()"); - - tput_read_config(g); - - for (last=g->segments; last->next; last=last->next); - for (oldest=g->segments,tmp=g->segments->next,i=0; tmp; tmp=tmp->next,i++) { - dtime = tmp->rel_secs + tmp->rel_usecs/1000000.0 - - (oldest->rel_secs + oldest->rel_usecs/1000000.0); - if (i>g->s.tput.nsegs) { - sum -= oldest->th_seglen; - oldest=oldest->next; - } - sum += tmp->th_seglen; - tput = sum / dtime; - debug(DBS_TPUT_ELMTS) printf ("tput=%f\n", tput); - if (tput > tputmax) - tputmax = tput; - t = tmp->rel_secs + tmp->rel_usecs / 1000000.0; - if (t > tmax) - tmax = t; - } - - t0 = g->segments->rel_secs + g->segments->rel_usecs / 1000000.0; - yy0 = 0; - ymax = tputmax; - - g->bounds.x0 = t0; - g->bounds.y0 = yy0; - g->bounds.width = tmax - t0; - g->bounds.height = ymax - yy0; - g->zoom.x = (g->geom.width - 1) / g->bounds.width; - g->zoom.y = (g->geom.height -1) / g->bounds.height; -} - -static void tput_read_config (struct graph *g) -{ - debug(DBS_FENTRY) puts ("tput_read_config()"); - - g->s.tput.width = 4; - g->s.tput.height = 4; - g->s.tput.nsegs = 20; - - g->title = (const char ** )g_malloc (2 * sizeof (char *)); - g->title[0] = "Throughput Graph"; - g->title[1] = NULL; - g->y_axis->label = (const char ** )g_malloc (3 * sizeof (char * )); - g->y_axis->label[0] = "[B/s]"; - g->y_axis->label[1] = "Throughput"; - g->y_axis->label[2] = NULL; - g->x_axis->label = (const char ** )g_malloc (2 * sizeof (char * )); - g->x_axis->label[0] = "Time[s]"; - g->x_axis->label[1] = NULL; - g->s.tput.flags = 0; -} - -static void tput_toggle_time_origin (struct graph *g) -{ - g->s.tput.flags ^= TIME_ORIGIN; - - if ((g->s.tput.flags & TIME_ORIGIN) == TIME_ORIGIN_CAP) - g->x_axis->min = g->bounds.x0; - else /* g->s.tput.flags & TIME_ORIGIN == TIME_ORIGIN_CONN */ - g->x_axis->min = 0; -} - -/* RTT graph */ - -static void rtt_read_config (struct graph *g) -{ - debug(DBS_FENTRY) puts ("rtt_read_config()"); - - g->s.rtt.width = 4; - g->s.rtt.height = 4; - g->s.rtt.flags = 0; - - g->title = (const char ** )g_malloc (2 * sizeof (char *)); - g->title[0] = "Round Trip Time Graph"; - g->title[1] = NULL; - g->y_axis->label = (const char ** )g_malloc (3 * sizeof (char * )); - g->y_axis->label[0] = "RTT [s]"; - g->y_axis->label[1] = NULL; - g->x_axis->label = (const char ** )g_malloc (2 * sizeof (char * )); - g->x_axis->label[0] = "Sequence Number[B]"; - g->x_axis->label[1] = NULL; -} - -static void rtt_initialize (struct graph *g) +static void tput_initialize(struct graph *g) { - struct segment *tmp, *first=NULL; - struct unack *unack = NULL, *u; - double rttmax=0; - double xx0, yy0, ymax; - guint32 xmax = 0; - guint32 seq_base = 0; - - debug(DBS_FENTRY) puts ("rtt_initialize()"); + struct segment *tmp, *oldest/*, *last*/; + int i, sum = 0; + double dtime, tput, tputmax = 0; + double t, t0, tmax = 0, yy0, ymax; - rtt_read_config (g); + debug(DBS_FENTRY) puts("tput_initialize()"); - for (tmp=g->segments; tmp; tmp=tmp->next) { - if(compare_headers(&g->src_address, &g->dst_address, - g->src_port, g->dst_port, - &tmp->ip_src, &tmp->ip_dst, - tmp->th_sport, tmp->th_dport, - COMPARE_CURR_DIR)) { - guint32 seqno = tmp->th_seq; + tput_read_config(g); - if (!first) { - first= tmp; - seq_base = seqno; - } - seqno -= seq_base; - if (tmp->th_seglen && !rtt_is_retrans (unack, seqno)) { - double time_val = tmp->rel_secs + tmp->rel_usecs / 1000000.0; - u = rtt_get_new_unack (time_val, seqno); - if (!u) return; - rtt_put_unack_on_list (&unack, u); - } - - if (seqno + tmp->th_seglen > xmax) - xmax = seqno + tmp->th_seglen; - } else if (first) { - guint32 ackno = tmp->th_ack -seq_base; - double time_val = tmp->rel_secs + tmp->rel_usecs / 1000000.0; - struct unack *v; - - for (u=unack; u; u=v) - if (ackno > u->seqno) { - double rtt = time_val - u->time; - if (rtt > rttmax) - rttmax = rtt; - v=u->next; - rtt_delete_unack_from_list (&unack, u); - } else - v=u->next; - } - } - - xx0 = seq_base; - yy0 = 0; - ymax = rttmax; - - g->bounds.x0 = xx0; - g->bounds.y0 = yy0; - g->bounds.width = xmax; - g->bounds.height = ymax - yy0; - g->zoom.x = g->geom.width / g->bounds.width; - g->zoom.y = g->geom.height / g->bounds.height; -} - -static int rtt_is_retrans (struct unack *list, unsigned int seqno) -{ - struct unack *u; - - for (u=list; u; u=u->next) - if (u->seqno== seqno) - return TRUE; - - return FALSE; -} - -static struct unack *rtt_get_new_unack (double time_val, unsigned int seqno) -{ - struct unack *u; - - u = (struct unack * )g_malloc (sizeof (struct unack)); - if (!u) - return NULL; - u->next = NULL; - u->time = time_val; - u->seqno = seqno; - return u; -} - -static void rtt_put_unack_on_list (struct unack **l, struct unack *new) -{ - struct unack *u, *list = *l; - - for (u=list; u; u=u->next) - if (!u->next) - break; - - if (u) - u->next = new; - else - *l = new; -} - -static void rtt_delete_unack_from_list (struct unack **l, struct unack *dead) -{ - struct unack *u, *list = *l; - - if (!dead || !list) - return; - - if (dead==list) { - *l = list->next; - g_free (list); - } else - for (u=list; u; u=u->next) - if (u->next == dead) { - u->next = u->next->next; - g_free (dead); - break; - } -} - -static void rtt_make_elmtlist (struct graph *g) -{ - struct segment *tmp; - struct unack *unack = NULL, *u; - struct element *elements, *e; - guint32 seq_base = (guint32) g->bounds.x0; - - debug(DBS_FENTRY) puts ("rtt_make_elmtlist()"); - - if (g->elists->elements == NULL) { - int n = 1 + get_num_dsegs (g); - e = elements = (struct element * )g_malloc (n*sizeof (struct element)); - } else { - e = elements = g->elists->elements; - } - - for (tmp=g->segments; tmp; tmp=tmp->next) { - if(compare_headers(&g->src_address, &g->dst_address, - g->src_port, g->dst_port, - &tmp->ip_src, &tmp->ip_dst, - tmp->th_sport, tmp->th_dport, - COMPARE_CURR_DIR)) { - guint32 seqno = tmp->th_seq -seq_base; - - if (tmp->th_seglen && !rtt_is_retrans (unack, seqno)) { - double time_val = tmp->rel_secs + tmp->rel_usecs / 1000000.0; - u = rtt_get_new_unack (time_val, seqno); - if (!u) return; - rtt_put_unack_on_list (&unack, u); - } - } else { - guint32 ackno = tmp->th_ack -seq_base; - double time_val = tmp->rel_secs + tmp->rel_usecs / 1000000.0; - struct unack *v; +#if 0 + for (last=g->segments; last->next; last=last->next); /* XXX: does nothing useful ? */ +#endif + for (oldest=g->segments, tmp=g->segments->next, i=0; tmp; tmp=tmp->next, i++) { + dtime = tmp->rel_secs + tmp->rel_usecs/1000000.0 - + (oldest->rel_secs + oldest->rel_usecs/1000000.0); + if (i > g->s.tput.nsegs) { + sum -= oldest->th_seglen; + oldest = oldest->next; + } + sum += tmp->th_seglen; + tput = sum / dtime; + debug(DBS_TPUT_ELMTS) printf("tput=%f\n", tput); + if (tput > tputmax) + tputmax = tput; + t = tmp->rel_secs + tmp->rel_usecs / 1000000.0; + if (t > tmax) + tmax = t; + } + + t0 = g->segments->rel_secs + g->segments->rel_usecs / 1000000.0; + yy0 = 0; + ymax = tputmax; + + g->bounds.x0 = t0; + g->bounds.y0 = yy0; + g->bounds.width = tmax - t0; + g->bounds.height = ymax - yy0; + g->zoom.x = (g->geom.width - 1) / g->bounds.width; + g->zoom.y = (g->geom.height -1) / g->bounds.height; +} + +static void tput_read_config(struct graph *g) +{ + debug(DBS_FENTRY) puts("tput_read_config()"); + + g->s.tput.width = 4; + g->s.tput.height = 4; + g->s.tput.nsegs = 20; + + g->title = (const char ** )g_malloc(2 * sizeof(char *)); + g->title[0] = "Throughput Graph"; + g->title[1] = NULL; + g->y_axis->label = (const char ** )g_malloc(3 * sizeof(char * )); + g->y_axis->label[0] = "[B/s]"; + g->y_axis->label[1] = "Throughput"; + g->y_axis->label[2] = NULL; + g->x_axis->label = (const char ** )g_malloc(2 * sizeof(char * )); + g->x_axis->label[0] = "Time[s]"; + g->x_axis->label[1] = NULL; + g->s.tput.flags = 0; +} + +static void tput_toggle_time_origin(struct graph *g) +{ + g->s.tput.flags ^= TIME_ORIGIN; + + if ((g->s.tput.flags & TIME_ORIGIN) == TIME_ORIGIN_CAP) + g->x_axis->min = g->bounds.x0; + else /* g->s.tput.flags & TIME_ORIGIN == TIME_ORIGIN_CONN */ + g->x_axis->min = 0; +} - for (u=unack; u; u=v) - if (ackno > u->seqno) { - double rtt = time_val - u->time; +/* RTT graph */ - e->type = ELMT_ELLIPSE; - e->parent = tmp; - e->p.ellipse.dim.width = g->s.rtt.width; - e->p.ellipse.dim.height = g->s.rtt.height; - e->p.ellipse.dim.x = g->zoom.x * u->seqno - g->s.rtt.width/2.0; - e->p.ellipse.dim.y = g->zoom.y * rtt + g->s.rtt.height/2.0; - e++; +static void rtt_read_config(struct graph *g) +{ + debug(DBS_FENTRY) puts("rtt_read_config()"); + + g->s.rtt.width = 4; + g->s.rtt.height = 4; + g->s.rtt.flags = 0; + + g->title = (const char ** )g_malloc(2 * sizeof(char *)); + g->title[0] = "Round Trip Time Graph"; + g->title[1] = NULL; + g->y_axis->label = (const char ** )g_malloc(3 * sizeof(char * )); + g->y_axis->label[0] = "RTT [s]"; + g->y_axis->label[1] = NULL; + g->x_axis->label = (const char ** )g_malloc(2 * sizeof(char * )); + g->x_axis->label[0] = "Sequence Number[B]"; + g->x_axis->label[1] = NULL; +} + +static void rtt_initialize(struct graph *g) +{ + struct segment *tmp, *first = NULL; + struct unack *unack = NULL, *u; + double rttmax = 0; + double xx0, yy0, ymax; + guint32 xmax = 0; + guint32 seq_base = 0; + + debug(DBS_FENTRY) puts("rtt_initialize()"); - v=u->next; - rtt_delete_unack_from_list (&unack, u); - } else - v=u->next; - } - } - e->type = ELMT_NONE; - g->elists->elements = elements; -} + rtt_read_config(g); + + for (tmp=g->segments; tmp; tmp=tmp->next) { + if (compare_headers(&g->src_address, &g->dst_address, + g->src_port, g->dst_port, + &tmp->ip_src, &tmp->ip_dst, + tmp->th_sport, tmp->th_dport, + COMPARE_CURR_DIR)) { + guint32 seqno = tmp->th_seq; + + if (!first) { + first = tmp; + seq_base = seqno; + } + seqno -= seq_base; + if (tmp->th_seglen && !rtt_is_retrans(unack, seqno)) { + double time_val = tmp->rel_secs + tmp->rel_usecs / 1000000.0; + u = rtt_get_new_unack(time_val, seqno); + if (!u) return; + rtt_put_unack_on_list(&unack, u); + } + + if (seqno + tmp->th_seglen > xmax) + xmax = seqno + tmp->th_seglen; + } else if (first) { + guint32 ackno = tmp->th_ack -seq_base; + double time_val = tmp->rel_secs + tmp->rel_usecs / 1000000.0; + struct unack *v; + + for (u=unack; u; u=v) { + if (ackno > u->seqno) { + double rtt = time_val - u->time; + if (rtt > rttmax) + rttmax = rtt; + v = u->next; + rtt_delete_unack_from_list(&unack, u); + } else + v = u->next; + } + } + } + + xx0 = seq_base; + yy0 = 0; + ymax = rttmax; + + g->bounds.x0 = xx0; + g->bounds.y0 = yy0; + g->bounds.width = xmax; + g->bounds.height = ymax - yy0; + g->zoom.x = g->geom.width / g->bounds.width; + g->zoom.y = g->geom.height / g->bounds.height; +} + +static int rtt_is_retrans(struct unack *list, unsigned int seqno) +{ + struct unack *u; + + for (u=list; u; u=u->next) { + if (u->seqno == seqno) + return TRUE; + } + return FALSE; +} + +static struct unack *rtt_get_new_unack(double time_val, unsigned int seqno) +{ + struct unack *u; + + u = (struct unack * )g_malloc(sizeof(struct unack)); + if (!u) + return NULL; + u->next = NULL; + u->time = time_val; + u->seqno = seqno; + return u; +} + +static void rtt_put_unack_on_list(struct unack **l, struct unack *new) +{ + struct unack *u, *list = *l; + + for (u=list; u; u=u->next) { + if (!u->next) + break; + } + if (u) + u->next = new; + else + *l = new; +} + +static void rtt_delete_unack_from_list(struct unack **l, struct unack *dead) +{ + struct unack *u, *list = *l; + + if (!dead || !list) + return; + + if (dead == list) { + *l = list->next; + g_free(list); + } else { + for (u=list; u; u=u->next) { + if (u->next == dead) { + u->next = u->next->next; + g_free(dead); + break; + } + } + } +} + +static void rtt_make_elmtlist(struct graph *g) +{ + struct segment *tmp; + struct unack *unack = NULL, *u; + struct element *elements, *e; + guint32 seq_base = (guint32) g->bounds.x0; + + debug(DBS_FENTRY) puts("rtt_make_elmtlist()"); + + if (g->elists->elements == NULL) { + int n = 1 + get_num_dsegs(g); + e = elements = (struct element * )g_malloc(n * sizeof(struct element)); + } else { + e = elements = g->elists->elements; + } + + for (tmp=g->segments; tmp; tmp=tmp->next) { + if (compare_headers(&g->src_address, &g->dst_address, + g->src_port, g->dst_port, + &tmp->ip_src, &tmp->ip_dst, + tmp->th_sport, tmp->th_dport, + COMPARE_CURR_DIR)) { + guint32 seqno = tmp->th_seq -seq_base; + + if (tmp->th_seglen && !rtt_is_retrans(unack, seqno)) { + double time_val = tmp->rel_secs + tmp->rel_usecs / 1000000.0; + u = rtt_get_new_unack(time_val, seqno); + if (!u) return; + rtt_put_unack_on_list(&unack, u); + } + } else { + guint32 ackno = tmp->th_ack -seq_base; + double time_val = tmp->rel_secs + tmp->rel_usecs / 1000000.0; + struct unack *v; -static void rtt_toggle_seq_origin (struct graph *g) -{ - g->s.rtt.flags ^= SEQ_ORIGIN; + for (u=unack; u; u=v) { + if (ackno > u->seqno) { + double rtt = time_val - u->time; - if ((g->s.rtt.flags & SEQ_ORIGIN) == SEQ_ORIGIN_ZERO) - g->x_axis->min = g->bounds.x0; - else - g->x_axis->min = 0; + e->type = ELMT_ELLIPSE; + e->parent = tmp; + e->p.ellipse.dim.width = g->s.rtt.width; + e->p.ellipse.dim.height = g->s.rtt.height; + e->p.ellipse.dim.x = g->zoom.x * u->seqno - g->s.rtt.width/2.0; + e->p.ellipse.dim.y = g->zoom.y * rtt + g->s.rtt.height/2.0; + e++; + + v = u->next; + rtt_delete_unack_from_list(&unack, u); + } else + v = u->next; + } + } + } + e->type = ELMT_NONE; + g->elists->elements = elements; +} + +static void rtt_toggle_seq_origin(struct graph *g) +{ + g->s.rtt.flags ^= SEQ_ORIGIN; + + if ((g->s.rtt.flags & SEQ_ORIGIN) == SEQ_ORIGIN_ZERO) + g->x_axis->min = g->bounds.x0; + else + g->x_axis->min = 0; } /* WSCALE Graph */ -static void wscale_read_config(struct graph* g) +static void wscale_read_config(struct graph *g) { - debug(DBS_FENTRY) puts ("wscale_read_config()"); + debug(DBS_FENTRY) puts("wscale_read_config()"); - g->s.wscale.win_width = 4; - g->s.wscale.win_height = 4; - g->s.wscale.flags = 0; + g->s.wscale.win_width = 4; + g->s.wscale.win_height = 4; + g->s.wscale.flags = 0; - g->title = (const char ** )g_malloc (2 * sizeof (char *)); - g->title[0] = "Window Scaling Graph"; - g->title[1] = NULL; - g->y_axis->label = (const char ** )g_malloc (3 * sizeof (char * )); - g->y_axis->label[0] = "[bytes]"; - g->y_axis->label[1] = "Windowsize"; - g->y_axis->label[2] = NULL; - g->x_axis->label = (const char ** )g_malloc (2 * sizeof (char * )); - g->x_axis->label[0] = "Time [s]"; - g->x_axis->label[1] = NULL; + g->title = (const char ** )g_malloc(2 * sizeof(char *)); + g->title[0] = "Window Scaling Graph"; + g->title[1] = NULL; + g->y_axis->label = (const char ** )g_malloc(3 * sizeof(char * )); + g->y_axis->label[0] = "[bytes]"; + g->y_axis->label[1] = "Windowsize"; + g->y_axis->label[2] = NULL; + g->x_axis->label = (const char ** )g_malloc(2 * sizeof(char * )); + g->x_axis->label[0] = "Time [s]"; + g->x_axis->label[1] = NULL; } /* (1) Find maximum and minimum values for Window-Size(scaled) and seconds (2) call function to define window related values */ -static void wscale_initialize(struct graph* g) +static void wscale_initialize(struct graph *g) { - struct segment* segm = NULL; - guint32 wsize_max = 0; - guint32 wsize_min = 0; - gdouble sec_max = 0.0; - gdouble sec_base = -1.0; + struct segment *segm = NULL; + guint32 wsize_max = 0; + guint32 wsize_min = 0; + gdouble sec_max = 0.0; + gdouble sec_base = -1.0; - wscale_read_config (g); + wscale_read_config(g); - debug(DBS_FENTRY) puts ("wscale_initialize()"); + debug(DBS_FENTRY) puts("wscale_initialize()"); - for (segm = g->segments; segm; segm = segm->next) - { - if (compare_headers(&g->src_address, &g->dst_address, - g->src_port, g->dst_port, - &segm->ip_src, &segm->ip_dst, - segm->th_sport, segm->th_dport, - COMPARE_CURR_DIR)) - { - gdouble sec = segm->rel_secs + ( segm->rel_usecs / 1000000.0 ); - guint16 flags = segm->th_flags; - guint32 wsize = segm->th_win; + for (segm=g->segments; segm; segm=segm->next) { + if (compare_headers(&g->src_address, &g->dst_address, + g->src_port, g->dst_port, + &segm->ip_src, &segm->ip_dst, + segm->th_sport, segm->th_dport, + COMPARE_CURR_DIR)) + { + gdouble sec = segm->rel_secs + ( segm->rel_usecs / 1000000.0 ); + guint16 flags = segm->th_flags; + guint32 wsize = segm->th_win; - /* only data segments */ - if ( (flags & (TH_SYN|TH_RST)) == 0 ) - if ( wsize > wsize_max ) - wsize_max = wsize; + /* only data segments */ + if ( (flags & (TH_SYN|TH_RST)) == 0 ) + if ( wsize > wsize_max ) + wsize_max = wsize; - /* remind time of first probe */ - if ( sec_base < 0 && sec > 0 ) - sec_base = sec; + /* remind time of first probe */ + if ((sec_base < 0) && (sec > 0)) + sec_base = sec; - if ( sec_max < sec ) - sec_max = sec; + if ( sec_max < sec ) + sec_max = sec; - } + } - } + } - g->bounds.x0 = 0; - g->bounds.y0 = wsize_min; - g->bounds.width = sec_max - sec_base + 5; - g->bounds.height = wsize_max + 5; - g->zoom.x = g->geom.width / g->bounds.width; - g->zoom.y = g->geom.height / g->bounds.height; + g->bounds.x0 = 0; + g->bounds.y0 = wsize_min; + g->bounds.width = sec_max - sec_base + 5; + g->bounds.height = wsize_max + 5; + g->zoom.x = g->geom.width / g->bounds.width; + g->zoom.y = g->geom.height / g->bounds.height; } /* (1) Fill & allocate memory for segments times elements, */ -static void wscale_make_elmtlist(struct graph* g) -{ - struct segment* segm = NULL; - struct element* elements = NULL; - struct element* e = NULL; - gdouble sec_base = -1.0; - - debug(DBS_FENTRY) puts ("wscale_make_elmtlist()"); - - /* Allocate memory for elements if not already done */ - if (g->elists->elements == NULL) - { - int n = 1 + get_num_dsegs(g); - e = elements = (struct element*)g_malloc(n*sizeof(struct element)); - } - else - e = elements = g->elists->elements; - - - for ( segm = g->segments; segm; segm = segm->next ) - { - if (compare_headers(&g->src_address, &g->dst_address, - g->src_port, g->dst_port, - &segm->ip_src, &segm->ip_dst, - segm->th_sport, segm->th_dport, - COMPARE_CURR_DIR)) - { - gdouble sec = segm->rel_secs + (segm->rel_usecs / 1000000.0); - guint16 flags = segm->th_flags; - guint32 wsize = segm->th_win; - - /* remind time of first probe */ - if ( sec_base < 0 && sec > 0 ) - sec_base = sec; - - /* only data or ack segments */ - if ( (flags & (TH_SYN|TH_RST)) == 0 ) - { - e->type = ELMT_ELLIPSE; - e->parent = segm; - e->p.ellipse.dim.width = g->s.wscale.win_width; - e->p.ellipse.dim.height = g->s.wscale.win_height; - e->p.ellipse.dim.x = g->zoom.x * (sec - sec_base) - g->s.wscale.win_width / 2.0; - e->p.ellipse.dim.y = g->zoom.y * wsize - g->s.wscale.win_height / 2.0; - e++; - } - } - } - /* finished populating element list */ - e->type = ELMT_NONE; - g->elists->elements = elements; +static void wscale_make_elmtlist(struct graph *g) +{ + struct segment *segm = NULL; + struct element *elements = NULL; + struct element *e = NULL; + gdouble sec_base = -1.0; + + debug(DBS_FENTRY) puts("wscale_make_elmtlist()"); + + /* Allocate memory for elements if not already done */ + if (g->elists->elements == NULL) + { + int n = 1 + get_num_dsegs(g); + e = elements = (struct element*)g_malloc(n*sizeof(struct element)); + } + else + e = elements = g->elists->elements; + + + for ( segm=g->segments; segm; segm=segm->next ) { + if (compare_headers(&g->src_address, &g->dst_address, + g->src_port, g->dst_port, + &segm->ip_src, &segm->ip_dst, + segm->th_sport, segm->th_dport, + COMPARE_CURR_DIR)) + { + gdouble sec = segm->rel_secs + (segm->rel_usecs / 1000000.0); + guint16 flags = segm->th_flags; + guint32 wsize = segm->th_win; + + /* remind time of first probe */ + if ((sec_base < 0) && (sec > 0)) + sec_base = sec; + + /* only data or ack segments */ + if ( (flags & (TH_SYN|TH_RST)) == 0 ) + { + e->type = ELMT_ELLIPSE; + e->parent = segm; + e->p.ellipse.dim.width = g->s.wscale.win_width; + e->p.ellipse.dim.height = g->s.wscale.win_height; + e->p.ellipse.dim.x = g->zoom.x * (sec - sec_base) - g->s.wscale.win_width / 2.0; + e->p.ellipse.dim.y = g->zoom.y * wsize - g->s.wscale.win_height / 2.0; + e++; + } + } + } + /* finished populating element list */ + e->type = ELMT_NONE; + g->elists->elements = elements; } #if defined(_WIN32) && !defined(__MINGW32__) /* replacement of Unix rint() for Windows */ -static int rint (double x) +static int rint(double x) { - char *buf; - int i,dec,sig; + char *buf; + int i, dec, sig; - buf = _fcvt(x, 0, &dec, &sig); - i = atoi(buf); - if(sig == 1) { - i = i * -1; - } - return(i); + buf = _fcvt(x, 0, &dec, &sig); + i = atoi(buf); + if (sig == 1) { + i = i * -1; + } + return(i); } #endif gboolean tcp_graph_selected_packet_enabled(frame_data *current_frame, epan_dissect_t *edt, gpointer callback_data _U_) { - return current_frame != NULL ? (edt->pi.ipproto == IP_PROTO_TCP) : FALSE; + return current_frame != NULL ? (edt->pi.ipproto == IP_PROTO_TCP) : FALSE; } |