2 * io_stat 2002 Ronnie Sahlberg
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
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.
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.
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.
30 #ifdef HAVE_SYS_TYPES_H
31 # include <sys/types.h>
40 #include <epan/epan_dissect.h>
41 #include <epan/packet_info.h>
43 #include "gtkglobals.h"
44 #include "gui_utils.h"
45 #include <epan/stat_cmd_args.h>
46 #include "../stat_menu.h"
47 #include "gui_stat_menu.h"
49 #include "../register.h"
50 #include "alert_box.h"
51 #include "simple_dialog.h"
52 #include "../globals.h"
54 #include "compat_macros.h"
55 #include "dlg_utils.h"
56 #include "filter_dlg.h"
58 #include "pixmap_save.h"
59 #include <epan/strutil.h>
61 void protect_thread_critical_region(void);
62 void unprotect_thread_critical_region(void);
67 #define LOGARITHMIC_YSCALE 0
68 #define AUTO_MAX_YSCALE 1
69 #define DEFAULT_YSCALE 1
70 static guint32 yscale_max[MAX_YSCALE] = {LOGARITHMIC_YSCALE, AUTO_MAX_YSCALE, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000, 2000000, 5000000, 10000000, 20000000, 50000000, 100000000, 200000000, 500000000, 1000000000, 2000000000};
72 #define MAX_PIXELS_PER_TICK 4
73 #define DEFAULT_PIXELS_PER_TICK 2
74 static guint32 pixels_per_tick[MAX_PIXELS_PER_TICK] = {1, 2, 5, 10};
77 #define DEFAULT_PLOT_STYLE 0
78 #define PLOT_STYLE_LINE 0
79 #define PLOT_STYLE_IMPULSE 1
80 #define PLOT_STYLE_FILLED_BAR 2
81 #define PLOT_STYLE_DOT 3
82 #define MAX_PLOT_STYLES 4
83 static const char *plot_style_name[MAX_PLOT_STYLES] = {
91 #define COUNT_TYPE_FRAMES 0
92 #define COUNT_TYPE_BYTES 1
93 #define COUNT_TYPE_BITS 2
94 #define COUNT_TYPE_ADVANCED 3
95 #define MAX_COUNT_TYPES 4
96 static const char *count_type_names[MAX_COUNT_TYPES] = {"Packets/Tick", "Bytes/Tick", "Bits/Tick", "Advanced..."};
99 #define MAX_TICK_VALUES 7
100 #define DEFAULT_TICK_VALUE 3
101 static const guint tick_interval_values[MAX_TICK_VALUES] = { 1, 10, 100, 1000, 10000, 60000, 600000 };
103 #define CALC_TYPE_SUM 0
104 #define CALC_TYPE_COUNT 1
105 #define CALC_TYPE_MAX 2
106 #define CALC_TYPE_MIN 3
107 #define CALC_TYPE_AVG 4
108 #define CALC_TYPE_LOAD 5
109 #define MAX_CALC_TYPES 6
110 static const char *calc_type_names[MAX_CALC_TYPES] = {"SUM(*)", "COUNT(*)", "MAX(*)", "MIN(*)", "AVG(*)", "LOAD(*)"};
113 typedef struct _io_stat_calc_type_t {
114 struct _io_stat_graph_t *gio;
116 } io_stat_calc_type_t;
118 #define NUM_IO_ITEMS 100000
119 typedef struct _io_item_t {
120 guint32 frames; /* always calculated, will hold number of frames*/
121 guint32 bytes; /* always calculated, will hold number of bytes*/
131 typedef struct _io_stat_graph_t {
132 struct _io_stat_t *io;
133 io_item_t items[NUM_IO_ITEMS];
136 GtkWidget *display_button;
137 GtkWidget *filter_field;
138 GtkWidget *advanced_buttons;
140 io_stat_calc_type_t calc_types[MAX_CALC_TYPES];
142 GtkWidget *calc_field;
145 construct_args_t *args;
146 GtkWidget *filter_bt;
150 typedef struct _io_stat_t {
151 gboolean needs_redraw;
152 gint32 interval; /* measurement interval in ms */
153 guint32 last_interval;
154 guint32 max_interval; /* XXX max_interval and num_items are redundant */
156 guint32 left_x_border;
157 guint32 right_x_border;
158 gboolean view_as_time;
161 struct _io_stat_graph_t graphs[MAX_GRAPHS];
163 GtkWidget *draw_area;
165 GtkAdjustment *scrollbar_adjustment;
166 GtkWidget *scrollbar;
167 guint first_frame_num[NUM_IO_ITEMS];
168 guint last_frame_num;
176 #if GTK_MAJOR_VERSION < 2
177 GtkRcStyle *rc_style;
178 GdkColormap *colormap;
183 static void init_io_stat_window(io_stat_t *io);
184 static gint filter_callback(GtkWidget *widget _U_, io_stat_graph_t *gio);
187 io_stat_set_title(io_stat_t *io)
194 title = g_strdup_printf("Wireshark IO Graphs: %s", cf_get_display_name(&cfile));
195 gtk_window_set_title(GTK_WINDOW(io->window), title);
200 io_stat_reset(io_stat_t *io)
204 io->needs_redraw=TRUE;
205 for(i=0;i<MAX_GRAPHS;i++){
206 for(j=0;j<NUM_IO_ITEMS;j++){
208 ioi=&io->graphs[i].items[j];
216 nstime_set_zero(&ioi->time_max);
217 nstime_set_zero(&ioi->time_min);
218 nstime_set_zero(&ioi->time_tot);
221 io->last_interval=0xffffffff;
224 io->start_time.secs=0;
225 io->start_time.nsecs=0;
226 for(j=0;j<NUM_IO_ITEMS;j++) {
227 io->first_frame_num[j]=0;
229 io->last_frame_num=0;
231 io_stat_set_title(io);
235 gtk_iostat_reset(void *g)
237 io_stat_graph_t *gio=g;
239 io_stat_reset(gio->io);
243 gtk_iostat_packet(void *g, packet_info *pinfo, epan_dissect_t *edt, const void *dummy _U_)
245 io_stat_graph_t *git=g;
250 /* we sometimes get called when git is disabled.
251 this is a bug since the tap listener should be removed first */
256 git->io->needs_redraw=TRUE;
259 * Find which interval this is supposed to go in and store the
260 * interval index as idx
262 time_delta=pinfo->fd->rel_ts;
263 if(time_delta.nsecs<0){
265 time_delta.nsecs+=1000000000;
267 if(time_delta.secs<0){
270 idx=(int) ((time_delta.secs*1000+time_delta.nsecs/1000000)/git->io->interval);
272 /* some sanity checks */
273 if((idx<0)||(idx>=NUM_IO_ITEMS)){
274 git->io->num_items = NUM_IO_ITEMS-1;
278 /* update num_items */
279 if((guint32)idx > git->io->num_items){
280 git->io->num_items=idx;
281 git->io->max_interval=(idx+1)*git->io->interval;
285 if(git->io->start_time.secs == 0 && git->io->start_time.nsecs == 0) {
286 git->io->start_time = pinfo->fd->abs_ts;
289 /* set first and last frame num in current interval */
290 if (git->io->first_frame_num[idx] == 0) {
291 git->io->first_frame_num[idx]=pinfo->fd->num;
293 git->io->last_frame_num=pinfo->fd->num;
296 * Find the appropriate io_item_t structure
302 * For ADVANCED mode we need to keep track of some more stuff
303 * than just frame and byte counts
305 if(git->io->count_type==COUNT_TYPE_ADVANCED){
309 gp=proto_get_finfo_ptr_array(edt->tree, git->hf_index);
314 /* update the appropriate counters, make sure that if
315 * fields==0 then this is the first seen value so
316 * set any min/max values accordingly
318 for(i=0;i<gp->len;i++){
322 switch(proto_registrar_get_ftype(git->hf_index)){
327 new_int=fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value);
329 if((new_int>it->int_max)||(it->fields==0)){
332 if((new_int<it->int_min)||(it->fields==0)){
335 it->int_tot+=new_int;
342 new_int=fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value);
343 if((new_int>it->int_max)||(it->fields==0)){
346 if((new_int<it->int_min)||(it->fields==0)){
349 it->int_tot+=new_int;
352 case FT_RELATIVE_TIME:
353 new_time=fvalue_get(&((field_info *)gp->pdata[0])->value);
355 switch(git->calc_type){
356 guint64 t, pt; /* time in us */
359 /* it is a LOAD calculation of a relative time field.
360 * add the time this call spanned to each
361 * interval it spanned according to its contribution
365 t=t*1000000+new_time->nsecs/1000;
367 /* handle current interval */
368 pt=pinfo->fd->rel_ts.secs*1000000+pinfo->fd->rel_ts.nsecs/1000;
369 pt=pt%(git->io->interval*1000);
374 git->items[i].time_tot.nsecs+=(int) (pt*1000);
375 if(git->items[i].time_tot.nsecs>1000000000){
376 git->items[i].time_tot.secs++;
377 git->items[i].time_tot.nsecs-=1000000000;
385 if(t > (guint32) (git->io->interval*1000)){
386 pt=git->io->interval*1000;
393 if( (new_time->secs>it->time_max.secs)
394 ||( (new_time->secs==it->time_max.secs)
395 &&(new_time->nsecs>it->time_max.nsecs))
397 it->time_max=*new_time;
399 if( (new_time->secs<it->time_min.secs)
400 ||( (new_time->secs==it->time_min.secs)
401 &&(new_time->nsecs<it->time_min.nsecs))
403 it->time_min=*new_time;
405 nstime_add(&it->time_tot, new_time);
413 it->bytes+=pinfo->fd->pkt_len;
419 get_frame_num(io_stat_t *io, guint32 idx, gboolean first)
421 guint i, frame_num=0;
423 if (idx>io->num_items) {
428 frame_num=io->first_frame_num[idx];
433 * If first frame not found we select the last
434 * frame in the previous interval
436 * If selecting the last frame we select the frame
437 * before the first frame in the next interval
439 for(i=idx+1;i<=io->num_items;i++) {
440 frame_num=io->first_frame_num[i];
441 if (frame_num != 0) {
447 * If not found we select the last frame
449 frame_num=io->last_frame_num;
456 get_it_value(io_stat_t *io, int graph_id, int idx)
462 it=&io->graphs[graph_id].items[idx];
464 switch(io->count_type){
465 case COUNT_TYPE_FRAMES:
467 case COUNT_TYPE_BYTES:
469 case COUNT_TYPE_BITS:
470 return (it->bytes * 8);
474 adv_type=proto_registrar_get_ftype(io->graphs[graph_id].hf_index);
477 switch(io->graphs[graph_id].calc_type){
478 case CALC_TYPE_COUNT:
493 switch(io->graphs[graph_id].calc_type){
497 case CALC_TYPE_COUNT:
508 value=it->int_tot/it->fields;
517 case FT_RELATIVE_TIME:
518 switch(io->graphs[graph_id].calc_type){
519 case CALC_TYPE_COUNT:
523 value=(guint32) (it->time_max.secs*1000000+it->time_max.nsecs/1000);
526 value=(guint32) (it->time_min.secs*1000000+it->time_min.nsecs/1000);
529 value=(guint32) (it->time_tot.secs*1000000+it->time_tot.nsecs/1000);
533 guint64 t; /* time in us */
536 t=t*1000000+it->time_tot.nsecs/1000;
537 value=(guint32) (t/it->fields);
543 value=(guint32) ((it->time_tot.secs*1000000+it->time_tot.nsecs/1000)/io->interval);
557 print_time_scale_string(char *buf, int buf_len, guint32 t, guint32 t_max, gboolean log)
559 if(t_max>=10000000 || (log && t_max>=1000000)){
560 g_snprintf(buf, buf_len, "%ds",t/1000000);
561 } else if(t_max>=1000000){
562 g_snprintf(buf, buf_len, "%d.%1ds",t/1000000,(t%1000000)/100000);
563 } else if(t_max>=10000 || (log && t_max>=1000)){
564 g_snprintf(buf, buf_len, "%dms",t/1000);
565 } else if(t_max>=1000){
566 g_snprintf(buf, buf_len, "%d.%1dms",t/1000,(t%1000)/100);
568 g_snprintf(buf, buf_len, "%dus",t);
574 print_interval_string(char *buf, int buf_len, guint32 interval, io_stat_t *io,
577 if (io->view_as_time) {
579 time_t sec_val = interval/1000 + io->start_time.secs;
580 gint32 nsec_val = interval%1000 + io->start_time.nsecs/1000000;
582 if(nsec_val >= 1000) {
586 tmp = localtime (&sec_val);
587 if(io->interval>=1000){
588 g_snprintf(buf, buf_len, "%02d:%02d:%02d", tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
589 } else if(io->interval>=100){
590 g_snprintf(buf, buf_len, "%02d:%02d:%02d.%1d", tmp->tm_hour, tmp->tm_min, tmp->tm_sec, nsec_val/100);
591 } else if(io->interval>=10){
592 g_snprintf(buf, buf_len, "%02d:%02d:%02d.%02d", tmp->tm_hour, tmp->tm_min, tmp->tm_sec, nsec_val/10);
594 g_snprintf(buf, buf_len, "%02d:%02d:%02d.%03d", tmp->tm_hour, tmp->tm_min, tmp->tm_sec, nsec_val);
597 if(io->interval>=60000 && ext){
598 g_snprintf(buf, buf_len, "%d%s", interval/60000, ext?"m":"");
599 } else if(io->interval>=1000){
600 g_snprintf(buf, buf_len, "%d%s", interval/1000, ext?"s":"");
601 } else if(io->interval>=100){
602 g_snprintf(buf, buf_len, "%d.%1d%s", interval/1000,(interval/100)%10, ext?"s":"");
603 } else if(io->interval>=10){
604 g_snprintf(buf, buf_len, "%d.%02d%s", interval/1000,(interval/10)%100, ext?"s":"");
606 g_snprintf(buf, buf_len, "%d.%03d%s", interval/1000,interval%1000, ext?"s":"");
612 io_stat_draw(io_stat_t *io)
614 int i, tics, ystart, ys;
615 guint32 last_interval, first_interval, interval_delta;
616 gint32 current_interval;
617 guint32 top_y_border;
618 guint32 bottom_y_border;
619 #if GTK_MAJOR_VERSION < 2
624 int label_width, label_height;
625 guint32 draw_width, draw_height;
626 char label_string[45];
629 guint32 num_time_intervals;
630 guint32 max_value; /* max value of seen data */
631 guint32 max_y; /* max value of the Y scale */
632 gboolean draw_y_as_time;
634 #if GTK_MAJOR_VERSION <2
635 font = io->draw_area->style->font;
638 if(!io->needs_redraw){
641 io->needs_redraw=FALSE;
645 * Find the length of the intervals we have data for
646 * so we know how large arrays we need to malloc()
648 num_time_intervals=io->num_items+1;
650 /* XXX move this check to _packet() */
651 if(num_time_intervals>NUM_IO_ITEMS){
652 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "IO-Stat error. There are too many entries, bailing out");
658 * find the max value so we can autoscale the y axis
661 for(i=0;i<MAX_GRAPHS;i++){
664 if(!io->graphs[i].display){
667 for(idx=0;(guint32) (idx) < num_time_intervals;idx++){
670 val=get_it_value(io, i, idx);
672 /* keep track of the max value we have encountered */
684 gdk_draw_rectangle(io->pixmap,
685 io->draw_area->style->white_gc,
688 io->draw_area->allocation.width,
689 io->draw_area->allocation.height);
692 * Calculate the y scale we should use
694 if(io->max_y_units==AUTO_MAX_YSCALE){
695 max_y=yscale_max[MAX_YSCALE-1];
696 for(i=MAX_YSCALE-1;i>1;i--){
697 if(max_value<yscale_max[i]){
701 } else if(io->max_y_units==LOGARITHMIC_YSCALE){
703 for(i=1000000000;i>1;i/=10){
704 if(max_value<(guint32)i){
709 /* the user had specified an explicit y scale to use */
710 max_y=io->max_y_units;
715 * If we use ADVANCED and all the graphs are plotting
716 * either MIN/MAX/AVG of an FT_RELATIVE_TIME field
717 * then we will do some some special processing for the
718 * labels for the Y axis below:
719 * we will append the time unit " s" " ms" or " us"
720 * and we will present the unit in decimal
722 draw_y_as_time=FALSE;
723 if(io->count_type==COUNT_TYPE_ADVANCED){
725 for(i=0;i<MAX_GRAPHS;i++){
728 if(!io->graphs[i].display){
731 adv_type=proto_registrar_get_ftype(io->graphs[i].hf_index);
733 case FT_RELATIVE_TIME:
734 switch(io->graphs[i].calc_type){
741 draw_y_as_time=FALSE;
745 draw_y_as_time=FALSE;
753 * Calculate size of borders surrounding the plot
754 * The border on the right side needs to be adjusted depending
755 * on the width of the text labels. For simplicity we assume that the
756 * top y scale label will be the widest one
759 if(io->max_y_units==LOGARITHMIC_YSCALE){
760 print_time_scale_string(label_string, 15, 100000, 100000, TRUE); /* 100 ms */
762 print_time_scale_string(label_string, 15, max_y, max_y, FALSE);
765 g_snprintf(label_string, 15, "%d", max_y);
767 #if GTK_MAJOR_VERSION < 2
768 label_width=gdk_string_width(font, label_string);
769 label_height=gdk_string_height(font, label_string);
771 layout = gtk_widget_create_pango_layout(io->draw_area, label_string);
772 pango_layout_get_pixel_size(layout, &label_width, &label_height);
774 io->left_x_border=10;
775 io->right_x_border=label_width+20;
777 bottom_y_border=label_height+20;
781 * Calculate the size of the drawing area for the actual plot
783 draw_width=io->pixmap_width-io->right_x_border-io->left_x_border;
784 draw_height=io->pixmap_height-top_y_border-bottom_y_border;
788 * Add a warning if too many entries
790 if (num_time_intervals == NUM_IO_ITEMS) {
791 g_snprintf (label_string, 45, "Warning: Graph limited to %d entries", NUM_IO_ITEMS);
792 #if GTK_MAJOR_VERSION < 2
793 gdk_draw_string(io->pixmap,
795 io->draw_area->style->black_gc, 5,
796 io->pixmap_height-bottom_y_border-draw_height+label_height/2,
799 pango_layout_set_text(layout, label_string, -1);
800 gdk_draw_layout(io->pixmap,
801 io->draw_area->style->black_gc, 5,
802 io->pixmap_height-bottom_y_border-draw_height-label_height/2,
808 * Draw the y axis and labels
809 * (we always draw the y scale with 11 ticks along the axis)
811 gdk_draw_line(io->pixmap, io->draw_area->style->black_gc,
812 io->pixmap_width-io->right_x_border+1,
814 io->pixmap_width-io->right_x_border+1,
815 io->pixmap_height-bottom_y_border);
817 if(io->max_y_units==LOGARITHMIC_YSCALE){
818 tics=(int)log10((double)max_y);
819 ystart=draw_height/10;
826 for(i=ys;i<=tics;i++){
827 int xwidth, lwidth, ypos;
830 if(io->max_y_units==LOGARITHMIC_YSCALE){
832 /* position for the 0 value */
833 ypos=io->pixmap_height-bottom_y_border;
835 /* position for the top value, do not draw logarithmic tics above graph */
836 ypos=io->pixmap_height-bottom_y_border-draw_height;
839 /* draw the logarithmic tics */
841 ypos=(int)(io->pixmap_height-bottom_y_border-(draw_height-ystart)*(i+log10((double)j))/tics-ystart);
843 gdk_draw_line(io->pixmap, io->draw_area->style->black_gc,
844 io->pixmap_width-io->right_x_border+1, ypos,
845 io->pixmap_width-io->right_x_border+1+xwidth, ypos);
847 ypos=io->pixmap_height-bottom_y_border-(draw_height-ystart)*i/tics-ystart;
849 /* all "main" logarithmic lines are slightly longer */
853 /* first, middle and last tick are slightly longer */
856 ypos=io->pixmap_height-bottom_y_border-draw_height*i/10;
859 gdk_draw_line(io->pixmap, io->draw_area->style->black_gc,
860 io->pixmap_width-io->right_x_border+1, ypos,
861 io->pixmap_width-io->right_x_border+1+xwidth, ypos);
862 /* draw the labels */
865 if(io->max_y_units==LOGARITHMIC_YSCALE){
866 value=(guint32)(max_y/pow(10,tics-i));
868 print_time_scale_string(label_string, 15, value, value, TRUE);
870 g_snprintf(label_string, 15, "%d", value);
875 print_time_scale_string(label_string, 15, value, max_y, FALSE);
877 g_snprintf(label_string, 15, "%d", value);
881 #if GTK_MAJOR_VERSION < 2
882 lwidth=gdk_string_width(font, label_string);
883 gdk_draw_string(io->pixmap,
885 io->draw_area->style->black_gc,
886 io->pixmap_width-io->right_x_border+15+label_width-lwidth,
890 pango_layout_set_text(layout, label_string, -1);
891 pango_layout_get_pixel_size(layout, &lwidth, NULL);
892 gdk_draw_layout(io->pixmap,
893 io->draw_area->style->black_gc,
894 io->pixmap_width-io->right_x_border+15+label_width-lwidth,
903 * if we have not specified the last_interval via the gui,
904 * then just pick the current end of the capture so that is scrolls
905 * nicely when doing live captures
907 if(io->last_interval==0xffffffff){
908 last_interval=io->max_interval;
910 last_interval=io->last_interval;
917 /* plot the x-scale */
918 gdk_draw_line(io->pixmap, io->draw_area->style->black_gc, io->left_x_border, io->pixmap_height-bottom_y_border+1, io->pixmap_width-io->right_x_border+1, io->pixmap_height-bottom_y_border+1);
920 if((last_interval/io->interval)>=draw_width/io->pixels_per_tick){
921 first_interval=(last_interval/io->interval)-draw_width/io->pixels_per_tick+1;
922 first_interval*=io->interval;
927 interval_delta=(100/io->pixels_per_tick)*io->interval;
928 for(current_interval=last_interval;current_interval>=(gint32)first_interval;current_interval=current_interval-io->interval){
931 /* if pixels_per_tick is 1 or 2, only draw every 10 ticks */
932 /* if pixels_per_tick is 5, only draw every 5 ticks */
933 if(((io->pixels_per_tick<5) && (current_interval%(10*io->interval))) ||
934 ((io->pixels_per_tick==5) && (current_interval%(5*io->interval)))){
938 if(!(current_interval%interval_delta)){
940 } else if(!(current_interval%(interval_delta/2))){
946 x=draw_width+io->left_x_border-((last_interval-current_interval)/io->interval)*io->pixels_per_tick;
947 gdk_draw_line(io->pixmap, io->draw_area->style->black_gc,
948 x-1-io->pixels_per_tick/2,
949 io->pixmap_height-bottom_y_border+1,
950 x-1-io->pixels_per_tick/2,
951 io->pixmap_height-bottom_y_border+xlen+1);
955 print_interval_string (label_string, 15, current_interval, io, TRUE);
956 #if GTK_MAJOR_VERSION < 2
957 lwidth=gdk_string_width(font, label_string);
959 pango_layout_set_text(layout, label_string, -1);
960 pango_layout_get_pixel_size(layout, &lwidth, NULL);
962 if ((x-1-io->pixels_per_tick/2-lwidth/2) < 5) {
964 } else if ((x-1-io->pixels_per_tick/2+lwidth/2) > (io->pixmap_width-5)) {
965 x_pos=io->pixmap_width-lwidth-5;
967 x_pos=x-1-io->pixels_per_tick/2-lwidth/2;
969 #if GTK_MAJOR_VERSION < 2
970 gdk_draw_string(io->pixmap,
972 io->draw_area->style->black_gc,
974 io->pixmap_height-bottom_y_border+15+label_height,
977 gdk_draw_layout(io->pixmap,
978 io->draw_area->style->black_gc,
980 io->pixmap_height-bottom_y_border+15,
986 #if GTK_MAJOR_VERSION >= 2
987 g_object_unref(G_OBJECT(layout));
993 * Loop over all graphs and draw them
995 for(i=MAX_GRAPHS-1;i>=0;i--){
997 guint32 interval, x_pos, y_pos, prev_x_pos, prev_y_pos;
999 if(!io->graphs[i].display){
1003 /* initialize prev x/y to the value of the first interval */
1004 prev_x_pos=draw_width-1-io->pixels_per_tick*((last_interval-first_interval)/io->interval)+io->left_x_border;
1005 val=get_it_value(io, i, first_interval/io->interval);
1008 } else if(io->max_y_units==LOGARITHMIC_YSCALE){
1010 prev_y_pos=(guint32)(draw_height-1+top_y_border);
1012 prev_y_pos=(guint32)((draw_height-ystart)-1-((log10((double)((gint64)val)))*(draw_height-ystart))/(log10((double)max_y))+top_y_border);
1015 prev_y_pos=(guint32)(draw_height-1-(val*draw_height)/max_y+top_y_border);
1018 for(interval=first_interval;interval<last_interval;interval+=io->interval){
1019 x_pos=draw_width-1-io->pixels_per_tick*((last_interval-interval)/io->interval)+io->left_x_border;
1021 val=get_it_value(io, i, interval/io->interval);
1024 } else if(io->max_y_units==LOGARITHMIC_YSCALE){
1026 y_pos=(guint32)(draw_height-1+top_y_border);
1028 y_pos=(guint32)((draw_height-ystart)-1-((log10((double)((gint64)val)))*(draw_height-ystart))/(log10((double)max_y))+top_y_border);
1031 y_pos=(guint32)(draw_height-1-(val*draw_height)/max_y+top_y_border);
1034 switch(io->graphs[i].plot_style){
1035 case PLOT_STYLE_LINE:
1036 /* dont need to draw anything if the segment
1037 * is entirely above the top of the graph
1039 if( (prev_y_pos!=0) || (y_pos!=0) ){
1040 gdk_draw_line(io->pixmap, io->graphs[i].gc,
1041 prev_x_pos, prev_y_pos,
1045 case PLOT_STYLE_IMPULSE:
1047 gdk_draw_line(io->pixmap, io->graphs[i].gc,
1048 x_pos, draw_height-1+top_y_border,
1052 case PLOT_STYLE_FILLED_BAR:
1054 gdk_draw_rectangle(io->pixmap,
1055 io->graphs[i].gc, TRUE,
1056 x_pos-io->pixels_per_tick/2,
1058 io->pixels_per_tick,
1059 draw_height-1+top_y_border-y_pos);
1062 case PLOT_STYLE_DOT:
1064 gdk_draw_rectangle(io->pixmap,
1065 io->graphs[i].gc, TRUE,
1066 x_pos-io->pixels_per_tick/2,
1067 y_pos-io->pixels_per_tick/2,
1068 io->pixels_per_tick,
1069 io->pixels_per_tick);
1081 gdk_draw_pixmap(io->draw_area->window,
1082 io->draw_area->style->fg_gc[GTK_WIDGET_STATE(io->draw_area)],
1086 io->pixmap_width, io->pixmap_height);
1089 /* update the scrollbar */
1090 io->scrollbar_adjustment->upper=(gfloat) io->max_interval;
1091 io->scrollbar_adjustment->step_increment=(gfloat) ((last_interval-first_interval)/10);
1092 io->scrollbar_adjustment->page_increment=(gfloat) (last_interval-first_interval);
1093 io->scrollbar_adjustment->page_size=io->scrollbar_adjustment->page_increment;
1094 io->scrollbar_adjustment->value=(gfloat)first_interval;
1095 gtk_adjustment_changed(io->scrollbar_adjustment);
1096 gtk_adjustment_value_changed(io->scrollbar_adjustment);
1101 io_stat_redraw(io_stat_t *io)
1103 io->needs_redraw=TRUE;
1108 gtk_iostat_draw(void *g)
1110 io_stat_graph_t *git=g;
1112 io_stat_draw(git->io);
1116 /* ok we get called with both the filter and the field.
1117 make sure the field is part of the filter.
1118 (make sure and make sure just append it)
1119 the field MUST be part of the filter or else we wont
1120 be able to pick up the field values after the edt tree has been
1124 enable_graph(io_stat_graph_t *gio, const char *filter, const char *field)
1126 char real_filter[262];
1132 /* skip all whitespaces */
1145 g_snprintf(real_filter, 257, "(%s)", filter);
1150 /* skip all whitespaces */
1163 if(real_filter[0]!=0){
1164 g_strlcat(real_filter, " && ", 262);
1166 g_strlcat(real_filter, field, 262);
1169 return register_tap_listener("frame", gio, real_filter[0]?real_filter:NULL,
1170 gtk_iostat_reset, gtk_iostat_packet, gtk_iostat_draw);
1174 disable_graph(io_stat_graph_t *gio)
1178 protect_thread_critical_region();
1179 remove_tap_listener(gio);
1180 unprotect_thread_critical_region();
1181 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gio->display_button),
1187 gtk_iostat_init(const char *optarg _U_, void* userdata _U_)
1191 static color_t col[MAX_GRAPHS] = {
1192 {0, 0x0000, 0x0000, 0x0000},
1193 {0, 0xffff, 0x0000, 0x0000},
1194 {0, 0x0000, 0xffff, 0x0000},
1195 {0, 0x0000, 0x0000, 0xffff},
1196 {0, 0xffff, 0x5000, 0xffff}
1198 GString *error_string;
1200 io=g_malloc(sizeof(io_stat_t));
1201 io->needs_redraw=TRUE;
1207 io->scrollbar_adjustment=NULL;
1208 io->pixmap_width=500;
1209 io->pixmap_height=200;
1210 io->pixels_per_tick=pixels_per_tick[DEFAULT_PIXELS_PER_TICK];
1211 io->max_y_units=AUTO_MAX_YSCALE;
1213 io->last_interval=0xffffffff;
1216 io->left_x_border=0;
1217 io->right_x_border=500;
1218 io->view_as_time=FALSE;
1219 io->start_time.secs=0;
1220 io->start_time.nsecs=0;
1222 for(i=0;i<MAX_GRAPHS;i++){
1223 io->graphs[i].gc=NULL;
1224 io->graphs[i].color.pixel=col[i].pixel;
1225 io->graphs[i].color.red=col[i].red;
1226 io->graphs[i].color.green=col[i].green;
1227 io->graphs[i].color.blue=col[i].blue;
1228 io->graphs[i].display=0;
1229 io->graphs[i].display_button=NULL;
1230 io->graphs[i].filter_field=NULL;
1231 io->graphs[i].advanced_buttons=NULL;
1232 io->graphs[i].io=io;
1234 io->graphs[i].args=g_malloc(sizeof(construct_args_t));
1235 io->graphs[i].args->title = NULL;
1236 io->graphs[i].args->wants_apply_button=TRUE;
1237 io->graphs[i].args->activate_on_ok=TRUE;
1238 io->graphs[i].args->modal_and_transient=FALSE;
1240 io->graphs[i].filter_bt=NULL;
1244 error_string=enable_graph(&io->graphs[0], NULL, NULL);
1246 fprintf(stderr, "wireshark: Can't attach io_stat tap: %s\n",
1248 g_string_free(error_string, TRUE);
1249 io->graphs[0].display=0;
1250 io->graphs[0].display_button=NULL;
1251 io->graphs[0].filter_field=NULL;
1252 io->graphs[0].advanced_buttons=NULL;
1257 init_io_stat_window(io);
1259 cf_retap_packets(&cfile, FALSE);
1264 quit(GtkWidget *widget, GdkEventExpose *event _U_)
1269 io=(io_stat_t *)OBJECT_GET_DATA(widget, "io_stat_t");
1271 for(i=0;i<MAX_GRAPHS;i++){
1272 if(io->graphs[i].display){
1273 protect_thread_critical_region();
1274 remove_tap_listener(&io->graphs[i]);
1275 unprotect_thread_critical_region();
1277 g_free( (gpointer) (io->graphs[i].args->title) );
1278 io->graphs[i].args->title=NULL;
1280 g_free(io->graphs[i].args);
1281 io->graphs[i].args=NULL;
1290 pixmap_clicked_event(GtkWidget *widget, GdkEventButton *event)
1292 io_stat_t *io=(io_stat_t *)OBJECT_GET_DATA(widget, "io_stat_t");
1293 guint32 draw_width, interval, last_interval;
1300 draw_width=io->pixmap_width-io->right_x_border-io->left_x_border;
1302 if ((event->x <= (draw_width+io->left_x_border+1-(draw_width/io->pixels_per_tick)*io->pixels_per_tick)) ||
1303 (event->x >= (draw_width+io->left_x_border-io->pixels_per_tick/2))) {
1304 /* Outside draw area */
1308 if ((event->button==1 || event->button==3) && io->pixmap!=NULL) {
1310 * Button 1 selects the first package in the interval.
1311 * Button 3 selects the last package in the interval.
1313 if (io->last_interval==0xffffffff) {
1314 last_interval=io->max_interval;
1316 last_interval=io->last_interval;
1319 interval=(guint32)((last_interval/io->interval)-(draw_width+io->left_x_border-event->x-io->pixels_per_tick/2-1)/io->pixels_per_tick);
1320 frame_num=get_frame_num (io, interval, event->button==1?TRUE:FALSE);
1321 if (frame_num != 0) {
1322 cf_goto_frame(&cfile, frame_num);
1329 /* create a new backing pixmap of the appropriate size */
1331 configure_event(GtkWidget *widget, GdkEventConfigure *event _U_)
1335 #if GTK_CHECK_VERSION(2,6,0)
1339 io=(io_stat_t *)OBJECT_GET_DATA(widget, "io_stat_t");
1345 gdk_pixmap_unref(io->pixmap);
1349 io->pixmap=gdk_pixmap_new(widget->window,
1350 widget->allocation.width,
1351 widget->allocation.height,
1353 io->pixmap_width=widget->allocation.width;
1354 io->pixmap_height=widget->allocation.height;
1356 #if GTK_CHECK_VERSION(2,6,0)
1357 save_bt = OBJECT_GET_DATA(io->window, "save_bt");
1358 OBJECT_SET_DATA(save_bt, "pixmap", io->pixmap);
1359 gtk_widget_set_sensitive(save_bt, TRUE);
1362 gdk_draw_rectangle(io->pixmap,
1363 widget->style->white_gc,
1366 widget->allocation.width,
1367 widget->allocation.height);
1369 /* set up the colors and the GC structs for this pixmap */
1370 for(i=0;i<MAX_GRAPHS;i++){
1371 io->graphs[i].gc=gdk_gc_new(io->pixmap);
1372 #if GTK_MAJOR_VERSION < 2
1373 colormap = gtk_widget_get_colormap (widget);
1374 if (!gdk_color_alloc (colormap, &io->graphs[i].color)){
1375 g_warning ("Couldn't allocate color");
1378 gdk_gc_set_foreground(io->graphs[i].gc, &io->graphs[i].color);
1380 gdk_gc_set_rgb_fg_color(io->graphs[i].gc, &io->graphs[i].color);
1390 scrollbar_changed(GtkWidget *widget _U_, gpointer data)
1392 io_stat_t *io=(io_stat_t *)data;
1395 mi=(guint32) (io->scrollbar_adjustment->value+io->scrollbar_adjustment->page_size);
1396 if(io->last_interval==mi){
1399 if( (io->last_interval==0xffffffff)
1400 && (mi==io->max_interval) ){
1404 io->last_interval=(mi/io->interval)*io->interval;
1410 /* redraw the screen from the backing pixmap */
1412 expose_event(GtkWidget *widget, GdkEventExpose *event)
1416 io=(io_stat_t *)OBJECT_GET_DATA(widget, "io_stat_t");
1422 gdk_draw_pixmap(widget->window,
1423 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
1425 event->area.x, event->area.y,
1426 event->area.x, event->area.y,
1427 event->area.width, event->area.height);
1434 create_draw_area(io_stat_t *io, GtkWidget *box)
1436 io->draw_area=gtk_drawing_area_new();
1437 SIGNAL_CONNECT(io->draw_area, "destroy", quit, io);
1438 OBJECT_SET_DATA(io->draw_area, "io_stat_t", io);
1440 WIDGET_SET_SIZE(io->draw_area, io->pixmap_width, io->pixmap_height);
1442 /* signals needed to handle backing pixmap */
1443 SIGNAL_CONNECT(io->draw_area, "expose_event", expose_event, NULL);
1444 SIGNAL_CONNECT(io->draw_area, "configure_event", configure_event, io);
1445 gtk_widget_add_events (io->draw_area, GDK_BUTTON_PRESS_MASK);
1446 SIGNAL_CONNECT(io->draw_area, "button-press-event", pixmap_clicked_event, NULL);
1448 gtk_widget_show(io->draw_area);
1449 gtk_box_pack_start(GTK_BOX(box), io->draw_area, TRUE, TRUE, 0);
1451 /* create the associated scrollbar */
1452 io->scrollbar_adjustment=(GtkAdjustment *)gtk_adjustment_new(0,0,0,0,0,0);
1453 io->scrollbar=gtk_hscrollbar_new(io->scrollbar_adjustment);
1454 gtk_widget_show(io->scrollbar);
1455 gtk_box_pack_start(GTK_BOX(box), io->scrollbar, FALSE, FALSE, 0);
1456 SIGNAL_CONNECT(io->scrollbar_adjustment, "value_changed", scrollbar_changed, io);
1461 tick_interval_select(GtkWidget *item, gpointer key)
1466 io=(io_stat_t *)key;
1467 val=(long)OBJECT_GET_DATA(item, "tick_interval");
1470 cf_retap_packets(&cfile, FALSE);
1475 pixels_per_tick_select(GtkWidget *item, gpointer key)
1480 io=(io_stat_t *)key;
1481 val=(long)OBJECT_GET_DATA(item, "pixels_per_tick");
1482 io->pixels_per_tick=val;
1487 plot_style_select(GtkWidget *item, gpointer key)
1490 io_stat_graph_t *ppt;
1492 ppt=(io_stat_graph_t *)key;
1493 val=(long)OBJECT_GET_DATA(item, "plot_style");
1495 ppt->plot_style=val;
1497 io_stat_redraw(ppt->io);
1501 create_pixels_per_tick_menu_items(io_stat_t *io, GtkWidget *menu)
1504 GtkWidget *menu_item;
1507 for(i=0;i<MAX_PIXELS_PER_TICK;i++){
1508 g_snprintf(str, 5, "%u", pixels_per_tick[i]);
1509 menu_item=gtk_menu_item_new_with_label(str);
1511 OBJECT_SET_DATA(menu_item, "pixels_per_tick",
1512 GUINT_TO_POINTER(pixels_per_tick[i]));
1513 SIGNAL_CONNECT(menu_item, "activate", pixels_per_tick_select, io);
1514 gtk_widget_show(menu_item);
1515 gtk_menu_append(GTK_MENU(menu), menu_item);
1517 gtk_menu_set_active(GTK_MENU(menu), DEFAULT_PIXELS_PER_TICK);
1523 yscale_select(GtkWidget *item, gpointer key)
1528 io=(io_stat_t *)key;
1529 val=(long)OBJECT_GET_DATA(item, "yscale_max");
1531 io->max_y_units=val;
1536 create_tick_interval_menu_items(io_stat_t *io, GtkWidget *menu)
1539 GtkWidget *menu_item;
1542 for(i=0;i<MAX_TICK_VALUES;i++){
1543 if(tick_interval_values[i]>=60000){
1544 g_snprintf(str, 15, "%u min", tick_interval_values[i]/60000);
1545 } else if(tick_interval_values[i]>=1000){
1546 g_snprintf(str, 15, "%u sec", tick_interval_values[i]/1000);
1547 } else if(tick_interval_values[i]>=100){
1548 g_snprintf(str, 15, "0.%1u sec", (tick_interval_values[i]/100)%10);
1549 } else if(tick_interval_values[i]>=10){
1550 g_snprintf(str, 15, "0.%02u sec", (tick_interval_values[i]/10)%10);
1552 g_snprintf(str, 15, "0.%03u sec", (tick_interval_values[i])%10);
1555 menu_item=gtk_menu_item_new_with_label(str);
1556 OBJECT_SET_DATA(menu_item, "tick_interval",
1557 GUINT_TO_POINTER(tick_interval_values[i]));
1558 SIGNAL_CONNECT(menu_item, "activate", tick_interval_select, (gpointer)io);
1559 gtk_widget_show(menu_item);
1560 gtk_menu_append(GTK_MENU(menu), menu_item);
1562 gtk_menu_set_active(GTK_MENU(menu), DEFAULT_TICK_VALUE);
1567 create_yscale_max_menu_items(io_stat_t *io, GtkWidget *menu)
1570 GtkWidget *menu_item;
1573 for(i=0;i<MAX_YSCALE;i++){
1574 if(yscale_max[i]==LOGARITHMIC_YSCALE){
1575 g_strlcpy(str, "Logarithmic", 15);
1576 } else if(yscale_max[i]==AUTO_MAX_YSCALE){
1577 g_strlcpy(str, "Auto", 15);
1579 g_snprintf(str, 15, "%u", yscale_max[i]);
1581 menu_item=gtk_menu_item_new_with_label(str);
1582 OBJECT_SET_DATA(menu_item, "yscale_max",
1583 GUINT_TO_POINTER(yscale_max[i]));
1584 SIGNAL_CONNECT(menu_item, "activate", yscale_select, io);
1585 gtk_widget_show(menu_item);
1586 gtk_menu_append(GTK_MENU(menu), menu_item);
1588 gtk_menu_set_active(GTK_MENU(menu), DEFAULT_YSCALE);
1593 count_type_select(GtkWidget *item, gpointer key)
1595 static gboolean advanced_visible=FALSE;
1599 io=(io_stat_t *)key;
1600 val=(long)OBJECT_GET_DATA(item, "count_type");
1604 if(io->count_type==COUNT_TYPE_ADVANCED){
1605 for(i=0;i<MAX_GRAPHS;i++){
1606 disable_graph(&io->graphs[i]);
1607 gtk_widget_show(io->graphs[i].advanced_buttons);
1608 /* redraw the entire window so the unhidden widgets show up, hopefully */
1609 {GdkRectangle update_rect;
1612 update_rect.width=io->window->allocation.width;
1613 update_rect.height=io->window->allocation.height;
1614 gtk_widget_draw(io->window, &update_rect);
1617 advanced_visible=TRUE;
1619 } else if (advanced_visible) {
1620 for(i=0;i<MAX_GRAPHS;i++){
1621 gtk_widget_hide(io->graphs[i].advanced_buttons);
1622 filter_callback(item, &io->graphs[i]);
1624 advanced_visible=FALSE;
1631 create_frames_or_bytes_menu_items(io_stat_t *io, GtkWidget *menu)
1633 GtkWidget *menu_item;
1636 for(i=0;i<MAX_COUNT_TYPES;i++){
1637 menu_item=gtk_menu_item_new_with_label(count_type_names[i]);
1638 OBJECT_SET_DATA(menu_item, "count_type", GINT_TO_POINTER(i));
1639 SIGNAL_CONNECT(menu_item, "activate", count_type_select, io);
1640 gtk_widget_show(menu_item);
1641 gtk_menu_append(GTK_MENU(menu), menu_item);
1647 create_ctrl_menu(io_stat_t *io, GtkWidget *box, const char *name, void (*func)(io_stat_t *io, GtkWidget *menu))
1651 GtkWidget *option_menu;
1654 hbox=gtk_hbox_new(FALSE, 0);
1655 gtk_container_add(GTK_CONTAINER(box), hbox);
1656 gtk_box_set_child_packing(GTK_BOX(box), hbox, FALSE, FALSE, 0, GTK_PACK_START);
1657 gtk_widget_show(hbox);
1659 label=gtk_label_new(name);
1660 gtk_widget_show(label);
1661 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1663 option_menu=gtk_option_menu_new();
1664 menu=gtk_menu_new();
1666 gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), menu);
1667 gtk_box_pack_end(GTK_BOX(hbox), option_menu, FALSE, FALSE, 0);
1668 gtk_widget_show(option_menu);
1672 view_as_time_toggle_dest(GtkWidget *widget _U_, gpointer key)
1676 io=(io_stat_t *)key;
1677 io->view_as_time = io->view_as_time ? FALSE : TRUE;
1683 create_ctrl_area(io_stat_t *io, GtkWidget *box)
1685 GtkWidget *frame_vbox;
1689 #if GTK_MAJOR_VERSION < 2
1690 GtkAccelGroup *accel_group;
1692 /* Accelerator group for the accelerators (or, as they're called in
1693 Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
1694 Ctrl+<key> is an accelerator). */
1695 accel_group = gtk_accel_group_new();
1696 gtk_window_add_accel_group(GTK_WINDOW(io->window), accel_group);
1699 frame_vbox=gtk_vbox_new(FALSE, 0);
1700 gtk_box_pack_start(GTK_BOX(box), frame_vbox, FALSE, FALSE, 0);
1701 gtk_widget_show(frame_vbox);
1703 frame = gtk_frame_new("X Axis");
1704 gtk_container_add(GTK_CONTAINER(frame_vbox), frame);
1705 gtk_widget_show(frame);
1707 vbox=gtk_vbox_new(FALSE, 0);
1708 gtk_container_add(GTK_CONTAINER(frame), vbox);
1709 gtk_container_border_width(GTK_CONTAINER(vbox), 3);
1710 gtk_box_set_child_packing(GTK_BOX(box), vbox, FALSE, FALSE, 0, GTK_PACK_END);
1711 gtk_widget_show(vbox);
1713 create_ctrl_menu(io, vbox, "Tick interval:", create_tick_interval_menu_items);
1714 create_ctrl_menu(io, vbox, "Pixels per tick:", create_pixels_per_tick_menu_items);
1716 view_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("_View as time of day", accel_group);
1717 gtk_container_add(GTK_CONTAINER(vbox), view_cb);
1718 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(view_cb), io->view_as_time);
1719 SIGNAL_CONNECT(view_cb, "toggled", view_as_time_toggle_dest, io);
1720 gtk_widget_show(view_cb);
1722 frame = gtk_frame_new("Y Axis");
1723 gtk_container_add(GTK_CONTAINER(frame_vbox), frame);
1724 gtk_widget_show(frame);
1726 vbox=gtk_vbox_new(FALSE, 0);
1727 gtk_container_add(GTK_CONTAINER(frame), vbox);
1728 gtk_container_border_width(GTK_CONTAINER(vbox), 3);
1729 gtk_box_set_child_packing(GTK_BOX(box), vbox, FALSE, FALSE, 0, GTK_PACK_END);
1730 gtk_widget_show(vbox);
1732 create_ctrl_menu(io, vbox, "Unit:", create_frames_or_bytes_menu_items);
1733 create_ctrl_menu(io, vbox, "Scale:", create_yscale_max_menu_items);
1740 filter_callback(GtkWidget *widget _U_, io_stat_graph_t *gio)
1743 const char *field=NULL;
1744 header_field_info *hfi;
1747 /* this graph is not active, just update display and redraw */
1748 if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gio->display_button))){
1750 io_stat_redraw(gio->io);
1754 /* first check if the field string is valid */
1755 if(gio->io->count_type==COUNT_TYPE_ADVANCED){
1756 field=gtk_entry_get_text(GTK_ENTRY(gio->calc_field));
1758 /* warn and bail out if there was no field specified */
1759 if(field==NULL || field[0]==0){
1760 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "You didn't specify a field name.");
1762 io_stat_redraw(gio->io);
1765 /* warn and bail out if the field could not be found */
1766 hfi=proto_registrar_get_byname(field);
1768 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "There is no field named '%s'.", field);
1770 io_stat_redraw(gio->io);
1773 gio->hf_index=hfi->id;
1774 /* check that the type is compatible */
1784 /* these values support all calculations except LOAD */
1785 switch(gio->calc_type){
1786 case CALC_TYPE_LOAD:
1787 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1788 "LOAD(*) is only supported for relative-time fields.");
1790 io_stat_redraw(gio->io);
1793 /* these types support all calculations */
1795 case FT_RELATIVE_TIME:
1796 /* this type only supports COUNT, MAX, MIN, AVG */
1797 switch(gio->calc_type){
1799 case CALC_TYPE_COUNT:
1803 case CALC_TYPE_LOAD:
1806 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1807 "%s is a relative-time field, so %s calculations are not supported on it.",
1809 calc_type_names[gio->calc_type]);
1811 io_stat_redraw(gio->io);
1818 * XXX - support this if gint64/guint64 are
1821 if(gio->calc_type!=CALC_TYPE_COUNT){
1822 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1823 "%s is a 64-bit integer, so %s calculations are not supported on it.",
1825 calc_type_names[gio->calc_type]);
1827 io_stat_redraw(gio->io);
1833 * XXX - support all operations on floating-point
1836 if(gio->calc_type!=CALC_TYPE_COUNT){
1837 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1838 "%s doesn't have integral values, so %s calculations are not supported on it.",
1840 calc_type_names[gio->calc_type]);
1842 io_stat_redraw(gio->io);
1849 /* first check if the filter string is valid. */
1850 filter=gtk_entry_get_text(GTK_ENTRY(gio->filter_field));
1851 if(!dfilter_compile(filter, &dfilter)) {
1852 bad_dfilter_alert_box(filter);
1854 io_stat_redraw(gio->io);
1857 if (dfilter != NULL)
1858 dfilter_free(dfilter);
1860 /* ok, we have a valid filter and the graph is active.
1861 first just try to delete any previous settings and then apply
1864 protect_thread_critical_region();
1865 remove_tap_listener(gio);
1866 unprotect_thread_critical_region();
1868 io_stat_reset(gio->io);
1869 enable_graph(gio, filter, field);
1870 cf_retap_packets(&cfile, FALSE);
1871 io_stat_redraw(gio->io);
1878 calc_type_select(GtkWidget *item _U_, gpointer key)
1880 io_stat_calc_type_t *ct=(io_stat_calc_type_t *)key;
1882 ct->gio->calc_type=ct->calc_type;
1884 /* disable the graph */
1885 disable_graph(ct->gio);
1886 io_stat_redraw(ct->gio->io);
1891 create_calc_types_menu_items(io_stat_graph_t *gio, GtkWidget *menu)
1893 GtkWidget *menu_item;
1896 for(i=0;i<MAX_CALC_TYPES;i++){
1897 gio->calc_types[i].gio=gio;
1898 gio->calc_types[i].calc_type=i;
1899 menu_item=gtk_menu_item_new_with_label(calc_type_names[i]);
1900 SIGNAL_CONNECT(menu_item, "activate", calc_type_select, &gio->calc_types[i]);
1901 gtk_widget_show(menu_item);
1902 gtk_menu_append(GTK_MENU(menu), menu_item);
1909 create_advanced_menu(io_stat_graph_t *gio, GtkWidget *box, const char *name, void (*func)(io_stat_graph_t *io, GtkWidget *menu))
1913 GtkWidget *option_menu;
1916 hbox=gtk_hbox_new(FALSE, 0);
1917 gtk_container_add(GTK_CONTAINER(box), hbox);
1918 gtk_box_set_child_packing(GTK_BOX(box), hbox, FALSE, FALSE, 0, GTK_PACK_START);
1919 gtk_widget_show(hbox);
1921 label=gtk_label_new(name);
1922 gtk_widget_show(label);
1923 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1925 option_menu=gtk_option_menu_new();
1926 menu=gtk_menu_new();
1928 gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), menu);
1929 gtk_box_pack_end(GTK_BOX(hbox), option_menu, FALSE, FALSE, 0);
1930 gtk_widget_show(option_menu);
1934 create_advanced_field(io_stat_graph_t *gio, GtkWidget *box)
1937 gio->calc_field=gtk_entry_new_with_max_length(50);
1938 gtk_box_pack_start(GTK_BOX(box), gio->calc_field, TRUE, TRUE, 0);
1939 gtk_widget_show(gio->calc_field);
1940 SIGNAL_CONNECT(gio->calc_field, "activate", filter_callback, gio);
1945 create_advanced_box(io_stat_graph_t *gio, GtkWidget *box)
1949 hbox=gtk_hbox_new(FALSE, 0);
1950 gio->advanced_buttons=hbox;
1951 gtk_container_add(GTK_CONTAINER(box), hbox);
1952 gtk_box_set_child_packing(GTK_BOX(box), hbox, TRUE, TRUE, 0, GTK_PACK_START);
1953 gtk_widget_hide(hbox);
1955 gio->calc_type=CALC_TYPE_SUM;
1956 create_advanced_menu(gio, hbox, "Calc:", create_calc_types_menu_items);
1957 create_advanced_field(gio, hbox);
1962 filter_button_clicked(GtkWidget *w, gpointer uio)
1964 io_stat_graph_t *gio=(io_stat_graph_t *)uio;
1966 display_filter_construct_cb(w, gio->args);
1971 create_filter_box(io_stat_graph_t *gio, GtkWidget *box, int num)
1973 GtkWidget *option_menu;
1975 GtkWidget *menu_item;
1981 hbox=gtk_hbox_new(FALSE, 3);
1982 gtk_container_add(GTK_CONTAINER(box), hbox);
1983 gtk_box_set_child_packing(GTK_BOX(box), hbox, FALSE, FALSE, 0, GTK_PACK_START);
1984 gtk_widget_show(hbox);
1986 g_snprintf(str, 256, "Graph %d", num);
1987 gio->display_button=gtk_toggle_button_new_with_label(str);
1988 gtk_box_pack_start(GTK_BOX(hbox), gio->display_button, FALSE, FALSE, 0);
1989 gtk_widget_show(gio->display_button);
1990 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gio->display_button), gio->display);
1991 SIGNAL_CONNECT(gio->display_button, "toggled", filter_callback, gio);
1993 label=gtk_label_new("Color");
1994 gtk_widget_show(label);
1995 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1997 #if GTK_MAJOR_VERSION < 2
1998 /* setting the color of the display button doesn't work */
1999 rc_style = gtk_rc_style_new ();
2000 rc_style->fg[GTK_STATE_NORMAL] = gio->color;
2001 rc_style->color_flags[GTK_STATE_NORMAL] |= GTK_RC_FG;
2002 rc_style->fg[GTK_STATE_ACTIVE] = gio->color;
2003 rc_style->color_flags[GTK_STATE_ACTIVE] |= GTK_RC_FG;
2004 rc_style->fg[GTK_STATE_PRELIGHT] = gio->color;
2005 rc_style->color_flags[GTK_STATE_PRELIGHT] |= GTK_RC_FG;
2006 rc_style->fg[GTK_STATE_SELECTED] = gio->color;
2007 rc_style->color_flags[GTK_STATE_SELECTED] |= GTK_RC_FG;
2008 rc_style->fg[GTK_STATE_INSENSITIVE] = gio->color;
2009 rc_style->color_flags[GTK_STATE_INSENSITIVE] |= GTK_RC_FG;
2010 gtk_widget_modify_style (label, rc_style);
2011 gtk_rc_style_unref (rc_style);
2013 gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &gio->color);
2014 gtk_widget_modify_fg(label, GTK_STATE_ACTIVE, &gio->color);
2015 gtk_widget_modify_fg(label, GTK_STATE_PRELIGHT, &gio->color);
2016 gtk_widget_modify_fg(label, GTK_STATE_SELECTED, &gio->color);
2017 gtk_widget_modify_fg(label, GTK_STATE_INSENSITIVE, &gio->color);
2019 /* gtk_signal_connect(GTK_OBJECT(gio->display_button), "toggled", GTK_SIGNAL_FUNC(filter_callback), gio);*/
2022 /* filter prefs dialog */
2023 gio->filter_bt=BUTTON_NEW_FROM_STOCK(WIRESHARK_STOCK_DISPLAY_FILTER_ENTRY);
2025 g_snprintf(str, 256, "Wireshark: Display Filter IO-Stat (Filter:%d)", num);
2026 if(gio->args->title){
2027 g_free( (gpointer) (gio->args->title) );
2029 gio->args->title=g_strdup(str);
2031 SIGNAL_CONNECT(gio->filter_bt, "clicked", filter_button_clicked, gio);
2032 SIGNAL_CONNECT(gio->filter_bt, "destroy", filter_button_destroy_cb, NULL);
2034 gtk_box_pack_start(GTK_BOX(hbox), gio->filter_bt, FALSE, TRUE, 0);
2035 gtk_widget_show(gio->filter_bt);
2037 gio->filter_field=gtk_entry_new_with_max_length(256);
2039 /* filter prefs dialog */
2040 OBJECT_SET_DATA(gio->filter_bt, E_FILT_TE_PTR_KEY, gio->filter_field);
2041 /* filter prefs dialog */
2043 gtk_box_pack_start(GTK_BOX(hbox), gio->filter_field, TRUE, TRUE, 0);
2044 gtk_widget_show(gio->filter_field);
2045 SIGNAL_CONNECT(gio->filter_field, "activate", filter_callback, gio);
2046 SIGNAL_CONNECT(gio->filter_field, "changed", filter_te_syntax_check_cb, NULL);
2048 create_advanced_box(gio, hbox);
2052 * create PlotStyle menu
2054 g_snprintf(str, 256, " Style:");
2055 label=gtk_label_new(str);
2056 gtk_widget_show(label);
2057 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
2059 option_menu=gtk_option_menu_new();
2060 menu=gtk_menu_new();
2061 for(i=0;i<MAX_PLOT_STYLES;i++){
2062 menu_item=gtk_menu_item_new_with_label(plot_style_name[i]);
2063 OBJECT_SET_DATA(menu_item, "plot_style", GINT_TO_POINTER(i));
2064 SIGNAL_CONNECT(menu_item, "activate", plot_style_select, &gio->io->graphs[num-1]);
2065 gtk_widget_show(menu_item);
2066 gtk_menu_append(GTK_MENU(menu), menu_item);
2068 gtk_menu_set_active(GTK_MENU(menu), DEFAULT_PLOT_STYLE);
2070 gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), menu);
2071 gtk_box_pack_end(GTK_BOX(hbox), option_menu, FALSE, FALSE, 0);
2072 gtk_widget_show(option_menu);
2079 create_filter_area(io_stat_t *io, GtkWidget *box)
2085 frame=gtk_frame_new("Graphs");
2086 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 0);
2087 gtk_widget_show(frame);
2089 vbox=gtk_vbox_new(FALSE, 1);
2090 gtk_container_add(GTK_CONTAINER(frame), vbox);
2091 gtk_container_border_width(GTK_CONTAINER(vbox), 3);
2092 gtk_box_set_child_packing(GTK_BOX(box), vbox, FALSE, FALSE, 0, GTK_PACK_START);
2093 gtk_widget_show(vbox);
2095 for(i=0;i<MAX_GRAPHS;i++){
2096 create_filter_box(&io->graphs[i], vbox, i+1);
2103 #if GTK_MAJOR_VERSION >= 2
2105 copy_as_csv_cb(GtkWindow *copy_bt _U_, gpointer data)
2107 guint32 i, interval, val;
2110 GString *CSV_str=g_string_new("");
2111 io_stat_t *io=(io_stat_t *)data;
2113 g_string_append(CSV_str, "Interval start");
2114 for(i=0;i<MAX_GRAPHS;i++) {
2115 if (io->graphs[i].display) {
2116 g_string_sprintfa(CSV_str, ",Graph %d", i+1);
2119 g_string_append(CSV_str,"\n");
2121 for(interval=0; interval<io->max_interval; interval+=io->interval) {
2122 print_interval_string (string, 15, interval, io, FALSE);
2123 g_string_append(CSV_str, string);
2124 for(i=0;i<MAX_GRAPHS;i++) {
2125 if (io->graphs[i].display) {
2126 val=get_it_value(io, i, interval/io->interval);
2127 g_string_sprintfa(CSV_str, ",%d", val);
2130 g_string_append(CSV_str,"\n");
2133 /* Now that we have the CSV data, copy it into the default clipboard */
2134 cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); /* Get the default clipboard */
2135 gtk_clipboard_set_text(cb, CSV_str->str, -1); /* Copy the CSV data into the clipboard */
2136 g_string_free(CSV_str, TRUE); /* Free the memory */
2142 init_io_stat_window(io_stat_t *io)
2147 GtkWidget *close_bt, *help_bt;
2148 GtkTooltips *tooltips = gtk_tooltips_new();
2149 #if GTK_MAJOR_VERSION >= 2
2152 #if GTK_CHECK_VERSION(2,6,0)
2156 /* create the main window */
2157 io->window=window_new(GTK_WINDOW_TOPLEVEL, "I/O Graphs");
2159 vbox=gtk_vbox_new(FALSE, 0);
2160 gtk_container_add(GTK_CONTAINER(io->window), vbox);
2161 gtk_widget_show(vbox);
2163 create_draw_area(io, vbox);
2165 hbox=gtk_hbox_new(FALSE, 3);
2166 gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
2167 gtk_container_border_width(GTK_CONTAINER(hbox), 3);
2168 gtk_box_set_child_packing(GTK_BOX(vbox), hbox, FALSE, FALSE, 0, GTK_PACK_START);
2169 gtk_widget_show(hbox);
2171 create_filter_area(io, hbox);
2172 create_ctrl_area(io, hbox);
2174 io_stat_set_title(io);
2176 if(topic_available(HELP_STATS_IO_GRAPH_DIALOG)) {
2177 #if GTK_CHECK_VERSION(2,6,0)
2178 bbox = dlg_button_row_new(GTK_STOCK_CLOSE, GTK_STOCK_SAVE,
2179 GTK_STOCK_COPY, GTK_STOCK_HELP, NULL);
2180 #elif GTK_MAJOR_VERSION >= 2
2182 bbox = dlg_button_row_new(GTK_STOCK_CLOSE, GTK_STOCK_COPY,
2183 GTK_STOCK_HELP, NULL);
2185 bbox = dlg_button_row_new(GTK_STOCK_CLOSE, GTK_STOCK_HELP, NULL);
2188 #if GTK_CHECK_VERSION(2,6,0)
2189 bbox = dlg_button_row_new(GTK_STOCK_CLOSE, GTK_STOCK_SAVE,
2190 GTK_STOCK_COPY, NULL);
2191 #elif GTK_MAJOR_VERSION >= 2
2192 bbox = dlg_button_row_new(GTK_STOCK_CLOSE, GTK_STOCK_COPY, NULL);
2194 bbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL);
2197 gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
2198 gtk_widget_show(bbox);
2200 close_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_CLOSE);
2201 window_set_cancel_button(io->window, close_bt, window_cancel_button_cb);
2202 gtk_tooltips_set_tip(tooltips, close_bt, "Close this dialog", NULL);
2204 #if GTK_CHECK_VERSION(2,6,0)
2205 save_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_SAVE);
2206 gtk_widget_set_sensitive(save_bt, FALSE);
2207 gtk_tooltips_set_tip(tooltips, save_bt, "Save the displayed graph to a file", NULL);
2208 SIGNAL_CONNECT(save_bt, "clicked", pixmap_save_cb, NULL);
2209 OBJECT_SET_DATA(io->window, "save_bt", save_bt);
2212 #if GTK_MAJOR_VERSION >= 2
2213 copy_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_COPY);
2214 gtk_tooltips_set_tip(tooltips, copy_bt,
2215 "Copy values from selected graphs to the clipboard in CSV (Comma Seperated Values) format", NULL);
2216 SIGNAL_CONNECT(copy_bt, "clicked", copy_as_csv_cb, io);
2219 if(topic_available(HELP_STATS_IO_GRAPH_DIALOG)) {
2220 help_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_HELP);
2221 SIGNAL_CONNECT(help_bt, "clicked", topic_cb, HELP_STATS_IO_GRAPH_DIALOG);
2222 gtk_tooltips_set_tip (tooltips, help_bt, "Show topic specific help", NULL);
2225 SIGNAL_CONNECT(io->window, "delete_event", window_delete_event_cb, NULL);
2227 gtk_widget_show(io->window);
2228 window_present(io->window);
2233 gtk_iostat_cb(GtkWidget *w _U_, gpointer d _U_)
2235 gtk_iostat_init(NULL,NULL);
2242 register_tap_listener_gtk_iostat(void)
2244 register_stat_cmd_arg("io,stat", gtk_iostat_init,NULL);
2246 register_stat_menu_item("_IO Graphs", REGISTER_STAT_GROUP_GENERIC,
2247 gtk_iostat_cb, NULL, NULL, NULL);