some more : try to make read/write not break the build if the return value is not...
[obnox/wireshark/wip.git] / gtk / sctp_graph_dlg.c
index 9116654ef152a1786586a8352a1ce67219fc68dd..137df2e378ee274dab61c75c02a83ea7267bcdfa 100644 (file)
@@ -1,10 +1,10 @@
-/* 
+/*
  * Copyright 2004, Irene Ruengeler <i.ruengeler [AT] fh-muenster.de>
  *
  * $Id$
  *
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@ethereal.com>
+ * 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
  * 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 <gtk/gtk.h>
+#include <gdk/gdk.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <math.h>
@@ -35,7 +36,6 @@
 #include "globals.h"
 #include "epan/filesystem.h"
 #include "../color.h"
-#include "tap_menu.h"
 #include "dlg_utils.h"
 #include "ui_util.h"
 #include "main.h"
 #define COUNT_TYPE_BYTES    1
 #define COUNT_TYPE_ADVANCED 2
 
-#define LEFT_BORDER 50
+#define LEFT_BORDER 60
 #define RIGHT_BORDER 10
 #define TOP_BORDER 10
 #define BOTTOM_BORDER 50
 
 #define SUB_32(a, b)   a-b
-#define MINI(a,b) (a<b)?a:b
-#define MAXI(a,b) (a>b)?a:b
+#define POINT_SIZE     3
 
 struct chunk_header {
        guint8  type;
@@ -91,6 +90,11 @@ struct init_chunk_header {
        guint32 initial_tsn;
 };
 
+struct gaps {
+       guint16 start;
+       guint16 end;
+};
+
 struct sack_chunk_header {
        guint8  type;
        guint8  flags;
@@ -99,18 +103,15 @@ struct sack_chunk_header {
        guint32 a_rwnd;
        guint16 nr_of_gaps;
        guint16 nr_of_dups;
-       guint8  *tsns;
-};
-
-struct gaps {
-       guint16 start;
-       guint16 end;
+       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;
 
 static void draw_sack_graph(struct sctp_udata *u_data)
 {
@@ -118,7 +119,8 @@ static void draw_sack_graph(struct sctp_udata *u_data)
        GList *list=NULL, *tlist;
        guint16 gap_start=0, gap_end=0, i, j, nr;
        guint8 type;
-       guint32 tsnumber, max_tsn=0, min_tsn=0;
+       guint32 tsnumber;
+       gint xvalue, yvalue;
        GdkColor red_color = {0, 65535, 0, 0};
        GdkColor green_color = {0, 0, 65535, 0};
        GdkGC *red_gc, *green_gc;
@@ -197,40 +199,57 @@ static void draw_sack_graph(struct sctp_udata *u_data)
                        {
                                sack_header =(struct sack_chunk_header *)tlist->data;
                                nr=ntohs(sack_header->nr_of_gaps);
-                               tsnumber = ntohl(sack_header->cum_tsn_ack);
-                               if (nr>0)
-                               {
-                                       gap = (struct gaps *)(sack_header->tsns+(4*(nr-1)));
-                                       gap_start=ntohs(gap->start);
-                                       gap_end = ntohs(gap->end);
-                                       max_num=gap_end+tsnumber;
-                               }
-                               else
-                                       max_num=tsnumber;
+                               tsnumber = g_ntohl(sack_header->cum_tsn_ack);
 
                                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=ntohs(gap->start);
+                                                       gap_end = ntohs(gap->end);
+                                                       max_num=gap_end+tsnumber;
                                                        for (j=gap_start; j<=gap_end; j++)
                                                        {
-                                                               diff=sack->secs*1000000+sack->usecs-u_data->io->min_x;
-                                                               gdk_draw_arc(u_data->io->pixmap,green_gc,TRUE,
-                                                                            (guint32)(LEFT_BORDER+u_data->io->offset+u_data->io->x_interval*diff),
-                                                                            (guint32)(u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset-((SUB_32(j+tsnumber,min_tsn))*u_data->io->y_interval)),
-                                                                            3, 3,0, (64*360) );
+                                                               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->pixmap_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->pixmap_width-RIGHT_BORDER+u_data->io->offset &&
+                                                                   yvalue >= TOP_BORDER-u_data->io->offset &&
+                                                                   yvalue <= u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset)
+                                                                       gdk_draw_arc(u_data->io->pixmap,green_gc,TRUE,
+                                                                                   xvalue,
+                                                                                   yvalue,
+                                                                                   POINT_SIZE, POINT_SIZE,0, (64*360) );
                                                        }
+                                                       if (i < nr-1)
+                                                               gap++;
                                                }
                                        }
+                                       else
+                                               max_num=tsnumber;
                                        if (tsnumber>=min_tsn)
                                        {
-                                               diff=sack->secs*1000000+sack->usecs-u_data->io->min_x;
-                                               gdk_draw_arc(u_data->io->pixmap,red_gc,TRUE,
-                                                            (guint32)(LEFT_BORDER+u_data->io->offset+u_data->io->x_interval*diff),
-                                                            (guint32)(u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset-((SUB_32(tsnumber,min_tsn))*u_data->io->y_interval)),
-                                                            3, 3,0, (64*360) );
+                                               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->pixmap_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->pixmap_width-RIGHT_BORDER+u_data->io->offset &&
+                                                   yvalue >= TOP_BORDER-u_data->io->offset &&
+                                                   yvalue <= u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset)
+                                                       gdk_draw_arc(u_data->io->pixmap,red_gc,TRUE,
+                                                                    xvalue,
+                                                                    yvalue,
+                                                                    POINT_SIZE, POINT_SIZE,0, (64*360) );
                                        }
                                }
                        tlist = g_list_next(tlist);
@@ -250,8 +269,9 @@ static void draw_tsn_graph(struct sctp_udata *u_data)
        tsn_t *tsn;
        GList *list=NULL, *tlist;
        guint8 type;
-       guint32 tsnumber=0, min_tsn=0, max_tsn=0;
+       guint32 tsnumber=0;
        guint32 min_secs=0, diff;
+       gint xvalue, yvalue;
 
        if (u_data->dir==1)
        {
@@ -290,15 +310,23 @@ static void draw_tsn_graph(struct sctp_udata *u_data)
                {
                        type = ((struct chunk_header *)tlist->data)->type;
                        if (type == SCTP_DATA_CHUNK_ID)
-                               tsnumber = ntohl(((struct data_chunk_header *)tlist->data)->tsn);
-
+                               tsnumber = g_ntohl(((struct data_chunk_header *)tlist->data)->tsn);
                        if (tsnumber>=min_tsn && tsnumber<=max_tsn && tsn->secs>=min_secs)
                        {
-                                       diff=tsn->secs*1000000+tsn->usecs-u_data->io->min_x;
-                                       gdk_draw_arc(u_data->io->pixmap,u_data->io->draw_area->style->black_gc,TRUE,
-                                                    (guint32)(LEFT_BORDER+u_data->io->offset+u_data->io->x_interval*diff),
-                                                    (guint32)(u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset-((SUB_32(tsnumber,min_tsn))*u_data->io->y_interval)),
-                                                    3, 3, 0, (64*360));
+                                       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->pixmap_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->pixmap_width-RIGHT_BORDER+u_data->io->offset &&
+                                           yvalue >= TOP_BORDER-u_data->io->offset &&
+                                           yvalue <= u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset)
+                                               gdk_draw_arc(u_data->io->pixmap,u_data->io->draw_area->style->black_gc,TRUE,
+                                                            xvalue,
+                                                            yvalue,
+                                                            POINT_SIZE, POINT_SIZE, 0, (64*360));
                        }
                        tlist = g_list_next(tlist);
                }
@@ -309,15 +337,17 @@ static void draw_tsn_graph(struct sctp_udata *u_data)
 
 static void sctp_graph_draw(struct sctp_udata *u_data)
 {
-       int length, lwidth, j, b;
-       guint32 label_width, label_height, distance=5, i, e, sec, w, start, a;
+       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;
 
 #if GTK_MAJOR_VERSION < 2
-               GdkFont *font;
+       GdkFont *font;
 #else
-                       PangoLayout  *layout;
+       PangoLayout  *layout;
 #endif
 
        if (u_data->io->x1_tmp_sec==0 && u_data->io->x1_tmp_usec==0)
@@ -325,8 +355,19 @@ static void sctp_graph_draw(struct sctp_udata *u_data)
        else
                u_data->io->offset=5;
 
-       u_data->io->min_x=u_data->io->x1_tmp_sec*1000000+u_data->io->x1_tmp_usec;
-       u_data->io->max_x=u_data->io->x2_tmp_sec*1000000+u_data->io->x2_tmp_usec;
+       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)
@@ -378,12 +419,12 @@ static void sctp_graph_draw(struct sctp_udata *u_data)
 
        /* 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);
+               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 = u_data->io->axis_width;
+               u_data->io->x_interval = (float)(u_data->io->axis_width);
        }
 
-       e=0;
+       e=0; /*number of decimals of x_interval*/
        if (u_data->io->x_interval<1)
        {
                dis=1/u_data->io->x_interval;
@@ -393,24 +434,24 @@ static void sctp_graph_draw(struct sctp_udata *u_data)
                        e++;
                }
                distance=1;
