2 * io_stat 2002 Ronnie Sahlberg
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
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"
47 #include "../register.h"
48 #include "alert_box.h"
49 #include "simple_dialog.h"
50 #include "../globals.h"
52 #include "compat_macros.h"
53 #include "dlg_utils.h"
54 #include "filter_dlg.h"
56 void protect_thread_critical_region(void);
57 void unprotect_thread_critical_region(void);
62 #define AUTO_MAX_YSCALE 0
63 static guint32 yscale_max[MAX_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};
65 #define MAX_PIXELS_PER_TICK 4
66 #define DEFAULT_PIXELS_PER_TICK 2
67 static guint32 pixels_per_tick[MAX_PIXELS_PER_TICK] = {1, 2, 5, 10};
70 #define DEFAULT_PLOT_STYLE 0
71 #define PLOT_STYLE_LINE 0
72 #define PLOT_STYLE_IMPULSE 1
73 #define PLOT_STYLE_FILLED_BAR 2
74 #define MAX_PLOT_STYLES 3
75 static char *plot_style_name[MAX_PLOT_STYLES] = {
82 #define COUNT_TYPE_FRAMES 0
83 #define COUNT_TYPE_BYTES 1
84 #define COUNT_TYPE_ADVANCED 2
85 #define MAX_COUNT_TYPES 3
86 static char *count_type_names[MAX_COUNT_TYPES] = {"Packets/Tick", "Bytes/Tick", "Advanced..."};
89 #define MAX_TICK_VALUES 5
90 #define DEFAULT_TICK_VALUE 3
91 static guint tick_interval_values[MAX_TICK_VALUES] = { 1, 10, 100, 1000, 10000 };
93 #define CALC_TYPE_SUM 0
94 #define CALC_TYPE_COUNT 1
95 #define CALC_TYPE_MAX 2
96 #define CALC_TYPE_MIN 3
97 #define CALC_TYPE_AVG 4
98 #define CALC_TYPE_LOAD 5
99 #define MAX_CALC_TYPES 6
100 static char *calc_type_names[MAX_CALC_TYPES] = {"SUM(*)", "COUNT(*)", "MAX(*)", "MIN(*)", "AVG(*)", "LOAD(*)"};
103 typedef struct _io_stat_calc_type_t {
104 struct _io_stat_graph_t *gio;
106 } io_stat_calc_type_t;
108 #define NUM_IO_ITEMS 100000
109 typedef struct _io_item_t {
110 guint32 frames; /* always calculated, will hold number of frames*/
111 guint32 bytes; /* always calculated, will hold number of bytes*/
120 typedef struct _io_stat_graph_t {
121 struct _io_stat_t *io;
122 io_item_t items[NUM_IO_ITEMS];
125 GtkWidget *display_button;
126 GtkWidget *filter_field;
127 GtkWidget *advanced_buttons;
129 io_stat_calc_type_t calc_types[MAX_CALC_TYPES];
131 GtkWidget *calc_field;
134 construct_args_t *args;
135 GtkWidget *filter_bt;
139 typedef struct _io_stat_t {
140 gboolean needs_redraw;
141 gint32 interval; /* measurement interval in ms */
142 guint32 last_interval;
143 guint32 max_interval; /* XXX max_interval and num_items are redundant */
146 struct _io_stat_graph_t graphs[MAX_GRAPHS];
148 GtkWidget *draw_area;
150 GtkAdjustment *scrollbar_adjustment;
151 GtkWidget *scrollbar;
159 #if GTK_MAJOR_VERSION < 2
160 GtkRcStyle *rc_style;
161 GdkColormap *colormap;
166 static void init_io_stat_window(io_stat_t *io);
169 io_stat_set_title(io_stat_t *io)
176 title = g_strdup_printf("Ethereal IO Graphs: %s", cf_get_display_name(&cfile));
177 gtk_window_set_title(GTK_WINDOW(io->window), title);
182 io_stat_reset(io_stat_t *io)
186 io->needs_redraw=TRUE;
187 for(i=0;i<MAX_GRAPHS;i++){
188 for(j=0;j<NUM_IO_ITEMS;j++){
190 ioi=&io->graphs[i].items[j];
197 ioi->time_max.secs=0;
198 ioi->time_max.nsecs=0;
199 ioi->time_min.secs=0;
200 ioi->time_min.nsecs=0;
201 ioi->time_tot.secs=0;
202 ioi->time_tot.nsecs=0;
205 io->last_interval=0xffffffff;
209 io_stat_set_title(io);
213 gtk_iostat_reset(void *g)
215 io_stat_graph_t *gio=g;
217 io_stat_reset(gio->io);
221 gtk_iostat_packet(void *g, packet_info *pinfo, epan_dissect_t *edt, void *dummy _U_)
223 io_stat_graph_t *git=g;
228 /* we sometimes get called when git is disabled.
229 this is a bug since the tap listener should be removed first */
234 git->io->needs_redraw=TRUE;
237 * Find which interval this is supposed to to in and store the
238 * interval index as idx
240 time_delta.secs=pinfo->fd->rel_secs;
241 time_delta.nsecs=pinfo->fd->rel_usecs*1000;
242 if(time_delta.nsecs<0){
244 time_delta.nsecs+=1000000000;
246 if(time_delta.secs<0){
249 idx=(time_delta.secs*1000+time_delta.nsecs/1000000)/git->io->interval;
251 /* some sanity checks */
252 if((idx<0)||(idx>=NUM_IO_ITEMS)){
256 /* update num_items */
257 if((guint32)idx > git->io->num_items){
258 git->io->num_items=idx;
259 git->io->max_interval=idx*git->io->interval;
263 * Find the appropriate io_item_t structure
269 * For ADVANCED mode we need to keep track of some more stuff
270 * than just frame and byte counts
272 if(git->io->count_type==COUNT_TYPE_ADVANCED){
276 gp=proto_get_finfo_ptr_array(edt->tree, git->hf_index);
281 /* update the appropriate counters, make sure that if
282 * frames==0 then this is the first seen value so
283 * set any min/max values accordingly
285 for(i=0;i<gp->len;i++){
289 switch(proto_registrar_get_ftype(git->hf_index)){
298 new_int=fvalue_get_integer(&((field_info *)gp->pdata[i])->value);
300 if((new_int>it->int_max)||(it->frames==0)){
303 if((new_int<it->int_min)||(it->frames==0)){
306 it->int_tot+=new_int;
308 case FT_RELATIVE_TIME:
309 new_time=fvalue_get(&((field_info *)gp->pdata[0])->value);
311 switch(git->calc_type){
313 guint64 t, pt; /* time in us */
319 /* it is a LOAD calculation of a relative time field.
320 * add the time this call spanned to each
321 * interval it spanned according to its contribution
325 t=t*1000000+new_time->nsecs/1000;
327 /* handle current interval */
328 pt=pinfo->fd->rel_secs*1000000+pinfo->fd->rel_usecs;
329 pt=pt%(git->io->interval*1000);
334 git->items[i].time_tot.nsecs+=pt*1000;
335 if(git->items[i].time_tot.nsecs>1000000000){
336 git->items[i].time_tot.secs++;
337 git->items[i].time_tot.nsecs-=1000000000;
345 if(t > (guint32) (git->io->interval*1000)){
346 pt=git->io->interval*1000;
353 if( (new_time->secs>it->time_max.secs)
354 ||( (new_time->secs==it->time_max.secs)
355 &&(new_time->nsecs>it->time_max.nsecs))
357 it->time_max.secs=new_time->secs;
358 it->time_max.nsecs=new_time->nsecs;
360 if( (new_time->secs<it->time_min.secs)
361 ||( (new_time->secs==it->time_min.secs)
362 &&(new_time->nsecs<it->time_min.nsecs))
364 it->time_min.secs=new_time->secs;
365 it->time_min.nsecs=new_time->nsecs;
367 it->time_tot.secs+=new_time->secs;
368 it->time_tot.nsecs+=new_time->nsecs;
369 if(it->time_tot.nsecs>=1000000000){
370 it->time_tot.nsecs-=1000000000;
380 it->bytes+=pinfo->fd->pkt_len;
387 get_it_value(io_stat_t *io, int graph_id, int idx)
393 it=&io->graphs[graph_id].items[idx];
395 switch(io->count_type){
396 case COUNT_TYPE_FRAMES:
398 case COUNT_TYPE_BYTES:
403 adv_type=proto_registrar_get_ftype(io->graphs[graph_id].hf_index);
406 switch(io->graphs[graph_id].calc_type){
407 case CALC_TYPE_COUNT:
422 switch(io->graphs[graph_id].calc_type){
426 case CALC_TYPE_COUNT:
437 value=it->int_tot/it->frames;
446 case FT_RELATIVE_TIME:
447 switch(io->graphs[graph_id].calc_type){
448 case CALC_TYPE_COUNT:
452 value=it->time_max.secs*1000000+it->time_max.nsecs/1000;
455 value=it->time_min.secs*1000000+it->time_min.nsecs/1000;
460 guint64 t; /* time in us */
465 t=t*1000000+it->time_tot.nsecs/1000;
472 value=(it->time_tot.secs*1000000+it->time_tot.nsecs/1000)/io->interval;
486 print_time_scale_string(char *buf, int buf_len, guint32 t)
489 g_snprintf(buf, buf_len, "%ds",t/1000000);
490 } else if(t>=1000000){
491 g_snprintf(buf, buf_len, "%d.%03ds",t/1000000,(t%1000000)/1000);
493 g_snprintf(buf, buf_len, "%dms",t/1000);
495 g_snprintf(buf, buf_len, "%d.%03dms",t/1000,t%1000);
497 g_snprintf(buf, buf_len, "%dus",t);
502 io_stat_draw(io_stat_t *io)
505 guint32 last_interval, first_interval, interval_delta, delta_multiplier;
506 gint32 current_interval;
507 guint32 left_x_border;
508 guint32 right_x_border;
509 guint32 top_y_border;
510 guint32 bottom_y_border;
511 #if GTK_MAJOR_VERSION < 2
516 guint32 label_width, label_height;
517 guint32 draw_width, draw_height;
518 char label_string[15];
521 guint32 num_time_intervals;
522 guint32 max_value; /* max value of seen data */
523 guint32 max_y; /* max value of the Y scale */
524 gboolean draw_y_as_time;
526 #if GTK_MAJOR_VERSION <2
527 font = io->draw_area->style->font;
530 if(!io->needs_redraw){
533 io->needs_redraw=FALSE;
537 * Find the length of the intervals we have data for
538 * so we know how large arrays we need to malloc()
540 num_time_intervals=io->num_items;
541 /* if there isnt anything to do, just return */
542 if(num_time_intervals==0){
545 num_time_intervals+=1;
546 /* XXX move this check to _packet() */
547 if(num_time_intervals>NUM_IO_ITEMS){
548 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "IO-Stat error. There are too many entries, bailing out");
554 * find the max value so we can autoscale the y axis
557 for(i=0;i<MAX_GRAPHS;i++){
560 if(!io->graphs[i].display){
563 for(idx=0;(guint32) (idx) < num_time_intervals;idx++){
566 val=get_it_value(io, i, idx);
568 /* keep track of the max value we have encountered */
580 gdk_draw_rectangle(io->pixmap,
581 io->draw_area->style->white_gc,
584 io->draw_area->allocation.width,
585 io->draw_area->allocation.height);
589 * Calculate the y scale we should use
591 if(io->max_y_units==AUTO_MAX_YSCALE){
592 max_y=yscale_max[MAX_YSCALE-1];
593 for(i=MAX_YSCALE-1;i>0;i--){
594 if(max_value<yscale_max[i]){
599 /* the user had specified an explicit y scale to use */
600 max_y=io->max_y_units;
605 * If we use ADVANCED and all the graphs are plotting
606 * either MIN/MAX/AVG of an FT_RELATIVE_TIME field
607 * then we will do some some special processing for the
608 * labels for the Y axis below:
609 * we will append the time unit " s" " ms" or " us"
610 * and we will present the unit in decimal
612 draw_y_as_time=FALSE;
613 if(io->count_type==COUNT_TYPE_ADVANCED){
615 for(i=0;i<MAX_GRAPHS;i++){
618 if(!io->graphs[i].display){
621 adv_type=proto_registrar_get_ftype(io->graphs[i].hf_index);
623 case FT_RELATIVE_TIME:
624 switch(io->graphs[i].calc_type){
630 draw_y_as_time=FALSE;
634 draw_y_as_time=FALSE;
642 * Calculate size of borders surrounding the plot
643 * The border on the right side needs to be adjusted depending
644 * on the width of the text labels. For simplicity we assume that the
645 * top y scale label will be the widest one
648 print_time_scale_string(label_string, 15, max_y);
650 g_snprintf(label_string, 15, "%d", max_y);
652 #if GTK_MAJOR_VERSION < 2
653 label_width=gdk_string_width(font, label_string);
654 label_height=gdk_string_height(font, label_string);
656 layout = gtk_widget_create_pango_layout(io->draw_area, label_string);
657 pango_layout_get_pixel_size(layout, &label_width, &label_height);
660 right_x_border=label_width+20;
662 bottom_y_border=label_height+20;
666 * Calculate the size of the drawing area for the actual plot
668 draw_width=io->pixmap_width-right_x_border-left_x_border;
669 draw_height=io->pixmap_height-top_y_border-bottom_y_border;
673 * Draw the y axis and labels
674 * (we always draw the y scale with 11 ticks along the axis)
676 gdk_draw_line(io->pixmap, io->draw_area->style->black_gc,
677 io->pixmap_width-right_x_border+1,
679 io->pixmap_width-right_x_border+1,
680 io->pixmap_height-bottom_y_border);
686 /* first, middle and last tick are slightly longer */
690 gdk_draw_line(io->pixmap, io->draw_area->style->black_gc,
691 io->pixmap_width-right_x_border+1,
692 io->pixmap_height-bottom_y_border-draw_height*i/10,
693 io->pixmap_width-right_x_border+1+xwidth,
694 io->pixmap_height-bottom_y_border-draw_height*i/10);
695 /* draw the labels */
698 print_time_scale_string(label_string, 15, (max_y*i/10));
700 g_snprintf(label_string, 15, "%d", max_y*i/10);
702 #if GTK_MAJOR_VERSION < 2
703 lwidth=gdk_string_width(font, label_string);
704 gdk_draw_string(io->pixmap,
706 io->draw_area->style->black_gc,
707 io->pixmap_width-right_x_border+15+label_width-lwidth,
708 io->pixmap_height-bottom_y_border-draw_height*i/10+label_height/2,
711 pango_layout_set_text(layout, label_string, -1);
712 pango_layout_get_pixel_size(layout, &lwidth, NULL);
713 gdk_draw_layout(io->pixmap,
714 io->draw_area->style->black_gc,
715 io->pixmap_width-right_x_border+15+label_width-lwidth,
716 io->pixmap_height-bottom_y_border-draw_height*i/10-label_height/2,
722 print_time_scale_string(label_string, 15, (max_y*i/10));
724 g_snprintf(label_string, 15, "%d", max_y*i/10);
726 #if GTK_MAJOR_VERSION < 2
727 lwidth=gdk_string_width(font, label_string);
728 gdk_draw_string(io->pixmap,
730 io->draw_area->style->black_gc,
731 io->pixmap_width-right_x_border+15+label_width-lwidth,
732 io->pixmap_height-bottom_y_border-draw_height*i/10+label_height/2,
735 pango_layout_set_text(layout, label_string, -1);
736 pango_layout_get_pixel_size(layout, &lwidth, NULL);
737 gdk_draw_layout(io->pixmap,
738 io->draw_area->style->black_gc,
739 io->pixmap_width-right_x_border+15+label_width-lwidth,
740 io->pixmap_height-bottom_y_border-draw_height*i/10-label_height/2,
746 print_time_scale_string(label_string, 15, (max_y*i/10));
748 g_snprintf(label_string, 15, "%d", max_y*i/10);
750 #if GTK_MAJOR_VERSION < 2
751 lwidth=gdk_string_width(font, label_string);
752 gdk_draw_string(io->pixmap,
754 io->draw_area->style->black_gc,
755 io->pixmap_width-right_x_border+15+label_width-lwidth,
756 io->pixmap_height-bottom_y_border-draw_height*i/10+label_height/2,
759 pango_layout_set_text(layout, label_string, -1);
760 pango_layout_get_pixel_size(layout, &lwidth, NULL);
761 gdk_draw_layout(io->pixmap,
762 io->draw_area->style->black_gc,
763 io->pixmap_width-right_x_border+15+label_width-lwidth,
764 io->pixmap_height-bottom_y_border-draw_height*i/10-label_height/2,
773 * if we have not specified the last_interval via the gui,
774 * then just pick the current end of the capture so that is scrolls
775 * nicely when doing live captures
777 if(io->last_interval==0xffffffff){
778 last_interval=io->max_interval;
780 last_interval=io->last_interval;
787 /* plot the x-scale */
788 gdk_draw_line(io->pixmap, io->draw_area->style->black_gc, left_x_border, io->pixmap_height-bottom_y_border+1, io->pixmap_width-right_x_border+1, io->pixmap_height-bottom_y_border+1);
790 if((last_interval/io->interval)>draw_width/io->pixels_per_tick+1){
791 first_interval=(last_interval/io->interval)-draw_width/io->pixels_per_tick+1;
792 first_interval*=io->interval;
799 while(interval_delta<((last_interval-first_interval)/10)){
800 interval_delta*=delta_multiplier;
801 if(delta_multiplier==5){
808 for(current_interval=last_interval;current_interval>(gint32)first_interval;current_interval=current_interval-io->interval){
811 /* if pixels_per_tick is <5, only draw every 10 ticks */
812 if((io->pixels_per_tick<10) && (current_interval%(10*io->interval))){
816 if(current_interval%interval_delta){
822 x=draw_width+left_x_border-((last_interval-current_interval)/io->interval)*io->pixels_per_tick;
823 gdk_draw_line(io->pixmap, io->draw_area->style->black_gc,
824 x-1-io->pixels_per_tick/2,
825 io->pixmap_height-bottom_y_border+1,
826 x-1-io->pixels_per_tick/2,
827 io->pixmap_height-bottom_y_border+xlen+1);
831 if(io->interval>=1000){
832 g_snprintf(label_string, 15, "%ds", current_interval/1000);
833 } else if(io->interval>=100){
834 g_snprintf(label_string, 15, "%d.%1ds", current_interval/1000,(current_interval/100)%10);
835 } else if(io->interval>=10){
836 g_snprintf(label_string, 15, "%d.%2ds", current_interval/1000,(current_interval/10)%100);
838 g_snprintf(label_string, 15, "%d.%3ds", current_interval/1000,current_interval%1000);
840 #if GTK_MAJOR_VERSION < 2
841 lwidth=gdk_string_width(font, label_string);
842 gdk_draw_string(io->pixmap,
844 io->draw_area->style->black_gc,
845 x-1-io->pixels_per_tick/2-lwidth/2,
846 io->pixmap_height-bottom_y_border+15+label_height,
849 pango_layout_set_text(layout, label_string, -1);
850 pango_layout_get_pixel_size(layout, &lwidth, NULL);
851 gdk_draw_layout(io->pixmap,
852 io->draw_area->style->black_gc,
853 x-1-io->pixels_per_tick/2-lwidth/2,
854 io->pixmap_height-bottom_y_border+15,
860 #if GTK_MAJOR_VERSION >= 2
861 g_object_unref(G_OBJECT(layout));
867 * Loop over all graphs and draw them
869 for(i=MAX_GRAPHS-1;i>=0;i--){
871 guint32 x_pos, y_pos, prev_x_pos, prev_y_pos;
873 if(!io->graphs[i].display){
877 /* initialize prev x/y to the low left corner of the graph */
878 prev_x_pos=draw_width-1-io->pixels_per_tick*((last_interval-first_interval)/io->interval+1)+left_x_border;
879 prev_y_pos=draw_height-1+top_y_border;
881 for(interval=first_interval+io->interval;interval<=last_interval;interval+=io->interval){
884 x_pos=draw_width-1-io->pixels_per_tick*((last_interval-interval)/io->interval+1)+left_x_border;
886 val=get_it_value(io, i, interval/io->interval);
890 y_pos=draw_height-1-(val*draw_height)/max_y+top_y_border;
893 /* dont need to draw anything if the segment
894 * is entirely above the top of the graph
896 if( (prev_y_pos==0) && (y_pos==0) ){
902 switch(io->graphs[i].plot_style){
903 case PLOT_STYLE_LINE:
904 gdk_draw_line(io->pixmap, io->graphs[i].gc,
905 prev_x_pos, prev_y_pos,
908 case PLOT_STYLE_IMPULSE:
910 gdk_draw_line(io->pixmap, io->graphs[i].gc,
911 x_pos, draw_height-1+top_y_border,
915 case PLOT_STYLE_FILLED_BAR:
917 gdk_draw_rectangle(io->pixmap,
918 io->graphs[i].gc, TRUE,
919 x_pos-io->pixels_per_tick/2,
920 draw_height-1-(val*draw_height)/max_y+top_y_border,
922 (val*draw_height)/max_y);
935 gdk_draw_pixmap(io->draw_area->window,
936 io->draw_area->style->fg_gc[GTK_WIDGET_STATE(io->draw_area)],
940 io->pixmap_width, io->pixmap_height);
943 /* update the scrollbar */
944 io->scrollbar_adjustment->upper=(gfloat) io->max_interval;
945 io->scrollbar_adjustment->step_increment=(gfloat) ((last_interval-first_interval)/10);
946 io->scrollbar_adjustment->page_increment=(gfloat) (last_interval-first_interval);
947 if((last_interval-first_interval)*100 < io->max_interval){
948 io->scrollbar_adjustment->page_size=(gfloat) (io->max_interval/100);
950 io->scrollbar_adjustment->page_size=(gfloat) (last_interval-first_interval);
952 io->scrollbar_adjustment->value=last_interval-io->scrollbar_adjustment->page_size;
953 gtk_adjustment_changed(io->scrollbar_adjustment);
954 gtk_adjustment_value_changed(io->scrollbar_adjustment);
959 io_stat_redraw(io_stat_t *io)
961 io->needs_redraw=TRUE;
966 gtk_iostat_draw(void *g)
968 io_stat_graph_t *git=g;
970 io_stat_draw(git->io);
974 /* ok we get called with both the filter and the field.
975 make sure the field is part of the filter.
976 (make sure and make sure just append it)
977 the field MUST be part of the filter or else we wont
978 be able to pick up the field values after the edt tree has been
982 enable_graph(io_stat_graph_t *gio, char *filter, char *field)
984 char real_filter[260];
990 /* skip all whitespaces */
1003 strncpy(real_filter, filter, 255);
1008 /* skip all whitespaces */
1021 if(real_filter[0]!=0){
1022 strcat(real_filter, " && ");
1024 strncat(real_filter, field, 259-strlen(real_filter));
1028 return register_tap_listener("frame", gio, real_filter[0]?real_filter:NULL,
1029 gtk_iostat_reset, gtk_iostat_packet, gtk_iostat_draw);
1033 disable_graph(io_stat_graph_t *gio)
1037 protect_thread_critical_region();
1038 remove_tap_listener(gio);
1039 unprotect_thread_critical_region();
1040 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gio->display_button),
1046 gtk_iostat_init(char *optarg _U_)
1050 static color_t col[MAX_GRAPHS] = {
1051 {0, 0x0000, 0x0000, 0x0000},
1052 {0, 0xffff, 0x0000, 0x0000},
1053 {0, 0x0000, 0xffff, 0x0000},
1054 {0, 0x0000, 0x0000, 0xffff},
1055 {0, 0xffff, 0x5000, 0xffff}
1057 GString *error_string;
1059 io=g_malloc(sizeof(io_stat_t));
1060 io->needs_redraw=TRUE;
1066 io->scrollbar_adjustment=NULL;
1067 io->pixmap_width=500;
1068 io->pixmap_height=200;
1069 io->pixels_per_tick=pixels_per_tick[DEFAULT_PIXELS_PER_TICK];
1070 io->max_y_units=AUTO_MAX_YSCALE;
1072 io->last_interval=0xffffffff;
1076 for(i=0;i<MAX_GRAPHS;i++){
1077 io->graphs[i].gc=NULL;
1078 io->graphs[i].color.pixel=col[i].pixel;
1079 io->graphs[i].color.red=col[i].red;
1080 io->graphs[i].color.green=col[i].green;
1081 io->graphs[i].color.blue=col[i].blue;
1082 io->graphs[i].display=0;
1083 io->graphs[i].display_button=NULL;
1084 io->graphs[i].filter_field=NULL;
1085 io->graphs[i].advanced_buttons=NULL;
1086 io->graphs[i].io=io;
1088 io->graphs[i].args=g_malloc(sizeof(construct_args_t));
1089 io->graphs[i].args->title = NULL;
1090 io->graphs[i].args->wants_apply_button=TRUE;
1091 io->graphs[i].args->activate_on_ok=TRUE;
1093 io->graphs[i].filter_bt=NULL;
1097 error_string=enable_graph(&io->graphs[0], NULL, NULL);
1099 fprintf(stderr, "ethereal: Can't attach io_stat tap: %s\n",
1101 g_string_free(error_string, TRUE);
1102 io->graphs[0].display=0;
1103 io->graphs[0].display_button=NULL;
1104 io->graphs[0].filter_field=NULL;
1105 io->graphs[0].advanced_buttons=NULL;
1110 init_io_stat_window(io);
1112 retap_packets(&cfile);
1117 quit(GtkWidget *widget, GdkEventExpose *event _U_)
1122 io=(io_stat_t *)OBJECT_GET_DATA(widget, "io_stat_t");
1124 for(i=0;i<MAX_GRAPHS;i++){
1125 if(io->graphs[i].display){
1126 protect_thread_critical_region();
1127 remove_tap_listener(&io->graphs[i]);
1128 unprotect_thread_critical_region();
1130 free(io->graphs[i].args->title);
1131 io->graphs[i].args->title=NULL;
1133 g_free(io->graphs[i].args);
1134 io->graphs[i].args=NULL;
1142 /* create a new backing pixmap of the appropriate size */
1144 configure_event(GtkWidget *widget, GdkEventConfigure *event _U_)
1149 io=(io_stat_t *)OBJECT_GET_DATA(widget, "io_stat_t");
1155 gdk_pixmap_unref(io->pixmap);
1159 io->pixmap=gdk_pixmap_new(widget->window,
1160 widget->allocation.width,
1161 widget->allocation.height,
1163 io->pixmap_width=widget->allocation.width;
1164 io->pixmap_height=widget->allocation.height;
1166 gdk_draw_rectangle(io->pixmap,
1167 widget->style->white_gc,
1170 widget->allocation.width,
1171 widget->allocation.height);
1173 /* set up the colors and the GC structs for this pixmap */
1174 for(i=0;i<MAX_GRAPHS;i++){
1175 io->graphs[i].gc=gdk_gc_new(io->pixmap);
1176 #if GTK_MAJOR_VERSION < 2
1177 colormap = gtk_widget_get_colormap (widget);
1178 if (!gdk_color_alloc (colormap, &io->graphs[i].color)){
1179 g_warning ("Couldn't allocate color");
1182 gdk_gc_set_foreground(io->graphs[i].gc, &io->graphs[i].color);
1184 gdk_gc_set_rgb_fg_color(io->graphs[i].gc, &io->graphs[i].color);
1194 scrollbar_changed(GtkWidget *widget _U_, gpointer data)
1196 io_stat_t *io=(io_stat_t *)data;
1199 mi=(guint32) (io->scrollbar_adjustment->value+io->scrollbar_adjustment->page_size);
1200 if(io->last_interval==mi){
1203 if( (io->last_interval==0xffffffff)
1204 && (mi==io->max_interval) ){
1208 io->last_interval=(mi/io->interval)*io->interval;
1214 /* redraw the screen from the backing pixmap */
1216 expose_event(GtkWidget *widget, GdkEventExpose *event)
1220 io=(io_stat_t *)OBJECT_GET_DATA(widget, "io_stat_t");
1226 gdk_draw_pixmap(widget->window,
1227 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
1229 event->area.x, event->area.y,
1230 event->area.x, event->area.y,
1231 event->area.width, event->area.height);
1238 create_draw_area(io_stat_t *io, GtkWidget *box)
1240 io->draw_area=gtk_drawing_area_new();
1241 SIGNAL_CONNECT(io->draw_area, "destroy", quit, io);
1242 OBJECT_SET_DATA(io->draw_area, "io_stat_t", io);
1244 WIDGET_SET_SIZE(io->draw_area, io->pixmap_width, io->pixmap_height);
1246 /* signals needed to handle backing pixmap */
1247 SIGNAL_CONNECT(io->draw_area, "expose_event", expose_event, NULL);
1248 SIGNAL_CONNECT(io->draw_area, "configure_event", configure_event, io);
1250 gtk_widget_show(io->draw_area);
1251 gtk_box_pack_start(GTK_BOX(box), io->draw_area, TRUE, TRUE, 0);
1253 /* create the associated scrollbar */
1254 io->scrollbar_adjustment=(GtkAdjustment *)gtk_adjustment_new(0,0,0,0,0,0);
1255 io->scrollbar=gtk_hscrollbar_new(io->scrollbar_adjustment);
1256 gtk_widget_show(io->scrollbar);
1257 gtk_box_pack_start(GTK_BOX(box), io->scrollbar, FALSE, FALSE, 0);
1258 SIGNAL_CONNECT(io->scrollbar_adjustment, "value_changed", scrollbar_changed, io);
1263 tick_interval_select(GtkWidget *item, gpointer key)
1268 io=(io_stat_t *)key;
1269 val=(int)OBJECT_GET_DATA(item, "tick_interval");
1272 retap_packets(&cfile);
1277 pixels_per_tick_select(GtkWidget *item, gpointer key)
1282 io=(io_stat_t *)key;
1283 val=(int)OBJECT_GET_DATA(item, "pixels_per_tick");
1284 io->pixels_per_tick=val;
1289 plot_style_select(GtkWidget *item, gpointer key)
1292 io_stat_graph_t *ppt;
1294 ppt=(io_stat_graph_t *)key;
1295 val=(int)OBJECT_GET_DATA(item, "plot_style");
1297 ppt->plot_style=val;
1299 io_stat_redraw(ppt->io);
1303 create_pixels_per_tick_menu_items(io_stat_t *io, GtkWidget *menu)
1306 GtkWidget *menu_item;
1309 for(i=0;i<MAX_PIXELS_PER_TICK;i++){
1310 g_snprintf(str, 5, "%d", pixels_per_tick[i]);
1311 menu_item=gtk_menu_item_new_with_label(str);
1313 OBJECT_SET_DATA(menu_item, "pixels_per_tick",
1314 pixels_per_tick[i]);
1315 SIGNAL_CONNECT(menu_item, "activate", pixels_per_tick_select, io);
1316 gtk_widget_show(menu_item);
1317 gtk_menu_append(GTK_MENU(menu), menu_item);
1319 gtk_menu_set_active(GTK_MENU(menu), DEFAULT_PIXELS_PER_TICK);
1325 yscale_select(GtkWidget *item, gpointer key)
1330 io=(io_stat_t *)key;
1331 val=(int)OBJECT_GET_DATA(item, "yscale_max");
1333 io->max_y_units=val;
1338 create_tick_interval_menu_items(io_stat_t *io, GtkWidget *menu)
1341 GtkWidget *menu_item;
1344 for(i=0;i<MAX_TICK_VALUES;i++){
1345 if(tick_interval_values[i]>=1000){
1346 g_snprintf(str, 15, "%d sec", tick_interval_values[i]/1000);
1347 } else if(tick_interval_values[i]>=100){
1348 g_snprintf(str, 15, "0.%1d sec", (tick_interval_values[i]/100)%10);
1349 } else if(tick_interval_values[i]>=10){
1350 g_snprintf(str, 15, "0.%02d sec", (tick_interval_values[i]/10)%10);
1352 g_snprintf(str, 15, "0.%03d sec", (tick_interval_values[i])%10);
1355 menu_item=gtk_menu_item_new_with_label(str);
1356 OBJECT_SET_DATA(menu_item, "tick_interval",
1357 tick_interval_values[i]);
1358 SIGNAL_CONNECT(menu_item, "activate", tick_interval_select, (gpointer)io);
1359 gtk_widget_show(menu_item);
1360 gtk_menu_append(GTK_MENU(menu), menu_item);
1362 gtk_menu_set_active(GTK_MENU(menu), DEFAULT_TICK_VALUE);
1367 create_yscale_max_menu_items(io_stat_t *io, GtkWidget *menu)
1370 GtkWidget *menu_item;
1373 for(i=0;i<MAX_YSCALE;i++){
1374 if(yscale_max[i]==AUTO_MAX_YSCALE){
1377 g_snprintf(str, 15, "%d", yscale_max[i]);
1379 menu_item=gtk_menu_item_new_with_label(str);
1380 OBJECT_SET_DATA(menu_item, "yscale_max", yscale_max[i]);
1381 SIGNAL_CONNECT(menu_item, "activate", yscale_select, io);
1382 gtk_widget_show(menu_item);
1383 gtk_menu_append(GTK_MENU(menu), menu_item);
1389 count_type_select(GtkWidget *item, gpointer key)
1394 io=(io_stat_t *)key;
1395 val=(int)OBJECT_GET_DATA(item, "count_type");
1399 if(io->count_type==COUNT_TYPE_ADVANCED){
1401 for(i=0;i<MAX_GRAPHS;i++){
1402 disable_graph(&io->graphs[i]);
1403 gtk_widget_show(io->graphs[i].advanced_buttons);
1404 /* redraw the entire window so the unhidden widgets show up, hopefully */
1405 {GdkRectangle update_rect;
1408 update_rect.width=io->window->allocation.width;
1409 update_rect.height=io->window->allocation.height;
1410 gtk_widget_draw(io->window, &update_rect);
1415 for(i=0;i<MAX_GRAPHS;i++){
1416 gtk_widget_hide(io->graphs[i].advanced_buttons);
1424 create_frames_or_bytes_menu_items(io_stat_t *io, GtkWidget *menu)
1426 GtkWidget *menu_item;
1429 for(i=0;i<MAX_COUNT_TYPES;i++){
1430 menu_item=gtk_menu_item_new_with_label(count_type_names[i]);
1431 OBJECT_SET_DATA(menu_item, "count_type", i);
1432 SIGNAL_CONNECT(menu_item, "activate", count_type_select, io);
1433 gtk_widget_show(menu_item);
1434 gtk_menu_append(GTK_MENU(menu), menu_item);
1440 create_ctrl_menu(io_stat_t *io, GtkWidget *box, char *name, void (*func)(io_stat_t *io, GtkWidget *menu))
1444 GtkWidget *option_menu;
1447 hbox=gtk_hbox_new(FALSE, 0);
1448 gtk_container_add(GTK_CONTAINER(box), hbox);
1449 gtk_box_set_child_packing(GTK_BOX(box), hbox, FALSE, FALSE, 0, GTK_PACK_START);
1450 gtk_widget_show(hbox);
1452 label=gtk_label_new(name);
1453 gtk_widget_show(label);
1454 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1456 option_menu=gtk_option_menu_new();
1457 menu=gtk_menu_new();
1459 gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), menu);
1460 gtk_box_pack_end(GTK_BOX(hbox), option_menu, FALSE, FALSE, 0);
1461 gtk_widget_show(option_menu);
1465 create_ctrl_area(io_stat_t *io, GtkWidget *box)
1467 GtkWidget *frame_vbox;
1471 frame_vbox=gtk_vbox_new(FALSE, 0);
1472 gtk_container_add(GTK_CONTAINER(box), frame_vbox);
1473 gtk_widget_show(frame_vbox);
1475 frame = gtk_frame_new("X Axis");
1476 gtk_container_add(GTK_CONTAINER(frame_vbox), frame);
1477 gtk_widget_show(frame);
1479 vbox=gtk_vbox_new(FALSE, 0);
1480 gtk_container_add(GTK_CONTAINER(frame), vbox);
1481 gtk_container_border_width(GTK_CONTAINER(vbox), 3);
1482 gtk_box_set_child_packing(GTK_BOX(box), vbox, FALSE, FALSE, 0, GTK_PACK_END);
1483 gtk_widget_show(vbox);
1485 create_ctrl_menu(io, vbox, "Tick interval:", create_tick_interval_menu_items);
1486 create_ctrl_menu(io, vbox, "Pixels per tick:", create_pixels_per_tick_menu_items);
1488 frame = gtk_frame_new("Y Axis");
1489 gtk_container_add(GTK_CONTAINER(frame_vbox), frame);
1490 gtk_widget_show(frame);
1492 vbox=gtk_vbox_new(FALSE, 0);
1493 gtk_container_add(GTK_CONTAINER(frame), vbox);
1494 gtk_container_border_width(GTK_CONTAINER(vbox), 3);
1495 gtk_box_set_child_packing(GTK_BOX(box), vbox, FALSE, FALSE, 0, GTK_PACK_END);
1496 gtk_widget_show(vbox);
1498 create_ctrl_menu(io, vbox, "Unit:", create_frames_or_bytes_menu_items);
1499 create_ctrl_menu(io, vbox, "Scale:", create_yscale_max_menu_items);
1506 filter_callback(GtkWidget *widget _U_, io_stat_graph_t *gio)
1510 header_field_info *hfi;
1513 field=(char *)gtk_entry_get_text(GTK_ENTRY(gio->calc_field));
1515 /* this graph is not active, just update display and redraw */
1516 if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gio->display_button))){
1518 io_stat_redraw(gio->io);
1522 /* first check if the field string is valid */
1523 if(gio->io->count_type==COUNT_TYPE_ADVANCED){
1524 /* warn and bail out if there was no field specified */
1525 if(field==NULL || field[0]==0){
1526 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "You did not specify a field name.");
1528 io_stat_redraw(gio->io);
1531 /* warn and bail out if the field could not be found */
1532 hfi=proto_registrar_get_byname(field);
1534 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "'%s' is not a valid field name.", field);
1536 io_stat_redraw(gio->io);
1539 gio->hf_index=hfi->id;
1540 /* check that the type is compatible */
1550 /* these values support all calculations except LOAD */
1551 switch(gio->calc_type){
1552 case CALC_TYPE_LOAD:
1553 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1554 "LOAD(*) is only supported for relative-time fields.");
1556 io_stat_redraw(gio->io);
1559 /* these types support all calculations */
1561 case FT_RELATIVE_TIME:
1562 /* this type only supports COUNT, MAX, MIN, AVG */
1563 switch(gio->calc_type){
1564 case CALC_TYPE_COUNT:
1568 case CALC_TYPE_LOAD:
1571 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1572 "%s is a relative-time field, so %s calculations are not supported on it.",
1574 calc_type_names[gio->calc_type]);
1576 io_stat_redraw(gio->io);
1583 * XXX - support this if gint64/guint64 are
1586 if(gio->calc_type!=CALC_TYPE_COUNT){
1587 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1588 "%s is a 64-bit integer, so %s calculations are not supported on it.",
1590 calc_type_names[gio->calc_type]);
1592 io_stat_redraw(gio->io);
1598 * XXX - support all operations on floating-point
1601 if(gio->calc_type!=CALC_TYPE_COUNT){
1602 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1603 "%s doesn't have integral values, so %s calculations are not supported on it.",
1605 calc_type_names[gio->calc_type]);
1607 io_stat_redraw(gio->io);
1614 /* first check if the filter string is valid. */
1615 filter=(char *)gtk_entry_get_text(GTK_ENTRY(gio->filter_field));
1616 if(!dfilter_compile(filter, &dfilter)) {
1617 bad_dfilter_alert_box(filter);
1619 io_stat_redraw(gio->io);
1622 if (dfilter != NULL)
1623 dfilter_free(dfilter);
1625 /* ok, we have a valid filter and the graph is active.
1626 first just try to delete any previous settings and then apply
1629 protect_thread_critical_region();
1630 remove_tap_listener(gio);
1631 unprotect_thread_critical_region();
1633 io_stat_reset(gio->io);
1634 enable_graph(gio, filter, field);
1635 retap_packets(&cfile);
1636 io_stat_redraw(gio->io);
1643 calc_type_select(GtkWidget *item _U_, gpointer key)
1645 io_stat_calc_type_t *ct=(io_stat_calc_type_t *)key;
1647 ct->gio->calc_type=ct->calc_type;
1649 /* disable the graph */
1650 disable_graph(ct->gio);
1651 io_stat_redraw(ct->gio->io);
1656 create_calc_types_menu_items(io_stat_graph_t *gio, GtkWidget *menu)
1658 GtkWidget *menu_item;
1661 for(i=0;i<MAX_CALC_TYPES;i++){
1662 gio->calc_types[i].gio=gio;
1663 gio->calc_types[i].calc_type=i;
1664 menu_item=gtk_menu_item_new_with_label(calc_type_names[i]);
1665 SIGNAL_CONNECT(menu_item, "activate", calc_type_select, &gio->calc_types[i]);
1666 gtk_widget_show(menu_item);
1667 gtk_menu_append(GTK_MENU(menu), menu_item);
1674 create_advanced_menu(io_stat_graph_t *gio, GtkWidget *box, char *name, void (*func)(io_stat_graph_t *io, GtkWidget *menu))
1678 GtkWidget *option_menu;
1681 hbox=gtk_hbox_new(FALSE, 0);
1682 gtk_container_add(GTK_CONTAINER(box), hbox);
1683 gtk_box_set_child_packing(GTK_BOX(box), hbox, FALSE, FALSE, 0, GTK_PACK_START);
1684 gtk_widget_show(hbox);
1686 label=gtk_label_new(name);
1687 gtk_widget_show(label);
1688 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1690 option_menu=gtk_option_menu_new();
1691 menu=gtk_menu_new();
1693 gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), menu);
1694 gtk_box_pack_end(GTK_BOX(hbox), option_menu, FALSE, FALSE, 0);
1695 gtk_widget_show(option_menu);
1699 create_advanced_field(io_stat_graph_t *gio, GtkWidget *box)
1702 gio->calc_field=gtk_entry_new_with_max_length(30);
1703 gtk_box_pack_start(GTK_BOX(box), gio->calc_field, FALSE, FALSE, 0);
1704 gtk_widget_show(gio->calc_field);
1705 SIGNAL_CONNECT(gio->calc_field, "activate", filter_callback, gio);
1710 create_advanced_box(io_stat_graph_t *gio, GtkWidget *box)
1714 hbox=gtk_hbox_new(FALSE, 0);
1715 gio->advanced_buttons=hbox;
1716 gtk_container_add(GTK_CONTAINER(box), hbox);
1717 gtk_box_set_child_packing(GTK_BOX(box), hbox, FALSE, FALSE, 0, GTK_PACK_START);
1718 gtk_widget_hide(hbox);
1720 gio->calc_type=CALC_TYPE_SUM;
1721 create_advanced_menu(gio, hbox, "Calc:", create_calc_types_menu_items);
1722 create_advanced_field(gio, hbox);
1727 filter_button_clicked(GtkWidget *w, gpointer uio)
1729 io_stat_graph_t *gio=(io_stat_graph_t *)uio;
1731 display_filter_construct_cb(w, gio->args);
1736 create_filter_box(io_stat_graph_t *gio, GtkWidget *box, int num)
1738 GtkWidget *option_menu;
1740 GtkWidget *menu_item;
1746 hbox=gtk_hbox_new(FALSE, 3);
1747 gtk_container_add(GTK_CONTAINER(box), hbox);
1748 gtk_box_set_child_packing(GTK_BOX(box), hbox, FALSE, FALSE, 0, GTK_PACK_START);
1749 gtk_widget_show(hbox);
1751 g_snprintf(str, 256, "Graph %d", num);
1752 gio->display_button=gtk_toggle_button_new_with_label(str);
1753 gtk_box_pack_start(GTK_BOX(hbox), gio->display_button, FALSE, FALSE, 0);
1754 gtk_widget_show(gio->display_button);
1755 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gio->display_button), gio->display);
1756 SIGNAL_CONNECT(gio->display_button, "toggled", filter_callback, gio);
1758 label=gtk_label_new("Color");
1759 gtk_widget_show(label);
1760 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1762 #if GTK_MAJOR_VERSION < 2
1763 /* setting the color of the display button doesn't work */
1764 rc_style = gtk_rc_style_new ();
1765 rc_style->fg[GTK_STATE_NORMAL] = gio->color;
1766 rc_style->color_flags[GTK_STATE_NORMAL] |= GTK_RC_FG;
1767 rc_style->fg[GTK_STATE_ACTIVE] = gio->color;
1768 rc_style->color_flags[GTK_STATE_ACTIVE] |= GTK_RC_FG;
1769 rc_style->fg[GTK_STATE_PRELIGHT] = gio->color;
1770 rc_style->color_flags[GTK_STATE_PRELIGHT] |= GTK_RC_FG;
1771 rc_style->fg[GTK_STATE_SELECTED] = gio->color;
1772 rc_style->color_flags[GTK_STATE_SELECTED] |= GTK_RC_FG;
1773 rc_style->fg[GTK_STATE_INSENSITIVE] = gio->color;
1774 rc_style->color_flags[GTK_STATE_INSENSITIVE] |= GTK_RC_FG;
1775 gtk_widget_modify_style (label, rc_style);
1776 gtk_rc_style_unref (rc_style);
1778 gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &gio->color);
1779 gtk_widget_modify_fg(label, GTK_STATE_ACTIVE, &gio->color);
1780 gtk_widget_modify_fg(label, GTK_STATE_PRELIGHT, &gio->color);
1781 gtk_widget_modify_fg(label, GTK_STATE_SELECTED, &gio->color);
1782 gtk_widget_modify_fg(label, GTK_STATE_INSENSITIVE, &gio->color);
1784 /* gtk_signal_connect(GTK_OBJECT(gio->display_button), "toggled", GTK_SIGNAL_FUNC(filter_callback), gio);*/
1787 /* filter prefs dialog */
1788 gio->filter_bt=BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_DISPLAY_FILTER_ENTRY);
1790 g_snprintf(str, 256, "Ethereal: Display Filter IO-Stat (Filter:%d)", num);
1791 if(gio->args->title){
1792 free(gio->args->title);
1794 gio->args->title=strdup(str);
1796 SIGNAL_CONNECT(gio->filter_bt, "clicked", filter_button_clicked, gio);
1797 SIGNAL_CONNECT(gio->filter_bt, "destroy", filter_button_destroy_cb, NULL);
1799 gtk_box_pack_start(GTK_BOX(hbox), gio->filter_bt, FALSE, TRUE, 0);
1800 gtk_widget_show(gio->filter_bt);
1802 gio->filter_field=gtk_entry_new_with_max_length(256);
1804 /* filter prefs dialog */
1805 OBJECT_SET_DATA(gio->filter_bt, E_FILT_TE_PTR_KEY, gio->filter_field);
1806 /* filter prefs dialog */
1808 gtk_box_pack_start(GTK_BOX(hbox), gio->filter_field, FALSE, FALSE, 0);
1809 gtk_widget_show(gio->filter_field);
1810 SIGNAL_CONNECT(gio->filter_field, "activate", filter_callback, gio);
1811 SIGNAL_CONNECT(gio->filter_field, "changed", filter_te_syntax_check_cb, NULL);
1813 create_advanced_box(gio, hbox);
1817 * create PlotStyle menu
1819 g_snprintf(str, 256, " Style:");
1820 label=gtk_label_new(str);
1821 gtk_widget_show(label);
1822 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1824 option_menu=gtk_option_menu_new();
1825 menu=gtk_menu_new();
1826 for(i=0;i<MAX_PLOT_STYLES;i++){
1827 menu_item=gtk_menu_item_new_with_label(plot_style_name[i]);
1828 OBJECT_SET_DATA(menu_item, "plot_style", i);
1829 SIGNAL_CONNECT(menu_item, "activate", plot_style_select, &gio->io->graphs[num-1]);
1830 gtk_widget_show(menu_item);
1831 gtk_menu_append(GTK_MENU(menu), menu_item);
1833 gtk_menu_set_active(GTK_MENU(menu), DEFAULT_PLOT_STYLE);
1835 gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), menu);
1836 gtk_box_pack_end(GTK_BOX(hbox), option_menu, FALSE, FALSE, 0);
1837 gtk_widget_show(option_menu);
1844 create_filter_area(io_stat_t *io, GtkWidget *box)
1850 frame=gtk_frame_new("Graphs");
1851 gtk_container_add(GTK_CONTAINER(box), frame);
1852 gtk_widget_show(frame);
1854 vbox=gtk_vbox_new(FALSE, 1);
1855 gtk_container_add(GTK_CONTAINER(frame), vbox);
1856 gtk_container_border_width(GTK_CONTAINER(vbox), 3);
1857 gtk_box_set_child_packing(GTK_BOX(box), vbox, FALSE, FALSE, 0, GTK_PACK_START);
1858 gtk_widget_show(vbox);
1860 for(i=0;i<MAX_GRAPHS;i++){
1861 create_filter_box(&io->graphs[i], vbox, i+1);
1869 init_io_stat_window(io_stat_t *io)
1873 GtkWidget *bt_close;
1875 /* create the main window */
1876 io->window=window_new(GTK_WINDOW_TOPLEVEL, "I/O Graphs");
1878 vbox=gtk_vbox_new(FALSE, 0);
1879 gtk_container_add(GTK_CONTAINER(io->window), vbox);
1880 gtk_widget_show(vbox);
1882 create_draw_area(io, vbox);
1884 hbox=gtk_hbox_new(FALSE, 3);
1885 gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
1886 gtk_container_border_width(GTK_CONTAINER(hbox), 3);
1887 gtk_box_set_child_packing(GTK_BOX(vbox), hbox, FALSE, FALSE, 0, GTK_PACK_START);
1888 gtk_widget_show(hbox);
1890 create_filter_area(io, hbox);
1891 create_ctrl_area(io, hbox);
1893 io_stat_set_title(io);
1895 hbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL);
1896 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1897 gtk_widget_show(hbox);
1899 bt_close = OBJECT_GET_DATA(hbox, GTK_STOCK_CLOSE);
1900 window_set_cancel_button(io->window, bt_close, window_cancel_button_cb);
1902 SIGNAL_CONNECT(io->window, "delete_event", window_delete_event_cb, NULL);
1904 gtk_widget_show(io->window);
1905 window_present(io->window);
1910 gtk_iostat_cb(GtkWidget *w _U_, gpointer d _U_)
1912 gtk_iostat_init(NULL);
1919 register_tap_listener_gtk_iostat(void)
1921 register_ethereal_tap("io,stat", gtk_iostat_init);
1923 register_tap_menu_item("_IO Graphs", REGISTER_TAP_GROUP_GENERIC,
1924 gtk_iostat_cb, NULL, NULL, NULL);