forked from osmocom/wireshark
![Guy Harris](/assets/img/avatar_default.png)
the ui directory. (Perhaps some other files that would be used by all flavors of Wireshark, for any GUI toolkit or for someting such as ncurses, and not for any command-line tool such as TShark, should be moved there as well.) Shuffle some #includes to put the "ui/XXX.h" includes together. svn path=/trunk/; revision=40529
1868 lines
54 KiB
C
1868 lines
54 KiB
C
/*
|
|
* Copyright 2004, Irene Ruengeler <i.ruengeler [AT] fh-muenster.de>
|
|
* Copyright 2009, Varun Notibala <nbvarun [AT] gmail.com>
|
|
*
|
|
* $Id$
|
|
*
|
|
* Wireshark - Network traffic analyzer
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
* Copyright 1998 Gerald Combs
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
#include <string.h>
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#include "epan/filesystem.h"
|
|
#include <epan/strutil.h>
|
|
|
|
#include "../globals.h"
|
|
#include "ui/ui_util.h"
|
|
#include "ui/simple_dialog.h"
|
|
|
|
#include "ui/gtk/dlg_utils.h"
|
|
#include "ui/gtk/main.h"
|
|
#include "ui/gtk/sctp_stat.h"
|
|
|
|
#include "ui/gtk/old-gtk-compat.h"
|
|
|
|
#define DEFAULT_PIXELS_PER_TICK 2
|
|
#define MAX_PIXELS_PER_TICK 4
|
|
#define AUTO_MAX_YSCALE 0
|
|
#define MAX_TICK_VALUES 5
|
|
#define DEFAULT_TICK_VALUE 3
|
|
#define MAX_YSCALE 22
|
|
#define MAX_COUNT_TYPES 3
|
|
|
|
#define COUNT_TYPE_FRAMES 0
|
|
#define COUNT_TYPE_BYTES 1
|
|
#define COUNT_TYPE_ADVANCED 2
|
|
|
|
#define LEFT_BORDER 60
|
|
#define RIGHT_BORDER 10
|
|
#define TOP_BORDER 10
|
|
#define BOTTOM_BORDER 50
|
|
|
|
#define SUB_32(a, b) ((a)-(b))
|
|
#define POINT_SIZE 3
|
|
|
|
static GtkWidget * sack_bt;
|
|
|
|
/*
|
|
* Global variables that help in redrawing graph
|
|
* for SACK and NRSACK
|
|
*/
|
|
static guint8 gIsSackChunkPresent = 0;
|
|
static guint8 gIsNRSackChunkPresent = 0;
|
|
|
|
struct chunk_header {
|
|
guint8 type;
|
|
guint8 flags;
|
|
guint16 length;
|
|
};
|
|
|
|
struct data_chunk_header {
|
|
guint8 type;
|
|
guint8 flags;
|
|
guint16 length;
|
|
guint32 tsn;
|
|
guint16 sid;
|
|
guint16 ssn;
|
|
guint32 ppi;
|
|
};
|
|
|
|
struct init_chunk_header {
|
|
guint8 type;
|
|
guint8 flags;
|
|
guint16 length;
|
|
guint32 initiate_tag;
|
|
guint32 a_rwnd;
|
|
guint16 mos;
|
|
guint16 mis;
|
|
guint32 initial_tsn;
|
|
};
|
|
|
|
struct gaps {
|
|
guint16 start;
|
|
guint16 end;
|
|
};
|
|
|
|
struct sack_chunk_header {
|
|
guint8 type;
|
|
guint8 flags;
|
|
guint16 length;
|
|
guint32 cum_tsn_ack;
|
|
guint32 a_rwnd;
|
|
guint16 nr_of_gaps;
|
|
guint16 nr_of_dups;
|
|
struct gaps gaps[1];
|
|
};
|
|
|
|
struct nr_sack_chunk_header {
|
|
guint8 type;
|
|
guint8 flags;
|
|
guint16 length;
|
|
guint32 cum_tsn_ack;
|
|
guint32 a_rwnd;
|
|
guint16 nr_of_gaps;
|
|
guint16 nr_of_nr_gaps;
|
|
guint16 nr_of_dups;
|
|
guint16 reserved;
|
|
struct gaps gaps[1];
|
|
};
|
|
|
|
static gboolean label_set = FALSE;
|
|
static guint32 max_tsn=0, min_tsn=0;
|
|
static void sctp_graph_set_title(struct sctp_udata *u_data);
|
|
static void create_draw_area(GtkWidget *box, struct sctp_udata *u_data);
|
|
static GtkWidget *zoomout_bt;
|
|
#if defined(_WIN32) && !defined(__MINGW32__)
|
|
static int rint (double ); /* compiler template for Windows */
|
|
#endif
|
|
|
|
static void
|
|
draw_sack_graph(struct sctp_udata *u_data)
|
|
{
|
|
tsn_t *sack;
|
|
GList *list=NULL, *tlist;
|
|
guint16 gap_start=0, gap_end=0, i, j, nr, dup_nr;
|
|
guint8 type;
|
|
guint32 tsnumber, dup;
|
|
gint xvalue, yvalue;
|
|
GdkColor red_color = {0, 65535, 0, 0};
|
|
GdkColor green_color = {0, 0, 65535, 0};
|
|
GdkColor cyan_color = {0, 0, 65535, 65535};
|
|
struct sack_chunk_header *sack_header;
|
|
struct gaps *gap;
|
|
guint32 /*max_num,*/ diff;
|
|
guint32 *dup_list;
|
|
cairo_t * cr = NULL;
|
|
|
|
if (u_data->dir==2)
|
|
{
|
|
|
|
list = g_list_last(u_data->assoc->sack2);
|
|
if (u_data->io->tmp==FALSE)
|
|
{
|
|
min_tsn=u_data->assoc->min_tsn2;
|
|
max_tsn=u_data->assoc->max_tsn2;
|
|
}
|
|
else
|
|
{
|
|
min_tsn=u_data->assoc->min_tsn2+u_data->io->tmp_min_tsn2;
|
|
max_tsn=u_data->assoc->min_tsn2+u_data->io->tmp_max_tsn2;
|
|
}
|
|
}
|
|
else if (u_data->dir==1)
|
|
{
|
|
list = g_list_last(u_data->assoc->sack1);
|
|
if (u_data->io->tmp==FALSE)
|
|
{
|
|
min_tsn=u_data->assoc->min_tsn1;
|
|
max_tsn=u_data->assoc->max_tsn1;
|
|
}
|
|
else
|
|
{
|
|
min_tsn=u_data->assoc->min_tsn1+u_data->io->tmp_min_tsn1;
|
|
max_tsn=u_data->assoc->min_tsn1+u_data->io->tmp_max_tsn1;
|
|
}
|
|
}
|
|
|
|
while (list)
|
|
{
|
|
sack = (tsn_t*) (list->data);
|
|
tlist = g_list_first(sack->tsns);
|
|
while (tlist)
|
|
{
|
|
type = ((struct chunk_header *)tlist->data)->type;
|
|
|
|
if (type == SCTP_SACK_CHUNK_ID)
|
|
{
|
|
gIsSackChunkPresent = 1;
|
|
sack_header =(struct sack_chunk_header *)tlist->data;
|
|
nr=g_ntohs(sack_header->nr_of_gaps);
|
|
tsnumber = g_ntohl(sack_header->cum_tsn_ack);
|
|
dup_nr=g_ntohs(sack_header->nr_of_dups);
|
|
|
|
if (sack->secs>=u_data->io->x1_tmp_sec)
|
|
{
|
|
if (nr>0)
|
|
{
|
|
gap = &sack_header->gaps[0];
|
|
for(i=0;i<nr; i++)
|
|
{
|
|
gap_start=g_ntohs(gap->start);
|
|
gap_end = g_ntohs(gap->end);
|
|
/* max_num=gap_end+tsnumber; */
|
|
for (j=gap_start; j<=gap_end; j++)
|
|
{
|
|
if (u_data->io->uoff)
|
|
diff = sack->secs - u_data->io->min_x;
|
|
else
|
|
diff=sack->secs*1000000+sack->usecs-u_data->io->min_x;
|
|
xvalue = (guint32)(LEFT_BORDER+u_data->io->offset+u_data->io->x_interval*diff);
|
|
yvalue = (guint32)(u_data->io->surface_height-BOTTOM_BORDER-POINT_SIZE-u_data->io->offset-((SUB_32(j+tsnumber,min_tsn))*u_data->io->y_interval));
|
|
if (xvalue >= LEFT_BORDER+u_data->io->offset &&
|
|
xvalue <= u_data->io->surface_width-RIGHT_BORDER+u_data->io->offset &&
|
|
yvalue >= TOP_BORDER-u_data->io->offset-POINT_SIZE &&
|
|
yvalue <= u_data->io->surface_height-BOTTOM_BORDER-u_data->io->offset) {
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cr = cairo_create (u_data->io->surface);
|
|
#else
|
|
cr = gdk_cairo_create (u_data->io->pixmap);
|
|
#endif
|
|
gdk_cairo_set_source_color (cr, &green_color);
|
|
cairo_arc(cr,
|
|
xvalue,
|
|
yvalue,
|
|
POINT_SIZE,
|
|
0,
|
|
2 * G_PI);
|
|
cairo_fill(cr);
|
|
cairo_destroy(cr);
|
|
}
|
|
}
|
|
if (i < nr-1)
|
|
gap++;
|
|
}
|
|
}
|
|
/*
|
|
else
|
|
max_num=tsnumber;
|
|
*/
|
|
if (tsnumber>=min_tsn)
|
|
{
|
|
if (u_data->io->uoff)
|
|
diff = sack->secs - u_data->io->min_x;
|
|
else
|
|
diff=sack->secs*1000000+sack->usecs-u_data->io->min_x;
|
|
xvalue = (guint32)(LEFT_BORDER+u_data->io->offset+u_data->io->x_interval*diff);
|
|
yvalue = (guint32)(u_data->io->surface_height-BOTTOM_BORDER-POINT_SIZE -u_data->io->offset-((SUB_32(tsnumber,min_tsn))*u_data->io->y_interval));
|
|
if (xvalue >= LEFT_BORDER+u_data->io->offset &&
|
|
xvalue <= u_data->io->surface_width-RIGHT_BORDER+u_data->io->offset &&
|
|
yvalue >= TOP_BORDER-u_data->io->offset-POINT_SIZE &&
|
|
yvalue <= u_data->io->surface_height-BOTTOM_BORDER-u_data->io->offset)
|
|
{
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cr = cairo_create (u_data->io->surface);
|
|
#else
|
|
cr = gdk_cairo_create (u_data->io->pixmap);
|
|
#endif
|
|
gdk_cairo_set_source_color (cr, &red_color);
|
|
cairo_arc(cr,
|
|
xvalue,
|
|
yvalue,
|
|
POINT_SIZE,
|
|
0,
|
|
2 * G_PI);
|
|
cairo_fill(cr);
|
|
cairo_destroy(cr);
|
|
|
|
}
|
|
}
|
|
if (dup_nr > 0)
|
|
{
|
|
dup_list = &sack_header->a_rwnd + 2 + nr;
|
|
for (i = 0; i < dup_nr; i++)
|
|
{
|
|
dup = g_ntohl(dup_list[i]);
|
|
if (dup >= min_tsn)
|
|
{
|
|
if (u_data->io->uoff)
|
|
diff = sack->secs - u_data->io->min_x;
|
|
else
|
|
diff=sack->secs*1000000+sack->usecs-u_data->io->min_x;
|
|
xvalue = (guint32)(LEFT_BORDER+u_data->io->offset+u_data->io->x_interval*diff);
|
|
yvalue = (guint32)(u_data->io->surface_height-BOTTOM_BORDER-POINT_SIZE -u_data->io->offset-((SUB_32(dup,min_tsn))*u_data->io->y_interval));
|
|
if (xvalue >= LEFT_BORDER+u_data->io->offset &&
|
|
xvalue <= u_data->io->surface_width-RIGHT_BORDER+u_data->io->offset &&
|
|
yvalue >= TOP_BORDER-u_data->io->offset-POINT_SIZE &&
|
|
yvalue <= u_data->io->surface_height-BOTTOM_BORDER-u_data->io->offset)
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cr = cairo_create (u_data->io->surface);
|
|
#else
|
|
cr = gdk_cairo_create (u_data->io->pixmap);
|
|
#endif
|
|
gdk_cairo_set_source_color (cr, &cyan_color);
|
|
cairo_arc(cr,
|
|
xvalue,
|
|
yvalue,
|
|
POINT_SIZE,
|
|
0,
|
|
2 * G_PI);
|
|
cairo_fill(cr);
|
|
cairo_destroy(cr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
tlist = g_list_next(tlist);
|
|
}
|
|
list = g_list_previous(list);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This function plots the NR_SACK gap ack and
|
|
* nr gap acks.
|
|
* Red dot - Cumulative TSN ack
|
|
* Green dot - Gap ack
|
|
* Blue circle - NR Gap ack
|
|
*/
|
|
static void
|
|
draw_nr_sack_graph(struct sctp_udata *u_data)
|
|
{
|
|
tsn_t *sack;
|
|
GList *list=NULL, *tlist;
|
|
guint16 gap_start=0, gap_end=0, i, numberOf_gaps, numberOf_nr_gaps;
|
|
guint8 type;
|
|
guint32 tsnumber, j;
|
|
gint xvalue, yvalue;
|
|
GdkColor red_color = {0, 65535, 0, 0};
|
|
GdkColor blue_color = {0, 0, 0, 65535};
|
|
GdkColor green_color = {0, 0, 65535, 0};
|
|
struct nr_sack_chunk_header *nr_sack_header;
|
|
struct gaps *nr_gap;
|
|
guint32 /*max_num,*/ diff;
|
|
/* This holds the sum of gap acks and nr gap acks */
|
|
guint16 total_gaps = 0;
|
|
cairo_t *cr = NULL;
|
|
|
|
if (u_data->dir==2)
|
|
{
|
|
list = g_list_last(u_data->assoc->sack2);
|
|
if (u_data->io->tmp==FALSE)
|
|
{
|
|
min_tsn=u_data->assoc->min_tsn2;
|
|
max_tsn=u_data->assoc->max_tsn2;
|
|
}
|
|
else
|
|
{
|
|
min_tsn=u_data->assoc->min_tsn2+u_data->io->tmp_min_tsn2;
|
|
max_tsn=u_data->assoc->min_tsn2+u_data->io->tmp_max_tsn2;
|
|
}
|
|
}
|
|
else if (u_data->dir==1)
|
|
{
|
|
list = g_list_last(u_data->assoc->sack1);
|
|
if (u_data->io->tmp==FALSE)
|
|
{
|
|
min_tsn=u_data->assoc->min_tsn1;
|
|
max_tsn=u_data->assoc->max_tsn1;
|
|
}
|
|
else
|
|
{
|
|
min_tsn=u_data->assoc->min_tsn1+u_data->io->tmp_min_tsn1;
|
|
max_tsn=u_data->assoc->min_tsn1+u_data->io->tmp_max_tsn1;
|
|
}
|
|
}
|
|
while (list)
|
|
{
|
|
sack = (tsn_t*) (list->data);
|
|
tlist = g_list_first(sack->tsns);
|
|
while (tlist)
|
|
{
|
|
type = ((struct chunk_header *)tlist->data)->type;
|
|
/*
|
|
* The tlist->data is memcpy ied to the appropriate structure
|
|
* They entire raw tvb bytes are copied on to one of the *_chunk_header
|
|
* structures in sctp_stat.c
|
|
*/
|
|
if (type == SCTP_NR_SACK_CHUNK_ID)
|
|
{
|
|
gIsNRSackChunkPresent = 1;
|
|
nr_sack_header =(struct nr_sack_chunk_header *)tlist->data;
|
|
numberOf_nr_gaps=g_ntohs(nr_sack_header->nr_of_nr_gaps);
|
|
numberOf_gaps=g_ntohs(nr_sack_header->nr_of_gaps);
|
|
tsnumber = g_ntohl(nr_sack_header->cum_tsn_ack);
|
|
total_gaps = numberOf_gaps + numberOf_nr_gaps;
|
|
if (sack->secs>=u_data->io->x1_tmp_sec)
|
|
{
|
|
/* If the number of nr_gaps is greater than 0 */
|
|
if ( total_gaps > 0 )
|
|
{
|
|
nr_gap = &nr_sack_header->gaps[0];
|
|
for ( i=0; i < total_gaps; i++ )
|
|
{
|
|
gap_start=g_ntohs(nr_gap->start);
|
|
gap_end = g_ntohs(nr_gap->end);
|
|
/* max_num= gap_end + tsnumber; */
|
|
for ( j = gap_start; j <= gap_end; j++)
|
|
{
|
|
if (u_data->io->uoff)
|
|
diff = sack->secs - u_data->io->min_x;
|
|
else
|
|
diff=sack->secs*1000000+sack->usecs-u_data->io->min_x;
|
|
xvalue = (guint32)(LEFT_BORDER+u_data->io->offset+u_data->io->x_interval*diff);
|
|
yvalue = (guint32)(u_data->io->surface_height-BOTTOM_BORDER-POINT_SIZE-u_data->io->offset-((SUB_32(j+tsnumber,min_tsn))*u_data->io->y_interval));
|
|
if (xvalue >= LEFT_BORDER+u_data->io->offset &&
|
|
xvalue <= u_data->io->surface_width-RIGHT_BORDER+u_data->io->offset &&
|
|
yvalue >= TOP_BORDER-u_data->io->offset-POINT_SIZE &&
|
|
yvalue <= u_data->io->surface_height-BOTTOM_BORDER-u_data->io->offset)
|
|
{
|
|
/* Check if this is an GAP ACK or NR GAP ACK */
|
|
if ( i >= numberOf_gaps)
|
|
{
|
|
/* This is a nr gap ack */
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cr = cairo_create (u_data->io->surface);
|
|
#else
|
|
cr = gdk_cairo_create (u_data->io->pixmap);
|
|
#endif
|
|
gdk_cairo_set_source_color (cr, &blue_color);
|
|
cairo_arc(cr,
|
|
xvalue,
|
|
yvalue,
|
|
POINT_SIZE,
|
|
0,
|
|
2 * G_PI);
|
|
cairo_stroke(cr);
|
|
cairo_destroy(cr);
|
|
|
|
|
|
/* All NR GAP Acks are also gap acks, so plot these as
|
|
* gap acks - green dot.
|
|
* These will be shown as points with a green dot - GAP ACK
|
|
* surrounded by a blue circle - NR GAP ack
|
|
*/
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cr = cairo_create (u_data->io->surface);
|
|
#else
|
|
cr = gdk_cairo_create (u_data->io->pixmap);
|
|
#endif
|
|
gdk_cairo_set_source_color (cr, &green_color);
|
|
cairo_arc(cr,
|
|
xvalue,
|
|
yvalue,
|
|
POINT_SIZE,
|
|
0,
|
|
2 * G_PI);
|
|
cairo_fill(cr);
|
|
cairo_destroy(cr);
|
|
}
|
|
else
|
|
{
|
|
/* This is just a gap ack */
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cr = cairo_create (u_data->io->surface);
|
|
#else
|
|
cr = gdk_cairo_create (u_data->io->pixmap);
|
|
#endif
|
|
gdk_cairo_set_source_color (cr, &green_color);
|
|
cairo_arc(cr,
|
|
xvalue,
|
|
yvalue,
|
|
POINT_SIZE,
|
|
0,
|
|
2 * G_PI);
|
|
cairo_fill(cr);
|
|
cairo_destroy(cr);
|
|
}
|
|
}
|
|
}
|
|
if (i < total_gaps-1)
|
|
nr_gap++;
|
|
}
|
|
}
|
|
/*
|
|
else
|
|
max_num=tsnumber;
|
|
*/
|
|
if (tsnumber>=min_tsn)
|
|
{
|
|
if (u_data->io->uoff)
|
|
diff = sack->secs - u_data->io->min_x;
|
|
else
|
|
diff=sack->secs*1000000+sack->usecs-u_data->io->min_x;
|
|
xvalue = (guint32)(LEFT_BORDER+u_data->io->offset+u_data->io->x_interval*diff);
|
|
yvalue = (guint32)(u_data->io->surface_height-BOTTOM_BORDER-POINT_SIZE -u_data->io->offset-((SUB_32(tsnumber,min_tsn))*u_data->io->y_interval));
|
|
if (xvalue >= LEFT_BORDER+u_data->io->offset &&
|
|
xvalue <= u_data->io->surface_width-RIGHT_BORDER+u_data->io->offset &&
|
|
yvalue >= TOP_BORDER-u_data->io->offset-POINT_SIZE &&
|
|
yvalue <= u_data->io->surface_height-BOTTOM_BORDER-u_data->io->offset)
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cr = cairo_create (u_data->io->surface);
|
|
#else
|
|
cr = gdk_cairo_create (u_data->io->pixmap);
|
|
#endif
|
|
gdk_cairo_set_source_color (cr, &red_color);
|
|
cairo_arc(cr,
|
|
xvalue,
|
|
yvalue,
|
|
POINT_SIZE,
|
|
0,
|
|
2 * G_PI);
|
|
cairo_fill(cr);
|
|
cairo_destroy(cr);
|
|
}
|
|
}
|
|
}
|
|
tlist = g_list_next(tlist);
|
|
}
|
|
list = g_list_previous(list);
|
|
}
|
|
}
|
|
|
|
static void
|
|
draw_tsn_graph(struct sctp_udata *u_data)
|
|
{
|
|
tsn_t *tsn;
|
|
GList *list=NULL, *tlist;
|
|
guint8 type;
|
|
guint32 tsnumber=0;
|
|
guint32 min_secs=0, diff;
|
|
gint xvalue, yvalue;
|
|
cairo_t *cr = NULL;
|
|
|
|
if (u_data->dir == 1)
|
|
{
|
|
list = g_list_last(u_data->assoc->tsn1);
|
|
if (u_data->io->tmp == FALSE)
|
|
{
|
|
min_tsn = u_data->assoc->min_tsn1;
|
|
max_tsn = u_data->assoc->max_tsn1;
|
|
}
|
|
else
|
|
{
|
|
min_tsn = u_data->assoc->min_tsn1 + u_data->io->tmp_min_tsn1;
|
|
max_tsn = u_data->assoc->min_tsn1 + u_data->io->tmp_max_tsn1;
|
|
}
|
|
}
|
|
else if (u_data->dir == 2)
|
|
{
|
|
list = g_list_last(u_data->assoc->tsn2);
|
|
if (u_data->io->tmp == FALSE)
|
|
{
|
|
min_tsn = u_data->assoc->min_tsn2;
|
|
max_tsn = u_data->assoc->max_tsn2;
|
|
}
|
|
else
|
|
{
|
|
min_tsn = u_data->assoc->min_tsn2 + u_data->io->tmp_min_tsn2;
|
|
max_tsn = u_data->assoc->min_tsn2 + u_data->io->tmp_max_tsn2;
|
|
}
|
|
}
|
|
|
|
while (list)
|
|
{
|
|
tsn = (tsn_t*) (list->data);
|
|
tlist = g_list_first(tsn->tsns);
|
|
while (tlist)
|
|
{
|
|
type = ((struct chunk_header *)tlist->data)->type;
|
|
if (type == SCTP_DATA_CHUNK_ID)
|
|
tsnumber = g_ntohl(((struct data_chunk_header *)tlist->data)->tsn);
|
|
if (tsnumber >= min_tsn && tsnumber <= max_tsn && tsn->secs >= min_secs)
|
|
{
|
|
if (u_data->io->uoff) {
|
|
diff = tsn->secs - u_data->io->min_x;
|
|
} else {
|
|
diff = tsn->secs * 1000000 + tsn->usecs - u_data->io->min_x;
|
|
}
|
|
xvalue = (guint32)(LEFT_BORDER + u_data->io->offset + u_data->io->x_interval * diff);
|
|
yvalue = (guint32)(u_data->io->surface_height - BOTTOM_BORDER - POINT_SIZE - u_data->io->offset - ((SUB_32(tsnumber,min_tsn))*u_data->io->y_interval));
|
|
if (xvalue >= LEFT_BORDER+u_data->io->offset &&
|
|
xvalue <= u_data->io->surface_width - RIGHT_BORDER + u_data->io->offset &&
|
|
yvalue >= TOP_BORDER - u_data->io->offset - POINT_SIZE &&
|
|
yvalue <= u_data->io->surface_height - BOTTOM_BORDER - u_data->io->offset) {
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cr = cairo_create (u_data->io->surface);
|
|
#else
|
|
cr = gdk_cairo_create (u_data->io->pixmap);
|
|
#endif
|
|
cairo_arc(cr,
|
|
xvalue,
|
|
yvalue,
|
|
POINT_SIZE,
|
|
0,
|
|
2 * G_PI);
|
|
cairo_fill(cr);
|
|
cairo_destroy(cr);
|
|
}
|
|
|
|
}
|
|
tlist = g_list_next(tlist);
|
|
}
|
|
list = g_list_previous(list);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
sctp_graph_draw(struct sctp_udata *u_data)
|
|
{
|
|
int length, lwidth;
|
|
guint32 distance=5, i, e, sec, w, start, a, b, j;
|
|
gint label_width, label_height;
|
|
char label_string[15];
|
|
gfloat dis;
|
|
gboolean write_label = FALSE;
|
|
PangoLayout *layout;
|
|
GtkAllocation widget_alloc;
|
|
cairo_t *cr;
|
|
|
|
if (u_data->io->x1_tmp_sec==0 && u_data->io->x1_tmp_usec==0)
|
|
u_data->io->offset=0;
|
|
else
|
|
u_data->io->offset=5;
|
|
|
|
if (u_data->io->x2_tmp_sec - u_data->io->x1_tmp_sec > 1500)
|
|
{
|
|
u_data->io->min_x=u_data->io->x1_tmp_sec;
|
|
u_data->io->max_x=u_data->io->x2_tmp_sec;
|
|
u_data->io->uoff = TRUE;
|
|
}
|
|
else
|
|
{
|
|
u_data->io->min_x=(guint32)(u_data->io->x1_tmp_sec*1000000.0+u_data->io->x1_tmp_usec);
|
|
u_data->io->max_x=(guint32)(u_data->io->x2_tmp_sec*1000000.0+u_data->io->x2_tmp_usec);
|
|
u_data->io->uoff = FALSE;
|
|
}
|
|
|
|
u_data->io->tmp_width=u_data->io->max_x-u_data->io->min_x;
|
|
|
|
if (u_data->dir==1)
|
|
{
|
|
if (u_data->io->tmp==FALSE)
|
|
{
|
|
if (u_data->assoc->tsn1!=NULL || u_data->assoc->sack1!=NULL)
|
|
u_data->io->max_y=u_data->io->tmp_max_tsn1 - u_data->io->tmp_min_tsn1;
|
|
else
|
|
u_data->io->max_y= 0;
|
|
u_data->io->min_y = 0;
|
|
}
|
|
else
|
|
{
|
|
u_data->io->max_y = u_data->io->tmp_max_tsn1;
|
|
u_data->io->min_y = u_data->io->tmp_min_tsn1;
|
|
}
|
|
}
|
|
else if (u_data->dir==2)
|
|
{
|
|
if (u_data->io->tmp==FALSE)
|
|
{
|
|
if (u_data->assoc->tsn2!=NULL || u_data->assoc->sack2!=NULL)
|
|
u_data->io->max_y=u_data->io->tmp_max_tsn2 -u_data->io->tmp_min_tsn2;
|
|
else
|
|
u_data->io->max_y= 0;
|
|
u_data->io->min_y = 0;
|
|
}
|
|
else
|
|
{
|
|
u_data->io->max_y = u_data->io->tmp_max_tsn2;
|
|
u_data->io->min_y = u_data->io->tmp_min_tsn2;
|
|
}
|
|
}
|
|
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cr = cairo_create (u_data->io->surface);
|
|
#else
|
|
cr = gdk_cairo_create (u_data->io->pixmap);
|
|
#endif
|
|
cairo_set_source_rgb (cr, 1, 1, 1);
|
|
gtk_widget_get_allocation(u_data->io->draw_area, &widget_alloc);
|
|
cairo_rectangle (cr,
|
|
0,
|
|
0,
|
|
widget_alloc.width,
|
|
widget_alloc.height);
|
|
cairo_fill (cr);
|
|
cairo_destroy (cr);
|
|
|
|
distance=5;
|
|
/* x_axis */
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cr = cairo_create (u_data->io->surface);
|
|
#else
|
|
cr = gdk_cairo_create (u_data->io->pixmap);
|
|
#endif
|
|
cairo_set_line_width (cr, 1.0);
|
|
cairo_move_to(cr, LEFT_BORDER+u_data->io->offset+0.5, u_data->io->surface_height - BOTTOM_BORDER+0.5);
|
|
cairo_line_to(cr, u_data->io->surface_width - RIGHT_BORDER + u_data->io->offset+0.5, u_data->io->surface_height - BOTTOM_BORDER+0.5);
|
|
|
|
cairo_move_to(cr, u_data->io->surface_width - RIGHT_BORDER + u_data->io->offset+0.5, u_data->io->surface_height - BOTTOM_BORDER+0.5);
|
|
cairo_line_to(cr, u_data->io->surface_width - RIGHT_BORDER + u_data->io->offset - 5+0.5, u_data->io->surface_height - BOTTOM_BORDER - 5+0.5);
|
|
|
|
cairo_move_to(cr, u_data->io->surface_width - RIGHT_BORDER + u_data->io->offset + 0.5, u_data->io->surface_height - BOTTOM_BORDER + 0.5);
|
|
cairo_line_to(cr, u_data->io->surface_width - RIGHT_BORDER + u_data->io->offset - 5.5, u_data->io->surface_height - BOTTOM_BORDER + 5.5);
|
|
cairo_stroke(cr);
|
|
cairo_destroy(cr);
|
|
|
|
u_data->io->axis_width=u_data->io->surface_width-LEFT_BORDER-RIGHT_BORDER-u_data->io->offset;
|
|
|
|
/* try to avoid dividing by zero */
|
|
if(u_data->io->tmp_width>0){
|
|
u_data->io->x_interval = (float)((u_data->io->axis_width*1.0)/u_data->io->tmp_width); /*distance in pixels between 2 data points*/
|
|
} else {
|
|
u_data->io->x_interval = (float)(u_data->io->axis_width);
|
|
}
|
|
|
|
e=0; /*number of decimals of x_interval*/
|
|
if (u_data->io->x_interval<1)
|
|
{
|
|
dis=1/u_data->io->x_interval;
|
|
while (dis >1)
|
|
{
|
|
dis/=10;
|
|
e++;
|
|
}
|
|
distance=1;
|
|
for (i=0; i<=e+1; i++)
|
|
distance*=10; /*distance per 100 pixels*/
|
|
}
|
|
else
|
|
distance=5;
|
|
|
|
g_snprintf(label_string, sizeof(label_string), "%d", 0);
|
|
memcpy(label_string,(gchar *)g_locale_to_utf8(label_string, -1 , NULL, NULL, NULL), sizeof(label_string));
|
|
layout = gtk_widget_create_pango_layout(u_data->io->draw_area, label_string);
|
|
pango_layout_get_pixel_size(layout, &label_width, &label_height);
|
|
|
|
if (u_data->io->x1_tmp_usec==0)
|
|
sec=u_data->io->x1_tmp_sec;
|
|
else
|
|
sec=u_data->io->x1_tmp_sec+1;
|
|
|
|
|
|
if (u_data->io->offset!=0)
|
|
{
|
|
g_snprintf(label_string, sizeof(label_string), "%u", u_data->io->x1_tmp_sec);
|
|
|
|
memcpy(label_string,(gchar *)g_locale_to_utf8(label_string, -1 , NULL, NULL, NULL), sizeof(label_string));
|
|
pango_layout_set_text(layout, label_string, -1);
|
|
pango_layout_get_pixel_size(layout, &lwidth, NULL);
|
|
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cr = cairo_create (u_data->io->surface);
|
|
#else
|
|
cr = gdk_cairo_create (u_data->io->pixmap);
|
|
#endif
|
|
cairo_move_to (cr,
|
|
LEFT_BORDER-25,
|
|
u_data->io->surface_height-BOTTOM_BORDER+20);
|
|
pango_cairo_show_layout (cr, layout);
|
|
cairo_destroy (cr);
|
|
cr = NULL;
|
|
|
|
}
|
|
|
|
w=(guint32)(500/(guint32)(distance*u_data->io->x_interval)); /*there will be a label for every w_th tic*/
|
|
|
|
if (w==0)
|
|
w=1;
|
|
|
|
if (w==4 || w==3 || w==2)
|
|
{
|
|
w=5;
|
|
a=distance/10; /*distance between two tics*/
|
|
b = (guint32)((u_data->io->min_x/100000))%10; /* start for labels*/
|
|
}
|
|
else
|
|
{
|
|
a=distance/5;
|
|
b=0;
|
|
}
|
|
|
|
|
|
if (!u_data->io->uoff)
|
|
{
|
|
if (a>=1000000)
|
|
{
|
|
start=u_data->io->min_x/1000000*1000000;
|
|
if (a==1000000)
|
|
b = 0;
|
|
}
|
|
else
|
|
{
|
|
start=u_data->io->min_x/100000;
|
|
if (start%2!=0)
|
|
start--;
|
|
start*=100000;
|
|
b = (guint32)((start/100000))%10;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
start = u_data->io->min_x;
|
|
if (start%2!=0)
|
|
start--;
|
|
b = 0;
|
|
|
|
}
|
|
|
|
for (i=start, j=b; i<=u_data->io->max_x; i+=a, j++)
|
|
{
|
|
if (!u_data->io->uoff)
|
|
if (i>=u_data->io->min_x && i%1000000!=0)
|
|
{
|
|
length=5;
|
|
g_snprintf(label_string, sizeof(label_string), "%d", i%1000000);
|
|
if (j%w==0)
|
|
{
|
|
length=10;
|
|
memcpy(label_string,(gchar *)g_locale_to_utf8(label_string, -1 , NULL, NULL, NULL), sizeof(label_string));
|
|
pango_layout_set_text(layout, label_string, -1);
|
|
pango_layout_get_pixel_size(layout, &lwidth, NULL);
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cr = cairo_create (u_data->io->surface);
|
|
#else
|
|
cr = gdk_cairo_create (u_data->io->pixmap);
|
|
#endif
|
|
cairo_move_to (cr,
|
|
LEFT_BORDER+u_data->io->offset+(i-u_data->io->min_x)*u_data->io->x_interval-lwidth/2,
|
|
u_data->io->surface_height-BOTTOM_BORDER+10);
|
|
pango_cairo_show_layout (cr, layout);
|
|
cairo_destroy (cr);
|
|
cr = NULL;
|
|
|
|
}
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cr = cairo_create (u_data->io->surface);
|
|
#else
|
|
cr = gdk_cairo_create (u_data->io->pixmap);
|
|
#endif
|
|
cairo_set_line_width (cr, 1.0);
|
|
cairo_move_to(cr,
|
|
LEFT_BORDER + u_data->io->offset + (i - u_data->io->min_x) * u_data->io->x_interval + 0.5,
|
|
u_data->io->surface_height - BOTTOM_BORDER + 0.5);
|
|
cairo_line_to(cr,
|
|
LEFT_BORDER + u_data->io->offset + (i - u_data->io->min_x) * u_data->io->x_interval + 0.5,
|
|
u_data->io->surface_height - BOTTOM_BORDER + length + 0.5);
|
|
cairo_stroke(cr);
|
|
cairo_destroy(cr);
|
|
}
|
|
|
|
if (!u_data->io->uoff)
|
|
{
|
|
if (i%1000000==0 && j%w==0)
|
|
{
|
|
sec=i/1000000;
|
|
write_label = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (j%w == 0)
|
|
{
|
|
sec = i;
|
|
write_label = TRUE;
|
|
}
|
|
}
|
|
if (write_label)
|
|
{
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cr = cairo_create (u_data->io->surface);
|
|
#else
|
|
cr = gdk_cairo_create (u_data->io->pixmap);
|
|
#endif
|
|
cairo_set_line_width (cr, 1.0);
|
|
cairo_move_to(cr,
|
|
LEFT_BORDER + u_data->io->offset + (i - u_data->io->min_x) * u_data->io->x_interval + 0.5,
|
|
u_data->io->surface_height - BOTTOM_BORDER + 0.5);
|
|
cairo_line_to(cr,
|
|
LEFT_BORDER + u_data->io->offset + (i - u_data->io->min_x) * u_data->io->x_interval + 0.5,
|
|
u_data->io->surface_height - BOTTOM_BORDER + 10 + 0.5);
|
|
cairo_stroke(cr);
|
|
cairo_destroy(cr);
|
|
|
|
g_snprintf(label_string, sizeof(label_string), "%d", sec);
|
|
memcpy(label_string,(gchar *)g_locale_to_utf8(label_string, -1 , NULL, NULL, NULL), sizeof(label_string));
|
|
pango_layout_set_text(layout, label_string, -1);
|
|
pango_layout_get_pixel_size(layout, &lwidth, NULL);
|
|
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cr = cairo_create (u_data->io->surface);
|
|
#else
|
|
cr = gdk_cairo_create (u_data->io->pixmap);
|
|
#endif
|
|
cairo_move_to (cr,
|
|
LEFT_BORDER+u_data->io->offset+(i-u_data->io->min_x)*u_data->io->x_interval-10,
|
|
u_data->io->surface_height-BOTTOM_BORDER+20);
|
|
pango_cairo_show_layout (cr, layout);
|
|
cairo_destroy (cr);
|
|
cr = NULL;
|
|
|
|
write_label = FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
g_strlcpy(label_string, "sec", sizeof(label_string));
|
|
|
|
memcpy(label_string,(gchar *)g_locale_to_utf8(label_string, -1 , NULL, NULL, NULL), sizeof(label_string));
|
|
pango_layout_set_text(layout, label_string, -1);
|
|
pango_layout_get_pixel_size(layout, &lwidth, NULL);
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cr = cairo_create (u_data->io->surface);
|
|
#else
|
|
cr = gdk_cairo_create (u_data->io->pixmap);
|
|
#endif
|
|
cairo_move_to (cr,
|
|
u_data->io->surface_width-RIGHT_BORDER-10,
|
|
u_data->io->surface_height-BOTTOM_BORDER+30);
|
|
pango_cairo_show_layout (cr, layout);
|
|
cairo_destroy (cr);
|
|
cr = NULL;
|
|
|
|
|
|
distance=5;
|
|
|
|
/* y-axis */
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cr = cairo_create (u_data->io->surface);
|
|
#else
|
|
cr = gdk_cairo_create (u_data->io->pixmap);
|
|
#endif
|
|
cairo_set_line_width (cr, 1.0);
|
|
cairo_move_to(cr, LEFT_BORDER + 0.5, TOP_BORDER - u_data->io->offset + 0.5);
|
|
cairo_line_to(cr, LEFT_BORDER + 0.5, u_data->io->surface_height - BOTTOM_BORDER - u_data->io->offset + 0.5);
|
|
|
|
cairo_move_to(cr, LEFT_BORDER + 0.5, TOP_BORDER - u_data->io->offset + 0.5);
|
|
cairo_line_to(cr, LEFT_BORDER - 5 + 0.5, TOP_BORDER - u_data->io->offset + 5 + 0.5);
|
|
|
|
cairo_move_to(cr, LEFT_BORDER + 0.5, TOP_BORDER - u_data->io->offset + 0.5);
|
|
cairo_line_to(cr, LEFT_BORDER +5 + 0.5, TOP_BORDER - u_data->io->offset + 5 + 0.5);
|
|
cairo_stroke(cr);
|
|
cairo_destroy(cr);
|
|
|
|
u_data->io->y_interval = (float)(((u_data->io->surface_height-TOP_BORDER-BOTTOM_BORDER)*1.0)/(u_data->io->max_y-u_data->io->min_y));
|
|
|
|
e=0;
|
|
if (u_data->io->y_interval<1)
|
|
{
|
|
dis=1/u_data->io->y_interval;
|
|
while (dis >1)
|
|
{
|
|
dis/=10;
|
|
e++;
|
|
}
|
|
distance=1;
|
|
for (i=0; i<=e; i++)
|
|
distance=distance*10;
|
|
}
|
|
else if (u_data->io->y_interval<2)
|
|
distance = 10;
|
|
|
|
if (u_data->io->max_y>0)
|
|
{
|
|
for (i=u_data->io->min_y/distance*distance; i<=u_data->io->max_y; i+=distance/5)
|
|
{
|
|
if (i>=u_data->io->min_y)
|
|
{
|
|
length=5;
|
|
g_snprintf(label_string, sizeof(label_string), "%d", i);
|
|
if (i%distance==0 || (distance<=5 && u_data->io->y_interval>10))
|
|
{
|
|
length=10;
|
|
|
|
memcpy(label_string,(gchar *)g_locale_to_utf8(label_string, -1 , NULL, NULL, NULL), sizeof(label_string));
|
|
pango_layout_set_text(layout, label_string, -1);
|
|
pango_layout_get_pixel_size(layout, &lwidth, NULL);
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cr = cairo_create (u_data->io->surface);
|
|
#else
|
|
cr = gdk_cairo_create (u_data->io->pixmap);
|
|
#endif
|
|
cairo_move_to (cr,
|
|
LEFT_BORDER-length-lwidth-5,
|
|
u_data->io->surface_height-BOTTOM_BORDER-u_data->io->offset-(i-u_data->io->min_y)*u_data->io->y_interval-POINT_SIZE);
|
|
pango_cairo_show_layout (cr, layout);
|
|
cairo_destroy (cr);
|
|
cr = NULL;
|
|
|
|
}
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cr = cairo_create (u_data->io->surface);
|
|
#else
|
|
cr = gdk_cairo_create (u_data->io->pixmap);
|
|
#endif
|
|
cairo_set_line_width (cr, 1.0);
|
|
cairo_move_to(cr,
|
|
LEFT_BORDER - length + 0.5,
|
|
u_data->io->surface_height - BOTTOM_BORDER - u_data->io->offset - (i - u_data->io->min_y) * u_data->io->y_interval + 0.5);
|
|
cairo_line_to(cr,
|
|
LEFT_BORDER + 0.5,
|
|
u_data->io->surface_height - BOTTOM_BORDER - u_data->io->offset - (i - u_data->io->min_y) * u_data->io->y_interval + 0.5);
|
|
cairo_stroke(cr);
|
|
cairo_destroy(cr);
|
|
|
|
}
|
|
}
|
|
}
|
|
else if ((u_data->dir==1 && u_data->assoc->n_array_tsn1==0) || (u_data->dir==2 && u_data->assoc->n_array_tsn2==0))
|
|
simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, "No Data Chunks sent");
|
|
|
|
g_object_unref(G_OBJECT(layout));
|
|
}
|
|
|
|
/* This function is used to change the title
|
|
* in the graph dialogue to NR_SACK or SACK based on the
|
|
* association
|
|
* If an association has both SAKC and NR_SACK PDU's
|
|
* a warning is popped
|
|
*/
|
|
static void
|
|
updateLabels(void)
|
|
{
|
|
if (gIsSackChunkPresent && gIsNRSackChunkPresent)
|
|
{
|
|
simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, "This data set contains both SACK and NR SACK PDUs.");
|
|
gtk_button_set_label( (GtkButton*) sack_bt, "Show both Sack and NR Sack");
|
|
}
|
|
else if (gIsSackChunkPresent)
|
|
gtk_button_set_label( (GtkButton*) sack_bt, "Show Only Sack");
|
|
else
|
|
/* gIsNRSackChunkPresent will be true here */
|
|
gtk_button_set_label( (GtkButton*) sack_bt, "Show Only NR Sack");
|
|
}
|
|
|
|
static void
|
|
sctp_graph_redraw(struct sctp_udata *u_data)
|
|
{
|
|
sctp_graph_t *ios;
|
|
GtkAllocation widget_alloc;
|
|
cairo_t *cr;
|
|
|
|
u_data->io->needs_redraw=TRUE;
|
|
|
|
sctp_graph_draw(u_data);
|
|
switch (u_data->io->graph_type)
|
|
{
|
|
case 0:
|
|
/* Show both TSN and SACK information
|
|
* Reset the global sack variable
|
|
* for sack and nr sack cases
|
|
*/
|
|
gIsSackChunkPresent = 0;
|
|
gIsNRSackChunkPresent = 0;
|
|
draw_sack_graph(u_data);
|
|
draw_nr_sack_graph(u_data);
|
|
draw_tsn_graph(u_data);
|
|
break;
|
|
case 1:
|
|
/* Show only TSN */
|
|
draw_tsn_graph(u_data);
|
|
break;
|
|
case 2:
|
|
/* Show only SACK information
|
|
* Reset the global sack variable
|
|
* for sack and nr sack cases
|
|
*/
|
|
gIsSackChunkPresent = 0;
|
|
gIsNRSackChunkPresent = 0;
|
|
draw_sack_graph(u_data);
|
|
draw_nr_sack_graph(u_data);
|
|
break;
|
|
}
|
|
|
|
/* Updates the sack / nr sack buttons */
|
|
updateLabels();
|
|
|
|
ios=(sctp_graph_t *)g_object_get_data(G_OBJECT(u_data->io->draw_area), "sctp_graph_t");
|
|
g_assert(ios != NULL);
|
|
|
|
cr = gdk_cairo_create (gtk_widget_get_window(u_data->io->draw_area));
|
|
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cairo_set_source_surface (cr, ios->surface, 0, 0);
|
|
#else
|
|
gdk_cairo_set_source_pixmap (cr, ios->pixmap, 0, 0);
|
|
#endif
|
|
gtk_widget_get_allocation(u_data->io->draw_area, &widget_alloc);
|
|
cairo_rectangle (cr, 0, 0, widget_alloc.width, widget_alloc.height);
|
|
cairo_fill (cr);
|
|
|
|
cairo_destroy (cr);
|
|
}
|
|
|
|
|
|
static void
|
|
on_sack_bt(GtkWidget *widget _U_, gpointer user_data)
|
|
{
|
|
struct sctp_udata *u_data = user_data;
|
|
|
|
u_data->io->graph_type=2;
|
|
sctp_graph_redraw(u_data);
|
|
}
|
|
|
|
static void
|
|
on_tsn_bt(GtkWidget *widget _U_, gpointer user_data)
|
|
{
|
|
struct sctp_udata *u_data = user_data;
|
|
|
|
u_data->io->graph_type=1;
|
|
sctp_graph_redraw(u_data);
|
|
}
|
|
|
|
static void
|
|
on_both_bt(GtkWidget *widget _U_, gpointer user_data)
|
|
{
|
|
struct sctp_udata *u_data = user_data;
|
|
|
|
u_data->io->graph_type=0;
|
|
sctp_graph_redraw(u_data);
|
|
}
|
|
|
|
static void
|
|
sctp_graph_close_cb(GtkWidget* widget _U_, gpointer user_data)
|
|
{
|
|
struct sctp_udata *u_data = user_data;
|
|
|
|
gtk_grab_remove(GTK_WIDGET(u_data->io->window));
|
|
gtk_widget_destroy(GTK_WIDGET(u_data->io->window));
|
|
|
|
}
|
|
|
|
static gboolean
|
|
configure_event(GtkWidget *widget, GdkEventConfigure *event _U_, gpointer user_data)
|
|
{
|
|
struct sctp_udata *u_data = user_data;
|
|
GtkAllocation widget_alloc;
|
|
cairo_t *cr;
|
|
|
|
g_assert(u_data->io != NULL);
|
|
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
if(u_data->io->surface){
|
|
cairo_surface_destroy (u_data->io->surface);
|
|
u_data->io->surface=NULL;
|
|
}
|
|
gtk_widget_get_allocation(widget, &widget_alloc);
|
|
u_data->io->surface = gdk_window_create_similar_surface (gtk_widget_get_window(widget),
|
|
CAIRO_CONTENT_COLOR,
|
|
widget_alloc.width,
|
|
widget_alloc.height);
|
|
#else
|
|
if(u_data->io->pixmap){
|
|
g_object_unref(u_data->io->pixmap);
|
|
u_data->io->pixmap=NULL;
|
|
}
|
|
gtk_widget_get_allocation(widget, &widget_alloc);
|
|
u_data->io->pixmap=gdk_pixmap_new(gtk_widget_get_window(widget),
|
|
widget_alloc.width,
|
|
widget_alloc.height,
|
|
-1);
|
|
#endif
|
|
|
|
u_data->io->surface_width=widget_alloc.width;
|
|
u_data->io->surface_height=widget_alloc.height;
|
|
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cr = cairo_create (u_data->io->surface);
|
|
#else
|
|
cr = gdk_cairo_create (u_data->io->pixmap);
|
|
#endif
|
|
cairo_rectangle (cr, 0, 0, widget_alloc.width, widget_alloc.height);
|
|
cairo_set_source_rgb (cr, 1, 1, 1);
|
|
cairo_fill (cr);
|
|
cairo_destroy (cr);
|
|
|
|
sctp_graph_redraw(u_data);
|
|
return TRUE;
|
|
}
|
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
static gboolean
|
|
draw_event(GtkWidget *widget, cairo_t *cr, gpointer user_data)
|
|
{
|
|
sctp_graph_t *ios = user_data;
|
|
GtkAllocation allocation;
|
|
|
|
gtk_widget_get_allocation (widget, &allocation);
|
|
cairo_set_source_surface (cr, ios->surface, 0, 0);
|
|
cairo_rectangle (cr, 0, 0, allocation.width, allocation.width);
|
|
cairo_fill (cr);
|
|
|
|
return FALSE;
|
|
}
|
|
#else
|
|
static gboolean
|
|
expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
|
|
{
|
|
sctp_graph_t *ios = user_data;
|
|
cairo_t *cr;
|
|
|
|
g_assert(ios != NULL);
|
|
|
|
cr = gdk_cairo_create (gtk_widget_get_window(widget));
|
|
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cairo_set_source_surface (cr, ios->surface, 0, 0);
|
|
#else
|
|
gdk_cairo_set_source_pixmap (cr, ios->pixmap, 0, 0);
|
|
#endif
|
|
cairo_rectangle (cr, event->area.x, event->area.y, event->area.width, event->area.height);
|
|
cairo_fill (cr);
|
|
|
|
cairo_destroy (cr);
|
|
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
on_zoomin_bt (GtkWidget *widget _U_, gpointer user_data)
|
|
{
|
|
struct sctp_udata *u_data = user_data;
|
|
sctp_min_max_t *tmp_minmax;
|
|
|
|
if (u_data->io->rectangle_present==TRUE)
|
|
{
|
|
tmp_minmax = g_malloc(sizeof(sctp_min_max_t));
|
|
|
|
u_data->io->tmp_min_tsn1=u_data->io->y1_tmp+u_data->io->min_y;
|
|
u_data->io->tmp_max_tsn1=u_data->io->y2_tmp+1+u_data->io->min_y;
|
|
u_data->io->tmp_min_tsn2=u_data->io->tmp_min_tsn1;
|
|
u_data->io->tmp_max_tsn2=u_data->io->tmp_max_tsn1;
|
|
tmp_minmax->tmp_min_secs=u_data->io->x1_tmp_sec;
|
|
tmp_minmax->tmp_min_usecs= u_data->io->x1_tmp_usec;
|
|
tmp_minmax->tmp_max_secs= u_data->io->x2_tmp_sec;
|
|
tmp_minmax->tmp_max_usecs= u_data->io->x2_tmp_usec;
|
|
tmp_minmax->tmp_min_tsn1=u_data->io->tmp_min_tsn1;
|
|
tmp_minmax->tmp_max_tsn1=u_data->io->tmp_max_tsn1;
|
|
tmp_minmax->tmp_min_tsn2=u_data->io->tmp_min_tsn2;
|
|
tmp_minmax->tmp_max_tsn2=u_data->io->tmp_max_tsn2;
|
|
u_data->assoc->min_max = g_slist_prepend(u_data->assoc->min_max, tmp_minmax);
|
|
u_data->io->length = g_slist_length(u_data->assoc->min_max);
|
|
u_data->io->tmp=TRUE;
|
|
u_data->io->rectangle=FALSE;
|
|
u_data->io->rectangle_present=FALSE;
|
|
gtk_widget_set_sensitive(zoomout_bt, TRUE);
|
|
sctp_graph_redraw(u_data);
|
|
}
|
|
else
|
|
{
|
|
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Please draw a rectangle around the area you want to zoom in!");
|
|
}
|
|
}
|
|
|
|
static void
|
|
zoomin_bt_fcn (struct sctp_udata *u_data)
|
|
{
|
|
sctp_min_max_t *tmp_minmax;
|
|
|
|
tmp_minmax = g_malloc(sizeof(sctp_min_max_t));
|
|
|
|
u_data->io->tmp_min_tsn1=u_data->io->y1_tmp+u_data->io->min_y;
|
|
u_data->io->tmp_max_tsn1=u_data->io->y2_tmp+1+u_data->io->min_y;
|
|
u_data->io->tmp_min_tsn2=u_data->io->tmp_min_tsn1;
|
|
u_data->io->tmp_max_tsn2=u_data->io->tmp_max_tsn1;
|
|
tmp_minmax->tmp_min_secs=u_data->io->x1_tmp_sec;
|
|
tmp_minmax->tmp_min_usecs= u_data->io->x1_tmp_usec;
|
|
tmp_minmax->tmp_max_secs= u_data->io->x2_tmp_sec;
|
|
tmp_minmax->tmp_max_usecs= u_data->io->x2_tmp_usec;
|
|
tmp_minmax->tmp_min_tsn1=u_data->io->tmp_min_tsn1;
|
|
tmp_minmax->tmp_max_tsn1=u_data->io->tmp_max_tsn1;
|
|
tmp_minmax->tmp_min_tsn2=u_data->io->tmp_min_tsn2;
|
|
tmp_minmax->tmp_max_tsn2=u_data->io->tmp_max_tsn2;
|
|
u_data->assoc->min_max = g_slist_prepend(u_data->assoc->min_max, tmp_minmax);
|
|
u_data->io->length = g_slist_length(u_data->assoc->min_max);
|
|
u_data->io->tmp=TRUE;
|
|
u_data->io->rectangle=FALSE;
|
|
u_data->io->rectangle_present=FALSE;
|
|
gtk_widget_set_sensitive(zoomout_bt, TRUE);
|
|
sctp_graph_redraw(u_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
on_zoomout_bt (GtkWidget *widget _U_, gpointer user_data)
|
|
{
|
|
struct sctp_udata *u_data = user_data;
|
|
sctp_min_max_t *tmp_minmax, *mm;
|
|
gint l;
|
|
|
|
l = g_slist_length(u_data->assoc->min_max);
|
|
|
|
if (u_data->assoc->min_max!=NULL)
|
|
{
|
|
mm=(sctp_min_max_t *)((u_data->assoc->min_max)->data);
|
|
u_data->assoc->min_max=g_slist_remove(u_data->assoc->min_max, mm);
|
|
g_free(mm);
|
|
if (l>2)
|
|
{
|
|
tmp_minmax = (sctp_min_max_t *)u_data->assoc->min_max->data;
|
|
u_data->io->x1_tmp_sec=tmp_minmax->tmp_min_secs;
|
|
u_data->io->x1_tmp_usec=tmp_minmax->tmp_min_usecs;
|
|
u_data->io->x2_tmp_sec=tmp_minmax->tmp_max_secs;
|
|
u_data->io->x2_tmp_usec=tmp_minmax->tmp_max_usecs;
|
|
u_data->io->tmp_min_tsn1=tmp_minmax->tmp_min_tsn1;
|
|
u_data->io->tmp_max_tsn1=tmp_minmax->tmp_max_tsn1;
|
|
u_data->io->tmp_min_tsn2=tmp_minmax->tmp_min_tsn2;
|
|
u_data->io->tmp_max_tsn2=tmp_minmax->tmp_max_tsn2;
|
|
u_data->io->tmp=TRUE;
|
|
}
|
|
else
|
|
{
|
|
u_data->io->x1_tmp_sec=u_data->assoc->min_secs;
|
|
u_data->io->x1_tmp_usec=u_data->assoc->min_usecs;
|
|
u_data->io->x2_tmp_sec=u_data->assoc->max_secs;
|
|
u_data->io->x2_tmp_usec=u_data->assoc->max_usecs;
|
|
u_data->io->tmp_min_tsn1=u_data->assoc->min_tsn1;
|
|
u_data->io->tmp_max_tsn1=u_data->assoc->max_tsn1;
|
|
u_data->io->tmp_min_tsn2=u_data->assoc->min_tsn2;
|
|
u_data->io->tmp_max_tsn2=u_data->assoc->max_tsn2;
|
|
u_data->io->tmp=FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
u_data->io->x1_tmp_sec=u_data->assoc->min_secs;
|
|
u_data->io->x1_tmp_usec=u_data->assoc->min_usecs;
|
|
u_data->io->x2_tmp_sec=u_data->assoc->max_secs;
|
|
u_data->io->x2_tmp_usec=u_data->assoc->max_usecs;
|
|
u_data->io->tmp_min_tsn1=u_data->assoc->min_tsn1;
|
|
u_data->io->tmp_max_tsn1=u_data->assoc->max_tsn1;
|
|
u_data->io->tmp_min_tsn2=u_data->assoc->min_tsn2;
|
|
u_data->io->tmp_max_tsn2=u_data->assoc->max_tsn2;
|
|
u_data->io->tmp=FALSE;
|
|
}
|
|
if (g_slist_length(u_data->assoc->min_max)==1)
|
|
gtk_widget_set_sensitive(zoomout_bt, FALSE);
|
|
sctp_graph_redraw(u_data);
|
|
}
|
|
|
|
static gboolean
|
|
on_button_press_event (GtkWidget *widget _U_, GdkEventButton *event, gpointer user_data)
|
|
{
|
|
struct sctp_udata *u_data = user_data;
|
|
sctp_graph_t *ios;
|
|
cairo_t *cr;
|
|
|
|
if (u_data->io->rectangle==TRUE)
|
|
{
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cr = cairo_create (u_data->io->surface);
|
|
#else
|
|
cr = gdk_cairo_create (u_data->io->pixmap);
|
|
#endif
|
|
cairo_rectangle (cr,
|
|
floor(MIN(u_data->io->x_old,u_data->io->x_new)),
|
|
floor(MIN(u_data->io->y_old,u_data->io->y_new)),
|
|
floor(abs((long)(u_data->io->x_new-u_data->io->x_old))),
|
|
floor(abs((long)(u_data->io->y_new-u_data->io->y_old))));
|
|
cairo_set_source_rgb (cr, 1, 1, 1);
|
|
cairo_stroke (cr);
|
|
cairo_destroy (cr);
|
|
|
|
ios=(sctp_graph_t *)g_object_get_data(G_OBJECT(u_data->io->draw_area), "sctp_graph_t");
|
|
|
|
g_assert(ios != NULL);
|
|
|
|
cr = gdk_cairo_create (gtk_widget_get_window(u_data->io->draw_area));
|
|
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cairo_set_source_surface (cr, ios->surface, 0, 0);
|
|
#else
|
|
gdk_cairo_set_source_pixmap (cr, ios->pixmap, 0, 0);
|
|
#endif
|
|
cairo_rectangle (cr, 0, 0, abs((long)(u_data->io->x_new-u_data->io->x_old)), abs((long)(u_data->io->y_new-u_data->io->y_old)));
|
|
cairo_fill (cr);
|
|
|
|
cairo_destroy (cr);
|
|
|
|
sctp_graph_redraw(u_data);
|
|
}
|
|
u_data->io->x_old=event->x;
|
|
u_data->io->y_old=event->y;
|
|
if (u_data->io->y_old>u_data->io->surface_height-BOTTOM_BORDER-u_data->io->offset-POINT_SIZE)
|
|
u_data->io->y_old=u_data->io->surface_height-BOTTOM_BORDER-u_data->io->offset-POINT_SIZE;
|
|
if (u_data->io->x_old<LEFT_BORDER+u_data->io->offset)
|
|
u_data->io->x_old=LEFT_BORDER+u_data->io->offset;
|
|
u_data->io->rectangle=FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static gboolean
|
|
on_button_release_event (GtkWidget *widget _U_, GdkEventButton *event, gpointer user_data)
|
|
{
|
|
struct sctp_udata *u_data = user_data;
|
|
sctp_graph_t *ios;
|
|
guint32 helpx, helpy, x1_tmp, x2_tmp, y_value, t_size=0, s_size=0, i, y_tolerance;
|
|
gint label_width, label_height;
|
|
gdouble x_value, position, s_diff=0, t_diff=0, x_tolerance=0.0001;
|
|
gint lwidth;
|
|
char label_string[30];
|
|
GPtrArray *tsnlist = NULL, *sacklist=NULL;
|
|
struct tsn_sort *tsn, *sack=NULL;
|
|
gboolean sack_found = FALSE;
|
|
GtkAllocation widget_alloc;
|
|
PangoLayout *layout;
|
|
cairo_t *cr;
|
|
|
|
g_snprintf(label_string, 15, "%d", 0);
|
|
memcpy(label_string,(gchar *)g_locale_to_utf8(label_string, -1 , NULL, NULL, NULL), 15);
|
|
layout = gtk_widget_create_pango_layout(u_data->io->draw_area, label_string);
|
|
pango_layout_get_pixel_size(layout, &label_width, &label_height);
|
|
|
|
if (event->y>u_data->io->surface_height-BOTTOM_BORDER-u_data->io->offset)
|
|
event->y = u_data->io->surface_height-BOTTOM_BORDER-u_data->io->offset;
|
|
if (event->x < LEFT_BORDER+u_data->io->offset)
|
|
event->x = LEFT_BORDER+u_data->io->offset;
|
|
if (abs((long)(event->x-u_data->io->x_old))>10 || abs((long)(event->y-u_data->io->y_old))>10)
|
|
{
|
|
u_data->io->rect_x_min = (gint)floor(MIN(u_data->io->x_old,event->x));
|
|
u_data->io->rect_x_max = (gint)ceil(MAX(u_data->io->x_old,event->x));
|
|
u_data->io->rect_y_min = (gint)floor(MIN(u_data->io->y_old,event->y));
|
|
u_data->io->rect_y_max = (gint)ceil(MAX(u_data->io->y_old,event->y))+POINT_SIZE;
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cr = cairo_create (u_data->io->surface);
|
|
#else
|
|
cr = gdk_cairo_create (u_data->io->pixmap);
|
|
#endif
|
|
cairo_rectangle (cr,
|
|
u_data->io->rect_x_min+0.5,
|
|
u_data->io->rect_y_min+0.5,
|
|
u_data->io->rect_x_max - u_data->io->rect_x_min,
|
|
u_data->io->rect_y_max - u_data->io->rect_y_min);
|
|
cairo_set_line_width (cr, 1.0);
|
|
cairo_stroke (cr);
|
|
cairo_destroy (cr);
|
|
|
|
ios=(sctp_graph_t *)g_object_get_data(G_OBJECT(u_data->io->draw_area), "sctp_graph_t");
|
|
|
|
g_assert(ios != NULL);
|
|
|
|
cr = gdk_cairo_create (gtk_widget_get_window(u_data->io->draw_area));
|
|
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cairo_set_source_surface (cr, ios->surface, 0, 0);
|
|
#else
|
|
gdk_cairo_set_source_pixmap (cr, ios->pixmap, 0, 0);
|
|
#endif
|
|
gtk_widget_get_allocation(u_data->io->draw_area, &widget_alloc);
|
|
cairo_rectangle (cr, 0, 0, widget_alloc.width, widget_alloc.height);
|
|
cairo_fill (cr);
|
|
|
|
cairo_destroy (cr);
|
|
|
|
x1_tmp=(unsigned int)floor(u_data->io->min_x+((u_data->io->x_old-LEFT_BORDER-u_data->io->offset)*u_data->io->tmp_width/u_data->io->axis_width));
|
|
x2_tmp=(unsigned int)floor(u_data->io->min_x+((event->x-LEFT_BORDER-u_data->io->offset)*u_data->io->tmp_width/u_data->io->axis_width));
|
|
helpx=MIN(x1_tmp, x2_tmp);
|
|
if (helpx==x2_tmp)
|
|
{
|
|
x2_tmp=x1_tmp;
|
|
x1_tmp=helpx;
|
|
}
|
|
if (u_data->io->uoff)
|
|
{
|
|
if (x2_tmp - x1_tmp <= 1500)
|
|
u_data->io->uoff = FALSE;
|
|
u_data->io->x1_tmp_sec=(guint32)x1_tmp;
|
|
u_data->io->x1_tmp_usec=0;
|
|
u_data->io->x2_tmp_sec=(guint32)x2_tmp;
|
|
u_data->io->x2_tmp_usec=0;
|
|
}
|
|
else
|
|
{
|
|
u_data->io->x1_tmp_sec=(guint32)x1_tmp/1000000;
|
|
u_data->io->x1_tmp_usec=x1_tmp%1000000;
|
|
u_data->io->x2_tmp_sec=(guint32)x2_tmp/1000000;
|
|
u_data->io->x2_tmp_usec=x2_tmp%1000000;
|
|
}
|
|
u_data->io->x1_akt_sec = u_data->io->x1_tmp_sec;
|
|
u_data->io->x1_akt_usec = u_data->io->x1_tmp_usec;
|
|
u_data->io->x2_akt_sec = u_data->io->x2_tmp_sec;
|
|
u_data->io->x2_akt_usec = u_data->io->x2_tmp_usec;
|
|
|
|
u_data->io->y1_tmp=(guint32)((u_data->io->surface_height-BOTTOM_BORDER-u_data->io->offset-u_data->io->y_old)/u_data->io->y_interval);
|
|
u_data->io->y2_tmp=(guint32)((u_data->io->surface_height-BOTTOM_BORDER-u_data->io->offset-event->y)/u_data->io->y_interval);
|
|
helpy = MIN(u_data->io->y1_tmp, u_data->io->y2_tmp);
|
|
u_data->io->y2_tmp = MAX(u_data->io->y1_tmp, u_data->io->y2_tmp);
|
|
u_data->io->y1_tmp = helpy;
|
|
u_data->io->x_new=event->x;
|
|
u_data->io->y_new=event->y;
|
|
u_data->io->rectangle=TRUE;
|
|
u_data->io->rectangle_present=TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (u_data->io->rectangle_present==TRUE)
|
|
{
|
|
u_data->io->rectangle_present=FALSE;
|
|
if (event->x >= u_data->io->rect_x_min && event->x <= u_data->io->rect_x_max &&
|
|
event->y >= u_data->io->rect_y_min && event->y <= u_data->io->rect_y_max)
|
|
zoomin_bt_fcn(u_data);
|
|
else
|
|
{
|
|
u_data->io->x1_tmp_sec = u_data->io->x1_akt_sec;
|
|
u_data->io->x1_tmp_usec = u_data->io->x1_akt_usec;
|
|
u_data->io->x2_tmp_sec = u_data->io->x2_akt_sec;
|
|
u_data->io->x2_tmp_usec = u_data->io->x2_akt_usec;
|
|
sctp_graph_redraw(u_data);
|
|
}
|
|
}
|
|
else if (label_set)
|
|
{
|
|
label_set = FALSE;
|
|
sctp_graph_redraw(u_data);
|
|
}
|
|
else
|
|
{
|
|
x_value = ((event->x-LEFT_BORDER-u_data->io->offset) * ((u_data->io->x2_tmp_sec+u_data->io->x2_tmp_usec/1000000.0)-(u_data->io->x1_tmp_sec+u_data->io->x1_tmp_usec/1000000.0)) / (u_data->io->surface_width-LEFT_BORDER-RIGHT_BORDER-u_data->io->offset))+u_data->io->x1_tmp_sec+u_data->io->x1_tmp_usec/1000000.0;
|
|
y_value = (gint)rint((u_data->io->surface_height-BOTTOM_BORDER-u_data->io->offset-event->y) * (max_tsn - min_tsn) / (u_data->io->surface_height-BOTTOM_BORDER-u_data->io->offset)) + min_tsn;
|
|
|
|
if (u_data->dir == 1)
|
|
{
|
|
tsnlist = u_data->assoc->sort_tsn1;
|
|
t_size = u_data->assoc->n_data_chunks_ep1;
|
|
sacklist = u_data->assoc->sort_sack1;
|
|
s_size = u_data->assoc->n_sack_chunks_ep1;
|
|
}
|
|
else
|
|
{
|
|
tsnlist = u_data->assoc->sort_tsn2;
|
|
t_size = u_data->assoc->n_data_chunks_ep2;
|
|
sacklist = u_data->assoc->sort_sack2;
|
|
s_size = u_data->assoc->n_sack_chunks_ep2;
|
|
}
|
|
x_tolerance = (gdouble)((u_data->io->tmp_width / u_data->io->axis_width*1.0))*5/1000000.0;
|
|
y_tolerance = (guint32)(((u_data->io->max_y - u_data->io->min_y) / (u_data->io->surface_height-TOP_BORDER-BOTTOM_BORDER-u_data->io->offset)) * 2.0);
|
|
if (y_tolerance==0)
|
|
y_tolerance = 2;
|
|
else if (y_tolerance > 5)
|
|
y_tolerance = 5;
|
|
|
|
for (i=0; i<s_size; i++)
|
|
{
|
|
sack = (struct tsn_sort*)(g_ptr_array_index(sacklist, i));
|
|
if ((guint32)abs(sack->tsnumber - y_value)<y_tolerance)
|
|
{
|
|
s_diff = fabs((sack->secs+sack->usecs/1000000.0)- x_value);
|
|
if (s_diff < x_tolerance)
|
|
sack_found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (i=0; i<t_size; i++)
|
|
{
|
|
tsn = (struct tsn_sort*)(g_ptr_array_index(tsnlist, i));
|
|
if ((guint32)abs(tsn->tsnumber - y_value)<y_tolerance)
|
|
{
|
|
t_diff = fabs((tsn->secs+tsn->usecs/1000000.0)- x_value);
|
|
if (sack_found && s_diff < t_diff)
|
|
{
|
|
cf_goto_frame(&cfile, sack->framenumber);
|
|
x_value = sack->secs+sack->usecs/1000000.0;
|
|
y_value = sack->tsnumber;
|
|
}
|
|
else if (t_diff < x_tolerance)
|
|
{
|
|
cf_goto_frame(&cfile, tsn->framenumber);
|
|
x_value = tsn->secs+tsn->usecs/1000000.0;
|
|
y_value = tsn->tsnumber;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
g_snprintf(label_string, sizeof(label_string), "(%.6lf, %u)", x_value, y_value);
|
|
|
|
label_set = TRUE;
|
|
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cr = cairo_create (u_data->io->surface);
|
|
#else
|
|
cr = gdk_cairo_create (u_data->io->pixmap);
|
|
#endif
|
|
cairo_set_line_width (cr, 1.0);
|
|
cairo_move_to(cr,
|
|
(event->x-2)+0.5,
|
|
(event->y)+0.5);
|
|
cairo_line_to(cr,
|
|
(event->x+2)+0.5,
|
|
(event->y)+0.5);
|
|
cairo_stroke(cr);
|
|
cairo_destroy(cr);
|
|
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cr = cairo_create (u_data->io->surface);
|
|
#else
|
|
cr = gdk_cairo_create (u_data->io->pixmap);
|
|
#endif
|
|
cairo_set_line_width (cr, 1.0);
|
|
cairo_move_to(cr,
|
|
(event->x)+0.5,
|
|
(event->y-2)+0.5);
|
|
cairo_line_to(cr,
|
|
(event->x)+0.5,
|
|
(event->y+2)+0.5);
|
|
cairo_stroke(cr);
|
|
cairo_destroy(cr);
|
|
|
|
if (event->x+150>=u_data->io->surface_width)
|
|
position = event->x - 150;
|
|
else
|
|
position = event->x + 5;
|
|
|
|
|
|
memcpy(label_string,(gchar *)g_locale_to_utf8(label_string, -1 , NULL, NULL, NULL), 15);
|
|
pango_layout_set_text(layout, label_string, -1);
|
|
pango_layout_get_pixel_size(layout, &lwidth, NULL);
|
|
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cr = cairo_create (u_data->io->surface);
|
|
#else
|
|
cr = gdk_cairo_create (u_data->io->pixmap);
|
|
#endif
|
|
cairo_move_to (cr,
|
|
position,
|
|
event->y-10);
|
|
pango_cairo_show_layout (cr, layout);
|
|
cairo_destroy (cr);
|
|
cr = NULL;
|
|
|
|
ios=(sctp_graph_t *)g_object_get_data(G_OBJECT(u_data->io->draw_area), "sctp_graph_t");
|
|
g_assert(ios != NULL);
|
|
|
|
cr = gdk_cairo_create (gtk_widget_get_window(u_data->io->draw_area));
|
|
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
cairo_set_source_surface (cr, ios->surface, 0, 0);
|
|
#else
|
|
gdk_cairo_set_source_pixmap (cr, ios->pixmap, 0, 0);
|
|
#endif
|
|
gtk_widget_get_allocation(u_data->io->draw_area, &widget_alloc);
|
|
cairo_rectangle (cr, 0, 0, widget_alloc.width, widget_alloc.height);
|
|
cairo_fill (cr);
|
|
|
|
cairo_destroy (cr);
|
|
}
|
|
}
|
|
|
|
g_object_unref(G_OBJECT(layout));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static void
|
|
init_sctp_graph_window(struct sctp_udata *u_data)
|
|
{
|
|
GtkWidget *vbox;
|
|
GtkWidget *hbox;
|
|
GtkWidget *bt_close, *tsn_bt, *both_bt, *zoomin_bt;
|
|
|
|
/* create the main window */
|
|
u_data->io->window= dlg_window_new("WSCTP Graphics"); /* transient_for top_level */
|
|
gtk_window_set_destroy_with_parent (GTK_WINDOW(u_data->io->window), TRUE);
|
|
|
|
vbox=gtk_vbox_new(FALSE, 0);
|
|
gtk_container_add(GTK_CONTAINER(u_data->io->window), vbox);
|
|
gtk_widget_show(vbox);
|
|
|
|
create_draw_area(vbox, u_data);
|
|
|
|
sctp_graph_set_title(u_data);
|
|
|
|
hbox = gtk_hbutton_box_new();
|
|
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
|
|
gtk_container_set_border_width(GTK_CONTAINER(hbox), 10);
|
|
gtk_button_box_set_layout(GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_SPREAD);
|
|
gtk_box_set_spacing(GTK_BOX (hbox), 0);
|
|
gtk_box_set_child_packing(GTK_BOX(vbox), hbox, FALSE, FALSE, 0, GTK_PACK_START);
|
|
gtk_widget_show(hbox);
|
|
sack_bt = gtk_button_new_with_label ("Show Only Sacks");
|
|
gtk_box_pack_start(GTK_BOX(hbox), sack_bt, FALSE, FALSE, 0);
|
|
gtk_widget_show(sack_bt);
|
|
g_signal_connect(sack_bt, "clicked", G_CALLBACK(on_sack_bt), u_data);
|
|
|
|
tsn_bt = gtk_button_new_with_label ("Show Only TSNs");
|
|
gtk_box_pack_start(GTK_BOX(hbox), tsn_bt, FALSE, FALSE, 0);
|
|
gtk_widget_show(tsn_bt);
|
|
g_signal_connect(tsn_bt, "clicked", G_CALLBACK(on_tsn_bt), u_data);
|
|
|
|
both_bt = gtk_button_new_with_label ("Show both");
|
|
gtk_box_pack_start(GTK_BOX(hbox), both_bt, FALSE, FALSE, 0);
|
|
gtk_widget_show(both_bt);
|
|
g_signal_connect(both_bt, "clicked", G_CALLBACK(on_both_bt), u_data);
|
|
|
|
zoomin_bt = gtk_button_new_with_label ("Zoom in");
|
|
gtk_box_pack_start(GTK_BOX(hbox), zoomin_bt, FALSE, FALSE, 0);
|
|
gtk_widget_show(zoomin_bt);
|
|
g_signal_connect(zoomin_bt, "clicked", G_CALLBACK(on_zoomin_bt), u_data);
|
|
gtk_widget_set_tooltip_text(zoomin_bt, "Zoom in the area you have selected");
|
|
|
|
zoomout_bt = gtk_button_new_with_label ("Zoom out");
|
|
gtk_box_pack_start(GTK_BOX(hbox), zoomout_bt, FALSE, FALSE, 0);
|
|
gtk_widget_show(zoomout_bt);
|
|
g_signal_connect(zoomout_bt, "clicked", G_CALLBACK(on_zoomout_bt), u_data);
|
|
gtk_widget_set_tooltip_text(zoomout_bt, "Zoom out one step");
|
|
gtk_widget_set_sensitive(zoomout_bt, FALSE);
|
|
|
|
bt_close = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
|
|
gtk_box_pack_start(GTK_BOX(hbox), bt_close, FALSE, FALSE, 0);
|
|
gtk_widget_show(bt_close);
|
|
g_signal_connect(bt_close, "clicked", G_CALLBACK(sctp_graph_close_cb), u_data);
|
|
|
|
g_signal_connect(u_data->io->draw_area,"button_press_event",G_CALLBACK(on_button_press_event), u_data);
|
|
g_signal_connect(u_data->io->draw_area,"button_release_event",G_CALLBACK(on_button_release_event), u_data);
|
|
gtk_widget_set_events(u_data->io->draw_area, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_EXPOSURE_MASK);
|
|
|
|
gtk_widget_show(u_data->io->window);
|
|
}
|
|
|
|
static void
|
|
sctp_graph_set_title(struct sctp_udata *u_data)
|
|
{
|
|
char *title;
|
|
|
|
if(!u_data->io->window)
|
|
{
|
|
return;
|
|
}
|
|
title = g_strdup_printf("SCTP TSNs and Sacks over Time: %s Port1 %u Port2 %u Endpoint %u",
|
|
cf_get_display_name(&cfile), u_data->parent->assoc->port1, u_data->parent->assoc->port2, u_data->dir);
|
|
gtk_window_set_title(GTK_WINDOW(u_data->io->window), title);
|
|
g_free(title);
|
|
}
|
|
|
|
static void
|
|
gtk_sctpgraph_init(struct sctp_udata *u_data)
|
|
{
|
|
sctp_graph_t *io;
|
|
sctp_min_max_t* tmp_minmax;
|
|
|
|
io=g_malloc(sizeof(sctp_graph_t));
|
|
io->needs_redraw=TRUE;
|
|
io->x_interval=1000;
|
|
io->window=NULL;
|
|
io->draw_area=NULL;
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
io->surface=NULL;
|
|
#else
|
|
io->pixmap=NULL;
|
|
#endif
|
|
io->surface_width=800;
|
|
io->surface_height=600;
|
|
io->graph_type=0;
|
|
u_data->io=io;
|
|
u_data->io->x1_tmp_sec=u_data->assoc->min_secs;
|
|
u_data->io->x1_tmp_usec=u_data->assoc->min_usecs;
|
|
u_data->io->x2_tmp_sec=u_data->assoc->max_secs;
|
|
u_data->io->x2_tmp_usec=u_data->assoc->max_usecs;
|
|
u_data->io->tmp_min_tsn1=u_data->assoc->min_tsn1;
|
|
u_data->io->tmp_max_tsn1=u_data->assoc->max_tsn1;
|
|
u_data->io->tmp_min_tsn2=u_data->assoc->min_tsn2;
|
|
u_data->io->tmp_max_tsn2=u_data->assoc->max_tsn2;
|
|
u_data->io->tmp=FALSE;
|
|
|
|
tmp_minmax = g_malloc(sizeof(sctp_min_max_t));
|
|
tmp_minmax->tmp_min_secs = u_data->assoc->min_secs;
|
|
tmp_minmax->tmp_min_usecs=u_data->assoc->min_usecs;
|
|
tmp_minmax->tmp_max_secs=u_data->assoc->max_secs;
|
|
tmp_minmax->tmp_max_usecs=u_data->assoc->max_usecs;
|
|
tmp_minmax->tmp_min_tsn2=u_data->assoc->min_tsn2;
|
|
tmp_minmax->tmp_min_tsn1=u_data->assoc->min_tsn1;
|
|
tmp_minmax->tmp_max_tsn1=u_data->assoc->max_tsn1;
|
|
tmp_minmax->tmp_max_tsn2=u_data->assoc->max_tsn2;
|
|
u_data->assoc->min_max = g_slist_prepend(u_data->assoc->min_max, tmp_minmax);
|
|
|
|
/* build the GUI */
|
|
init_sctp_graph_window(u_data);
|
|
sctp_graph_redraw(u_data);
|
|
|
|
}
|
|
|
|
|
|
static void
|
|
quit(GObject *object _U_, gpointer user_data)
|
|
{
|
|
struct sctp_udata *u_data=user_data;
|
|
|
|
decrease_childcount(u_data->parent);
|
|
remove_child(u_data, u_data->parent);
|
|
|
|
g_free(u_data->io);
|
|
|
|
u_data->assoc->min_max = NULL;
|
|
g_free(u_data);
|
|
}
|
|
|
|
|
|
static void
|
|
create_draw_area(GtkWidget *box, struct sctp_udata *u_data)
|
|
{
|
|
|
|
u_data->io->draw_area=gtk_drawing_area_new();
|
|
g_object_set_data(G_OBJECT(u_data->io->draw_area), "sctp_graph_t", u_data->io);
|
|
g_signal_connect(u_data->io->draw_area, "destroy", G_CALLBACK(quit), u_data);
|
|
|
|
gtk_widget_set_size_request(u_data->io->draw_area, u_data->io->surface_width, u_data->io->surface_height);
|
|
|
|
/* signals needed to handle backing pixmap */
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
g_signal_connect(u_data->io->draw_area, "draw", G_CALLBACK(draw_event), u_data->io);
|
|
#else
|
|
g_signal_connect(u_data->io->draw_area, "expose_event", G_CALLBACK(expose_event), u_data->io);
|
|
#endif
|
|
g_signal_connect(u_data->io->draw_area, "configure_event", G_CALLBACK(configure_event), u_data);
|
|
|
|
gtk_widget_show(u_data->io->draw_area);
|
|
gtk_box_pack_start(GTK_BOX(box), u_data->io->draw_area, TRUE, TRUE, 0);
|
|
}
|
|
|
|
|
|
|
|
void
|
|
create_graph(guint16 dir, struct sctp_analyse* userdata)
|
|
{
|
|
struct sctp_udata *u_data;
|
|
|
|
u_data=g_malloc(sizeof(struct sctp_udata));
|
|
u_data->assoc=userdata->assoc;
|
|
u_data->io=NULL;
|
|
u_data->dir = dir;
|
|
u_data->parent = userdata;
|
|
if ((u_data->dir==1 && u_data->assoc->n_array_tsn1==0)|| (u_data->dir==2 && u_data->assoc->n_array_tsn2==0))
|
|
simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, "No Data Chunks sent");
|
|
else
|
|
{
|
|
set_child(u_data, u_data->parent);
|
|
increase_childcount(u_data->parent);
|
|
gtk_sctpgraph_init(u_data);
|
|
}
|
|
}
|
|
|
|
#if defined(_WIN32) && !defined(__MINGW32__)
|
|
/* replacement of Unix rint() for Windows */
|
|
static int
|
|
rint (double x)
|
|
{
|
|
char *buf;
|
|
int i,dec,sig;
|
|
|
|
buf = _fcvt(x, 0, &dec, &sig);
|
|
i = atoi(buf);
|
|
if(sig == 1) {
|
|
i = i * -1;
|
|
}
|
|
return(i);
|
|
}
|
|
#endif
|