-                       for (i=0; i<=e+1; i++)
-                       distance*=10;
+               for (i=0; i<=e+1; i++)
+                       distance*=10; /*distance per 100 pixels*/
        }
        else
                distance=5;
 
 #if GTK_MAJOR_VERSION < 2
-               font = u_data->io->draw_area->style->font;
+       font = u_data->io->draw_area->style->font;
 #endif
 
 #if GTK_MAJOR_VERSION < 2
-               label_width=gdk_string_width(font, label_string);
-               label_height=gdk_string_height(font, label_string);
+       label_width=gdk_string_width(font, label_string);
+       label_height=gdk_string_height(font, label_string);
 #else
-               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);
+       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);
 
 #endif
 
@@ -423,53 +464,72 @@ static void sctp_graph_draw(struct sctp_udata *u_data)
        if (u_data->io->offset!=0)
        {
                g_snprintf(label_string, 15, "%u", u_data->io->x1_tmp_sec);
-               
+
 #if GTK_MAJOR_VERSION < 2
                lwidth=gdk_string_width(font, label_string);
-                                       gdk_draw_string(u_data->io->pixmap,font,u_data->io->draw_area->style->black_gc,
-                                       LEFT_BORDER-10,
-                                       u_data->io->pixmap_height-BOTTOM_BORDER+20,
-                                       label_string);
+               gdk_draw_string(u_data->io->pixmap,font,u_data->io->draw_area->style->black_gc,
+                               LEFT_BORDER-25,
+                               u_data->io->pixmap_height-BOTTOM_BORDER+20,
+                               label_string);
 #else
                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);
 
                gdk_draw_layout(u_data->io->pixmap,u_data->io->draw_area->style->black_gc,
-                               LEFT_BORDER-10,
+                               LEFT_BORDER-25,
                                u_data->io->pixmap_height-BOTTOM_BORDER+20,
                                layout);
 #endif
