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