da81208ce1104f4cca1b64849cbb84b3072d61f8
[obnox/wireshark/wip.git] / gtk / sctp_byte_graph_dlg.c
1 /*
2  * Copyright 2004, Irene Ruengeler <i.ruengeler [AT] fh-muenster.de>
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #  include <config.h>
27 #endif
28
29
30 #include <gtk/gtk.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <math.h>
34 #include <string.h>
35 #include "globals.h"
36 #include "epan/filesystem.h"
37 #include "../color.h"
38 #include "dlg_utils.h"
39 #include "ui_util.h"
40 #include "main.h"
41 #include "compat_macros.h"
42 #include "simple_dialog.h"
43 #include "sctp_stat.h"
44 #include <epan/strutil.h>
45
46 #define DEFAULT_PIXELS_PER_TICK 2
47 #define MAX_PIXELS_PER_TICK     4
48 #define AUTO_MAX_YSCALE         0
49 #define MAX_TICK_VALUES         5
50 #define DEFAULT_TICK_VALUE      3
51 #define MAX_YSCALE              22
52 #define MAX_COUNT_TYPES         3
53
54 #define COUNT_TYPE_FRAMES   0
55 #define COUNT_TYPE_BYTES    1
56 #define COUNT_TYPE_ADVANCED 2
57
58 #define LEFT_BORDER   80
59 #define RIGHT_BORDER  10
60 #define TOP_BORDER    10
61 #define BOTTOM_BORDER 50
62
63 #define SUB_32(a, b)    a-b
64
65 struct chunk_header {
66         guint8  type;
67         guint8  flags;
68         guint16 length;
69 };
70
71 struct data_chunk_header {
72         guint8  type;
73         guint8  flags;
74         guint16 length;
75         guint32  tsn;
76         guint16 sid;
77         guint16 ssn;
78         guint32  ppi;
79 };
80
81 struct init_chunk_header {
82         guint8  type;
83         guint8  flags;
84         guint16 length;
85         guint32  initiate_tag;
86         guint32  a_rwnd;
87         guint16 mos;
88         guint16 mis;
89         guint32  initial_tsn;
90 };
91
92 struct sack_chunk_header {
93         guint8  type;
94         guint8  flags;
95         guint16 length;
96         guint32  cum_tsn_ack;
97         guint32  a_rwnd;
98         guint16 nr_of_gaps;
99         guint16 nr_of_dups;
100         guint8  *tsns;
101 };
102
103 struct gaps {
104         guint16 start;
105         guint16 end;
106 };
107
108 static gboolean label_set = FALSE;
109 static guint32 max_tsn=0, min_tsn=0;
110
111
112 static void sctp_graph_set_title(struct sctp_udata *u_data);
113 static void create_draw_area(GtkWidget *box, struct sctp_udata *u_data);
114 static GtkWidget *zoomout_bt;
115
116 static void draw_sack_graph(struct sctp_udata *u_data)
117 {
118         GdkColor red_color = {0, 65535, 0, 0};
119         GdkColor green_color = {0, 0, 65535, 0};
120         GdkGC *red_gc, *green_gc;
121         gint diff;
122         GPtrArray *array = NULL;
123         guint32 i, size = 0, start=0, end;
124         gboolean more = FALSE;
125         gint width;
126
127         red_gc = gdk_gc_new(u_data->io->draw_area->window);
128         gdk_gc_set_rgb_fg_color(red_gc, &red_color);
129
130         green_gc = gdk_gc_new(u_data->io->draw_area->window);
131         gdk_gc_set_rgb_fg_color(green_gc, &green_color);
132
133         if (u_data->dir == 1)
134         {
135                 array = u_data->assoc->sort_sack1;
136                 size=u_data->assoc->n_sack_chunks_ep1;
137                 if (u_data->io->tmp == FALSE)
138                 {
139                         min_tsn = 0;
140                         max_tsn = u_data->assoc->max_bytes1;
141                 }
142                 else
143                 {
144                         min_tsn = u_data->io->tmp_min_tsn1;
145                         max_tsn = u_data->io->tmp_max_tsn1;
146                 }
147         }
148         else if (u_data->dir == 2)
149         {
150                 array = u_data->assoc->sort_sack2;
151                 size = u_data->assoc->n_sack_chunks_ep2;
152                 if (u_data->io->tmp == FALSE)
153                 {
154                         min_tsn = 0;
155                         max_tsn = u_data->assoc->max_bytes2;
156                 }
157                 else
158                 {
159                         min_tsn = u_data->io->tmp_min_tsn2;
160                         max_tsn = u_data->io->tmp_max_tsn2;
161                 }
162         }
163
164         width = u_data->io->max_x - u_data->io->min_x;
165
166         for (i=0; i<size; i++)
167         {
168                 if (u_data->io->uoff)
169                         diff = (gint)((struct tsn_sort*)(g_ptr_array_index(array,  i)))->secs - u_data->io->min_x;
170                 else
171                         diff = (gint)((struct tsn_sort*)(g_ptr_array_index(array,  i)))->secs * 1000000 + ((struct tsn_sort*)(g_ptr_array_index(array,  i)))->usecs - u_data->io->min_x;
172                 end = start + ((struct tsn_sort*)(g_ptr_array_index(array,  i)))->length;
173                 if (end>max_tsn)
174                 {
175                         end = max_tsn;
176                         more = TRUE;
177                 }
178
179                 if (start >= min_tsn && diff > 0 && diff <= width)
180                 {
181                         gdk_draw_line(u_data->io->pixmap,red_gc,
182                                      (guint32)(LEFT_BORDER+u_data->io->offset+u_data->io->x_interval*diff),
183                                      (guint32)(u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset-((SUB_32(start,min_tsn))*u_data->io->y_interval)),
184                                      (guint32)(LEFT_BORDER+u_data->io->offset+u_data->io->x_interval*diff),
185                                      (guint32)(u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset-((SUB_32(end,min_tsn))*u_data->io->y_interval)));
186                         if (more == TRUE)
187                         {
188                                 gdk_draw_line(u_data->io->pixmap,green_gc,
189                                               (guint32)(LEFT_BORDER+u_data->io->offset+u_data->io->x_interval*diff),
190                                               (guint32)(u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset-((SUB_32(end,min_tsn))*u_data->io->y_interval)),
191                                               (guint32)(LEFT_BORDER+u_data->io->offset+u_data->io->x_interval*diff),
192                                               (guint32)(u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset-((SUB_32(end+10,min_tsn))*u_data->io->y_interval)));
193                                 more = FALSE;
194                         }
195                 }
196
197         }
198         g_object_unref(G_OBJECT(red_gc));
199         g_object_unref(G_OBJECT(green_gc));
200 }
201
202
203 static void draw_tsn_graph(struct sctp_udata *u_data)
204 {
205 GPtrArray *array = NULL;
206 guint32 i, size = 0, start, end;
207 gint diff, width;
208
209         if (u_data->dir == 1)
210         {
211                 array = u_data->assoc->sort_tsn1;
212                 size = u_data->assoc->n_data_chunks_ep1;
213                 if (u_data->io->tmp == FALSE)
214                 {
215                         min_tsn = 0;
216                         max_tsn = u_data->assoc->max_bytes1;
217                 }
218                 else
219                 {
220                         min_tsn = u_data->io->tmp_min_tsn1;
221                         max_tsn = u_data->io->tmp_max_tsn1;
222                 }
223         }
224         else if (u_data->dir == 2)
225         {
226                 array = u_data->assoc->sort_tsn2;
227                 size  = u_data->assoc->n_data_chunks_ep2;
228                 if (u_data->io->tmp == FALSE)
229                 {
230                         min_tsn = 0;
231                         max_tsn = u_data->assoc->max_bytes2;
232                 }
233                 else
234                 {
235                         min_tsn = u_data->io->tmp_min_tsn2;
236                         max_tsn = u_data->io->tmp_max_tsn2;
237                 }
238         }
239         width = u_data->io->max_x - u_data->io->min_x;
240
241         for (i=0; i<size; i++)
242         {
243                 if (u_data->io->uoff)
244                         diff = (gint)((struct tsn_sort*)(g_ptr_array_index(array, i)))->secs -u_data->io->min_x;
245                 else
246                         diff = (gint)((struct tsn_sort*)(g_ptr_array_index(array, i)))->secs*1000000 + ((struct tsn_sort*)(g_ptr_array_index(array, i)))->usecs-u_data->io->min_x;
247                 start = ((struct tsn_sort*)(g_ptr_array_index(array, i)))->offset;
248                 end = start + ((struct tsn_sort*)(g_ptr_array_index(array, i)))->length;
249                 if (start >= min_tsn && diff > 0 && diff <= width)
250                         gdk_draw_line(u_data->io->pixmap,
251                                       u_data->io->draw_area->style->black_gc,
252                                       (guint32)(LEFT_BORDER+u_data->io->offset+u_data->io->x_interval*diff),
253                                       (guint32)(u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset-((SUB_32(start,min_tsn))*u_data->io->y_interval)),
254                                       (guint32)(LEFT_BORDER+u_data->io->offset+u_data->io->x_interval*diff),
255                                       (guint32)(u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset-((SUB_32(end,min_tsn))*u_data->io->y_interval)));
256         }
257
258 }
259
260
261 static void sctp_graph_draw(struct sctp_udata *u_data)
262 {
263         int length, lwidth;
264         guint32 distance=5, i, e, sec, w, start, a, j, b;
265         gint label_width, label_height;
266         char label_string[15];
267         gfloat dis;
268         gboolean write_label = FALSE;
269         PangoLayout  *layout;
270
271         if (u_data->io->x1_tmp_sec == 0 && u_data->io->x1_tmp_usec == 0)
272                 u_data->io->offset = 0;
273         else
274                 u_data->io->offset = 5;
275
276         if (u_data->io->x2_tmp_sec - u_data->io->x1_tmp_sec > 1500)
277         {
278                 u_data->io->min_x=u_data->io->x1_tmp_sec;
279                 u_data->io->max_x=u_data->io->x2_tmp_sec;
280                 u_data->io->uoff = TRUE;
281         }
282         else
283         {
284                 u_data->io->min_x=((guint32) (u_data->io->x1_tmp_sec*1000000.0))+u_data->io->x1_tmp_usec;
285                 u_data->io->max_x=((guint32) (u_data->io->x2_tmp_sec*1000000.0))+u_data->io->x2_tmp_usec;               
286                 u_data->io->uoff = FALSE;
287         }       
288
289         u_data->io->tmp_width = u_data->io->max_x - u_data->io->min_x;
290
291         if (u_data->dir == 1)
292         {
293                 if (u_data->io->tmp == FALSE)
294                 {
295                         if (u_data->assoc->sort_tsn1 != NULL)
296                                 u_data->io->max_y = u_data->io->tmp_max_tsn1 - u_data->io->tmp_min_tsn1;
297                         else
298                                 u_data->io->max_y = 0;
299                         u_data->io->min_y = 0;
300                 }
301                 else
302                 {
303                         u_data->io->max_y = u_data->io->tmp_max_tsn1;
304                         u_data->io->min_y = u_data->io->tmp_min_tsn1;
305                 }
306         }
307         else if (u_data->dir == 2)
308         {
309                 if (u_data->io->tmp == FALSE)
310                 {
311                         if (u_data->assoc->tsn2 != NULL)
312                                 u_data->io->max_y = u_data->io->tmp_max_tsn2 - u_data->io->tmp_min_tsn2;
313                         else
314                                 u_data->io->max_y = 0;
315                         u_data->io->min_y = 0;
316                 }
317                 else
318                 {
319                         u_data->io->max_y = u_data->io->tmp_max_tsn2;
320                         u_data->io->min_y = u_data->io->tmp_min_tsn2;
321                 }
322         }
323         gdk_draw_rectangle(u_data->io->pixmap, u_data->io->draw_area->style->white_gc,
324                            TRUE, 0, 0, u_data->io->draw_area->allocation.width,
325                            u_data->io->draw_area->allocation.height);
326
327         distance = 5;
328         /* x_axis */
329         gdk_draw_line(u_data->io->pixmap,u_data->io->draw_area->style->black_gc,
330                       LEFT_BORDER+u_data->io->offset,u_data->io->pixmap_height - BOTTOM_BORDER,
331                       u_data->io->pixmap_width - RIGHT_BORDER + u_data->io->offset, u_data->io->pixmap_height - BOTTOM_BORDER);
332         gdk_draw_line(u_data->io->pixmap,u_data->io->draw_area->style->black_gc,
333                       u_data->io->pixmap_width - RIGHT_BORDER + u_data->io->offset, u_data->io->pixmap_height - BOTTOM_BORDER, u_data->io->pixmap_width - RIGHT_BORDER + u_data->io->offset - 5, u_data->io->pixmap_height - BOTTOM_BORDER - 5);
334         gdk_draw_line(u_data->io->pixmap,u_data->io->draw_area->style->black_gc,
335                       u_data->io->pixmap_width - RIGHT_BORDER + u_data->io->offset, u_data->io->pixmap_height - BOTTOM_BORDER, u_data->io->pixmap_width - RIGHT_BORDER + u_data->io->offset - 5, u_data->io->pixmap_height - BOTTOM_BORDER + 5);
336         u_data->io->axis_width = u_data->io->pixmap_width - LEFT_BORDER - RIGHT_BORDER - u_data->io->offset;
337
338         if(u_data->io->tmp_width>0){
339                 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*/
340         } else {
341                 u_data->io->x_interval = (float)(u_data->io->axis_width);
342         }
343
344         e=0;
345         if (u_data->io->x_interval < 1)
346         {
347                 dis = 1 / u_data->io->x_interval;
348                 while (dis >1)
349                 {
350                         dis /= 10;
351                         e++;
352                 }
353                 distance = 1;
354                         for (i=0; i<=e+1; i++)
355                         distance *= 10;
356         }
357         else
358                 distance = 5;
359
360         g_snprintf(label_string, 15, "%d", 0);
361         memcpy(label_string,(gchar *)g_locale_to_utf8(label_string, -1 , NULL, NULL, NULL), 15);
362         layout = gtk_widget_create_pango_layout(u_data->io->draw_area, label_string);
363         pango_layout_get_pixel_size(layout, &label_width, &label_height);
364
365         if (u_data->io->x1_tmp_usec == 0)
366                 sec = u_data->io->x1_tmp_sec;
367         else
368                 sec = u_data->io->x1_tmp_sec+1;
369
370         if (u_data->io->offset != 0)
371         {
372                 g_snprintf(label_string, 15, "%u", u_data->io->x1_tmp_sec);
373                 memcpy(label_string,(gchar *)g_locale_to_utf8(label_string, -1 , NULL, NULL, NULL), 15);
374                 pango_layout_set_text(layout, label_string, -1);
375                 pango_layout_get_pixel_size(layout, &lwidth, NULL);
376
377                 gdk_draw_layout(u_data->io->pixmap,u_data->io->draw_area->style->black_gc,
378                                 LEFT_BORDER - 25,
379                                 u_data->io->pixmap_height - BOTTOM_BORDER + 20,
380                                 layout);
381         }
382         w = (guint32)(500 / (guint32)(distance * u_data->io->x_interval));
383         if (w == 0)
384                 w = 1;
385         if (w == 4 || w==3 || w==2)
386         {
387                 w = 5;
388                 a = distance / 10;
389                 b = (guint32)((u_data->io->min_x/100000))%10; /* start for labels*/
390         }
391         else
392         {
393                 a = distance / 5;
394                 b = 0;
395         }
396
397         if (!u_data->io->uoff)  
398         {
399                 if (a>=1000000)
400                 {
401                         start=u_data->io->min_x/1000000*1000000;
402                         if (a==1000000)
403                                 b = 0;
404                 }
405                 else
406                 {
407                         start=u_data->io->min_x/100000;
408                         if (start%2!=0)
409                                 start--;
410                         start*=100000;
411                         b = (guint32)((start/100000))%10;
412                 }
413         }
414         else
415         {
416                 start = u_data->io->min_x;
417                 if (start%2!=0)
418                         start--;
419                 b = 0;
420                 
421         }
422
423         for (i=start, j=b; i<=u_data->io->max_x; i+=a, j++)
424         {
425                 if (!u_data->io->uoff)
426                 if (i >= u_data->io->min_x && i % 1000000 != 0)
427                 {
428                         length = 5;
429                         g_snprintf(label_string, 15, "%d", i%1000000);
430
431                         if (j % w == 0)
432                         {
433                                 length = 10;
434
435                                 memcpy(label_string,(gchar *)g_locale_to_utf8(label_string, -1 , NULL, NULL, NULL), 15);
436                                 pango_layout_set_text(layout, label_string, -1);
437                                 pango_layout_get_pixel_size(layout, &lwidth, NULL);
438                                 gdk_draw_layout(u_data->io->pixmap,
439                                                 u_data->io->draw_area->style->black_gc,
440                                                 (guint32)(LEFT_BORDER + u_data->io->offset + (i - u_data->io->min_x) * u_data->io->x_interval - lwidth / 2),
441                                                 u_data->io->pixmap_height - BOTTOM_BORDER + 10,
442                                                 layout);
443                         }
444                         gdk_draw_line(u_data->io->pixmap,
445                                       u_data->io->draw_area->style->black_gc,
446                                       (guint32)(LEFT_BORDER + u_data->io->offset + (i - u_data->io->min_x) * u_data->io->x_interval),
447                                       u_data->io->pixmap_height - BOTTOM_BORDER,
448                                       (guint32)(LEFT_BORDER + u_data->io->offset + (i - u_data->io->min_x) * u_data->io->x_interval),
449                                       u_data->io->pixmap_height - BOTTOM_BORDER + length);
450                 }
451
452                 if (!u_data->io->uoff)
453                 {
454                         if (i%1000000==0 && j%w==0)
455                         {
456                                 sec=i/1000000;
457                                 write_label = TRUE;
458                         }
459                 }
460                 else
461                 {
462                         if (j%w == 0)
463                         {
464                                 sec = i;
465                                 write_label = TRUE;
466                         }
467                 }
468                 if (write_label)
469                 {
470                         gdk_draw_line(u_data->io->pixmap,u_data->io->draw_area->style->black_gc,
471                                       (guint32)(LEFT_BORDER + u_data->io->offset + (i - u_data->io->min_x) * u_data->io->x_interval),
472                                       u_data->io->pixmap_height - BOTTOM_BORDER,
473                                       (guint32)(LEFT_BORDER + u_data->io->offset + (i - u_data->io->min_x) * u_data->io->x_interval),
474                                       u_data->io->pixmap_height - BOTTOM_BORDER + 10);
475
476                         g_snprintf(label_string, 15, "%d", sec);
477                         memcpy(label_string,(gchar *)g_locale_to_utf8(label_string, -1 , NULL, NULL, NULL), 15);
478                         pango_layout_set_text(layout, label_string, -1);
479                         pango_layout_get_pixel_size(layout, &lwidth, NULL);
480                         gdk_draw_layout(u_data->io->pixmap,u_data->io->draw_area->style->black_gc,
481                                         (guint32)(LEFT_BORDER + u_data->io->offset + (i - u_data->io->min_x) * u_data->io->x_interval-10),
482                                         u_data->io->pixmap_height - BOTTOM_BORDER + 20,
483                                         layout);
484                         write_label = FALSE;
485                 }
486         }
487
488         g_strlcpy(label_string, "sec", 15);
489
490         memcpy(label_string,(gchar *)g_locale_to_utf8(label_string, -1 , NULL, NULL, NULL), 15);
491         pango_layout_set_text(layout, label_string, -1);
492         pango_layout_get_pixel_size(layout, &lwidth, NULL);
493         gdk_draw_layout(u_data->io->pixmap,
494                         u_data->io->draw_area->style->black_gc,
495                         u_data->io->pixmap_width - RIGHT_BORDER - 10,
496                         u_data->io->pixmap_height - BOTTOM_BORDER + 30,
497                         layout);
498         distance = 5;
499
500         /* y-axis */
501         gdk_draw_line(u_data->io->pixmap,
502                       u_data->io->draw_area->style->black_gc,
503                       LEFT_BORDER,TOP_BORDER - u_data->io->offset,
504                       LEFT_BORDER,
505                       u_data->io->pixmap_height - BOTTOM_BORDER - u_data->io->offset);
506         gdk_draw_line(u_data->io->pixmap,
507                       u_data->io->draw_area->style->black_gc,
508                       LEFT_BORDER,
509                       TOP_BORDER - u_data->io->offset,
510                       LEFT_BORDER - 5,
511                       TOP_BORDER - u_data->io->offset + 5);
512         gdk_draw_line(u_data->io->pixmap,
513                       u_data->io->draw_area->style->black_gc,
514                       LEFT_BORDER,
515                       TOP_BORDER - u_data->io->offset,
516                       LEFT_BORDER + 5,
517                       TOP_BORDER - u_data->io->offset + 5);
518
519         u_data->io->y_interval = (float)(((u_data->io->pixmap_height - TOP_BORDER - BOTTOM_BORDER) * 1.0)/(u_data->io->max_y - u_data->io->min_y));
520
521         e = 0;
522         if (u_data->io->y_interval < 1)
523         {
524                 dis = 1 / u_data->io->y_interval;
525                 while (dis > 1)
526                 {
527                         dis /= 10;
528                         e++;
529                 }
530                 distance = 1;
531                 for (i=0; i<=e; i++)
532                         distance = distance * 10;
533         }
534         else if (u_data->io->y_interval<2)
535                 distance = 10;
536
537         if (u_data->io->max_y > 0)
538         {
539                 for (i=u_data->io->min_y/distance*distance; i<=u_data->io->max_y; i+=distance/5)
540                 {
541                         if (i >= u_data->io->min_y)
542                         {
543                                 length = 5;
544                                 g_snprintf(label_string, 15, "%d", i);
545
546                                 if (i%distance == 0 || (distance <= 5 && u_data->io->y_interval > 10))
547                                 {
548                                         length = 10;
549
550                                         memcpy(label_string,(gchar *)g_locale_to_utf8(label_string, -1 , NULL, NULL, NULL), 15);
551                                         pango_layout_set_text(layout, label_string, -1);
552                                         pango_layout_get_pixel_size(layout, &lwidth, NULL);
553                                         gdk_draw_layout(u_data->io->pixmap,u_data->io->draw_area->style->black_gc,
554                                                         LEFT_BORDER - length - lwidth - 5,
555                                                         (guint32)(u_data->io->pixmap_height - BOTTOM_BORDER - u_data->io->offset - (i - u_data->io->min_y) * u_data->io->y_interval - 3),
556                                                         layout);
557                                 }
558                         gdk_draw_line(u_data->io->pixmap,u_data->io->draw_area->style->black_gc,
559                                       LEFT_BORDER - length,
560                                       (guint32)(u_data->io->pixmap_height - BOTTOM_BORDER - u_data->io->offset - (i - u_data->io->min_y) * u_data->io->y_interval),
561                                       LEFT_BORDER,
562                                       (guint32)(u_data->io->pixmap_height - BOTTOM_BORDER - u_data->io->offset - (i - u_data->io->min_y) * u_data->io->y_interval));
563                         }
564                 }
565         }
566         else
567                 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, "No Data Chunks sent");
568 }
569
570
571 static void sctp_graph_redraw(struct sctp_udata *u_data)
572 {
573         sctp_graph_t *ios;
574
575         u_data->io->needs_redraw = TRUE;
576
577         sctp_graph_draw(u_data);
578         switch (u_data->io->graph_type)
579         {
580                 case 0:
581                         draw_sack_graph(u_data);
582                         draw_tsn_graph(u_data);
583                         break;
584                 case 1:
585                         draw_tsn_graph(u_data);
586                         break;
587                 case 2:
588                         draw_sack_graph(u_data);
589                         break;
590         }
591         ios=(sctp_graph_t *)g_object_get_data(G_OBJECT(u_data->io->draw_area), "sctp_graph_t");
592
593         if(!ios){
594                 exit(10);
595         }
596
597
598         gdk_draw_pixmap(u_data->io->draw_area->window,
599                         u_data->io->draw_area->style->fg_gc[GTK_WIDGET_STATE(u_data->io->draw_area)],
600                         ios->pixmap,
601                         0,0,
602                         0, 0,
603                         u_data->io->draw_area->allocation.width,
604                         u_data->io->draw_area->allocation.height);
605 }
606
607
608 static void on_sack_bt(GtkWidget *widget _U_, struct sctp_udata *u_data)
609 {
610         u_data = (struct sctp_udata *) u_data;
611         u_data->io->graph_type = 2;
612         sctp_graph_redraw(u_data);
613 }
614
615 static void on_tsn_bt(GtkWidget *widget _U_, struct sctp_udata *u_data)
616 {
617         u_data->io->graph_type = 1;
618         sctp_graph_redraw(u_data);
619 }
620
621 static void on_both_bt(GtkWidget *widget _U_, struct sctp_udata *u_data)
622 {
623         u_data->io->graph_type = 0;
624         sctp_graph_redraw(u_data);
625 }
626
627 static void
628 sctp_graph_close_cb(GtkWidget* widget _U_, gpointer u_data)
629 {
630         struct sctp_udata *udata;
631         int dir;
632
633         udata = (struct sctp_udata *)u_data;
634         dir = udata->dir - 1;
635         gtk_grab_remove(GTK_WIDGET(udata->io->window));
636         gtk_widget_destroy(GTK_WIDGET(udata->io->window));
637 }
638
639
640
641 static gint
642 configure_event(GtkWidget *widget, GdkEventConfigure *event _U_, struct sctp_udata *u_data)
643 {
644         if(!u_data->io){
645                 exit(10);
646         }
647
648         if(u_data->io->pixmap){
649                 gdk_pixmap_unref(u_data->io->pixmap);
650                 u_data->io->pixmap = NULL;
651         }
652
653         u_data->io->pixmap = gdk_pixmap_new(widget->window,
654                                             widget->allocation.width,
655                                             widget->allocation.height,
656                                             -1);
657         u_data->io->pixmap_width = widget->allocation.width;
658         u_data->io->pixmap_height = widget->allocation.height;
659
660         gdk_draw_rectangle(u_data->io->pixmap,
661                            widget->style->white_gc,
662                            TRUE,
663                            0, 0,
664                            widget->allocation.width,
665                            widget->allocation.height);
666         sctp_graph_redraw(u_data);
667         return TRUE;
668 }
669
670 static gint
671 expose_event(GtkWidget *widget, GdkEventExpose *event)
672 {
673         sctp_graph_t *ios;
674
675         ios=(sctp_graph_t *)g_object_get_data(G_OBJECT(widget), "sctp_graph_t");
676         if(!ios){
677                 exit(10);
678         }
679
680         gdk_draw_pixmap(widget->window,
681                         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
682                         ios->pixmap,
683                         event->area.x, event->area.y,
684                         event->area.x, event->area.y,
685                         event->area.width, event->area.height);
686
687         return FALSE;
688 }
689
690
691 static void
692 on_zoomin_bt (GtkWidget *widget _U_, struct sctp_udata *u_data)
693 {
694         sctp_min_max_t *tmp_minmax;
695
696         if (u_data->io->rectangle==TRUE)
697         {
698                 tmp_minmax = g_malloc(sizeof(sctp_min_max_t));
699
700                 u_data->io->tmp_min_tsn1=u_data->io->y1_tmp+u_data->io->min_y;
701                 u_data->io->tmp_max_tsn1=u_data->io->y2_tmp+1+u_data->io->min_y;
702
703                 u_data->io->tmp_min_tsn2=u_data->io->tmp_min_tsn1;
704                 u_data->io->tmp_max_tsn2=u_data->io->tmp_max_tsn1;
705                 tmp_minmax->tmp_min_secs=u_data->io->x1_tmp_sec;
706                 tmp_minmax->tmp_min_usecs=      u_data->io->x1_tmp_usec;
707                 tmp_minmax->tmp_max_secs=       u_data->io->x2_tmp_sec;
708                 tmp_minmax->tmp_max_usecs=      u_data->io->x2_tmp_usec;
709                 tmp_minmax->tmp_min_tsn1=u_data->io->tmp_min_tsn1;
710                 tmp_minmax->tmp_max_tsn1=u_data->io->tmp_max_tsn1;
711                 tmp_minmax->tmp_min_tsn2=u_data->io->tmp_min_tsn2;
712                 tmp_minmax->tmp_max_tsn2=u_data->io->tmp_max_tsn2;
713                 u_data->assoc->min_max = g_slist_prepend(u_data->assoc->min_max, tmp_minmax);
714                 u_data->io->length = g_slist_length(u_data->assoc->min_max);
715                 u_data->io->tmp=TRUE;
716                 u_data->io->rectangle=FALSE;
717                 gtk_widget_set_sensitive(zoomout_bt, TRUE);
718                 sctp_graph_redraw(u_data);
719         }
720         else
721         {
722                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Please draw a rectangle around the area you want to zoom in!");
723         }
724 }
725
726 static void
727 zoomin_bt (struct sctp_udata *u_data)
728 {
729         sctp_min_max_t *tmp_minmax;
730
731         tmp_minmax = g_malloc(sizeof(sctp_min_max_t));
732
733         u_data->io->tmp_min_tsn1=u_data->io->y1_tmp+u_data->io->min_y;
734         u_data->io->tmp_max_tsn1=u_data->io->y2_tmp+1+u_data->io->min_y;
735
736         u_data->io->tmp_min_tsn2=u_data->io->tmp_min_tsn1;
737         u_data->io->tmp_max_tsn2=u_data->io->tmp_max_tsn1;
738         tmp_minmax->tmp_min_secs=u_data->io->x1_tmp_sec;
739         tmp_minmax->tmp_min_usecs=u_data->io->x1_tmp_usec;
740         tmp_minmax->tmp_max_secs=u_data->io->x2_tmp_sec;
741         tmp_minmax->tmp_max_usecs=u_data->io->x2_tmp_usec;
742         tmp_minmax->tmp_min_tsn1=u_data->io->tmp_min_tsn1;
743         tmp_minmax->tmp_max_tsn1=u_data->io->tmp_max_tsn1;
744         tmp_minmax->tmp_min_tsn2=u_data->io->tmp_min_tsn2;
745         tmp_minmax->tmp_max_tsn2=u_data->io->tmp_max_tsn2;
746         u_data->assoc->min_max = g_slist_prepend(u_data->assoc->min_max, tmp_minmax);
747         u_data->io->length = g_slist_length(u_data->assoc->min_max);
748         u_data->io->tmp=TRUE;
749         u_data->io->rectangle=FALSE;
750         gtk_widget_set_sensitive(zoomout_bt, TRUE);
751         sctp_graph_redraw(u_data);
752 }
753
754 static void
755 on_zoomout_bt (GtkWidget *widget _U_, struct sctp_udata *u_data)
756 {
757         sctp_min_max_t *tmp_minmax, *mm;
758         gint l;
759
760         l = g_slist_length(u_data->assoc->min_max);
761
762         if (u_data->assoc->min_max!=NULL)
763         {
764                 mm=(sctp_min_max_t *)((u_data->assoc->min_max)->data);
765                 u_data->assoc->min_max=g_slist_remove(u_data->assoc->min_max, mm);
766                 g_free(mm);
767
768                 if (l>2)
769                 {
770                         tmp_minmax = (sctp_min_max_t *)u_data->assoc->min_max->data;
771                         u_data->io->x1_tmp_sec=tmp_minmax->tmp_min_secs;
772                         u_data->io->x1_tmp_usec=tmp_minmax->tmp_min_usecs;
773                         u_data->io->x2_tmp_sec=tmp_minmax->tmp_max_secs;
774                         u_data->io->x2_tmp_usec=tmp_minmax->tmp_max_usecs;
775                         u_data->io->tmp_min_tsn1=tmp_minmax->tmp_min_tsn1;
776                         u_data->io->tmp_max_tsn1=tmp_minmax->tmp_max_tsn1;
777                         u_data->io->tmp_min_tsn2=tmp_minmax->tmp_min_tsn2;
778                         u_data->io->tmp_max_tsn2=tmp_minmax->tmp_max_tsn2;
779                         u_data->io->tmp=TRUE;
780                 }
781                 else
782                 {
783                         u_data->io->x1_tmp_sec=u_data->assoc->min_secs;
784                         u_data->io->x1_tmp_usec=u_data->assoc->min_usecs;
785                         u_data->io->x2_tmp_sec=u_data->assoc->max_secs;
786                         u_data->io->x2_tmp_usec=u_data->assoc->max_usecs;
787                         u_data->io->tmp_min_tsn1=0;
788                         u_data->io->tmp_max_tsn1=u_data->assoc->max_bytes1;
789                         u_data->io->tmp_min_tsn2=0;
790                         u_data->io->tmp_max_tsn2=u_data->assoc->max_bytes2;
791                         u_data->io->tmp=FALSE;
792                 }
793         }
794         else
795         {
796                 u_data->io->x1_tmp_sec=u_data->assoc->min_secs;
797                 u_data->io->x1_tmp_usec=u_data->assoc->min_usecs;
798                 u_data->io->x2_tmp_sec=u_data->assoc->max_secs;
799                 u_data->io->x2_tmp_usec=u_data->assoc->max_usecs;
800                 u_data->io->tmp_min_tsn1=0;
801                 u_data->io->tmp_max_tsn1=u_data->assoc->max_bytes1;
802                 u_data->io->tmp_min_tsn2=0;
803                 u_data->io->tmp_max_tsn2=u_data->assoc->max_bytes2;
804                 u_data->io->tmp=FALSE;
805         }
806         if (g_slist_length(u_data->assoc->min_max)==1)
807                 gtk_widget_set_sensitive(zoomout_bt, FALSE);
808         sctp_graph_redraw(u_data);
809 }
810
811
812 static gint
813 on_button_press (GtkWidget *widget _U_, GdkEventButton *event, struct sctp_udata *u_data)
814 {
815         sctp_graph_t *ios;
816
817         if (u_data->io->rectangle==TRUE)
818         {
819                 gdk_draw_rectangle(u_data->io->pixmap,u_data->io->draw_area->style->white_gc,
820                                    FALSE,
821                                    (gint)floor(MIN(u_data->io->x_old,u_data->io->x_new)),
822                                    (gint)floor(MIN(u_data->io->y_old,u_data->io->y_new)),
823                                    (gint)abs((long)(u_data->io->x_new-u_data->io->x_old)),
824                                    (gint)abs((long)(u_data->io->y_new-u_data->io->y_old)));
825                 ios=(sctp_graph_t *)g_object_get_data(G_OBJECT(u_data->io->draw_area), "sctp_graph_t");
826
827                 if(!ios){
828                         exit(10);
829                 }
830
831                 gdk_draw_pixmap(u_data->io->draw_area->window,
832                                 u_data->io->draw_area->style->fg_gc[GTK_WIDGET_STATE(u_data->io->draw_area)],
833                                 ios->pixmap,
834                                 0, 0,
835                                 0, 0,
836                                 (gint)abs((long)(u_data->io->x_new-u_data->io->x_old)),
837                                 (gint)abs((long)(u_data->io->y_new-u_data->io->y_old)));
838                 sctp_graph_redraw(u_data);
839         }
840
841         u_data->io->x_old=event->x;
842         u_data->io->y_old=event->y;
843         if (u_data->io->y_old>u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset)
844                 u_data->io->y_old=u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset;
845         if (u_data->io->x_old<LEFT_BORDER+u_data->io->offset)
846                 u_data->io->x_old=LEFT_BORDER+u_data->io->offset;
847         u_data->io->rectangle=FALSE;
848
849         return TRUE;
850 }
851
852
853 static gint
854 on_button_release (GtkWidget *widget _U_, GdkEventButton *event, struct sctp_udata *u_data)
855 {
856         sctp_graph_t *ios;
857         guint32 helpx, helpy, x1_tmp, x2_tmp, y_value, frame;
858         gint label_width, label_height;
859         gdouble x_value, position, tfirst;
860         gint lwidth;
861         char label_string[30];
862         GdkGC *text_color;
863         GList *tsnlist=NULL;
864         tsn_t *tsn, *tmptsn;
865         PangoLayout  *layout;
866         g_snprintf(label_string, 15, "%d", 0);
867         memcpy(label_string,(gchar *)g_locale_to_utf8(label_string, -1 , NULL, NULL, NULL), 15);
868         layout = gtk_widget_create_pango_layout(u_data->io->draw_area, label_string);
869         pango_layout_get_pixel_size(layout, &label_width, &label_height);
870
871         if (event->y > u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset)
872                 event->y = u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset;
873         if (event->x < LEFT_BORDER+u_data->io->offset)
874                 event->x = LEFT_BORDER+u_data->io->offset;
875
876         if (abs((long)(event->x-u_data->io->x_old))>10 || abs((long)(event->y-u_data->io->y_old))>10)
877         {
878                 u_data->io->rect_x_min = (guint32) floor(MIN(u_data->io->x_old,event->x));
879                 u_data->io->rect_x_max = (guint32) ceil(MAX(u_data->io->x_old,event->x));
880                 u_data->io->rect_y_min = (guint32) floor(MIN(u_data->io->y_old,event->y));
881                 u_data->io->rect_y_max = (guint32) ceil(MAX(u_data->io->y_old,event->y));
882                 gdk_draw_rectangle(u_data->io->pixmap,u_data->io->draw_area->style->black_gc,
883                                    FALSE,
884                                    u_data->io->rect_x_min, u_data->io->rect_y_min,
885                                    u_data->io->rect_x_max - u_data->io->rect_x_min,
886                                    u_data->io->rect_y_max - u_data->io->rect_y_min);
887                 ios=(sctp_graph_t *)g_object_get_data(G_OBJECT(u_data->io->draw_area), "sctp_graph_t");
888
889                 if(!ios){
890                         exit(10);
891                 }
892
893                 gdk_draw_pixmap(u_data->io->draw_area->window,
894                                 u_data->io->draw_area->style->fg_gc[GTK_WIDGET_STATE(u_data->io->draw_area)],
895                                 ios->pixmap,
896                                 0, 0,
897                                 0, 0,
898                                 u_data->io->draw_area->allocation.width,
899                                 u_data->io->draw_area->allocation.height);
900
901                 x1_tmp=(guint32) 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));
902                 x2_tmp=(guint32) floor(u_data->io->min_x+((event->x-LEFT_BORDER-u_data->io->offset)*u_data->io->tmp_width/u_data->io->axis_width));
903                 helpx=MIN(x1_tmp, x2_tmp);
904                 if (helpx==x2_tmp)
905                 {
906                         x2_tmp=x1_tmp;
907                         x1_tmp=helpx;
908                 }
909                 if (u_data->io->uoff)
910                 {
911                         if (x2_tmp - x1_tmp <= 1500)                    
912                                 u_data->io->uoff = FALSE;
913                         u_data->io->x1_tmp_sec=(guint32)x1_tmp;
914                         u_data->io->x1_tmp_usec=0;
915                         u_data->io->x2_tmp_sec=(guint32)x2_tmp;
916                         u_data->io->x2_tmp_usec=0;
917                 }
918                 else 
919                 {
920                         u_data->io->x1_tmp_sec=(guint32)x1_tmp/1000000;
921                         u_data->io->x1_tmp_usec=x1_tmp%1000000;
922                         u_data->io->x2_tmp_sec=(guint32)x2_tmp/1000000;
923                         u_data->io->x2_tmp_usec=x2_tmp%1000000;
924                 }
925                 u_data->io->x1_akt_sec = u_data->io->x1_tmp_sec;
926                 u_data->io->x1_akt_usec = u_data->io->x1_tmp_usec;
927                 u_data->io->x2_akt_sec = u_data->io->x2_tmp_sec;
928                 u_data->io->x2_akt_usec = u_data->io->x2_tmp_usec;
929
930                 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);
931                 u_data->io->y2_tmp=(guint32)((u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset-event->y)/u_data->io->y_interval);
932                 helpy = MIN(u_data->io->y1_tmp, u_data->io->y2_tmp);
933                 u_data->io->y2_tmp = MAX(u_data->io->y1_tmp, u_data->io->y2_tmp);
934                 u_data->io->y1_tmp = helpy;
935                 u_data->io->x_new=event->x;
936                 u_data->io->y_new=event->y;
937                 u_data->io->rectangle=TRUE;
938                 u_data->io->rectangle_present=TRUE;
939         }
940                 else
941         {
942                 if (u_data->io->rectangle_present==TRUE)
943                 {
944                         u_data->io->rectangle_present=FALSE;
945                         if (event->x >= u_data->io->rect_x_min && event->x <= u_data->io->rect_x_max && 
946                              event->y >= u_data->io->rect_y_min && event->y <= u_data->io->rect_y_max)
947                                 zoomin_bt(u_data);
948                         else
949                         {
950                                 u_data->io->x1_tmp_sec = u_data->io->x1_akt_sec;
951                                 u_data->io->x1_tmp_usec = u_data->io->x1_akt_usec;
952                                 u_data->io->x2_tmp_sec = u_data->io->x2_akt_sec;
953                                 u_data->io->x2_tmp_usec = u_data->io->x2_akt_usec;
954                                 sctp_graph_redraw(u_data);
955                         }
956                 }
957                 else if (label_set)
958                 {
959                         label_set = FALSE;
960                         sctp_graph_redraw(u_data);
961                 }
962                 else
963                 {
964                         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-RIGHT_BORDER-u_data->io->offset))+u_data->io->x1_tmp_sec+u_data->io->x1_tmp_usec/1000000.0;
965                         y_value = (guint32) 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;
966                         text_color = u_data->io->draw_area->style->black_gc;
967
968                         if (u_data->dir == 1)
969                                 tsnlist = g_list_last(u_data->assoc->tsn1);
970                         else
971                                 tsnlist = g_list_last(u_data->assoc->tsn2);
972
973                         tsn = (tsn_t*) (tsnlist->data);
974                         tmptsn =(tsn_t*)(tsnlist->data);
975                         tfirst = tsn->secs + tsn->usecs/1000000.0;
976                         frame = tsn->frame_number;
977                         
978                         while (tsnlist)
979                         {
980                                 tsnlist = g_list_previous(tsnlist);
981                                 tsn = (tsn_t*) (tsnlist->data);
982                                 if (tsn->secs+tsn->usecs/1000000.0<x_value)
983                                 {
984                                         tfirst = tsn->secs+tsn->usecs/1000000.0;
985                                         tmptsn =tsn;
986                                 }
987                                 else
988                                 {
989                                         if ((tfirst+tsn->secs+tsn->usecs/1000000.0)/2.0<x_value)
990                                         {
991                                                 x_value = tsn->secs+tsn->usecs/1000000.0;
992                                                 tmptsn = tsn;
993                                         }
994                                         else
995                                                 x_value = tmptsn->secs+tmptsn->usecs/1000000.0;
996                                         break;
997                                 }
998                         }
999                         cf_goto_frame(&cfile, tmptsn->frame_number);
1000                         g_snprintf(label_string, 30, "(%.6f, %u)", x_value, y_value);
1001                         label_set = TRUE;
1002
1003                         gdk_draw_line(u_data->io->pixmap,text_color, (gint)(event->x-2), (gint)(event->y), (gint)(event->x+2), (gint)(event->y));
1004                         gdk_draw_line(u_data->io->pixmap,text_color, (gint)(event->x), (gint)(event->y-2), (gint)(event->x), (gint)(event->y+2));
1005                         if (event->x+150>=u_data->io->pixmap_width)
1006                                 position = event->x - 150;
1007                         else
1008                                 position = event->x + 5;
1009
1010                         memcpy(label_string,(gchar *)g_locale_to_utf8(label_string, -1 , NULL, NULL, NULL), 15);
1011                         pango_layout_set_text(layout, label_string, -1);
1012                         pango_layout_get_pixel_size(layout, &lwidth, NULL);
1013
1014                         gdk_draw_layout(u_data->io->pixmap,text_color,
1015                                         (gint)(position),
1016                                         (gint)(event->y-10),
1017                                         layout);
1018                         ios=(sctp_graph_t *)g_object_get_data(G_OBJECT(u_data->io->draw_area), "sctp_graph_t");
1019
1020                         if(!ios){
1021                                 exit(10);
1022                         }
1023                         gdk_draw_pixmap(u_data->io->draw_area->window,
1024                                     u_data->io->draw_area->style->fg_gc[GTK_WIDGET_STATE(u_data->io->draw_area)],
1025                                     ios->pixmap,
1026                                     0, 0,
1027                                     0, 0,
1028                                     u_data->io->draw_area->allocation.width,
1029                                     u_data->io->draw_area->allocation.height);
1030                 }
1031         }
1032         return TRUE;
1033 }
1034
1035 static void init_sctp_graph_window(struct sctp_udata *u_data)
1036 {
1037         GtkWidget *vbox;
1038         GtkWidget *hbox;
1039         GtkWidget *bt_close, *sack_bt, *tsn_bt, *both_bt, *zoomin_bt;
1040         GtkTooltips *tooltip_in, *tooltip_out;
1041
1042         /* create the main window */
1043
1044         u_data->io->window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
1045
1046         gtk_widget_set_name(u_data->io->window, "SCTP Graphics");
1047
1048         vbox=gtk_vbox_new(FALSE, 0);
1049         gtk_container_add(GTK_CONTAINER(u_data->io->window), vbox);
1050         gtk_widget_show(vbox);
1051
1052         create_draw_area(vbox, u_data);
1053
1054         sctp_graph_set_title(u_data);
1055
1056         hbox = gtk_hbutton_box_new();
1057         gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1058         gtk_container_set_border_width(GTK_CONTAINER(hbox), 10);
1059         gtk_button_box_set_layout(GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_SPREAD);
1060         gtk_button_box_set_spacing(GTK_BUTTON_BOX (hbox), 0);
1061         gtk_box_set_child_packing(GTK_BOX(vbox), hbox, FALSE, FALSE, 0, GTK_PACK_START);
1062         gtk_widget_show(hbox);
1063
1064         sack_bt = gtk_button_new_with_label ("Adv. Rec. Window");
1065         gtk_box_pack_start(GTK_BOX(hbox), sack_bt, FALSE, FALSE, 0);
1066         gtk_widget_show(sack_bt);
1067
1068         gtk_signal_connect(GTK_OBJECT(sack_bt), "clicked", (GtkSignalFunc)on_sack_bt, u_data);
1069
1070         tsn_bt = gtk_button_new_with_label ("Data bytes sent");
1071         gtk_box_pack_start(GTK_BOX(hbox), tsn_bt, FALSE, FALSE, 0);
1072         gtk_widget_show(tsn_bt);
1073         g_signal_connect(tsn_bt, "clicked", G_CALLBACK(on_tsn_bt), u_data);
1074
1075         both_bt = gtk_button_new_with_label ("Show both");
1076         gtk_box_pack_start(GTK_BOX(hbox), both_bt, FALSE, FALSE, 0);
1077         gtk_widget_show(both_bt);
1078         g_signal_connect(both_bt, "clicked", G_CALLBACK(on_both_bt), u_data);
1079
1080         zoomin_bt = gtk_button_new_with_label ("Zoom in");
1081         gtk_box_pack_start(GTK_BOX(hbox), zoomin_bt, FALSE, FALSE, 0);
1082         gtk_widget_show(zoomin_bt);
1083         g_signal_connect(zoomin_bt, "clicked", G_CALLBACK(on_zoomin_bt), u_data);
1084         tooltip_in = gtk_tooltips_new();
1085         gtk_tooltips_set_tip(tooltip_in, zoomin_bt, "Zoom in the area you have selected", NULL);
1086
1087         zoomout_bt = gtk_button_new_with_label ("Zoom out");
1088         gtk_box_pack_start(GTK_BOX(hbox), zoomout_bt, FALSE, FALSE, 0);
1089         gtk_widget_show(zoomout_bt);
1090         g_signal_connect(zoomout_bt, "clicked", G_CALLBACK(on_zoomout_bt), u_data);
1091         tooltip_out = gtk_tooltips_new();
1092         gtk_tooltips_set_tip(tooltip_out, zoomout_bt, "Zoom out one step", NULL);
1093         gtk_widget_set_sensitive(zoomout_bt, FALSE);
1094
1095         bt_close = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1096         gtk_box_pack_start(GTK_BOX(hbox), bt_close, FALSE, FALSE, 0);
1097         gtk_widget_show(bt_close);
1098         g_signal_connect(bt_close, "clicked", G_CALLBACK(sctp_graph_close_cb), u_data);
1099
1100         gtk_signal_connect(GTK_OBJECT(u_data->io->draw_area),"button_press_event",(GtkSignalFunc)on_button_press, u_data);
1101         gtk_signal_connect(GTK_OBJECT(u_data->io->draw_area),"button_release_event",(GtkSignalFunc)on_button_release, u_data);
1102         gtk_widget_set_events(u_data->io->draw_area, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_EXPOSURE_MASK);
1103         /* dlg_set_cancel(u_data->io->window, bt_close); */
1104
1105
1106         gtk_widget_show(u_data->io->window);
1107 }
1108
1109 static void sctp_graph_set_title(struct sctp_udata *u_data)
1110 {
1111         char *title;
1112
1113         if(!u_data->io->window)
1114         {
1115                 return;
1116         }
1117         title = g_strdup_printf("SCTP Data and Adv.Rcv.Window over Time: %s Port1 %u Port2 %u Endpoint %u",
1118                                 cf_get_display_name(&cfile), u_data->parent->assoc->port1, u_data->parent->assoc->port2, u_data->dir);
1119         gtk_window_set_title(GTK_WINDOW(u_data->io->window), title);
1120         g_free(title);
1121 }
1122
1123
1124 static void
1125 gtk_sctpgraph_init(struct sctp_udata *u_data)
1126 {
1127         sctp_graph_t *io;
1128         gint dir;
1129         sctp_min_max_t* tmp_minmax;
1130
1131         io=g_malloc(sizeof(sctp_graph_t));
1132         io->needs_redraw=TRUE;
1133         io->x_interval=1000;
1134         io->window=NULL;
1135         io->draw_area=NULL;
1136         io->pixmap=NULL;
1137         io->pixmap_width=800;
1138         io->pixmap_height=600;
1139         io->graph_type=0;
1140         dir=u_data->dir-1;
1141         u_data->io=io;
1142
1143
1144         u_data->io->x1_tmp_sec=u_data->assoc->min_secs;
1145         u_data->io->x1_tmp_usec=u_data->assoc->min_usecs;
1146         u_data->io->x2_tmp_sec=u_data->assoc->max_secs;
1147         u_data->io->x2_tmp_usec=u_data->assoc->max_usecs;
1148         u_data->io->tmp_min_tsn1=0;
1149         u_data->io->tmp_max_tsn1=u_data->assoc->max_bytes1;
1150         u_data->io->tmp_min_tsn2=0;
1151         u_data->io->tmp_max_tsn2=u_data->assoc->max_bytes2;
1152         u_data->io->tmp=FALSE;
1153         tmp_minmax = g_malloc(sizeof(sctp_min_max_t));
1154         tmp_minmax->tmp_min_secs = u_data->assoc->min_secs;
1155         tmp_minmax->tmp_min_usecs=u_data->assoc->min_usecs;
1156         tmp_minmax->tmp_max_secs=u_data->assoc->max_secs;
1157         tmp_minmax->tmp_max_usecs=u_data->assoc->max_usecs;
1158         tmp_minmax->tmp_min_tsn2=u_data->io->tmp_min_tsn2;
1159         tmp_minmax->tmp_min_tsn1=u_data->io->tmp_min_tsn1;
1160         tmp_minmax->tmp_max_tsn1=u_data->io->tmp_max_tsn1;
1161         tmp_minmax->tmp_max_tsn2=u_data->io->tmp_max_tsn2;
1162         u_data->assoc->min_max = g_slist_prepend(u_data->assoc->min_max, tmp_minmax);
1163
1164         /* build the GUI */
1165         init_sctp_graph_window(u_data);
1166         sctp_graph_redraw(u_data);
1167 }
1168
1169
1170 static gint
1171 quit(GtkObject *object _U_, gpointer user_data)
1172 {
1173         struct sctp_udata *u_data=(struct sctp_udata*)user_data;
1174
1175         decrease_childcount(u_data->parent);
1176         remove_child(u_data, u_data->parent);
1177         g_free(u_data->io);
1178         u_data->assoc->min_max = NULL;
1179         g_free(u_data);
1180         return TRUE;
1181 }
1182
1183
1184 static void create_draw_area(GtkWidget *box, struct sctp_udata *u_data)
1185 {
1186         u_data->io->draw_area=gtk_drawing_area_new();
1187         g_signal_connect(u_data->io->draw_area, "destroy", G_CALLBACK(quit), u_data);
1188         g_object_set_data(G_OBJECT(u_data->io->draw_area), "sctp_graph_t", u_data->io);
1189
1190         gtk_widget_set_size_request(u_data->io->draw_area, u_data->io->pixmap_width, u_data->io->pixmap_height);
1191
1192         /* signals needed to handle backing pixmap */
1193         g_signal_connect(u_data->io->draw_area, "expose_event", G_CALLBACK(expose_event), NULL);
1194         g_signal_connect(u_data->io->draw_area, "configure_event", G_CALLBACK(configure_event), u_data);
1195
1196         gtk_widget_show(u_data->io->draw_area);
1197         gtk_box_pack_start(GTK_BOX(box), u_data->io->draw_area, TRUE, TRUE, 0);
1198 }
1199
1200 static void insertion(GPtrArray *array, guint32 N)
1201 {
1202         guint32 i, j;
1203         guint32 v;
1204         struct tsn_sort *help=NULL;
1205
1206         for (i=1; i<N; i++)
1207         {
1208                 v = ((struct tsn_sort*)(g_ptr_array_index(array,i)))->tsnumber;
1209                 j=i;
1210                 while (j>=1 && ((struct tsn_sort*)(g_ptr_array_index(array, j-1)))->tsnumber > v)
1211                 {
1212                         help=g_ptr_array_index(array, j);
1213                         g_ptr_array_index(array, j)=g_ptr_array_index(array, j-1);
1214                         g_ptr_array_index(array, j-1)=help;
1215                         j--;
1216                 }
1217                 ((struct tsn_sort*)(g_ptr_array_index(array, j)))->tsnumber=v;
1218         }
1219 }
1220
1221 static void set_arw_offsets(struct sctp_udata *u_data)
1222 {
1223         GPtrArray *s_array=NULL, *t_array=NULL;
1224         guint32 i, j=0;
1225
1226         if (u_data->dir==1 && u_data->assoc->n_sack_chunks_ep1>0)
1227         {
1228                 s_array=u_data->assoc->sort_sack1;
1229                 t_array=u_data->assoc->sort_tsn1;
1230                 insertion(s_array,u_data->assoc->n_sack_chunks_ep1);
1231
1232                 for (i=0; i<u_data->assoc->n_sack_chunks_ep1; i++)
1233                 {
1234                         while (((struct tsn_sort*)(g_ptr_array_index(s_array, i)))->tsnumber > ((struct tsn_sort*)(g_ptr_array_index(t_array, j)))->tsnumber)
1235                         {
1236                                 j++;
1237                         }
1238                         ((struct tsn_sort*)(g_ptr_array_index(s_array,i)))->offset = ((struct tsn_sort*)(g_ptr_array_index(t_array, j)))->offset
1239                           + ((struct tsn_sort*)(g_ptr_array_index(t_array, j)))->length;
1240                 }
1241
1242                 u_data->assoc->sort_sack1=s_array;
1243         }
1244
1245         if (u_data->dir==2 && u_data->assoc->n_sack_chunks_ep2>0)
1246         {
1247                 s_array=u_data->assoc->sort_sack2;
1248                 t_array=u_data->assoc->sort_tsn2;
1249                 insertion(s_array,u_data->assoc->n_sack_chunks_ep2);
1250                 j=0;
1251                 for (i=0; i<u_data->assoc->n_sack_chunks_ep2; i++)
1252                 {
1253                         while (((struct tsn_sort*)(g_ptr_array_index(s_array, i)))->tsnumber > ((struct tsn_sort*)(g_ptr_array_index(t_array,j)))->tsnumber)
1254                         {
1255                                 j++;
1256                         }
1257                         ((struct tsn_sort*)(g_ptr_array_index(s_array, i)))->offset = ((struct tsn_sort*)(g_ptr_array_index(t_array, j)))->offset
1258                          + ((struct tsn_sort*)(g_ptr_array_index(t_array, j)))->length;
1259                 }
1260                 u_data->assoc->sort_sack2=s_array;
1261         }
1262 }
1263
1264 static void compute_offsets(struct sctp_udata *u_data)
1265 {
1266         struct tsn_sort t_sort;
1267         GPtrArray *array=NULL;
1268         guint32 i;
1269         guint32 sum=0;
1270         guint32 tsntmp=0;
1271
1272         if (u_data->dir==1 && u_data->assoc->n_array_tsn1>0)
1273         {
1274                 array=u_data->assoc->sort_tsn1;
1275                 insertion(array,u_data->assoc->n_array_tsn1);
1276
1277                 for (i=0; i<u_data->assoc->n_array_tsn1; i++)
1278                 {
1279                         ((struct tsn_sort*)(g_ptr_array_index(array, i)))->offset=sum;
1280                         t_sort.tsnumber=((struct tsn_sort*)(g_ptr_array_index(array, i)))->tsnumber;
1281                         if (t_sort.tsnumber>tsntmp)
1282                                 sum+=((struct tsn_sort*)(g_ptr_array_index(array, i)))->length;
1283                         tsntmp=t_sort.tsnumber;
1284                 }
1285                 u_data->assoc->max_bytes1= ((struct tsn_sort*)(g_ptr_array_index(array, i-1)))->offset + ((struct tsn_sort*)(g_ptr_array_index(array, i-1)))->length;
1286                 u_data->assoc->sort_tsn1=array;
1287         }
1288         if (u_data->dir==2 && u_data->assoc->n_array_tsn2>0)
1289         {
1290                 sum=0;
1291                 array=u_data->assoc->sort_tsn2;
1292                 insertion(array,u_data->assoc->n_array_tsn2);
1293
1294                 for (i=0; i<u_data->assoc->n_array_tsn2; i++)
1295                 {
1296                         ((struct tsn_sort*)(g_ptr_array_index(array,i)))->offset=sum;
1297                         t_sort.tsnumber=((struct tsn_sort*)(g_ptr_array_index(array, i)))->tsnumber;
1298                         if (t_sort.tsnumber>tsntmp)
1299                                 sum+=((struct tsn_sort*)(g_ptr_array_index(array, i)))->length;
1300                         tsntmp=t_sort.tsnumber;
1301                 }
1302
1303                 u_data->assoc->max_bytes2= ((struct tsn_sort*)(g_ptr_array_index(array,  u_data->assoc->n_data_chunks_ep2-1)))->offset + ((struct tsn_sort*)(g_ptr_array_index(array,  u_data->assoc->n_data_chunks_ep2-1)))->length;
1304                 u_data->assoc->sort_tsn2=array;
1305         }
1306 }
1307
1308 void create_byte_graph(guint16 dir, struct sctp_analyse* userdata)
1309 {
1310         struct sctp_udata *u_data;
1311
1312         u_data=g_malloc(sizeof(struct sctp_udata));
1313         u_data->assoc=g_malloc(sizeof(sctp_assoc_info_t));
1314         u_data->assoc=userdata->assoc;
1315         u_data->io=NULL;
1316         u_data->dir = dir;
1317         u_data->parent = userdata;
1318         if ((u_data->dir==1 && (u_data->assoc->n_array_tsn1==0))|| (u_data->dir==2 && (u_data->assoc->n_array_tsn2==0)))
1319                 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, "No Data Chunks sent");
1320         else
1321         {
1322                 set_child(u_data, u_data->parent);
1323                 increase_childcount(u_data->parent);
1324                 compute_offsets(u_data);
1325                 set_arw_offsets(u_data);
1326                 gtk_sctpgraph_init(u_data);
1327         }
1328
1329 }
1330