-}
+       }
+
+       w=(guint32)(500/(guint32)(distance*u_data->io->x_interval)); /*there will be a label for every w_th tic*/
 
-       w=(guint32)(500/(guint32)(distance*u_data->io->x_interval));
        if (w==0)
                w=1;
-       if (w==4)
+       
+       if (w==4 || w==3 || w==2)
        {
                w=5;
-               a=distance/10;
-               b=10+(((u_data->io->min_x/100000)-1)%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 (a>1000000)
-               start=u_data->io->min_x/1000000*1000000;
+       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/100000;
+               start = u_data->io->min_x;
                if (start%2!=0)
                        start--;
-               start*=100000;
+               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;
@@ -501,9 +561,24 @@ static void sctp_graph_draw(struct sctp_udata *u_data)
                                u_data->io->pixmap_height-BOTTOM_BORDER+length);
                }
 
-               if (i%1000000==0)
+               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)
                {
-                       sec=i/1000000;
                        gdk_draw_line(u_data->io->pixmap,u_data->io->draw_area->style->black_gc,
                        (guint32)(LEFT_BORDER+u_data->io->offset+(i-u_data->io->min_x)*u_data->io->x_interval),
                        u_data->io->pixmap_height-BOTTOM_BORDER,
@@ -514,7 +589,7 @@ static void sctp_graph_draw(struct sctp_udata *u_data)
                        #if GTK_MAJOR_VERSION < 2
                                lwidth=gdk_string_width(font, label_string);
                                gdk_draw_string(u_data->io->pixmap,font,u_data->io->draw_area->style->black_gc,
-                                       (guint32)(LEFT_BORDER+u_data->io->offset+(i-u_data->io->min_x)*u_data->io->x_interval),
+                                       (guint32)(LEFT_BORDER+u_data->io->offset+(i-u_data->io->min_x)*u_data->io->x_interval-10),
                                        u_data->io->pixmap_height-BOTTOM_BORDER+20,
                                        label_string);
                        #else
@@ -523,11 +598,13 @@ static void sctp_graph_draw(struct sctp_udata *u_data)
                                pango_layout_get_pixel_size(layout, &lwidth, NULL);
 
                                gdk_draw_layout(u_data->io->pixmap,u_data->io->draw_area->style->black_gc,
-                               (guint32)(LEFT_BORDER+u_data->io->offset+(i-u_data->io->min_x)*u_data->io->x_interval),
+                               (guint32)(LEFT_BORDER+u_data->io->offset+(i-u_data->io->min_x)*u_data->io->x_interval-10),
                                        u_data->io->pixmap_height-BOTTOM_BORDER+20,
                                        layout);
                        #endif
+                       write_label = FALSE;
                }
+               
        }
 
        strcpy(label_string, "sec");
