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.
36 #include <epan/epan_dissect.h>
37 #include <epan/packet_info.h>
38 #include <epan/stat_cmd_args.h>
40 #include <epan/strutil.h>
42 #include "../stat_menu.h"
43 #include "ui/alert_box.h"
44 #include "ui/simple_dialog.h"
46 #include "ui/gtk/gtkglobals.h"
47 #include "ui/gtk/gui_utils.h"
48 #include "ui/gtk/gui_stat_menu.h"
49 #include "ui/gtk/stock_icons.h"
50 #include "ui/gtk/dlg_utils.h"
51 #include "ui/gtk/filter_dlg.h"
52 #include "ui/gtk/help_dlg.h"
53 #include "ui/gtk/pixmap_save.h"
54 #include "ui/gtk/main.h"
55 #include "ui/gtk/filter_autocomplete.h"
56 #include "ui/main_statusbar.h"
58 #include "ui/gtk/old-gtk-compat.h"
63 #define LOGARITHMIC_YSCALE 0
64 #define AUTO_MAX_YSCALE 1
65 #define DEFAULT_YSCALE_INDEX 1
66 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};
68 #define NO_FILTER_ORDER 0
69 #define MAX_MOVING_AVERAGE_ORDER 10
70 static guint32 moving_average_orders[MAX_MOVING_AVERAGE_ORDER] = {NO_FILTER_ORDER, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
72 #define MOVING_AVERAGE_FILTER 1
74 #define MAX_PIXELS_PER_TICK 4
75 #define DEFAULT_PIXELS_PER_TICK_INDEX 2
76 static guint32 pixels_per_tick[MAX_PIXELS_PER_TICK] = {1, 2, 5, 10};
79 #define DEFAULT_PLOT_STYLE 0
80 #define PLOT_STYLE_LINE 0
81 #define PLOT_STYLE_IMPULSE 1
82 #define PLOT_STYLE_FILLED_BAR 2
83 #define PLOT_STYLE_DOT 3
84 #define MAX_PLOT_STYLES 4
85 static const char *plot_style_name[MAX_PLOT_STYLES] = {
92 #define DEFAULT_COUNT_TYPE 0
93 #define COUNT_TYPE_FRAMES 0
94 #define COUNT_TYPE_BYTES 1
95 #define COUNT_TYPE_BITS 2
96 #define COUNT_TYPE_ADVANCED 3
97 #define MAX_COUNT_TYPES 4
98 static const char *count_type_names[MAX_COUNT_TYPES] = {"Packets/Tick", "Bytes/Tick", "Bits/Tick", "Advanced..."};
101 #define MAX_TICK_VALUES 7
102 #define DEFAULT_TICK_VALUE_INDEX 3
103 static const guint tick_interval_values[MAX_TICK_VALUES] = { 1, 10, 100, 1000, 10000, 60000, 600000 };
105 #define CALC_TYPE_SUM 0
106 #define CALC_TYPE_COUNT 1
107 #define CALC_TYPE_MAX 2
108 #define CALC_TYPE_MIN 3
109 #define CALC_TYPE_AVG 4
110 #define CALC_TYPE_LOAD 5
111 #define MAX_CALC_TYPES 6
112 #define DEFAULT_CALC_TYPE 0
113 static const char *calc_type_names[MAX_CALC_TYPES] = {"SUM(*)", "COUNT(*)", "MAX(*)", "MIN(*)", "AVG(*)", "LOAD(*)"};
116 typedef struct _io_stat_calc_type_t {
117 struct _io_stat_graph_t *gio;
119 } io_stat_calc_type_t;
121 #define NUM_IO_ITEMS 100000
122 typedef struct _io_item_t {
123 guint32 frames; /* always calculated, will hold number of frames*/
124 guint32 bytes; /* always calculated, will hold number of bytes*/
138 guint32 first_frame_in_invl;
139 guint32 last_frame_in_invl;
142 typedef struct _io_stat_graph_t {
143 struct _io_stat_t *io;
144 io_item_t items[NUM_IO_ITEMS];
147 GtkWidget *display_button;
148 GtkWidget *filter_field;
149 GtkWidget *advanced_buttons;
152 GtkWidget *calc_field;
154 #if GTK_CHECK_VERSION(3,0,0)
157 construct_args_t *args;
158 GtkWidget *filter_bt;
162 typedef struct _io_stat_t {
163 gboolean needs_redraw;
164 guint32 interval; /* measurement interval in ms */
165 guint32 last_interval; /* the last *displayed* interval */
166 guint32 max_interval; /* the maximum interval based on the capture duration */
167 guint32 num_items; /* total number of items in all intervals (zero relative) */
168 guint32 left_x_border;
169 guint32 right_x_border;
170 gboolean view_as_time;
173 struct _io_stat_graph_t graphs[MAX_GRAPHS];
175 GtkWidget *draw_area;
176 #if GTK_CHECK_VERSION(2,22,0)
177 cairo_surface_t *surface;
181 GtkAdjustment *scrollbar_adjustment;
182 GtkWidget *scrollbar;
190 guint32 filter_order;
195 static void init_io_stat_window(io_stat_t *io);
196 static void filter_callback(GtkWidget *widget _U_, gpointer user_data);
199 io_stat_set_title(io_stat_t *io)
206 title = g_strdup_printf("Wireshark IO Graphs: %s", cf_get_display_name(&cfile));
207 gtk_window_set_title(GTK_WINDOW(io->window), title);
212 io_stat_reset(io_stat_t *io)
216 io->needs_redraw=TRUE;
217 for(i=0;i<MAX_GRAPHS;i++){
218 for(j=0;j<NUM_IO_ITEMS;j++){
220 ioi=&io->graphs[i].items[j];
234 nstime_set_zero(&ioi->time_max);
235 nstime_set_zero(&ioi->time_min);
236 nstime_set_zero(&ioi->time_tot);
237 ioi->first_frame_in_invl=0;
238 ioi->last_frame_in_invl=0;
241 io->last_interval=0xffffffff;
244 io->start_time.secs=0;
245 io->start_time.nsecs=0;
246 io_stat_set_title(io);
250 tap_iostat_reset(void *g)
252 io_stat_graph_t *gio=g;
254 io_stat_reset(gio->io);
258 tap_iostat_packet(void *g, packet_info *pinfo, epan_dissect_t *edt, const void *dummy _U_)
260 io_stat_graph_t *graph = g;
266 /* we sometimes get called when the graph is disabled.
267 this is a bug since the tap listener should be removed first */
272 io = graph->io; /* Point up to the parent io_stat_t struct */
273 io->needs_redraw = TRUE;
276 * Find in which interval this is supposed to go and store the interval index as idx
278 time_delta = pinfo->fd->rel_ts;
279 if(time_delta.nsecs<0){
281 time_delta.nsecs += 1000000000;
283 if(time_delta.secs<0){
286 idx = (int) ((time_delta.secs*1000 + time_delta.nsecs/1000000) / io->interval);
288 /* some sanity checks */
289 if((idx < 0) || (idx >= NUM_IO_ITEMS)) {
290 io->num_items = NUM_IO_ITEMS-1;
294 /* update num_items */
295 if((guint32)idx > io->num_items){
296 io->num_items = (guint32) idx;
300 if(io->start_time.secs == 0 && io->start_time.nsecs == 0) {
301 nstime_delta (&io->start_time, &pinfo->fd->abs_ts, &pinfo->fd->rel_ts);
304 /* Point to the appropriate io_item_t struct */
305 it = &graph->items[idx];
307 /* Set the first and last frame num in current interval matching the target field+filter */
308 if (it->first_frame_in_invl == 0) {
309 it->first_frame_in_invl = pinfo->fd->num;
311 it->last_frame_in_invl = pinfo->fd->num;
314 * For ADVANCED mode we need to keep track of some more stuff than just frame and byte counts */
315 if(io->count_type==COUNT_TYPE_ADVANCED){
319 gp = proto_get_finfo_ptr_array(edt->tree, graph->hf_index);
324 /* Update the appropriate counters. If fields==0, this is the first seen
325 * value so set any min/max values accordingly. */
326 for(i=0; i<gp->len; i++) {
332 switch(proto_registrar_get_ftype(graph->hf_index)){
337 new_int = fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value);
339 if((new_int > it->int_max)||(it->fields==0)){
340 it->int_max = new_int;
342 if((new_int < it->int_min)||(it->fields==0)){
343 it->int_min = new_int;
345 it->int_tot += new_int;
352 new_int = fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value);
353 if((new_int>it->int_max) || (it->fields==0)){
354 it->int_max = new_int;
356 if((new_int<it->int_min) || (it->fields==0)){
357 it->int_min = new_int;
359 it->int_tot += new_int;
363 new_float = (gfloat)fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
364 if((new_float>it->float_max) || (it->fields==0)){
365 it->float_max = new_float;
367 if((new_float<it->float_min) || (it->fields==0)){
368 it->float_min = new_float;
370 it->float_tot += new_float;
374 new_double = fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
375 if((new_double > it->double_max) || (it->fields==0)){
376 it->double_max = new_double;
378 if((new_double < it->double_min) || (it->fields==0)){
379 it->double_min = new_double;
381 it->double_tot += new_double;
384 case FT_RELATIVE_TIME:
385 new_time = fvalue_get(&((field_info *)gp->pdata[0])->value);
387 switch(graph->calc_type){
388 guint64 t, pt; /* time in us */
392 * Add the time this call spanned each interval according to its contribution
396 t = t * 1000000 + new_time->nsecs / 1000;
399 * Handle current interval */
400 pt = pinfo->fd->rel_ts.secs * 1000000 + pinfo->fd->rel_ts.nsecs / 1000;
401 pt = pt % (io->interval * 1000);
406 graph->items[j].time_tot.nsecs += (int) (pt * 1000);
407 if(graph->items[j].time_tot.nsecs > 1000000000){
408 graph->items[j].time_tot.secs++;
409 graph->items[j].time_tot.nsecs -= 1000000000;
417 if(t > io->interval * 1000) {
418 pt = (guint64) io->interval * 1000;
425 if( (new_time->secs > it->time_max.secs)
426 ||( (new_time->secs==it->time_max.secs)
427 &&(new_time->nsecs > it->time_max.nsecs))
429 it->time_max = *new_time;
431 if( (new_time->secs<it->time_min.secs)
432 ||( (new_time->secs==it->time_min.secs)
433 &&(new_time->nsecs < it->time_min.nsecs))
435 it->time_min = *new_time;
437 nstime_add(&it->time_tot, new_time);
443 * "Can't happen"; see the "check that the
444 * type is compatible" check in
447 g_assert_not_reached();
454 it->bytes += pinfo->fd->pkt_len;
460 get_it_value(io_stat_t *io, int graph, int idx)
467 it = &io->graphs[graph].items[idx];
469 switch(io->count_type){
470 case COUNT_TYPE_FRAMES:
472 case COUNT_TYPE_BYTES:
474 case COUNT_TYPE_BITS:
475 return (it->bytes * 8);
479 adv_type=proto_registrar_get_ftype(io->graphs[graph].hf_index);
482 switch(io->graphs[graph].calc_type){
483 case CALC_TYPE_COUNT:
498 switch(io->graphs[graph].calc_type){
502 case CALC_TYPE_COUNT:
513 value=it->int_tot/it->fields;
523 switch(io->graphs[graph].calc_type){
527 case CALC_TYPE_COUNT:
538 value=it->float_tot/it->fields;
548 switch(io->graphs[graph].calc_type){
550 value=it->double_tot;
552 case CALC_TYPE_COUNT:
556 value=it->double_max;
559 value=it->double_min;
563 value=it->double_tot/it->fields;
572 case FT_RELATIVE_TIME:
573 switch(io->graphs[graph].calc_type){
574 case CALC_TYPE_COUNT:
578 value=(guint32) (it->time_max.secs*1000000 + it->time_max.nsecs/1000);
581 value=(guint32) (it->time_min.secs*1000000 + it->time_min.nsecs/1000);
584 value=(guint32) (it->time_tot.secs*1000000 + it->time_tot.nsecs/1000);
588 guint64 t; /* time in us */
591 t=t*1000000+it->time_tot.nsecs/1000;
592 value=(guint32) (t/it->fields);
598 if (idx==(int)io->num_items) {
599 interval = (guint32)((cfile.elapsed_time.secs*1000) +
600 ((cfile.elapsed_time.nsecs+500000)/1000000));
601 interval -= (io->interval * idx);
603 interval = io->interval;
605 value = (guint32) ((it->time_tot.secs*1000000 + it->time_tot.nsecs/1000) / interval);
614 return (guint32)value; /* FIXME: loss of precision, visible on the graph for small values */
618 print_time_scale_string(char *buf, int buf_len, guint32 t, guint32 t_max, gboolean log_flag)
620 if(t_max>=10000000 || (log_flag && t_max>=1000000)){
621 g_snprintf(buf, buf_len, "%ds",t/1000000);
622 } else if(t_max>=1000000){
623 g_snprintf(buf, buf_len, "%d.%1ds",t/1000000,(t%1000000)/100000);
624 } else if(t_max>=10000 || (log_flag && t_max>=1000)){
625 g_snprintf(buf, buf_len, "%dms",t/1000);
626 } else if(t_max>=1000){
627 g_snprintf(buf, buf_len, "%d.%1dms",t/1000,(t%1000)/100);
629 g_snprintf(buf, buf_len, "%dus",t);
634 print_interval_string(char *buf, int buf_len, guint32 interval, io_stat_t *io,
637 if (io->view_as_time) {
639 time_t sec_val = interval/1000 + io->start_time.secs;
640 gint32 nsec_val = interval%1000 + io->start_time.nsecs/1000000;
642 if(nsec_val >= 1000) {
646 tmp = localtime (&sec_val);
647 if(io->interval>=1000){
648 g_snprintf(buf, buf_len, "%02d:%02d:%02d", tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
649 } else if(io->interval>=100){
650 g_snprintf(buf, buf_len, "%02d:%02d:%02d.%1d", tmp->tm_hour, tmp->tm_min, tmp->tm_sec, nsec_val/100);
651 } else if(io->interval>=10){
652 g_snprintf(buf, buf_len, "%02d:%02d:%02d.%02d", tmp->tm_hour, tmp->tm_min, tmp->tm_sec, nsec_val/10);
654 g_snprintf(buf, buf_len, "%02d:%02d:%02d.%03d", tmp->tm_hour, tmp->tm_min, tmp->tm_sec, nsec_val);
658 g_snprintf(buf, buf_len, "%d.%03d", interval/1000,interval%1000);
659 } else if(io->interval>=60000){
660 g_snprintf(buf, buf_len, "%dm", interval/60000);
661 } else if(io->interval>=1000){
662 g_snprintf(buf, buf_len, "%ds", interval/1000);
663 } else if(io->interval>=100){
664 g_snprintf(buf, buf_len, "%d.%1ds", interval/1000,(interval/100)%10);
665 } else if(io->interval>=10){
666 g_snprintf(buf, buf_len, "%d.%02ds", interval/1000,(interval/10)%100);
668 g_snprintf(buf, buf_len, "%d.%03ds", interval/1000,interval%1000);
674 io_stat_draw(io_stat_t *io)
676 int i, tics, ystart, ys;
677 guint32 last_interval, first_interval, interval_delta;
678 gint32 current_interval;
679 guint32 top_y_border;
680 guint32 bottom_y_border;
682 int label_width, label_height;
683 guint32 draw_width, draw_height;
684 char label_string[45];
685 GtkAllocation widget_alloc;
687 guint32 num_time_intervals; /* number of intervals relative to 1 */
688 guint32 max_value; /* max value of seen data */
689 guint32 max_y; /* max value of the Y scale */
690 gboolean draw_y_as_time;
693 if(!io->needs_redraw){
696 io->needs_redraw=FALSE;
698 * Set max_interval to duration rounded to the nearest ms. Add the Tick Interval so the last
699 * interval will be displayed. For example, if duration = 11.844 secs and 'Tick Interval'== 1,
700 * max_interval=12000; if 0.1, 11900; if 0.01, 11850; and if 0.001, 11845.
702 io->max_interval = (guint32)((cfile.elapsed_time.secs*1000) +
703 ((cfile.elapsed_time.nsecs+500000)/1000000) +
705 io->max_interval = (io->max_interval / io->interval) * io->interval;
707 * Find the length of the intervals we have data for
708 * so we know how large arrays we need to malloc()
710 num_time_intervals = io->num_items+1;
712 /* XXX move this check to _packet() */
713 if(num_time_intervals > NUM_IO_ITEMS){
714 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "IO-Stat error. There are too many entries, bailing out");
719 * find the max value so we can autoscale the y axis
722 for(i=0;i<MAX_GRAPHS;i++){
725 if(!io->graphs[i].display){
728 for(idx=0; (guint32)(idx) < num_time_intervals; idx++){
731 val=get_it_value(io, i, idx);
733 /* keep track of the max value we have encountered */
743 #if GTK_CHECK_VERSION(2,22,0)
744 cr = cairo_create (io->surface);
746 cr = gdk_cairo_create (io->pixmap);
748 cairo_set_source_rgb (cr, 1, 1, 1);
749 gtk_widget_get_allocation(io->draw_area, &widget_alloc);
750 cairo_rectangle (cr, 0, 0, widget_alloc.width,widget_alloc.height);
754 * Calculate the y scale we should use
756 if(io->max_y_units==AUTO_MAX_YSCALE){
757 max_y = yscale_max[MAX_YSCALE-1];
758 for(i=MAX_YSCALE-1; i>1; i--){
759 if(max_value < yscale_max[i]){
760 max_y = yscale_max[i];
763 } else if(io->max_y_units==LOGARITHMIC_YSCALE){
765 for(i=1000000000; i>1; i/=10){
766 if(max_value<(guint32)i){
771 /* the user had specified an explicit y scale to use */
772 max_y=io->max_y_units;
776 * If we use ADVANCED and all the graphs are plotting
777 * either MIN/MAX/AVG of an FT_RELATIVE_TIME field
778 * then we will do some some special processing for the
779 * labels for the Y axis below:
780 * we will append the time unit " s" " ms" or " us"
781 * and we will present the unit in decimal
783 draw_y_as_time = FALSE;
784 if(io->count_type==COUNT_TYPE_ADVANCED){
785 draw_y_as_time = TRUE;
786 for(i=0; i<MAX_GRAPHS; i++){
789 if(!io->graphs[i].display){
792 adv_type=proto_registrar_get_ftype(io->graphs[i].hf_index);
794 case FT_RELATIVE_TIME:
795 switch(io->graphs[i].calc_type){
802 draw_y_as_time = FALSE;
806 draw_y_as_time = FALSE;
812 * Calculate size of borders surrounding the plot
813 * The border on the right side needs to be adjusted depending
814 * on the width of the text labels. For simplicity we assume that the
815 * top y scale label will be the widest one
818 if(io->max_y_units==LOGARITHMIC_YSCALE){
819 print_time_scale_string(label_string, 15, 100000, 100000, TRUE); /* 100 ms */
821 print_time_scale_string(label_string, 15, max_y, max_y, FALSE);
824 g_snprintf(label_string, 15, "%d", max_y);
826 layout = gtk_widget_create_pango_layout(io->draw_area, label_string);
827 pango_layout_get_pixel_size(layout, &label_width, &label_height);
829 io->left_x_border = 10;
830 io->right_x_border = label_width + 20;
832 bottom_y_border = label_height + 20;
835 * Calculate the size of the drawing area for the actual plot
837 draw_width = io->pixmap_width-io->right_x_border - io->left_x_border;
838 draw_height = io->pixmap_height-top_y_border - bottom_y_border;
841 * Add a warning if too many entries
843 if (num_time_intervals >= NUM_IO_ITEMS-1) {
844 g_snprintf (label_string, 45, "Warning: Graph limited to %d entries", NUM_IO_ITEMS);
845 pango_layout_set_text(layout, label_string, -1);
847 #if GTK_CHECK_VERSION(2,22,0)
848 cr = cairo_create (io->surface);
850 cr = gdk_cairo_create (io->pixmap);
852 cairo_move_to (cr, 5, io->pixmap_height-bottom_y_border-draw_height-label_height/2);
853 pango_cairo_show_layout (cr, layout);
858 /* Draw the y axis and labels
859 * (we always draw the y scale with 11 ticks along the axis)
861 #if GTK_CHECK_VERSION(2,22,0)
862 cr = cairo_create (io->surface);
864 cr = gdk_cairo_create (io->pixmap);
866 cairo_set_line_width (cr, 1.0);
867 cairo_move_to(cr, io->pixmap_width-io->right_x_border+1.5, top_y_border + 0.5);
868 cairo_line_to(cr, io->pixmap_width-io->right_x_border+1.5, io->pixmap_height-bottom_y_border + 0.5);
871 if(io->max_y_units==LOGARITHMIC_YSCALE){
872 tics = (int)log10((double)max_y);
873 ystart = draw_height/10;
880 for(i=ys;i<=tics;i++){
881 int xwidth, lwidth, ypos;
884 if(io->max_y_units==LOGARITHMIC_YSCALE){
886 /* position for the 0 value */
887 ypos=io->pixmap_height-bottom_y_border;
888 } else if (i==tics) {
889 /* position for the top value, do not draw logarithmic tics above graph */
890 ypos=io->pixmap_height-bottom_y_border-draw_height;
893 /* draw the logarithmic tics */
894 for(j=2; j<10; j++) {
895 ypos=(int)(io->pixmap_height-bottom_y_border-(draw_height-ystart)*(i+log10((double)j))/tics-ystart);
897 #if GTK_CHECK_VERSION(2,22,0)
898 cr = cairo_create (io->surface);
900 cr = gdk_cairo_create (io->pixmap);
902 cairo_set_line_width (cr, 1.0);
903 cairo_move_to(cr, io->pixmap_width-io->right_x_border+1.5, ypos+0.5);
904 cairo_line_to(cr, io->pixmap_width-io->right_x_border+1.5+xwidth,ypos+0.5);
908 ypos=io->pixmap_height-bottom_y_border-(draw_height-ystart)*i/tics-ystart;
910 /* all "main" logarithmic lines are slightly longer */
914 /* first, middle and last tick are slightly longer */
917 ypos=io->pixmap_height-bottom_y_border-draw_height*i/10;
920 #if GTK_CHECK_VERSION(2,22,0)
921 cr = cairo_create (io->surface);
923 cr = gdk_cairo_create (io->pixmap);
925 cairo_set_line_width (cr, 1.0);
926 cairo_move_to(cr, io->pixmap_width-io->right_x_border+1.5, ypos+0.5);
927 cairo_line_to(cr, io->pixmap_width-io->right_x_border+1.5+xwidth,ypos+0.5);
930 /* draw the labels */
933 if(io->max_y_units==LOGARITHMIC_YSCALE){
934 value = (guint32)(max_y / pow(10,tics-i));
936 print_time_scale_string(label_string, 15, value, value, TRUE);
938 g_snprintf(label_string, 15, "%d", value);
941 value = (max_y/10)*i;
943 print_time_scale_string(label_string, 15, value, max_y, FALSE);
945 g_snprintf(label_string, 15, "%d", value);
949 pango_layout_set_text(layout, label_string, -1);
950 pango_layout_get_pixel_size(layout, &lwidth, NULL);
952 #if GTK_CHECK_VERSION(2,22,0)
953 cr = cairo_create (io->surface);
955 cr = gdk_cairo_create (io->pixmap);
957 cairo_move_to (cr, io->pixmap_width-io->right_x_border+15+label_width-lwidth, ypos-label_height/2);
958 pango_cairo_show_layout (cr, layout);
965 /* If we have not specified the last_interval via the GUI, just pick the current end of the
966 * capture so that it scrolls nicely when doing live captures.
968 if(io->last_interval==0xffffffff) {
969 last_interval = io->max_interval;
971 last_interval = io->last_interval;
975 /* plot the x-scale */
976 #if GTK_CHECK_VERSION(2,22,0)
977 cr = cairo_create (io->surface);
979 cr = gdk_cairo_create (io->pixmap);
981 cairo_set_line_width (cr, 1.0);
982 cairo_move_to(cr, io->left_x_border+0.5, io->pixmap_height-bottom_y_border+1.5);
983 cairo_line_to(cr, io->pixmap_width-io->right_x_border+1.5,io->pixmap_height-bottom_y_border+1.5);
986 if((last_interval/io->interval)>=draw_width/io->pixels_per_tick){
987 first_interval=(last_interval/io->interval)-draw_width/io->pixels_per_tick+1;
988 first_interval*=io->interval;
993 interval_delta=(100/io->pixels_per_tick)*io->interval;
994 for(current_interval=last_interval;current_interval>=(gint32)first_interval;current_interval=current_interval-io->interval){
997 /* if pixels_per_tick is 1 or 2, only draw every 10 ticks */
998 /* if pixels_per_tick is 5, only draw every 5 ticks */
999 if(((io->pixels_per_tick<5) && (current_interval%(10*io->interval))) ||
1000 ((io->pixels_per_tick==5) && (current_interval%(5*io->interval)))){
1004 if(!(current_interval%interval_delta)){
1006 } else if(!(current_interval%(interval_delta/2))){
1011 x=draw_width+io->left_x_border-((last_interval-current_interval)/io->interval)*io->pixels_per_tick;
1012 #if GTK_CHECK_VERSION(2,22,0)
1013 cr = cairo_create (io->surface);
1015 cr = gdk_cairo_create (io->pixmap);
1017 cairo_set_line_width (cr, 1.0);
1018 cairo_move_to(cr, x-1-io->pixels_per_tick/2+0.5, io->pixmap_height-bottom_y_border+1.5);
1019 cairo_line_to(cr, x-1-io->pixels_per_tick/2+0.5, io->pixmap_height-bottom_y_border+xlen+1.5);
1024 print_interval_string (label_string, 15, current_interval, io, TRUE);
1025 pango_layout_set_text(layout, label_string, -1);
1026 pango_layout_get_pixel_size(layout, &lwidth, NULL);
1028 if ((x-1-io->pixels_per_tick/2-lwidth/2) < 5) {
1030 } else if ((x-1-io->pixels_per_tick/2+lwidth/2) > (io->pixmap_width-5)) {
1031 x_pos=io->pixmap_width-lwidth-5;
1033 x_pos=x-1-io->pixels_per_tick/2-lwidth/2;
1035 #if GTK_CHECK_VERSION(2,22,0)
1036 cr = cairo_create (io->surface);
1038 cr = gdk_cairo_create (io->pixmap);
1040 cairo_move_to (cr, x_pos, io->pixmap_height-bottom_y_border+15);
1041 pango_cairo_show_layout (cr, layout);
1047 g_object_unref(G_OBJECT(layout));
1050 * Loop over all graphs and draw them
1052 for(i=MAX_GRAPHS-1; i>=0; i--){
1054 guint32 interval, x_pos, y_pos, prev_x_pos, prev_y_pos;
1055 /* Moving average variables */
1056 guint32 mavg_in_average_count = 0, mavg_left = 0, mavg_right = 0;
1057 guint64 mavg_cumulated = 0;
1058 guint32 mavg_to_remove = 0, mavg_to_add = 0;
1060 if(!io->graphs[i].display){
1064 if(io->filter_type == MOVING_AVERAGE_FILTER){
1065 /* "Warm-up phase" - calculate average on some data not displayed;
1066 just to make sure average on leftmost and rightmost displayed
1067 values is as reliable as possible
1069 guint32 warmup_interval;
1071 if(first_interval/io->interval > io->filter_order/2){
1072 warmup_interval = first_interval/io->interval - io->filter_order/2;
1073 warmup_interval*= io->interval;
1075 warmup_interval = 0;
1077 mavg_to_remove = warmup_interval;
1078 for(;warmup_interval<first_interval;warmup_interval+=io->interval){
1079 mavg_cumulated += get_it_value(io, i, warmup_interval/io->interval);
1080 mavg_in_average_count++;
1083 mavg_cumulated += get_it_value(io, i, warmup_interval/io->interval);
1084 mavg_in_average_count++;
1085 for(warmup_interval += io->interval;
1086 ((warmup_interval < (first_interval + (io->filter_order/2) * io->interval)) &&
1087 (warmup_interval <= (io->num_items * io->interval)));
1088 warmup_interval += io->interval) {
1090 mavg_cumulated += get_it_value(io, i, warmup_interval / io->interval);
1091 mavg_in_average_count++;
1094 mavg_to_add = warmup_interval;
1097 /* initialize prev x/y to the value of the first interval */
1098 prev_x_pos = draw_width-1 -
1099 io->pixels_per_tick * ((last_interval - first_interval) / io->interval) +
1101 val = get_it_value(io, i, first_interval / io->interval);
1103 if(io->filter_type==MOVING_AVERAGE_FILTER
1104 && mavg_in_average_count > 0) {
1105 val = mavg_cumulated / mavg_in_average_count;
1110 } else if (io->max_y_units==LOGARITHMIC_YSCALE){
1112 prev_y_pos = (guint32)(draw_height - 1 + top_y_border);
1114 prev_y_pos = (guint32) (
1115 (draw_height - ystart)-1 -
1116 ((log10((double)((gint64)val)) * (draw_height - ystart)) / log10((double)max_y)) +
1121 prev_y_pos=(guint32)(draw_height-1-(val*draw_height)/max_y+top_y_border);
1124 for(interval = first_interval;
1125 interval < last_interval;
1126 interval += io->interval) {
1127 x_pos=draw_width-1-io->pixels_per_tick*((last_interval-interval)/io->interval)+io->left_x_border;
1129 val = get_it_value(io, i, interval/io->interval);
1130 /* Moving average calculation */
1131 if (io->filter_type==MOVING_AVERAGE_FILTER) {
1132 if (interval != first_interval){
1134 if (mavg_left > io->filter_order/2) {
1136 mavg_in_average_count--;
1137 mavg_cumulated -= get_it_value(io, i, mavg_to_remove/io->interval);
1138 mavg_to_remove += io->interval;
1140 if (mavg_to_add<=io->num_items*io->interval){
1141 mavg_in_average_count++;
1142 mavg_cumulated += get_it_value(io, i, mavg_to_add/io->interval);
1143 mavg_to_add += io->interval;
1148 if (mavg_in_average_count > 0) {
1149 val = mavg_cumulated / mavg_in_average_count;
1155 } else if (io->max_y_units==LOGARITHMIC_YSCALE) {
1157 y_pos=(guint32)(draw_height-1+top_y_border);
1160 (draw_height - ystart) - 1 -
1161 (log10((double)(gint64)val) * (draw_height - ystart)) / log10((double)max_y) +
1166 y_pos = (guint32)(draw_height - 1 -
1167 ((val * draw_height) / max_y) +
1171 switch(io->graphs[i].plot_style){
1172 case PLOT_STYLE_LINE:
1173 /* Dont draw anything if the segment entirely above the top of the graph
1175 if( (prev_y_pos!=0) || (y_pos!=0) ){
1176 #if GTK_CHECK_VERSION(2,22,0)
1177 cr = cairo_create (io->surface);
1179 cr = gdk_cairo_create (io->pixmap);
1181 gdk_cairo_set_source_color (cr, &io->graphs[i].color);
1182 cairo_set_line_width (cr, 1.0);
1183 cairo_move_to(cr, prev_x_pos+0.5, prev_y_pos+0.5);
1184 cairo_line_to(cr, x_pos+0.5, y_pos+0.5);
1189 case PLOT_STYLE_IMPULSE:
1191 #if GTK_CHECK_VERSION(2,22,0)
1192 cr = cairo_create (io->surface);
1194 cr = gdk_cairo_create (io->pixmap);
1196 gdk_cairo_set_source_color (cr, &io->graphs[i].color);
1197 cairo_set_line_width (cr, 1.0);
1198 cairo_move_to(cr, x_pos+0.5, draw_height-1+top_y_border+0.5);
1199 cairo_line_to(cr, x_pos+0.5, y_pos+0.5);
1204 case PLOT_STYLE_FILLED_BAR:
1206 #if GTK_CHECK_VERSION(2,22,0)
1207 cr = cairo_create (io->surface);
1209 cr = gdk_cairo_create (io->pixmap);
1211 cairo_rectangle (cr,
1212 x_pos-(gdouble)io->pixels_per_tick/2+0.5,
1214 io->pixels_per_tick,
1215 draw_height-1+top_y_border-y_pos);
1216 gdk_cairo_set_source_color (cr, &io->graphs[i].color);
1221 case PLOT_STYLE_DOT:
1223 #if GTK_CHECK_VERSION(2,22,0)
1224 cr = cairo_create (io->surface);
1226 cr = gdk_cairo_create (io->pixmap);
1231 (gdouble)io->pixels_per_tick/2,
1234 gdk_cairo_set_source_color (cr, &io->graphs[i].color);
1246 cr = gdk_cairo_create (gtk_widget_get_window(io->draw_area));
1248 #if GTK_CHECK_VERSION(2,22,0)
1249 cairo_set_source_surface (cr, io->surface, 0, 0);
1251 gdk_cairo_set_source_pixmap (cr, io->pixmap, 0, 0);
1253 cairo_rectangle (cr, 0, 0, io->pixmap_width, io->pixmap_height);
1258 /* update the scrollbar */
1259 if (io->max_interval == 0) {
1260 gtk_adjustment_set_upper(io->scrollbar_adjustment, (gfloat) io->interval);
1261 gtk_adjustment_set_step_increment(io->scrollbar_adjustment, (gfloat) (io->interval/10));
1262 gtk_adjustment_set_page_increment(io->scrollbar_adjustment, (gfloat) io->interval);
1264 gtk_adjustment_set_upper(io->scrollbar_adjustment, (gfloat) io->max_interval);
1265 gtk_adjustment_set_step_increment(io->scrollbar_adjustment, (gfloat) ((last_interval-first_interval)/10));
1266 gtk_adjustment_set_page_increment(io->scrollbar_adjustment, (gfloat) (last_interval-first_interval));
1268 gtk_adjustment_set_page_size(io->scrollbar_adjustment, gtk_adjustment_get_page_increment(io->scrollbar_adjustment));
1269 gtk_adjustment_set_value(io->scrollbar_adjustment, (gfloat)first_interval);
1270 gtk_adjustment_changed(io->scrollbar_adjustment);
1271 gtk_adjustment_value_changed(io->scrollbar_adjustment);
1276 io_stat_redraw(io_stat_t *io)
1278 io->needs_redraw=TRUE;
1283 tap_iostat_draw(void *g)
1285 io_stat_graph_t *git=g;
1287 io_stat_draw(git->io);
1290 /* ok we get called with both the filter and the field.
1291 make sure the field is part of the filter.
1292 (make sure and make sure just append it)
1293 the field MUST be part of the filter or else we wont
1294 be able to pick up the field values after the edt tree has been
1298 enable_graph(io_stat_graph_t *gio, const char *filter, const char *field)
1300 char real_filter[262];
1306 /* skip all whitespaces */
1319 g_snprintf(real_filter, 257, "(%s)", filter);
1324 /* skip all whitespaces */
1337 if(real_filter[0]!=0){
1338 g_strlcat(real_filter, " && ", 262);
1340 g_strlcat(real_filter, field, 262);
1343 return register_tap_listener("frame", gio, real_filter[0]?real_filter:NULL,
1344 TL_REQUIRES_PROTO_TREE,
1345 tap_iostat_reset, tap_iostat_packet, tap_iostat_draw);
1349 disable_graph(io_stat_graph_t *gio)
1353 protect_thread_critical_region();
1354 remove_tap_listener(gio);
1355 unprotect_thread_critical_region();
1356 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gio->display_button),
1362 iostat_init(const char *optarg _U_, void* userdata _U_)
1366 static GdkColor col[MAX_GRAPHS] = {
1367 {0, 0x0000, 0x0000, 0x0000}, /* Black */
1368 {0, 0xffff, 0x0000, 0x0000}, /* Red */
1369 {0, 0x0000, 0xffff, 0x0000}, /* Green */
1370 {0, 0x0000, 0x0000, 0xffff}, /* Blue */
1371 {0, 0xffff, 0x5000, 0xffff} /* Light brilliant magenta */
1373 #if GTK_CHECK_VERSION(3,0,0)
1374 static GdkRGBA rgba_col[MAX_GRAPHS] = {
1375 {0.0, 0.0, 0.0, 1.0}, /* Black */
1376 {1.0, 0.0, 0.1, 1.0}, /* Red */
1377 {0.0, 1.0, 0.0, 1.0}, /* Green */
1378 {0.0, 0.0, 1.0, 1.0}, /* Blue */
1379 {1.0, 0.314, 1.0, 1.0} /* Light brilliant magenta */
1382 GString *error_string;
1384 io=g_malloc(sizeof(io_stat_t));
1385 io->needs_redraw=TRUE;
1386 io->interval=tick_interval_values[DEFAULT_TICK_VALUE_INDEX];
1389 #if GTK_CHECK_VERSION(2,22,0)
1395 io->scrollbar_adjustment=NULL;
1396 io->pixmap_width=500;
1397 io->pixmap_height=200;
1398 io->pixels_per_tick=pixels_per_tick[DEFAULT_PIXELS_PER_TICK_INDEX];
1399 io->max_y_units=AUTO_MAX_YSCALE;
1401 io->last_interval=0xffffffff;
1404 io->left_x_border=0;
1405 io->right_x_border=500;
1406 io->view_as_time=FALSE;
1407 io->start_time.secs=0;
1408 io->start_time.nsecs=0;
1410 for(i=0;i<MAX_GRAPHS;i++){
1411 io->graphs[i].color.pixel=col[i].pixel;
1412 io->graphs[i].color.red=col[i].red;
1413 io->graphs[i].color.green=col[i].green;
1414 io->graphs[i].color.blue=col[i].blue;
1415 #if GTK_CHECK_VERSION(3,0,0)
1416 io->graphs[i].rgba_color.red=rgba_col[i].red;
1417 io->graphs[i].rgba_color.green=rgba_col[i].green;
1418 io->graphs[i].rgba_color.blue=rgba_col[i].blue;
1419 io->graphs[i].rgba_color.alpha=rgba_col[i].alpha;
1421 io->graphs[i].display=0;
1422 io->graphs[i].display_button=NULL;
1423 io->graphs[i].filter_field=NULL;
1424 io->graphs[i].advanced_buttons=NULL;
1425 io->graphs[i].io=io;
1427 io->graphs[i].args=g_malloc(sizeof(construct_args_t));
1428 io->graphs[i].args->title = NULL;
1429 io->graphs[i].args->wants_apply_button=TRUE;
1430 io->graphs[i].args->activate_on_ok=TRUE;
1431 io->graphs[i].args->modal_and_transient=FALSE;
1433 io->graphs[i].filter_bt=NULL;
1437 error_string=enable_graph(&io->graphs[0], NULL, NULL);
1438 g_assert((error_string == NULL) && "Can't attach io_stat tap !");
1442 fprintf(stderr, "wireshark: Can't attach io_stat tap: %s\n",
1444 g_string_free(error_string, TRUE);
1445 io->graphs[0].display=0;
1446 io->graphs[0].display_button=NULL;
1447 io->graphs[0].filter_field=NULL;
1448 io->graphs[0].advanced_buttons=NULL;
1453 init_io_stat_window(io);
1455 cf_retap_packets(&cfile);
1456 gdk_window_raise(gtk_widget_get_window(io->window));
1461 draw_area_destroy_cb(GtkWidget *widget _U_, gpointer user_data)
1463 io_stat_t *io = user_data;
1465 GtkWidget *save_bt = g_object_get_data(G_OBJECT(io->window), "save_bt");
1466 surface_info_t *surface_info = g_object_get_data(G_OBJECT(save_bt), "surface-info");
1468 g_free(surface_info);
1470 for(i=0;i<MAX_GRAPHS;i++){
1471 if(io->graphs[i].display){
1472 protect_thread_critical_region();
1473 remove_tap_listener(&io->graphs[i]);
1474 unprotect_thread_critical_region();
1476 g_free( (gpointer) (io->graphs[i].args->title) );
1477 io->graphs[i].args->title=NULL;
1479 g_free(io->graphs[i].args);
1480 io->graphs[i].args=NULL;
1489 pixmap_clicked_event(GtkWidget *widget _U_, GdkEventButton *event, gpointer g)
1492 io_stat_graph_t *graph;
1494 guint32 draw_width, interval, last_interval, frame_num=0;
1496 gboolean load=FALSE, outstanding_call=FALSE;
1498 draw_width = io->pixmap_width - io->right_x_border - io->left_x_border;
1500 if ((event->x <= (draw_width+io->left_x_border+1-(draw_width/io->pixels_per_tick)*io->pixels_per_tick)) ||
1501 (event->x >= (draw_width+io->left_x_border-io->pixels_per_tick/2))) {
1502 /* Outside draw area */
1507 * An interval in the IO Graph drawing area has been clicked. If left-clicked (button 1), the frame
1508 * with the first response in that interval or if left-clicked (button 3) the last is highlighted.
1510 #if GTK_CHECK_VERSION(2,22,0)
1511 if ((event->button==1 || event->button==3) && io->surface!=NULL) {
1513 if ((event->button==1 || event->button==3) && io->pixmap!=NULL) {
1515 if (io->last_interval==0xffffffff)
1516 last_interval = io->max_interval;
1518 last_interval = io->last_interval;
1520 /* Get the interval that was clicked */
1521 interval = (guint32) (
1522 (last_interval / io->interval) -
1523 ((draw_width + io->left_x_border - event->x-io->pixels_per_tick / 2 - 1) / io->pixels_per_tick)
1526 /* Determine the lowest or highest frame number depending on whether button 1 or 3 was clicked,
1527 * respectively, among the up to 5 currently displayed graphs. */
1528 for(i=0; i<MAX_GRAPHS; i++) {
1529 graph = &io->graphs[i];
1530 if(graph->display) {
1531 it = &graph->items[interval];
1532 if (event->button==1) {
1533 if(frame_num==0 || (it->first_frame_in_invl < frame_num))
1534 frame_num = it->first_frame_in_invl;
1536 if(it->last_frame_in_invl > frame_num)
1537 frame_num = it->last_frame_in_invl;
1539 if(graph->calc_type==CALC_TYPE_LOAD) {
1541 if (it->time_tot.secs + it->time_tot.nsecs > 0)
1542 outstanding_call = TRUE;
1547 /* XXX - If the frame numbers of *calls* can somehow be determined, the first call or
1548 * response, whichever is first, and the last call or response, whichever is last,
1549 * could be highlighted. */
1550 if(frame_num==0 && load && outstanding_call) {
1551 statusbar_push_temporary_msg(
1552 "There is no response but at least one call is outstanding in this interval.");
1557 cf_goto_frame(&cfile, frame_num);
1562 /* create a new backing pixmap of the appropriate size */
1564 draw_area_configure_event(GtkWidget *widget, GdkEventConfigure *event _U_, gpointer user_data)
1566 io_stat_t *io = user_data;
1568 GtkAllocation widget_alloc;
1570 #if GTK_CHECK_VERSION(2,22,0)
1571 surface_info_t *surface_info = g_new(surface_info_t, 1);
1574 #if GTK_CHECK_VERSION(2,22,0)
1576 cairo_surface_destroy (io->surface);
1581 g_object_unref(io->pixmap);
1586 gtk_widget_get_allocation(widget, &widget_alloc);
1587 #if GTK_CHECK_VERSION(2,22,0)
1588 io->surface = gdk_window_create_similar_surface (gtk_widget_get_window(widget),
1589 CAIRO_CONTENT_COLOR,
1591 widget_alloc.height);
1594 io->pixmap=gdk_pixmap_new(gtk_widget_get_window(widget),
1596 widget_alloc.height,
1599 io->pixmap_width=widget_alloc.width;
1600 io->pixmap_height=widget_alloc.height;
1602 save_bt = g_object_get_data(G_OBJECT(io->window), "save_bt");
1603 #if GTK_CHECK_VERSION(2,22,0)
1604 surface_info->surface = io->surface;
1605 surface_info->width = widget_alloc.width;
1606 surface_info->height = widget_alloc.height;
1607 g_object_set_data(G_OBJECT(save_bt), "surface-info", surface_info);
1608 gtk_widget_set_sensitive(save_bt, TRUE);
1610 cr = cairo_create (io->surface);
1612 g_object_set_data(G_OBJECT(save_bt), "pixmap", io->pixmap);
1613 gtk_widget_set_sensitive(save_bt, TRUE);
1615 cr = gdk_cairo_create (io->pixmap);
1617 cairo_rectangle (cr, 0, 0, widget_alloc.width, widget_alloc.height);
1618 cairo_set_source_rgb (cr, 1, 1, 1);
1627 scrollbar_changed(GtkWidget *widget _U_, gpointer user_data)
1629 io_stat_t *io = user_data;
1632 mi=(guint32) (gtk_adjustment_get_value(io->scrollbar_adjustment) + gtk_adjustment_get_page_size(io->scrollbar_adjustment));
1634 if (io->last_interval==mi) {
1638 io->last_interval = (mi/io->interval)*io->interval;
1642 #if GTK_CHECK_VERSION(3,0,0)
1644 draw_area_draw(GtkWidget *widget, cairo_t *cr, gpointer user_data)
1646 io_stat_t *io = user_data;
1647 GtkAllocation allocation;
1649 gtk_widget_get_allocation (widget, &allocation);
1650 cairo_set_source_surface (cr, io->surface, 0, 0);
1651 cairo_rectangle (cr, 0, 0, allocation.width, allocation.width);
1657 /* redraw the screen from the backing pixmap */
1659 draw_area_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
1661 io_stat_t *io = user_data;
1662 cairo_t *cr = gdk_cairo_create (gtk_widget_get_window(widget));
1664 #if GTK_CHECK_VERSION(2,22,0)
1665 cairo_set_source_surface (cr, io->surface, 0, 0);
1667 gdk_cairo_set_source_pixmap (cr, io->pixmap, 0, 0);
1669 cairo_rectangle (cr, event->area.x, event->area.y, event->area.width, event->area.height);
1678 create_draw_area(io_stat_t *io, GtkWidget *box)
1680 io->draw_area=gtk_drawing_area_new();
1681 g_signal_connect(io->draw_area, "destroy", G_CALLBACK(draw_area_destroy_cb), io);
1683 gtk_widget_set_size_request(io->draw_area, io->pixmap_width, io->pixmap_height);
1685 /* signals needed to handle backing pixmap */
1686 #if GTK_CHECK_VERSION(3,0,0)
1687 g_signal_connect(io->draw_area, "draw", G_CALLBACK(draw_area_draw), io);
1689 g_signal_connect(io->draw_area, "expose-event", G_CALLBACK(draw_area_expose_event), io);
1691 g_signal_connect(io->draw_area, "configure-event", G_CALLBACK(draw_area_configure_event), io);
1692 gtk_widget_add_events (io->draw_area, GDK_BUTTON_PRESS_MASK);
1693 g_signal_connect(io->draw_area, "button-press-event", G_CALLBACK(pixmap_clicked_event), io);
1695 gtk_widget_show(io->draw_area);
1696 gtk_box_pack_start(GTK_BOX(box), io->draw_area, TRUE, TRUE, 0);
1698 /* create the associated scrollbar */
1699 io->scrollbar_adjustment=(GtkAdjustment *)gtk_adjustment_new(0,0,0,0,0,0);
1700 io->scrollbar=gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL, io->scrollbar_adjustment);
1701 gtk_widget_show(io->scrollbar);
1702 gtk_box_pack_start(GTK_BOX(box), io->scrollbar, FALSE, FALSE, 0);
1703 g_signal_connect(io->scrollbar_adjustment, "value-changed", G_CALLBACK(scrollbar_changed), io);
1707 tick_interval_select(GtkWidget *item, gpointer user_data)
1709 io_stat_t *io = user_data;
1712 i = gtk_combo_box_get_active (GTK_COMBO_BOX(item));
1714 io->interval=tick_interval_values[i];
1715 cf_retap_packets(&cfile);
1716 gdk_window_raise(gtk_widget_get_window(io->window));
1721 pixels_per_tick_select(GtkWidget *item, gpointer user_data)
1723 io_stat_t *io = user_data;
1726 i = gtk_combo_box_get_active (GTK_COMBO_BOX(item));
1727 io->pixels_per_tick=pixels_per_tick[i];
1732 plot_style_select(GtkWidget *item, gpointer user_data)
1734 io_stat_graph_t *ppt = user_data;
1737 val=gtk_combo_box_get_active (GTK_COMBO_BOX(item));
1739 ppt->plot_style=val;
1741 io_stat_redraw(ppt->io);
1745 create_pixels_per_tick_menu_items(io_stat_t *io)
1748 GtkWidget *combo_box;
1750 combo_box = gtk_combo_box_text_new ();
1752 for(i=0;i<MAX_PIXELS_PER_TICK;i++){
1753 g_snprintf(str, 5, "%u", pixels_per_tick[i]);
1754 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box), str);
1756 gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), DEFAULT_PIXELS_PER_TICK_INDEX);
1757 g_signal_connect(combo_box, "changed", G_CALLBACK(pixels_per_tick_select), io);
1763 yscale_select(GtkWidget *item, gpointer user_data)
1765 io_stat_t *io = user_data;
1768 i = gtk_combo_box_get_active (GTK_COMBO_BOX(item));
1770 io->max_y_units = yscale_max[i];
1775 filter_select(GtkWidget *item, gpointer user_data)
1777 io_stat_t *io = user_data;
1780 i = gtk_combo_box_get_active (GTK_COMBO_BOX(item));
1782 if(i==NO_FILTER_ORDER){
1783 io->filter_type = NO_FILTER;
1785 io->filter_type = MOVING_AVERAGE_FILTER;
1786 io->filter_order = moving_average_orders[i];
1792 create_tick_interval_menu_items(io_stat_t *io)
1794 GtkWidget *combo_box;
1798 combo_box = gtk_combo_box_text_new ();
1800 for(i=0;i<MAX_TICK_VALUES;i++){
1801 if(tick_interval_values[i]>=60000){
1802 g_snprintf(str, sizeof(str), "%u min", tick_interval_values[i]/60000);
1803 } else if(tick_interval_values[i]>=1000){
1804 g_snprintf(str, sizeof(str), "%u sec", tick_interval_values[i]/1000);
1805 } else if(tick_interval_values[i]>=100){
1806 g_snprintf(str, sizeof(str), "0.%1u sec", (tick_interval_values[i]/100)%10);
1807 } else if(tick_interval_values[i]>=10){
1808 g_snprintf(str, sizeof(str), "0.%02u sec", (tick_interval_values[i]/10)%10);
1810 g_snprintf(str, sizeof(str), "0.%03u sec", (tick_interval_values[i])%10);
1812 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box), str);
1814 gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), DEFAULT_TICK_VALUE_INDEX);
1815 g_signal_connect(combo_box, "changed", G_CALLBACK(tick_interval_select), io);
1821 create_yscale_max_menu_items(io_stat_t *io)
1824 GtkWidget *combo_box;
1827 combo_box = gtk_combo_box_text_new ();
1828 for(i=0;i<MAX_YSCALE;i++){
1829 if(yscale_max[i]==LOGARITHMIC_YSCALE){
1830 g_strlcpy(str, "Logarithmic", 15);
1831 } else if(yscale_max[i]==AUTO_MAX_YSCALE){
1832 g_strlcpy(str, "Auto", 15);
1834 g_snprintf(str, 15, "%u", yscale_max[i]);
1836 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box), str);
1838 gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), DEFAULT_YSCALE_INDEX);
1839 g_signal_connect(combo_box, "changed", G_CALLBACK(yscale_select), io);
1844 create_filter_menu_items(io_stat_t *io)
1847 GtkWidget *combo_box;
1850 combo_box = gtk_combo_box_text_new ();
1852 for(i=0;i<MAX_MOVING_AVERAGE_ORDER;i++){
1853 if(i==NO_FILTER_ORDER){
1854 g_strlcpy(str, "No filter", 15);
1856 g_snprintf(str, 15, "M.avg %u", moving_average_orders[i]);
1858 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box), str);
1860 gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), 0);
1861 g_signal_connect(combo_box, "changed", G_CALLBACK(filter_select), io);
1866 count_type_select(GtkWidget *item, gpointer user_data)
1868 io_stat_t *io = user_data;
1869 static gboolean advanced_visible=FALSE;
1871 GtkAllocation widget_alloc;
1873 io->count_type = gtk_combo_box_get_active (GTK_COMBO_BOX(item));
1875 if(io->count_type==COUNT_TYPE_ADVANCED){
1876 for(i=0;i<MAX_GRAPHS;i++){
1877 disable_graph(&io->graphs[i]);
1878 gtk_widget_show(io->graphs[i].advanced_buttons);
1879 /* redraw the entire window so the unhidden widgets show up, hopefully */
1880 gtk_widget_get_allocation(io->window, &widget_alloc);
1881 gtk_widget_queue_draw_area(io->window,
1885 widget_alloc.height);
1887 advanced_visible=TRUE;
1889 } else if (advanced_visible) {
1890 for(i=0;i<MAX_GRAPHS;i++){
1891 gtk_widget_hide(io->graphs[i].advanced_buttons);
1892 filter_callback(item, &io->graphs[i]);
1894 advanced_visible=FALSE;
1901 create_frames_or_bytes_menu_items(io_stat_t *io)
1903 GtkWidget *combo_box;
1906 combo_box = gtk_combo_box_text_new ();
1908 for(i=0;i<MAX_COUNT_TYPES;i++){
1909 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box), count_type_names[i]);
1911 gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), DEFAULT_COUNT_TYPE);
1912 g_signal_connect(combo_box, "changed", G_CALLBACK(count_type_select), io);
1917 create_ctrl_menu(io_stat_t *io, GtkWidget *box, const char *name, GtkWidget * (*func)(io_stat_t *io))
1921 GtkWidget *combo_box;
1923 hbox=ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0, FALSE);
1924 gtk_container_add(GTK_CONTAINER(box), hbox);
1925 gtk_box_set_child_packing(GTK_BOX(box), hbox, FALSE, FALSE, 0, GTK_PACK_START);
1926 gtk_widget_show(hbox);
1928 label=gtk_label_new(name);
1929 gtk_widget_show(label);
1930 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1932 combo_box = (*func)(io);
1933 gtk_box_pack_end(GTK_BOX(hbox), combo_box, FALSE, FALSE, 0);
1934 gtk_widget_show(combo_box);
1938 view_as_time_toggle_dest(GtkWidget *widget _U_, gpointer user_data)
1940 io_stat_t *io = user_data;
1942 io->view_as_time = io->view_as_time ? FALSE : TRUE;
1948 create_ctrl_area(io_stat_t *io, GtkWidget *box)
1950 GtkWidget *frame_vbox;
1955 frame_vbox=ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE);
1956 gtk_box_pack_start(GTK_BOX(box), frame_vbox, FALSE, FALSE, 0);
1957 gtk_widget_show(frame_vbox);
1959 frame = gtk_frame_new("X Axis");
1960 gtk_container_add(GTK_CONTAINER(frame_vbox), frame);
1961 gtk_widget_show(frame);
1963 vbox=ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE);
1964 gtk_container_add(GTK_CONTAINER(frame), vbox);
1965 gtk_container_set_border_width(GTK_CONTAINER(vbox), 3);
1966 gtk_box_set_child_packing(GTK_BOX(box), vbox, FALSE, FALSE, 0, GTK_PACK_END);
1967 gtk_widget_show(vbox);
1969 create_ctrl_menu(io, vbox, "Tick interval:", create_tick_interval_menu_items);
1970 create_ctrl_menu(io, vbox, "Pixels per tick:", create_pixels_per_tick_menu_items);
1972 view_cb = gtk_check_button_new_with_mnemonic("_View as time of day");
1973 gtk_container_add(GTK_CONTAINER(vbox), view_cb);
1974 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(view_cb), io->view_as_time);
1975 g_signal_connect(view_cb, "toggled", G_CALLBACK(view_as_time_toggle_dest), io);
1976 gtk_widget_show(view_cb);
1978 frame = gtk_frame_new("Y Axis");
1979 gtk_container_add(GTK_CONTAINER(frame_vbox), frame);
1980 gtk_widget_show(frame);
1982 vbox=ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE);
1983 gtk_container_add(GTK_CONTAINER(frame), vbox);
1984 gtk_container_set_border_width(GTK_CONTAINER(vbox), 3);
1985 gtk_box_set_child_packing(GTK_BOX(box), vbox, FALSE, FALSE, 0, GTK_PACK_END);
1986 gtk_widget_show(vbox);
1988 create_ctrl_menu(io, vbox, "Unit:", create_frames_or_bytes_menu_items);
1989 create_ctrl_menu(io, vbox, "Scale:", create_yscale_max_menu_items);
1990 create_ctrl_menu(io, vbox, "Smooth:", create_filter_menu_items);
1996 filter_callback(GtkWidget *widget _U_, gpointer user_data)
1998 io_stat_graph_t *gio = user_data;
2000 const char *field=NULL;
2001 header_field_info *hfi;
2004 /* this graph is not active, just update display and redraw */
2005 if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gio->display_button))){
2007 io_stat_redraw(gio->io);
2011 /* first check if the field string is valid */
2012 if(gio->io->count_type==COUNT_TYPE_ADVANCED){
2013 field=gtk_entry_get_text(GTK_ENTRY(gio->calc_field));
2015 /* warn and bail out if there was no field specified */
2016 if(field==NULL || field[0]==0){
2017 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "You didn't specify a field name.");
2019 io_stat_redraw(gio->io);
2022 /* warn and bail out if the field could not be found */
2023 hfi=proto_registrar_get_byname(field);
2025 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "There is no field named '%s'.", field);
2027 io_stat_redraw(gio->io);
2030 gio->hf_index=hfi->id;
2031 /* check that the type is compatible */
2043 /* these values support all calculations except LOAD */
2044 switch(gio->calc_type){
2045 case CALC_TYPE_LOAD:
2046 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2047 "LOAD(*) is only supported for relative-time fields.");
2049 io_stat_redraw(gio->io);
2052 /* these types support all calculations */
2054 case FT_RELATIVE_TIME:
2055 /* this type only supports COUNT, MAX, MIN, AVG */
2056 switch(gio->calc_type){
2058 case CALC_TYPE_COUNT:
2062 case CALC_TYPE_LOAD:
2065 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2066 "%s is a relative-time field, so %s calculations are not supported on it.",
2068 calc_type_names[gio->calc_type]);
2070 io_stat_redraw(gio->io);
2077 * XXX - support this if gint64/guint64 are
2080 if(gio->calc_type!=CALC_TYPE_COUNT){
2081 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2082 "%s is a 64-bit integer, so %s calculations are not supported on it.",
2084 calc_type_names[gio->calc_type]);
2086 io_stat_redraw(gio->io);
2091 if(gio->calc_type!=CALC_TYPE_COUNT){
2092 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2093 "%s doesn't have integral or float values, so %s calculations are not supported on it.",
2095 calc_type_names[gio->calc_type]);
2097 io_stat_redraw(gio->io);
2104 /* first check if the filter string is valid. */
2105 filter=gtk_entry_get_text(GTK_ENTRY(gio->filter_field));
2106 if(!dfilter_compile(filter, &dfilter)) {
2107 bad_dfilter_alert_box(filter);
2109 io_stat_redraw(gio->io);
2112 if (dfilter != NULL)
2113 dfilter_free(dfilter);
2115 /* ok, we have a valid filter and the graph is active.
2116 first just try to delete any previous settings and then apply
2119 protect_thread_critical_region();
2120 remove_tap_listener(gio);
2121 unprotect_thread_critical_region();
2123 io_stat_reset(gio->io);
2124 enable_graph(gio, filter, field);
2125 cf_retap_packets(&cfile);
2126 gdk_window_raise(gtk_widget_get_window(gio->io->window));
2127 io_stat_redraw(gio->io);
2133 calc_type_select(GtkWidget *item, gpointer user_data)
2135 io_stat_graph_t *gio = user_data;
2137 gio->calc_type=gtk_combo_box_get_active (GTK_COMBO_BOX(item));
2139 /* disable the graph */
2141 io_stat_redraw(gio->io);
2145 create_calc_types_menu_items(io_stat_graph_t *gio)
2147 GtkWidget *combo_box;
2150 combo_box = gtk_combo_box_text_new ();
2151 for(i=0;i<MAX_CALC_TYPES;i++){
2152 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box), calc_type_names[i]);
2154 gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), DEFAULT_CALC_TYPE);
2155 g_signal_connect(combo_box, "changed", G_CALLBACK(calc_type_select), gio);
2160 create_advanced_menu(io_stat_graph_t *gio, GtkWidget *box, const char *name, GtkWidget *(*func)(io_stat_graph_t *io))
2164 GtkWidget *combo_box;
2166 hbox=ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0, FALSE);
2167 gtk_container_add(GTK_CONTAINER(box), hbox);
2168 gtk_box_set_child_packing(GTK_BOX(box), hbox, FALSE, FALSE, 0, GTK_PACK_START);
2169 gtk_widget_show(hbox);
2171 label=gtk_label_new(name);
2172 gtk_widget_show(label);
2173 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
2175 combo_box = (*func)(gio);
2176 gtk_box_pack_end(GTK_BOX(hbox), combo_box, FALSE, FALSE, 0);
2177 gtk_widget_show(combo_box);
2181 create_advanced_field(io_stat_graph_t *gio, GtkWidget *box)
2184 gio->calc_field=gtk_entry_new();
2185 gtk_entry_set_max_length(GTK_ENTRY(gio->calc_field),100);
2186 gtk_box_pack_start(GTK_BOX(box), gio->calc_field, TRUE, TRUE, 0);
2187 gtk_widget_show(gio->calc_field);
2188 g_signal_connect(gio->calc_field, "activate", G_CALLBACK(filter_callback), gio);
2189 g_object_set_data (G_OBJECT(gio->calc_field), E_FILT_FIELD_NAME_ONLY_KEY, "");
2190 g_signal_connect(gio->calc_field, "changed", G_CALLBACK(filter_te_syntax_check_cb), NULL);
2191 g_object_set_data(G_OBJECT(box), E_FILT_AUTOCOMP_PTR_KEY, NULL);
2192 g_signal_connect(gio->calc_field, "key-press-event", G_CALLBACK (filter_string_te_key_pressed_cb), NULL);
2193 g_signal_connect(gio->io->window, "key-press-event", G_CALLBACK (filter_parent_dlg_key_pressed_cb), NULL);
2194 colorize_filter_te_as_empty(gio->calc_field);
2198 create_advanced_box(io_stat_graph_t *gio, GtkWidget *box)
2202 hbox=ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0, FALSE);
2203 gio->advanced_buttons=hbox;
2204 gtk_container_add(GTK_CONTAINER(box), hbox);
2205 gtk_box_set_child_packing(GTK_BOX(box), hbox, TRUE, TRUE, 0, GTK_PACK_START);
2206 gtk_widget_hide(hbox);
2208 gio->calc_type=CALC_TYPE_SUM;
2209 create_advanced_menu(gio, hbox, "Calc:", create_calc_types_menu_items);
2210 create_advanced_field(gio, hbox);
2214 filter_button_clicked(GtkWidget *w, gpointer user_data)
2216 io_stat_graph_t *gio = user_data;
2218 display_filter_construct_cb(w, gio->args);
2223 create_filter_box(io_stat_graph_t *gio, GtkWidget *box, int num)
2225 GtkWidget *combo_box;
2231 hbox=ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
2232 gtk_container_add(GTK_CONTAINER(box), hbox);
2233 gtk_box_set_child_packing(GTK_BOX(box), hbox, FALSE, FALSE, 0, GTK_PACK_START);
2234 gtk_widget_show(hbox);
2236 g_snprintf(str, 256, "Graph %d", num);
2237 gio->display_button=gtk_toggle_button_new_with_label(str);
2238 gtk_box_pack_start(GTK_BOX(hbox), gio->display_button, FALSE, FALSE, 0);
2239 gtk_widget_show(gio->display_button);
2240 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gio->display_button), gio->display);
2241 g_signal_connect(gio->display_button, "toggled", G_CALLBACK(filter_callback), gio);
2243 label=gtk_label_new("Color");
2244 gtk_widget_show(label);
2245 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
2247 #if GTK_CHECK_VERSION(3,0,0)
2248 gtk_widget_override_color(label, GTK_STATE_NORMAL, &gio->rgba_color);
2249 gtk_widget_override_color(label, GTK_STATE_ACTIVE, &gio->rgba_color);
2250 gtk_widget_override_color(label, GTK_STATE_PRELIGHT, &gio->rgba_color);
2251 gtk_widget_override_color(label, GTK_STATE_SELECTED, &gio->rgba_color);
2252 gtk_widget_override_color(label, GTK_STATE_INSENSITIVE, &gio->rgba_color);
2254 gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &gio->color);
2255 gtk_widget_modify_fg(label, GTK_STATE_ACTIVE, &gio->color);
2256 gtk_widget_modify_fg(label, GTK_STATE_PRELIGHT, &gio->color);
2257 gtk_widget_modify_fg(label, GTK_STATE_SELECTED, &gio->color);
2258 gtk_widget_modify_fg(label, GTK_STATE_INSENSITIVE, &gio->color);
2260 /* g_signal_connect(gio->display_button, "toggled", G_CALLBACK(filter_callback), gio);*/
2263 /* filter prefs dialog */
2264 gio->filter_bt=gtk_button_new_from_stock(WIRESHARK_STOCK_DISPLAY_FILTER_ENTRY);
2266 g_snprintf(str, 256, "Wireshark: Display Filter IO-Stat (Filter:%d)", num);
2267 g_free( (gpointer) (gio->args->title) );
2268 gio->args->title=g_strdup(str);
2270 g_signal_connect(gio->filter_bt, "clicked", G_CALLBACK(filter_button_clicked), gio);
2271 g_signal_connect(gio->filter_bt, "destroy", G_CALLBACK(filter_button_destroy_cb), NULL);
2273 gtk_box_pack_start(GTK_BOX(hbox), gio->filter_bt, FALSE, TRUE, 0);
2274 gtk_widget_show(gio->filter_bt);
2276 gio->filter_field=gtk_entry_new();
2277 gtk_entry_set_max_length(GTK_ENTRY(gio->filter_field),256);
2278 /* filter prefs dialog */
2279 g_object_set_data(G_OBJECT(gio->filter_bt), E_FILT_TE_PTR_KEY, gio->filter_field);
2280 /* filter prefs dialog */
2282 gtk_box_pack_start(GTK_BOX(hbox), gio->filter_field, TRUE, TRUE, 0);
2283 gtk_widget_show(gio->filter_field);
2284 g_signal_connect(gio->filter_field, "activate", G_CALLBACK(filter_callback), gio);
2285 g_signal_connect(gio->filter_field, "changed", G_CALLBACK(filter_te_syntax_check_cb), NULL);
2286 g_object_set_data(G_OBJECT(box), E_FILT_AUTOCOMP_PTR_KEY, NULL);
2287 g_signal_connect(gio->filter_field, "key-press-event", G_CALLBACK (filter_string_te_key_pressed_cb), NULL);
2288 g_signal_connect(gio->io->window, "key-press-event", G_CALLBACK (filter_parent_dlg_key_pressed_cb), NULL);
2289 colorize_filter_te_as_empty(gio->filter_field);
2291 create_advanced_box(gio, hbox);
2294 * create PlotStyle menu
2296 g_snprintf(str, 256, " Style:");
2297 label=gtk_label_new(str);
2298 gtk_widget_show(label);
2299 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
2301 combo_box = gtk_combo_box_text_new ();
2302 for(i=0;i<MAX_PLOT_STYLES;i++){
2303 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box), plot_style_name[i]);
2305 gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), DEFAULT_PLOT_STYLE);
2306 g_signal_connect(combo_box, "changed", G_CALLBACK(plot_style_select), &gio->io->graphs[num-1]);
2308 gtk_box_pack_end(GTK_BOX(hbox), combo_box, FALSE, FALSE, 0);
2309 gtk_widget_show(combo_box);
2315 create_filter_area(io_stat_t *io, GtkWidget *box)
2321 frame=gtk_frame_new("Graphs");
2322 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 0);
2323 gtk_widget_show(frame);
2325 vbox=ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 1, FALSE);
2326 gtk_container_add(GTK_CONTAINER(frame), vbox);
2327 gtk_container_set_border_width(GTK_CONTAINER(vbox), 3);
2328 gtk_box_set_child_packing(GTK_BOX(box), vbox, FALSE, FALSE, 0, GTK_PACK_START);
2329 gtk_widget_show(vbox);
2331 for(i=0;i<MAX_GRAPHS;i++){
2332 create_filter_box(&io->graphs[i], vbox, i+1);
2339 copy_as_csv_cb(GtkWindow *copy_bt _U_, gpointer user_data)
2341 guint32 i, interval, val;
2344 GString *CSV_str=g_string_new("");
2345 io_stat_t *io = user_data;
2347 g_string_append(CSV_str, "\"Interval start\"");
2348 for(i=0;i<MAX_GRAPHS;i++) {
2349 if (io->graphs[i].display) {
2350 g_string_append_printf(CSV_str, ",\"Graph %d\"", i+1);
2353 g_string_append(CSV_str,"\n");
2355 for(interval=0; interval<io->max_interval; interval+=io->interval) {
2356 print_interval_string (string, 15, interval, io, FALSE);
2357 g_string_append_printf(CSV_str, "\"%s\"", string);
2358 for(i=0;i<MAX_GRAPHS;i++) {
2359 if (io->graphs[i].display) {
2360 val=get_it_value(io, i, interval/io->interval);
2361 g_string_append_printf(CSV_str, ",\"%d\"", val);
2364 g_string_append(CSV_str,"\n");
2367 /* Now that we have the CSV data, copy it into the default clipboard */
2368 cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); /* Get the default clipboard */
2369 gtk_clipboard_set_text(cb, CSV_str->str, -1); /* Copy the CSV data into the clipboard */
2370 g_string_free(CSV_str, TRUE); /* Free the memory */
2374 init_io_stat_window(io_stat_t *io)
2379 GtkWidget *close_bt, *help_bt;
2383 /* create the main window, transient_for top_level */
2384 io->window = dlg_window_new("I/O Graphs");
2385 gtk_window_set_destroy_with_parent (GTK_WINDOW(io->window), TRUE);
2387 vbox=ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE);
2388 gtk_container_add(GTK_CONTAINER(io->window), vbox);
2389 gtk_widget_show(vbox);
2391 create_draw_area(io, vbox);
2393 hbox=ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
2394 gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
2395 gtk_container_set_border_width(GTK_CONTAINER(hbox), 3);
2396 gtk_box_set_child_packing(GTK_BOX(vbox), hbox, FALSE, FALSE, 0, GTK_PACK_START);
2397 gtk_widget_show(hbox);
2399 create_filter_area(io, hbox);
2400 create_ctrl_area(io, hbox);
2402 io_stat_set_title(io);
2404 bbox = dlg_button_row_new(GTK_STOCK_CLOSE, GTK_STOCK_SAVE,
2405 GTK_STOCK_COPY, GTK_STOCK_HELP, NULL);
2406 gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
2407 gtk_widget_show(bbox);
2409 close_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
2410 window_set_cancel_button(io->window, close_bt, window_cancel_button_cb);
2411 gtk_widget_set_tooltip_text(close_bt, "Close this dialog");
2412 save_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_SAVE);
2413 gtk_widget_set_sensitive(save_bt, FALSE);
2414 gtk_widget_set_tooltip_text(save_bt, "Save the displayed graph to a file");
2415 g_signal_connect(save_bt, "clicked", G_CALLBACK(pixmap_save_cb), NULL);
2416 g_object_set_data(G_OBJECT(io->window), "save_bt", save_bt);
2418 copy_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_COPY);
2419 gtk_widget_set_tooltip_text(copy_bt, "Copy values from selected graphs to the clipboard in CSV (Comma Separated Values) format");
2420 g_signal_connect(copy_bt, "clicked", G_CALLBACK(copy_as_csv_cb), io);
2422 help_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
2423 g_signal_connect(help_bt, "clicked", G_CALLBACK(topic_cb), (gpointer)HELP_STATS_IO_GRAPH_DIALOG);
2424 gtk_widget_set_tooltip_text (help_bt, "Show topic specific help");
2425 g_signal_connect(io->window, "delete-event", G_CALLBACK(window_delete_event_cb), NULL);
2427 gtk_widget_show(io->window);
2428 window_present(io->window);
2432 gui_iostat_cb(GtkAction *action _U_, gpointer user_data _U_)
2434 iostat_init(NULL,NULL);
2438 register_tap_listener_gtk_iostat(void)
2440 register_stat_cmd_arg("io,stat", iostat_init,NULL);