@@ -538,7 +615,7 @@ static void sctp_graph_draw(struct sctp_udata *u_data)
                        font,
                        u_data->io->draw_area->style->black_gc,
                        u_data->io->pixmap_width-RIGHT_BORDER-10,
-                       u_data->io->pixmap_height-BOTTOM_BORDER+20,
+                       u_data->io->pixmap_height-BOTTOM_BORDER+30,
                        label_string);
 #else
        memcpy(label_string,(gchar *)g_locale_to_utf8(label_string, -1 , NULL, NULL, NULL), 15);
@@ -547,7 +624,7 @@ static void sctp_graph_draw(struct sctp_udata *u_data)
        gdk_draw_layout(u_data->io->pixmap,
                        u_data->io->draw_area->style->black_gc,
                        u_data->io->pixmap_width-RIGHT_BORDER-10,
-                       u_data->io->pixmap_height-BOTTOM_BORDER+25,
+                       u_data->io->pixmap_height-BOTTOM_BORDER+30,
                        layout);
 #endif
 
@@ -573,6 +650,8 @@ static void sctp_graph_draw(struct sctp_udata *u_data)
                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)
        {
@@ -590,7 +669,7 @@ static void sctp_graph_draw(struct sctp_udata *u_data)
                                                lwidth=gdk_string_width(font, label_string);
                                                gdk_draw_string(u_data->io->pixmap,font,u_data->io->draw_area->style->black_gc,
                                                                LEFT_BORDER-length-lwidth-5,
-                                                               (guint32)(u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset-(i-u_data->io->min_y)*u_data->io->y_interval-3),
+                                                               (guint32)(u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset-(i-u_data->io->min_y)*u_data->io->y_interval-POINT_SIZE),
                                                                label_string);
 #else
                                                memcpy(label_string,(gchar *)g_locale_to_utf8(label_string, -1 , NULL, NULL, NULL), 15);
@@ -598,7 +677,7 @@ static void sctp_graph_draw(struct sctp_udata *u_data)
                                                pango_layout_get_pixel_size(layout, &lwidth, NULL);
                                                gdk_draw_layout(u_data->io->pixmap,u_data->io->draw_area->style->black_gc,
                                                                LEFT_BORDER-length-lwidth-5,
-                                                               (guint32)(u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset-(i-u_data->io->min_y)*u_data->io->y_interval-3),
+                                                               (guint32)(u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset-(i-u_data->io->min_y)*u_data->io->y_interval-POINT_SIZE),
                                                                layout);
 #endif
                                }
@@ -627,7 +706,7 @@ sctp_graph_t *ios;
                        draw_sack_graph(u_data);
                        draw_tsn_graph(u_data);
                        break;
-               case 1: 
+               case 1:
                        draw_tsn_graph(u_data);
                        break;
                case 2:
@@ -712,7 +791,6 @@ configure_event(GtkWidget *widget, GdkEventConfigure *event _U_, struct sctp_uda
                        widget->allocation.width,
                        widget->allocation.height);
        sctp_graph_redraw(u_data);
-       sctp_graph_redraw(u_data);
        return TRUE;
 }
 
@@ -742,7 +820,7 @@ on_zoomin_bt (GtkWidget *widget _U_, struct sctp_udata *u_data)
 {
        sctp_min_max_t *tmp_minmax;
 
-       if (u_data->io->rectangle==TRUE)
+       if (u_data->io->rectangle_present==TRUE)
        {
                tmp_minmax = g_malloc(sizeof(sctp_min_max_t));
 
@@ -762,10 +840,47 @@ on_zoomin_bt (GtkWidget *widget _U_, struct sctp_udata *u_data)
                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 (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_, struct sctp_udata *u_data)
 {
@@ -817,11 +932,11 @@ on_zoomout_bt (GtkWidget *widget _U_, struct sctp_udata *u_data)
                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 gint
 on_button_press (GtkWidget *widget _U_, GdkEventButton *event, struct sctp_udata *u_data)
 {
@@ -831,8 +946,8 @@ on_button_press (GtkWidget *widget _U_, GdkEventButton *event, struct sctp_udata
        {
                gdk_draw_rectangle(u_data->io->pixmap,u_data->io->draw_area->style->white_gc,
                                   FALSE,
-                                  (gint)floor(MINI(u_data->io->x_old,u_data->io->x_new)),
-                                  (gint)floor(MINI(u_data->io->y_old,u_data->io->y_new)),
+                                  (gint)floor(MIN(u_data->io->x_old,u_data->io->x_new)),
+                                  (gint)floor(MIN(u_data->io->y_old,u_data->io->y_new)),
                                   (gint)floor(abs((long)(u_data->io->x_new-u_data->io->x_old))),
                                   (gint)floor(abs((long)(u_data->io->y_new-u_data->io->y_old))));
                ios=(sctp_graph_t *)OBJECT_GET_DATA(u_data->io->draw_area, "sctp_graph_t");
@@ -852,8 +967,8 @@ on_button_press (GtkWidget *widget _U_, GdkEventButton *event, struct sctp_udata
        }
        u_data->io->x_old=event->x;
        u_data->io->y_old=event->y;
-       if (u_data->io->y_old>u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset)
-               u_data->io->y_old=u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset;
+       if (u_data->io->y_old>u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset-POINT_SIZE)
+               u_data->io->y_old=u_data->io->pixmap_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;
@@ -866,8 +981,37 @@ static gint
 on_button_release (GtkWidget *widget _U_, GdkEventButton *event, struct sctp_udata *u_data)
 {
        sctp_graph_t *ios;
-       guint32 helpx;
-       guint32 helpy, x1_tmp, x2_tmp;
+       guint32 helpx, helpy, x1_tmp, x2_tmp,  y_value, frame, tmpnum=0, count=0, tsnumber=0;
+       gint label_width, label_height;
+       gdouble x_value, position, tfirst, s_diff, t_diff;
+       gint lwidth;
+       char label_string[30];
+       GdkGC *text_color;
+       GList *tsnlist=NULL, *tlist=NULL, *sacklist=NULL;
+       tsn_t *tsn, *tmptsn, *tmpsack, *sack;
+       guint8 type;
+       gboolean sack_type = FALSE;
+
+       #if GTK_MAJOR_VERSION < 2
+               GdkFont *font;
+#else
+               PangoLayout  *layout;
+#endif
+
+#if GTK_MAJOR_VERSION < 2
+               font = u_data->io->draw_area->style->font;
+#endif
+
+#if GTK_MAJOR_VERSION < 2
+               label_width=gdk_string_width(font, label_string);
+               label_height=gdk_string_height(font, label_string);
+#else
+               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);
+
+#endif
 
        if (event->y>u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset)
                event->y = u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset;
@@ -875,11 +1019,15 @@ on_button_release (GtkWidget *widget _U_, GdkEventButton *event, struct sctp_uda
                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;
                gdk_draw_rectangle(u_data->io->pixmap,u_data->io->draw_area->style->black_gc,
                                   FALSE,
-                                  (gint)floor(MINI(u_data->io->x_old,event->x)), (gint)floor(MINI(u_data->io->y_old,event->y)),
-                                  (gint)abs((long)(event->x-u_data->io->x_old)),
-                                  (gint)abs((long)(event->y-u_data->io->y_old)));
+                                  u_data->io->rect_x_min, u_data->io->rect_y_min,
+                                  u_data->io->rect_x_max - u_data->io->rect_x_min,
+                                  u_data->io->rect_y_max - u_data->io->rect_y_min);
                ios=(sctp_graph_t *)OBJECT_GET_DATA(u_data->io->draw_area, "sctp_graph_t");
 
                if(!ios){
@@ -896,26 +1044,219 @@ on_button_release (GtkWidget *widget _U_, GdkEventButton *event, struct sctp_uda
 
                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=MINI(x1_tmp, x2_tmp);
+               helpx=MIN(x1_tmp, x2_tmp);
                if (helpx==x2_tmp)
                {
                        x2_tmp=x1_tmp;
                        x1_tmp=helpx;
                }
-               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->y1_tmp=(guint32)((u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->y_old)/u_data->io->y_interval);
-               u_data->io->y2_tmp=(guint32)((u_data->io->pixmap_height-BOTTOM_BORDER-event->y)/u_data->io->y_interval);
-               helpy = MINI(u_data->io->y1_tmp, u_data->io->y2_tmp);
-               u_data->io->y2_tmp = MAXI(u_data->io->y1_tmp, u_data->io->y2_tmp);
+               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->pixmap_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->pixmap_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(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->pixmap_width-LEFT_BORDER-u_data->io->offset))+u_data->io->x1_tmp_sec+u_data->io->x1_tmp_usec/1000000.0;
+                       y_value = (gint)floor((u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset-event->y) * (max_tsn - min_tsn) / (u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset)) + min_tsn;
+                       text_color = u_data->io->draw_area->style->black_gc;
+
+                       if (u_data->dir == 1)
+                       {
+                               tsnlist = g_list_last(u_data->assoc->tsn1);
+                               sacklist = g_list_last(u_data->assoc->sack1);
+                       }
+                       else
+                       {
+                               tsnlist = g_list_last(u_data->assoc->tsn2);
+                               sacklist = g_list_last(u_data->assoc->sack2);
+                       }
 
+                       tsn = (tsn_t*) (tsnlist->data);
+                       tmptsn =(tsn_t*)(tsnlist->data);
+                       tfirst = tsn->secs + tsn->usecs/1000000.0;
+                       frame = tsn->frame_number;
+                       
+                       while (tsnlist)
+                       {
+                               tsnlist = g_list_previous(tsnlist);
+                               tsn = (tsn_t*) (tsnlist->data);
+                               if (tsn->secs+tsn->usecs/1000000.0<x_value)
+                               {
+                                       tfirst = tsn->secs+tsn->usecs/1000000.0;
+                                       tmptsn =tsn;
+                               }
+                               else
+                               {
+                                       if ((tfirst+tsn->secs+tsn->usecs/1000000.0)/2.0<x_value)
+                                       {
+                                               t_diff = tsn->secs+tsn->usecs/1000000.0 - x_value;
+                                               tmptsn = tsn;
+                                       }
+                                       else
+                                               t_diff = x_value - tmptsn->secs+tmptsn->usecs/1000000.0;
+                                       break;
+                               }
+                       }
+                       sack = (tsn_t*) (sacklist->data);
+                       tmpsack =(tsn_t*)(sacklist->data);
+                       tfirst = sack->secs + sack->usecs/1000000.0;
+                       
+                       while (sacklist)
+                       {
+                               sacklist = g_list_previous(sacklist);
+                               sack = (tsn_t*) (sacklist->data);
+                               if (sack->secs+sack->usecs/1000000.0<x_value)
+                               {
+                                       tfirst = sack->secs+sack->usecs/1000000.0;
+                                       tmpsack =sack;
+                               }
+                               else
+                               {
+                                       if ((tfirst+sack->secs+sack->usecs/1000000.0)/2.0<x_value)
+                                       {
+                                               s_diff = sack->secs+sack->usecs/1000000.0 - x_value;
+                                               tmpsack = sack;
+                                       }
+                                       else
+                                               s_diff = x_value - tmpsack->secs+tmpsack->usecs/1000000.0;
+                                       break;
+                               }
+                       }
+                       if (s_diff < t_diff)
+                       {
+                               cf_goto_frame(&cfile, tmpsack->frame_number);
+                               x_value = tmpsack->secs+tmpsack->usecs/1000000.0;
+                               tlist = g_list_first(tmpsack->tsns);
+                               sack_type = TRUE;
+                       }
+                       else
+                       {
+                               cf_goto_frame(&cfile, tmptsn->frame_number);
+                               x_value = tmptsn->secs+tmptsn->usecs/1000000.0;
+                               tlist = g_list_first(tmptsn->tsns);
+                               sack_type = FALSE;
+                       }
+                       count++;
+                       while (tlist)
+                       {
+                               type = ((struct chunk_header *)tlist->data)->type;
+                               if (type == SCTP_DATA_CHUNK_ID && !sack_type)
+                                       tsnumber = g_ntohl(((struct data_chunk_header *)tlist->data)->tsn);
+                               else if (type == SCTP_SACK_CHUNK_ID && sack_type)
+                                       tsnumber = g_ntohl(((struct sack_chunk_header *)tlist->data)->cum_tsn_ack);
+                               if (tsnumber < y_value && g_list_length(tlist)-count>0)
+                               {
+                                       tmpnum = tsnumber;
+                               }
+                               else
+                               {
+                                       if ((tmpnum+tsnumber)/2 < y_value)
+                                       {
+                                               y_value = tsnumber;
+                                               tmpnum = tsnumber;
+                                       }
+                                       else
+                                       {
+                                               y_value = tmpnum;
+                                       }
+                                       break;
+                               }
+                               tlist = g_list_next(tlist);
+                               count++;
+                       }
+                       g_snprintf(label_string, 30, "(%.6lf, %u)", x_value, y_value);
+                       label_set = TRUE;
+
+                       gdk_draw_line(u_data->io->pixmap,text_color, (gint)(event->x-2), (gint)(event->y), (gint)(event->x+2), (gint)(event->y));
+                       gdk_draw_line(u_data->io->pixmap,text_color, (gint)(event->x), (gint)(event->y-2), (gint)(event->x), (gint)(event->y+2));
+                       if (event->x+150>=u_data->io->pixmap_width)
+                               position = event->x - 150;
+                       else
+                               position = event->x + 5;
+
+
+#if GTK_MAJOR_VERSION < 2
+                       lwidth=gdk_string_width(font, label_string);
+                                           gdk_draw_string(u_data->io->pixmap,font,text_color,
+                                           (gint)position,
+                                           (gint)(event->y-10),
+                                           label_string);
+#else
+                       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);
+
+                       gdk_draw_layout(u_data->io->pixmap,text_color,
+                                           (gint)position,
+                                           (gint)(event->y-10),
+                                           layout);
+       #endif
+
+
+
+                       ios=(sctp_graph_t *)OBJECT_GET_DATA(u_data->io->draw_area, "sctp_graph_t");
+
+                       if(!ios){
+                               exit(10);
+                       }
+                       gdk_draw_pixmap(u_data->io->draw_area->window,
+                                   u_data->io->draw_area->style->fg_gc[GTK_WIDGET_STATE(u_data->io->draw_area)],
+                                   ios->pixmap,
+                                   0, 0,
+                                   0, 0,
+                                   u_data->io->draw_area->allocation.width,
+                                   u_data->io->draw_area->allocation.height);
+               }
+       }
        return TRUE;
 }
 
@@ -924,7 +1265,7 @@ static void init_sctp_graph_window(struct sctp_udata *u_data)
 {
        GtkWidget *vbox;
        GtkWidget *hbox;
-       GtkWidget *bt_close, *sack_bt, *tsn_bt, *both_bt, *zoomin_bt, *zoomout_bt;
+       GtkWidget *bt_close, *sack_bt, *tsn_bt, *both_bt, *zoomin_bt;
        GtkTooltips *tooltip_in, *tooltip_out;
 
        /* create the main window */
@@ -970,7 +1311,7 @@ static void init_sctp_graph_window(struct sctp_udata *u_data)
        gtk_widget_show(zoomin_bt);
        SIGNAL_CONNECT(zoomin_bt, "clicked", on_zoomin_bt, u_data);
        tooltip_in = gtk_tooltips_new();
-       gtk_tooltips_set_tip(tooltip_in, zoomin_bt, "Draw a rectangle around the area you want to zoom in", NULL);
+       gtk_tooltips_set_tip(tooltip_in, zoomin_bt, "Zoom in the area you have selected", NULL);
 
        zoomout_bt = gtk_button_new_with_label ("Zoom out");
        gtk_box_pack_start(GTK_BOX(hbox), zoomout_bt, FALSE, FALSE, 0);
@@ -978,7 +1319,7 @@ static void init_sctp_graph_window(struct sctp_udata *u_data)
        SIGNAL_CONNECT(zoomout_bt, "clicked", on_zoomout_bt, u_data);
        tooltip_out = gtk_tooltips_new();
        gtk_tooltips_set_tip(tooltip_out, zoomout_bt, "Zoom out one step", NULL);
-
+       gtk_widget_set_sensitive(zoomout_bt, FALSE);
 
        bt_close = BUTTON_NEW_FROM_STOCK(GTK_STOCK_CLOSE);
        gtk_box_pack_start(GTK_BOX(hbox), bt_close, FALSE, FALSE, 0);
@@ -988,8 +1329,7 @@ static void init_sctp_graph_window(struct sctp_udata *u_data)
        gtk_signal_connect(GTK_OBJECT(u_data->io->draw_area),"button_press_event",(GtkSignalFunc)on_button_press, u_data);
        gtk_signal_connect(GTK_OBJECT(u_data->io->draw_area),"button_release_event",(GtkSignalFunc)on_button_release, u_data);
        gtk_widget_set_events(u_data->io->draw_area, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_EXPOSURE_MASK);
-       /* dlg_set_cancel(u_data->io->window, bt_close); */
-       
+
        gtk_widget_show(u_data->io->window);
 }
 
@@ -1024,7 +1364,6 @@ gtk_sctpgraph_init(struct sctp_udata *u_data)
        io->pixmap_height=600;
        io->graph_type=0;
        dir=u_data->dir-1;
-
        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;