Fix numerous instances of a variable/parameter name "shadowing" a library function...
[metze/wireshark/wip.git] / ui / gtk / io_stat.c
index 629566b601b5061bd25e400cb7aaa91698843656..9c4e092e84d1d75de9c5dab1e4b3a6ea6fd1e1cc 100644 (file)
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
 
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
+#include "config.h"
 
 #include <stdio.h>
 #include <string.h>
@@ -142,7 +140,7 @@ typedef struct _io_item_t {
 
 typedef struct _io_stat_graph_t {
        struct _io_stat_t *io;
-       io_item_t items[NUM_IO_ITEMS];
+       gpointer items[NUM_IO_ITEMS];
        int plot_style;
        gboolean display;
        GtkWidget *display_button;
@@ -182,8 +180,8 @@ typedef struct _io_stat_t {
        GtkAdjustment *scrollbar_adjustment;
        GtkWidget *scrollbar;
 
-       int pixmap_width;
-       int pixmap_height;
+       int surface_width;
+       int surface_height;
        int pixels_per_tick;
        int max_y_units;
        int count_type;
@@ -214,7 +212,7 @@ io_stat_reset(io_stat_t *io)
        for(i=0;i<MAX_GRAPHS;i++){
                for(j=0;j<NUM_IO_ITEMS;j++){
                        io_item_t *ioi;
-                       ioi=&io->graphs[i].items[j];
+                       ioi=io->graphs[i].items[j];
 
                        ioi->frames=0;
                        ioi->bytes=0;
@@ -299,7 +297,7 @@ tap_iostat_packet(void *g, packet_info *pinfo, epan_dissect_t *edt, const void *
        }
 
        /* Point to the appropriate io_item_t struct */
-       it = &graph->items[idx];
+       it = graph->items[idx];
 
        /* Set the first and last frame num in current interval matching the target field+filter  */
        if (it->first_frame_in_invl == 0) {
@@ -413,10 +411,13 @@ tap_iostat_packet(void *g, packet_info *pinfo, epan_dissect_t *edt, const void *
                                                pt = t;
                                        }
                                        while(t){
-                                               graph->items[j].time_tot.nsecs += (int) (pt * 1000);
-                                               if(graph->items[j].time_tot.nsecs > 1000000000){
-                                                       graph->items[j].time_tot.secs++;
-                                                       graph->items[j].time_tot.nsecs -= 1000000000;
+                                               io_item_t *item;
+
+                                               item = (io_item_t*)graph->items[j];
+                                               item->time_tot.nsecs += (int) (pt * 1000);
+                                               if(item->time_tot.nsecs > 1000000000){
+                                                       item->time_tot.secs++;
+                                                       item->time_tot.nsecs -= 1000000000;
                                                }
 
                                                if(j==0){
@@ -449,12 +450,23 @@ tap_iostat_packet(void *g, packet_info *pinfo, epan_dissect_t *edt, const void *
                                }
                                break;
                        default:
-                               /*
-                                * "Can't happen"; see the "check that the
-                                * type is compatible" check in
-                                * filter_callback().
-                                */
-                               g_assert_not_reached();
+                               if(graph->calc_type == CALC_TYPE_COUNT_FRAMES ||
+                                       graph->calc_type == CALC_TYPE_COUNT_FIELDS) {
+                                       /*
+                                        * It's not an integeresque type, but
+                                        * all we want to do is count it, so
+                                        * that's all right.
+                                        */
+                                       it->fields++;
+                               }
+                               else {
+                                       /*
+                                        * "Can't happen"; see the "check that the
+                                        * type is compatible" check in
+                                        * filter_callback().
+                                        */
+                                       g_assert_not_reached();
+                               }
                                break;
                        }
                }
@@ -469,12 +481,12 @@ tap_iostat_packet(void *g, packet_info *pinfo, epan_dissect_t *edt, const void *
 static guint64
 get_it_value(io_stat_t *io, int graph, int idx)
 {
-       double value=0;
+       guint64 value=0; /* FIXME: loss of precision, visible on the graph for small values */
        int adv_type;
        io_item_t *it;
        guint32 interval;
 
-       it = &io->graphs[graph].items[idx];
+       it = io->graphs[graph].items[idx];
 
        switch(io->count_type){
        case COUNT_TYPE_FRAMES:
@@ -483,23 +495,24 @@ get_it_value(io_stat_t *io, int graph, int idx)
                return it->bytes;
        case COUNT_TYPE_BITS:
                return (it->bytes * 8);
-       }
-
-
-       adv_type=proto_registrar_get_ftype(io->graphs[graph].hf_index);
-       switch(adv_type){
-       case FT_NONE:
+       case COUNT_TYPE_ADVANCED:
                switch(io->graphs[graph].calc_type){
                case CALC_TYPE_COUNT_FRAMES:
-                       value=it->frames;
-                       break;
+                       return it->frames;
                case CALC_TYPE_COUNT_FIELDS:
-                       value=it->fields;
-                       break;
+                       return it->fields;
                default:
+                       /* If it's COUNT_TYPE_ADVANCED but not one of the
+                        * generic ones we'll get it when we switch on the
+                        * adv_type below. */
                        break;
                }
                break;
+       }
+
+
+       adv_type=proto_registrar_get_ftype(io->graphs[graph].hf_index);
+       switch(adv_type){
        case FT_UINT8:
        case FT_UINT16:
        case FT_UINT24:
@@ -514,12 +527,6 @@ get_it_value(io_stat_t *io, int graph, int idx)
                case CALC_TYPE_SUM:
                        value=it->int_tot;
                        break;
-               case CALC_TYPE_COUNT_FRAMES:
-                       value=it->frames;
-                       break;
-               case CALC_TYPE_COUNT_FIELDS:
-                       value=it->fields;
-                       break;
                case CALC_TYPE_MAX:
                        value=it->int_max;
                        break;
@@ -540,23 +547,17 @@ get_it_value(io_stat_t *io, int graph, int idx)
        case FT_FLOAT:
                switch(io->graphs[graph].calc_type){
                case CALC_TYPE_SUM:
-                       value=it->float_tot;
-                       break;
-               case CALC_TYPE_COUNT_FRAMES:
-                       value=it->frames;
-                       break;
-               case CALC_TYPE_COUNT_FIELDS:
-                       value=it->fields;
+                       value=(guint64)it->float_tot;
                        break;
                case CALC_TYPE_MAX:
-                       value=it->float_max;
+                       value=(guint64)it->float_max;
                        break;
                case CALC_TYPE_MIN:
-                       value=it->float_min;
+                       value=(guint64)it->float_min;
                        break;
                case CALC_TYPE_AVG:
                        if(it->fields){
-                               value=it->float_tot/it->fields;
+                               value=(guint64)it->float_tot/it->fields;
                        } else {
                                value=0;
                        }
@@ -568,23 +569,17 @@ get_it_value(io_stat_t *io, int graph, int idx)
        case FT_DOUBLE:
                switch(io->graphs[graph].calc_type){
                case CALC_TYPE_SUM:
-                       value=it->double_tot;
-                       break;
-               case CALC_TYPE_COUNT_FRAMES:
-                       value=it->frames;
-                       break;
-               case CALC_TYPE_COUNT_FIELDS:
-                       value=it->fields;
+                       value=(guint64)it->double_tot;
                        break;
                case CALC_TYPE_MAX:
-                       value=it->double_max;
+                       value=(guint64)it->double_max;
                        break;
                case CALC_TYPE_MIN:
-                       value=it->double_min;
+                       value=(guint64)it->double_min;
                        break;
                case CALC_TYPE_AVG:
                        if(it->fields){
-                               value=it->double_tot/it->fields;
+                               value=(guint64)it->double_tot/it->fields;
                        } else {
                                value=0;
                        }
@@ -595,20 +590,14 @@ get_it_value(io_stat_t *io, int graph, int idx)
                break;
        case FT_RELATIVE_TIME:
                switch(io->graphs[graph].calc_type){
-               case CALC_TYPE_COUNT_FRAMES:
-                       value=it->frames;
-                       break;
-               case CALC_TYPE_COUNT_FIELDS:
-                       value=it->fields;
-                       break;
                case CALC_TYPE_MAX:
-                       value=(guint32) (it->time_max.secs*1000000 + it->time_max.nsecs/1000);
+                       value=(guint64) (it->time_max.secs*1000000 + it->time_max.nsecs/1000);
                        break;
                case CALC_TYPE_MIN:
-                       value=(guint32) (it->time_min.secs*1000000 + it->time_min.nsecs/1000);
+                       value=(guint64) (it->time_min.secs*1000000 + it->time_min.nsecs/1000);
                        break;
                case CALC_TYPE_SUM:
-                       value=(guint32) (it->time_tot.secs*1000000 + it->time_tot.nsecs/1000);
+                       value=(guint64) (it->time_tot.secs*1000000 + it->time_tot.nsecs/1000);
                        break;
                case CALC_TYPE_AVG:
                        if(it->fields){
@@ -616,7 +605,7 @@ get_it_value(io_stat_t *io, int graph, int idx)
 
                                t=it->time_tot.secs;
                                t=t*1000000+it->time_tot.nsecs/1000;
-                               value=(guint32) (t/it->fields);
+                               value=(guint64) (t/it->fields);
                        } else {
                                value=0;
                        }
@@ -629,7 +618,7 @@ get_it_value(io_stat_t *io, int graph, int idx)
                        } else {
                                interval = io->interval;
                        }
-                       value = (guint32) ((it->time_tot.secs*1000000 + it->time_tot.nsecs/1000) / interval);
+                       value = (guint64) ((it->time_tot.secs*1000000 + it->time_tot.nsecs/1000) / interval);
                        break;
                default:
                        break;
@@ -638,7 +627,7 @@ get_it_value(io_stat_t *io, int graph, int idx)
        default:
                break;
        }
-       return (guint64)value; /* FIXME: loss of precision, visible on the graph for small values */
+       return value;
 }
 
 static void
@@ -698,604 +687,545 @@ print_interval_string(char *buf, int buf_len, guint32 interval, io_stat_t *io,
 }
 
 static void
-io_stat_draw(io_stat_t *io)
+    io_stat_draw(io_stat_t *io)
 {
-       int i, tics, ystart, ys;
-       guint32 last_interval, first_interval, interval_delta;
-       gint32 current_interval;
-       guint32 top_y_border;
-       guint32 bottom_y_border;
-       PangoLayout  *layout;
-       int label_width, label_height;
-       guint32 draw_width, draw_height;
-       char label_string[45];
-       GtkAllocation widget_alloc;
-       /* new variables */
-       guint32 num_time_intervals; /* number of intervals relative to 1 */
-       guint32 max_value;              /* max value of seen data */
-       guint32 max_y;                  /* max value of the Y scale */
-       gboolean draw_y_as_time;
-       cairo_t *cr;
-
-       if(!io->needs_redraw){
-               return;
-       }
-       io->needs_redraw=FALSE;
-       /*
-        * Set max_interval to duration rounded to the nearest ms. Add the Tick Interval so the last
-        * interval will be displayed. For example, if duration = 11.844 secs and 'Tick Interval'== 1,
-        * max_interval=12000; if 0.1, 11900; if 0.01, 11850; and if 0.001, 11845.
-        */
-       io->max_interval = (guint32)((cfile.elapsed_time.secs*1000) +
-                                    ((cfile.elapsed_time.nsecs+500000)/1000000) +
-                                    io->interval);
-       io->max_interval = (io->max_interval / io->interval) * io->interval;
-       /*
-        * Find the length of the intervals we have data for
-        * so we know how large arrays we need to malloc()
-        */
-       num_time_intervals = io->num_items+1;
-
-       /* XXX move this check to _packet() */
-       if(num_time_intervals > NUM_IO_ITEMS){
-               simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "IO-Stat error. There are too many entries, bailing out");
-               return;
-       }
-
-       /*
-        * find the max value so we can autoscale the y axis
-        */
-       max_value=0;
-       for(i=0;i<MAX_GRAPHS;i++){
-               int idx;
-
-               if(!io->graphs[i].display){
-                       continue;
-               }
-               for(idx=0; (guint32)(idx) < num_time_intervals; idx++){
-                       guint64 val;
-
-                       val=get_it_value(io, i, idx);
-
-                       /* keep track of the max value we have encountered */
-                       if(val>max_value){
-                               max_value=val;
-                       }
-               }
-       }
-
-       /*
-        * Clear out old plot
-        */
-#if GTK_CHECK_VERSION(2,22,0)
-       cr = cairo_create (io->surface);
-#else
-       cr = gdk_cairo_create (io->pixmap);
-#endif
-       cairo_set_source_rgb (cr, 1, 1, 1);
-       gtk_widget_get_allocation(io->draw_area, &widget_alloc);
-       cairo_rectangle (cr, 0, 0, widget_alloc.width,widget_alloc.height);
-       cairo_fill (cr);
-       cairo_destroy (cr);
-       /*
-        * Calculate the y scale we should use
-        */
-       if(io->max_y_units==AUTO_MAX_YSCALE){
-               max_y = yscale_max[MAX_YSCALE-1];
-               for(i=MAX_YSCALE-1; i>1; i--){
-                       if(max_value < yscale_max[i]){
-                               max_y = yscale_max[i];
-                       }
-               }
-       } else if(io->max_y_units==LOGARITHMIC_YSCALE){
-               max_y = 1000000000;
-               for(i=1000000000; i>1; i/=10){
-                       if(max_value<(guint32)i){
-                               max_y=i;
-                       }
-               }
-       } else {
-               /* the user had specified an explicit y scale to use */
-               max_y=io->max_y_units;
-       }
-
-       /*
-        * If we use ADVANCED and all the graphs are plotting
-        * either MIN/MAX/AVG of an FT_RELATIVE_TIME field
-        * then we will do some some special processing for the
-        * labels for the Y axis below:
-        *   we will append the time unit " s" " ms" or " us"
-        *   and we will present the unit in decimal
-        */
-       draw_y_as_time = FALSE;
-       if(io->count_type==COUNT_TYPE_ADVANCED){
-               draw_y_as_time = TRUE;
-               for(i=0; i<MAX_GRAPHS; i++){
-                       int adv_type;
-
-                       if(!io->graphs[i].display){
-                               continue;
-                       }
-                       adv_type=proto_registrar_get_ftype(io->graphs[i].hf_index);
-                       switch(adv_type) {
-                       case FT_RELATIVE_TIME:
-                               switch(io->graphs[i].calc_type){
-                               case CALC_TYPE_SUM:
-                               case CALC_TYPE_MAX:
-                               case CALC_TYPE_MIN:
-                               case CALC_TYPE_AVG:
-                                       break;
-                               default:
-                                       draw_y_as_time = FALSE;
-                               }
-                               break;
-                       default:
-                               draw_y_as_time = FALSE;
-                       }
-               }
-       }
-
-       /*
-        * Calculate size of borders surrounding the plot
-        * The border on the right side needs to be adjusted depending
-        * on the width of the text labels. For simplicity we assume that the
-        * top y scale label will be the widest one
-        */
-       if(draw_y_as_time){
-               if(io->max_y_units==LOGARITHMIC_YSCALE){
-                       print_time_scale_string(label_string, 15, 100000, 100000, TRUE); /* 100 ms */
-               } else {
-                       print_time_scale_string(label_string, 15, max_y, max_y, FALSE);
-               }
-       } else {
-               g_snprintf(label_string, 15, "%d", max_y);
-       }
-       layout = gtk_widget_create_pango_layout(io->draw_area, label_string);
-       pango_layout_get_pixel_size(layout, &label_width, &label_height);
-
-       io->left_x_border = 10;
-       io->right_x_border = label_width + 20;
-       top_y_border = 10;
-       bottom_y_border = label_height + 20;
-
-       /*
-        * Calculate the size of the drawing area for the actual plot
-        */
-       draw_width = io->pixmap_width-io->right_x_border - io->left_x_border;
-       draw_height = io->pixmap_height-top_y_border - bottom_y_border;
-
-       /*
-        * Add a warning if too many entries
-        */
-       if (num_time_intervals >= NUM_IO_ITEMS-1) {
-               g_snprintf (label_string, 45, "Warning: Graph limited to %d entries", NUM_IO_ITEMS);
-               pango_layout_set_text(layout, label_string, -1);
-
-#if GTK_CHECK_VERSION(2,22,0)
-               cr = cairo_create (io->surface);
-#else
-               cr = gdk_cairo_create (io->pixmap);
-#endif
-               cairo_move_to (cr, 5, io->pixmap_height-bottom_y_border-draw_height-label_height/2);
-               pango_cairo_show_layout (cr, layout);
-               cairo_destroy (cr);
-               cr = NULL;
-       }
-
-       /* Draw the y axis and labels
-       * (we always draw the y scale with 11 ticks along the axis)
-       */
-#if GTK_CHECK_VERSION(2,22,0)
-       cr = cairo_create (io->surface);
-#else
-       cr = gdk_cairo_create (io->pixmap);
-#endif
-       cairo_set_line_width (cr, 1.0);
-       cairo_move_to(cr, io->pixmap_width-io->right_x_border+1.5, top_y_border + 0.5);
-       cairo_line_to(cr, io->pixmap_width-io->right_x_border+1.5, io->pixmap_height-bottom_y_border + 0.5);
-       cairo_stroke(cr);
-       cairo_destroy(cr);
-       if(io->max_y_units==LOGARITHMIC_YSCALE){
-               tics = (int)log10((double)max_y);
-               ystart = draw_height/10;
-               ys = -1;
-       } else {
-               tics = 10;
-               ystart=ys=0;
-       }
-
-       for(i=ys;i<=tics;i++){
-               int xwidth, lwidth, ypos;
-
-               xwidth = 5;
-               if(io->max_y_units==LOGARITHMIC_YSCALE){
-                       if (i==ys) {
-                               /* position for the 0 value */
-                               ypos=io->pixmap_height-bottom_y_border;
-                       } else if (i==tics) {
-                               /* position for the top value, do not draw logarithmic tics above graph */
-                               ypos=io->pixmap_height-bottom_y_border-draw_height;
-                       } else {
-                               int j;
-                               /* draw the logarithmic tics */
-                               for(j=2; j<10; j++) {
-                                       ypos=(int)(io->pixmap_height-bottom_y_border-(draw_height-ystart)*(i+log10((double)j))/tics-ystart);
-                                       /* draw the tick */
-#if GTK_CHECK_VERSION(2,22,0)
-                                       cr = cairo_create (io->surface);
-#else
-                                       cr = gdk_cairo_create (io->pixmap);
-#endif
-                                       cairo_set_line_width (cr, 1.0);
-                                       cairo_move_to(cr, io->pixmap_width-io->right_x_border+1.5, ypos+0.5);
-                                       cairo_line_to(cr, io->pixmap_width-io->right_x_border+1.5+xwidth,ypos+0.5);
-                                       cairo_stroke(cr);
-                                       cairo_destroy(cr);
-                               }
-                               ypos=io->pixmap_height-bottom_y_border-(draw_height-ystart)*i/tics-ystart;
-                       }
-                       /* all "main" logarithmic lines are slightly longer */
-                       xwidth=10;
-               } else {
-                       if (!(i%5)) {
-                               /* first, middle and last tick are slightly longer */
-                               xwidth = 10;
-                       }
-                       ypos=io->pixmap_height-bottom_y_border-draw_height*i/10;
-               }
-               /* draw the tick */
+    int i, tics, ystart, ys;
+    guint32 last_interval, first_interval, interval_delta;
+    gint32 current_interval;
+    guint32 top_y_border;
+    guint32 bottom_y_border;
+    PangoLayout  *layout;
+    int label_width, label_height;
+    guint32 draw_width, draw_height;
+    char label_string[45];
+    GtkAllocation widget_alloc;
+    /* new variables */
+    guint32 num_time_intervals; /* number of intervals relative to 1 */
+    guint64 max_value;         /* max value of seen data */
+    guint32 max_y;                     /* max value of the Y scale */
+    gboolean draw_y_as_time;
+    cairo_t *cr;
+
+    if(!io->needs_redraw){
+        return;
+    }
+    io->needs_redraw=FALSE;
+    /*
+    * Set max_interval to duration rounded to the nearest ms. Add the Tick Interval so the last
+    * interval will be displayed. For example, if duration = 11.844 secs and 'Tick Interval'== 1,
+    * max_interval=12000; if 0.1, 11900; if 0.01, 11850; and if 0.001, 11845.
+    */
+    io->max_interval = (guint32)((cfile.elapsed_time.secs*1000) +
+        ((cfile.elapsed_time.nsecs+500000)/1000000) +
+        io->interval);
+    io->max_interval = (io->max_interval / io->interval) * io->interval;
+    /*
+    * Find the length of the intervals we have data for
+    * so we know how large arrays we need to malloc()
+    */
+    num_time_intervals = io->num_items+1;
+
+    /* XXX move this check to _packet() */
+    if(num_time_intervals > NUM_IO_ITEMS){
+        simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "IO-Stat error. There are too many entries, bailing out");
+        return;
+    }
+
+    /*
+    * find the max value so we can autoscale the y axis
+    */
+    max_value=0;
+    for(i=0;i<MAX_GRAPHS;i++){
+        int idx;
+
+        if(!io->graphs[i].display){
+            continue;
+        }
+        for(idx=0; (guint32)(idx) < num_time_intervals; idx++){
+            guint64 val;
+
+            val=get_it_value(io, i, idx);
+
+            /* keep track of the max value we have encountered */
+            if(val>max_value){
+                max_value=val;
+            }
+        }
+    }
+
+    /*
+    * Clear out old plot
+    */
 #if GTK_CHECK_VERSION(2,22,0)
-               cr = cairo_create (io->surface);
+    cr = cairo_create (io->surface);
 #else
-               cr = gdk_cairo_create (io->pixmap);
+    cr = gdk_cairo_create (io->pixmap);
 #endif
-               cairo_set_line_width (cr, 1.0);
-               cairo_move_to(cr, io->pixmap_width-io->right_x_border+1.5, ypos+0.5);
-               cairo_line_to(cr, io->pixmap_width-io->right_x_border+1.5+xwidth,ypos+0.5);
-               cairo_stroke(cr);
-               cairo_destroy(cr);
-               /* draw the labels */
-               if(xwidth==10) {
-                       guint32 value;
-                       if(io->max_y_units==LOGARITHMIC_YSCALE){
-                               value = (guint32)(max_y / pow(10,tics-i));
-                               if(draw_y_as_time){
-                                       print_time_scale_string(label_string, 15, value, value, TRUE);
-                               } else {
-                                       g_snprintf(label_string, 15, "%d", value);
-                               }
-                       } else {
-                               value = (max_y/10)*i;
-                               if(draw_y_as_time){
-                                       print_time_scale_string(label_string, 15, value, max_y, FALSE);
-                               } else {
-                                       g_snprintf(label_string, 15, "%d", value);
-                               }
-                       }
-
-                       pango_layout_set_text(layout, label_string, -1);
-                       pango_layout_get_pixel_size(layout, &lwidth, NULL);
-
-#if GTK_CHECK_VERSION(2,22,0)
-                       cr = cairo_create (io->surface);
-#else
-                       cr = gdk_cairo_create (io->pixmap);
-#endif
-                       cairo_move_to (cr, io->pixmap_width-io->right_x_border+15+label_width-lwidth, ypos-label_height/2);
-                       pango_cairo_show_layout (cr, layout);
-                       cairo_destroy (cr);
-                       cr = NULL;
-
-               }
-       }
+    cairo_set_source_rgb (cr, 1, 1, 1);
+    gtk_widget_get_allocation(io->draw_area, &widget_alloc);
+    cairo_rectangle (cr, 0, 0, widget_alloc.width,widget_alloc.height);
+    cairo_fill (cr);
+    cairo_destroy (cr);
+    /*
+    * Calculate the y scale we should use
+    */
+    if(io->max_y_units==AUTO_MAX_YSCALE){
+        max_y = yscale_max[MAX_YSCALE-1];
+        for(i=MAX_YSCALE-1; i>1; i--){
+            if(max_value < yscale_max[i]){
+                max_y = yscale_max[i];
+            }
+        }
+    } else if(io->max_y_units==LOGARITHMIC_YSCALE){
+        max_y = 1000000000;
+        for(i=1000000000; i>1; i/=10){
+            if(max_value<(guint32)i){
+                max_y=i;
+            }
+        }
+    } else {
+        /* the user had specified an explicit y scale to use */
+        max_y=io->max_y_units;
+    }
+
+    /*
+    * If we use ADVANCED and all the graphs are plotting
+    * either MIN/MAX/AVG of an FT_RELATIVE_TIME field
+    * then we will do some some special processing for the
+    * labels for the Y axis below:
+    *   we will append the time unit " s" " ms" or " us"
+    *   and we will present the unit in decimal
+    */
+    draw_y_as_time = FALSE;
+    if(io->count_type==COUNT_TYPE_ADVANCED){
+        draw_y_as_time = TRUE;
+        for(i=0; i<MAX_GRAPHS; i++){
+            int adv_type;
+
+            if(!io->graphs[i].display){
+                continue;
+            }
+            adv_type=proto_registrar_get_ftype(io->graphs[i].hf_index);
+            switch(adv_type) {
+            case FT_RELATIVE_TIME:
+                switch(io->graphs[i].calc_type){
+                case CALC_TYPE_SUM:
+                case CALC_TYPE_MAX:
+                case CALC_TYPE_MIN:
+                case CALC_TYPE_AVG:
+                    break;
+                default:
+                    draw_y_as_time = FALSE;
+                }
+                break;
+            default:
+                draw_y_as_time = FALSE;
+            }
+        }
+    }
+
+    /*
+    * Calculate size of borders surrounding the plot
+    * The border on the right side needs to be adjusted depending
+    * on the width of the text labels. For simplicity we assume that the
+    * top y scale label will be the widest one
+    */
+    if(draw_y_as_time){
+        if(io->max_y_units==LOGARITHMIC_YSCALE){
+            print_time_scale_string(label_string, 15, 100000, 100000, TRUE); /* 100 ms */
+        } else {
+            print_time_scale_string(label_string, 15, max_y, max_y, FALSE);
+        }
+    } else {
+        g_snprintf(label_string, 15, "%d", max_y);
+    }
+    layout = gtk_widget_create_pango_layout(io->draw_area, label_string);
+    pango_layout_get_pixel_size(layout, &label_width, &label_height);
+
+    io->left_x_border = 10;
+    io->right_x_border = label_width + 20;
+    top_y_border = 10;
+    bottom_y_border = label_height + 20;
+
+    /*
+    * Calculate the size of the drawing area for the actual plot
+    */
+    draw_width = io->surface_width-io->right_x_border - io->left_x_border;
+    draw_height = io->surface_height-top_y_border - bottom_y_border;
+
+    /*
+    * Add a warning if too many entries
+    */
+    if (num_time_intervals >= NUM_IO_ITEMS-1) {
+        g_snprintf (label_string, 45, "Warning: Graph limited to %d entries", NUM_IO_ITEMS);
+        pango_layout_set_text(layout, label_string, -1);
 
-       /* If we have not specified the last_interval via the GUI, just pick the current end of the
-        *  capture so that it scrolls nicely when doing live captures.
-        */
-       if(io->last_interval==0xffffffff) {
-               last_interval = io->max_interval;
-       } else {
-               last_interval = io->last_interval;
-       }
-
-/*XXX*/
-       /* plot the x-scale */
 #if GTK_CHECK_VERSION(2,22,0)
-               cr = cairo_create (io->surface);
+        cr = cairo_create (io->surface);
 #else
-               cr = gdk_cairo_create (io->pixmap);
+        cr = gdk_cairo_create (io->pixmap);
 #endif
-               cairo_set_line_width (cr, 1.0);
-               cairo_move_to(cr, io->left_x_border+0.5, io->pixmap_height-bottom_y_border+1.5);
-               cairo_line_to(cr, io->pixmap_width-io->right_x_border+1.5,io->pixmap_height-bottom_y_border+1.5);
-               cairo_stroke(cr);
-               cairo_destroy(cr);
-       if((last_interval/io->interval)>=draw_width/io->pixels_per_tick){
-               first_interval=(last_interval/io->interval)-draw_width/io->pixels_per_tick+1;
-               first_interval*=io->interval;
-       } else {
-               first_interval=0;
-       }
-
-       interval_delta=(100/io->pixels_per_tick)*io->interval;
-       for(current_interval=last_interval;current_interval>=(gint32)first_interval;current_interval=current_interval-io->interval){
-               int x, xlen;
-
-               /* if pixels_per_tick is 1 or 2, only draw every 10 ticks */
-               /* if pixels_per_tick is 5, only draw every 5 ticks */
-               if(((io->pixels_per_tick<5) && (current_interval%(10*io->interval))) ||
-                  ((io->pixels_per_tick==5) && (current_interval%(5*io->interval)))){
-                       continue;
-               }
-
-               if(!(current_interval%interval_delta)){
-                       xlen=10;
-               } else if(!(current_interval%(interval_delta/2))){
-                       xlen=8;
-               } else {
-                       xlen=5;
-               }
-               x=draw_width+io->left_x_border-((last_interval-current_interval)/io->interval)*io->pixels_per_tick;
+        cairo_move_to (cr, 5, io->surface_height-bottom_y_border-draw_height-label_height/2);
+        pango_cairo_show_layout (cr, layout);
+        cairo_destroy (cr);
+        cr = NULL;
+    }
+
+    /* Draw the y axis and labels
+    * (we always draw the y scale with 11 ticks along the axis)
+    */
 #if GTK_CHECK_VERSION(2,22,0)
-               cr = cairo_create (io->surface);
+    cr = cairo_create (io->surface);
 #else
-               cr = gdk_cairo_create (io->pixmap);
+    cr = gdk_cairo_create (io->pixmap);
 #endif
-               cairo_set_line_width (cr, 1.0);
-               cairo_move_to(cr, x-1-io->pixels_per_tick/2+0.5, io->pixmap_height-bottom_y_border+1.5);
-               cairo_line_to(cr, x-1-io->pixels_per_tick/2+0.5, io->pixmap_height-bottom_y_border+xlen+1.5);
-               cairo_stroke(cr);
-               cairo_destroy(cr);
-               if(xlen==10){
-                       int lwidth, x_pos;
-                       print_interval_string (label_string, 15, current_interval, io, TRUE);
-                       pango_layout_set_text(layout, label_string, -1);
-                       pango_layout_get_pixel_size(layout, &lwidth, NULL);
-
-                       if ((x-1-io->pixels_per_tick/2-lwidth/2) < 5) {
-                               x_pos=5;
-                       } else if ((x-1-io->pixels_per_tick/2+lwidth/2) > (io->pixmap_width-5)) {
-                               x_pos=io->pixmap_width-lwidth-5;
-                       } else {
-                               x_pos=x-1-io->pixels_per_tick/2-lwidth/2;
-                       }
+    cairo_set_line_width (cr, 1.0);
+    cairo_move_to(cr, io->surface_width-io->right_x_border+1.5, top_y_border + 0.5);
+    cairo_line_to(cr, io->surface_width-io->right_x_border+1.5, io->surface_height-bottom_y_border + 0.5);
+    cairo_stroke(cr);
+    if(io->max_y_units==LOGARITHMIC_YSCALE){
+        tics = (int)log10((double)max_y);
+        ystart = draw_height/10;
+        ys = -1;
+    } else {
+        tics = 10;
+        ystart=ys=0;
+    }
+
+    for(i=ys;i<=tics;i++){
+        int xwidth, lwidth, ypos;
+
+        xwidth = 5;
+        if(io->max_y_units==LOGARITHMIC_YSCALE){
+            if (i==ys) {
+                /* position for the 0 value */
+                ypos=io->surface_height-bottom_y_border;
+            } else if (i==tics) {
+                /* position for the top value, do not draw logarithmic tics above graph */
+                ypos=io->surface_height-bottom_y_border-draw_height;
+            } else {
+                int j;
+                /* draw the logarithmic tics */
+                for(j=2; j<10; j++) {
+                    ypos=(int)(io->surface_height-bottom_y_border-(draw_height-ystart)*(i+log10((double)j))/tics-ystart);
+                    /* draw the tick */
+                    cairo_move_to(cr, io->surface_width-io->right_x_border+1.5, ypos+0.5);
+                    cairo_line_to(cr, io->surface_width-io->right_x_border+1.5+xwidth,ypos+0.5);
+                    cairo_stroke(cr);
+                }
+                ypos=io->surface_height-bottom_y_border-(draw_height-ystart)*i/tics-ystart;
+            }
+            /* all "main" logarithmic lines are slightly longer */
+            xwidth=10;
+        } else {
+            if (!(i%5)) {
+                /* first, middle and last tick are slightly longer */
+                xwidth = 10;
+            }
+            ypos=io->surface_height-bottom_y_border-draw_height*i/10;
+        }
+        /* draw the tick */
+        cairo_move_to(cr, io->surface_width-io->right_x_border+1.5, ypos+0.5);
+        cairo_line_to(cr, io->surface_width-io->right_x_border+1.5+xwidth,ypos+0.5);
+        cairo_stroke(cr);
+        /* draw the labels */
+        if(xwidth==10) {
+            guint32 value;
+            if(io->max_y_units==LOGARITHMIC_YSCALE){
+                value = (guint32)(max_y / pow(10,tics-i));
+                if(draw_y_as_time){
+                    print_time_scale_string(label_string, 15, value, value, TRUE);
+                } else {
+                    g_snprintf(label_string, 15, "%d", value);
+                }
+            } else {
+                value = (max_y/10)*i;
+                if(draw_y_as_time){
+                    print_time_scale_string(label_string, 15, value, max_y, FALSE);
+                } else {
+                    g_snprintf(label_string, 15, "%d", value);
+                }
+            }
+
+            pango_layout_set_text(layout, label_string, -1);
+            pango_layout_get_pixel_size(layout, &lwidth, NULL);
+
+            cairo_move_to (cr, io->surface_width-io->right_x_border+15+label_width-lwidth, ypos-label_height/2);
+            pango_cairo_show_layout (cr, layout);
+
+        }
+    }
+
+    /* If we have not specified the last_interval via the GUI, just pick the current end of the
+    *  capture so that it scrolls nicely when doing live captures.
+    */
+    if(io->last_interval==0xffffffff) {
+        last_interval = io->max_interval;
+    } else {
+        last_interval = io->last_interval;
+    }
+
+    /*XXX*/
+    /* plot the x-scale */
+    cairo_move_to(cr, io->left_x_border+0.5, io->surface_height-bottom_y_border+1.5);
+    cairo_line_to(cr, io->surface_width-io->right_x_border+1.5,io->surface_height-bottom_y_border+1.5);
+    cairo_stroke(cr);
+    if((last_interval/io->interval)>=draw_width/io->pixels_per_tick){
+        first_interval=(last_interval/io->interval)-draw_width/io->pixels_per_tick+1;
+        first_interval*=io->interval;
+    } else {
+        first_interval=0;
+    }
+
+    interval_delta=(100/io->pixels_per_tick)*io->interval;
+    for(current_interval=last_interval;current_interval>=(gint32)first_interval;current_interval=current_interval-io->interval){
+        int x, xlen;
+
+        /* if pixels_per_tick is 1 or 2, only draw every 10 ticks */
+        /* if pixels_per_tick is 5, only draw every 5 ticks */
+        if(((io->pixels_per_tick<5) && (current_interval%(10*io->interval))) ||
+            ((io->pixels_per_tick==5) && (current_interval%(5*io->interval)))){
+                continue;
+        }
+
+        if(!(current_interval%interval_delta)){
+            xlen=10;
+        } else if(!(current_interval%(interval_delta/2))){
+            xlen=8;
+        } else {
+            xlen=5;
+        }
+        x=draw_width+io->left_x_border-((last_interval-current_interval)/io->interval)*io->pixels_per_tick;
+        cairo_move_to(cr, x-1-io->pixels_per_tick/2+0.5, io->surface_height-bottom_y_border+1.5);
+        cairo_line_to(cr, x-1-io->pixels_per_tick/2+0.5, io->surface_height-bottom_y_border+xlen+1.5);
+        cairo_stroke(cr);
+        if(xlen==10){
+            int lwidth, x_pos;
+            print_interval_string (label_string, 15, current_interval, io, TRUE);
+            pango_layout_set_text(layout, label_string, -1);
+            pango_layout_get_pixel_size(layout, &lwidth, NULL);
+
+            if ((x-1-io->pixels_per_tick/2-lwidth/2) < 5) {
+                x_pos=5;
+            } else if ((x-1-io->pixels_per_tick/2+lwidth/2) > (io->surface_width-5)) {
+                x_pos=io->surface_width-lwidth-5;
+            } else {
+                x_pos=x-1-io->pixels_per_tick/2-lwidth/2;
+            }
+            cairo_move_to (cr, x_pos, io->surface_height-bottom_y_border+15);
+            pango_cairo_show_layout (cr, layout);
+        }
+
+    }
+    cairo_destroy (cr);
+    cr = NULL;
+    g_object_unref(G_OBJECT(layout));
+
+    /*
+    * Loop over all graphs and draw them
+    */
 #if GTK_CHECK_VERSION(2,22,0)
-                       cr = cairo_create (io->surface);
+    cr = cairo_create (io->surface);
 #else
-                       cr = gdk_cairo_create (io->pixmap);
+    cr = gdk_cairo_create (io->pixmap);
 #endif
-                       cairo_move_to (cr, x_pos, io->pixmap_height-bottom_y_border+15);
-                       pango_cairo_show_layout (cr, layout);
-                       cairo_destroy (cr);
-                       cr = NULL;
-               }
+    cairo_set_line_width (cr, 1.0);
 
-       }
-       g_object_unref(G_OBJECT(layout));
-
-       /*
-        * Loop over all graphs and draw them
-        */
        for(i=MAX_GRAPHS-1; i>=0; i--){
-               guint64 val;
-               guint32 interval, x_pos, y_pos, prev_x_pos, prev_y_pos;
-               /* Moving average variables */
-               guint32 mavg_in_average_count = 0, mavg_left = 0, mavg_right = 0;
-               guint64 mavg_cumulated = 0;
-               guint32 mavg_to_remove = 0, mavg_to_add = 0;
-
-               if(!io->graphs[i].display){
-                       continue;
-               }
-
-               if(io->filter_type == MOVING_AVERAGE_FILTER){
-                       /* "Warm-up phase" - calculate average on some data not displayed;
-                          just to make sure average on leftmost and rightmost displayed
-                          values is as reliable as possible
-                       */
-                       guint64 warmup_interval;
-
-                       if(first_interval/io->interval > io->filter_order/2){
-                               warmup_interval = first_interval/io->interval - io->filter_order/2;
-                               warmup_interval*= io->interval;
-                       } else {
-                               warmup_interval = 0;
-                       }
-                       mavg_to_remove = warmup_interval;
-                       for(;warmup_interval<first_interval;warmup_interval+=io->interval){
-                               mavg_cumulated += get_it_value(io, i, warmup_interval/io->interval);
-                               mavg_in_average_count++;
-                               mavg_left++;
-                       }
-                       mavg_cumulated += get_it_value(io, i, warmup_interval/io->interval);
-                       mavg_in_average_count++;
-                       for(warmup_interval += io->interval;
-                           ((warmup_interval < (first_interval + (io->filter_order/2) * io->interval)) &&
-                           (warmup_interval <= (io->num_items * io->interval)));
-                           warmup_interval += io->interval) {
-
-                               mavg_cumulated += get_it_value(io, i, warmup_interval / io->interval);
-                               mavg_in_average_count++;
-                               mavg_right++;
-                       }
-                       mavg_to_add = warmup_interval;
-               }
-
-               /* initialize prev x/y to the value of the first interval */
-               prev_x_pos = draw_width-1 -
-                            io->pixels_per_tick * ((last_interval - first_interval) / io->interval) +
-                            io->left_x_border;
-               val = get_it_value(io, i, first_interval / io->interval);
-
-               if(io->filter_type==MOVING_AVERAGE_FILTER
-               && mavg_in_average_count > 0) {
-                   val = mavg_cumulated / mavg_in_average_count;
-               }
-
-               if(val>max_y){
-                       prev_y_pos=0;
-               } else if (io->max_y_units==LOGARITHMIC_YSCALE){
-                       if (val==0) {
-                               prev_y_pos = (guint32)(draw_height - 1 + top_y_border);
-                       } else {
-                               prev_y_pos = (guint32) (
-                                                       (draw_height - ystart)-1 -
-                                                       ((log10((double)((gint64)val)) * (draw_height - ystart)) / log10((double)max_y)) +
-                                                       top_y_border
-                                                      );
-                       }
-               } else {
-                       prev_y_pos=(guint32)(draw_height-1-(val*draw_height)/max_y+top_y_border);
-               }
-
-               for(interval = first_interval;
-                       interval < last_interval;
-                       interval += io->interval) {
-                       x_pos=draw_width-1-io->pixels_per_tick*((last_interval-interval)/io->interval)+io->left_x_border;
-
-                       val = get_it_value(io, i, interval/io->interval);
-                       /* Moving average calculation */
-                       if (io->filter_type==MOVING_AVERAGE_FILTER) {
-                               if (interval != first_interval){
-                                       mavg_left++;
-                                       if (mavg_left > io->filter_order/2) {
-                                               mavg_left--;
-                                               mavg_in_average_count--;
-                                               mavg_cumulated -= get_it_value(io, i, mavg_to_remove/io->interval);
-                                               mavg_to_remove += io->interval;
-                                       }
-                                       if (mavg_to_add<=io->num_items*io->interval){
-                                               mavg_in_average_count++;
-                                               mavg_cumulated += get_it_value(io, i, mavg_to_add/io->interval);
-                                               mavg_to_add += io->interval;
-                                       } else {
-                                               mavg_right--;
-                                       }
-                               }
-                               if (mavg_in_average_count > 0) {
-                                       val = mavg_cumulated / mavg_in_average_count;
-                               }
-                       }
-
-                       if (val>max_y) {
-                               y_pos=0;
-                       } else if (io->max_y_units==LOGARITHMIC_YSCALE) {
-                               if (val==0) {
-                                       y_pos=(guint32)(draw_height-1+top_y_border);
-                               } else {
-                                       y_pos = (guint32) (
-                                                          (draw_height - ystart) - 1 -
-                                                          (log10((double)(gint64)val) * (draw_height - ystart)) / log10((double)max_y) +
-                                                          top_y_border
-                                                         );
-                               }
-                       } else {
-                               y_pos = (guint32)(draw_height - 1 -
-                                                 ((val * draw_height) / max_y) +
-                                                 top_y_border);
-                       }
-
-                       switch(io->graphs[i].plot_style){
-                       case PLOT_STYLE_LINE:
-                               /* Dont draw anything if the segment entirely above the top of the graph
-                                */
-                               if( (prev_y_pos!=0) || (y_pos!=0) ){
-#if GTK_CHECK_VERSION(2,22,0)
-                                       cr = cairo_create (io->surface);
-#else
-                                       cr = gdk_cairo_create (io->pixmap);
-#endif
-                                       gdk_cairo_set_source_color (cr, &io->graphs[i].color);
-                                       cairo_set_line_width (cr, 1.0);
-                                       cairo_move_to(cr, prev_x_pos+0.5, prev_y_pos+0.5);
-                                       cairo_line_to(cr, x_pos+0.5, y_pos+0.5);
-                                       cairo_stroke(cr);
-                                       cairo_destroy(cr);
-                               }
-                               break;
-                       case PLOT_STYLE_IMPULSE:
-                               if(val){
-#if GTK_CHECK_VERSION(2,22,0)
-                                       cr = cairo_create (io->surface);
-#else
-                                       cr = gdk_cairo_create (io->pixmap);
-#endif
-                                       gdk_cairo_set_source_color (cr, &io->graphs[i].color);
-                                       cairo_set_line_width (cr, 1.0);
-                                       cairo_move_to(cr, x_pos+0.5, draw_height-1+top_y_border+0.5);
-                                       cairo_line_to(cr, x_pos+0.5, y_pos+0.5);
-                                       cairo_stroke(cr);
-                                       cairo_destroy(cr);
-                               }
-                               break;
-                       case PLOT_STYLE_FILLED_BAR:
-                               if(val){
-#if GTK_CHECK_VERSION(2,22,0)
-                                       cr = cairo_create (io->surface);
-#else
-                                       cr = gdk_cairo_create (io->pixmap);
-#endif
-                                       cairo_rectangle (cr,
-                                               x_pos-(gdouble)io->pixels_per_tick/2+0.5,
-                                               y_pos+0.5,
-                                               io->pixels_per_tick,
-                                               draw_height-1+top_y_border-y_pos);
-                                       gdk_cairo_set_source_color (cr, &io->graphs[i].color);
-                                       cairo_fill (cr);
-                                       cairo_destroy (cr);
-                               }
-                               break;
-                       case PLOT_STYLE_DOT:
-                               if(val){
-#if GTK_CHECK_VERSION(2,22,0)
-                                       cr = cairo_create (io->surface);
-#else
-                                       cr = gdk_cairo_create (io->pixmap);
-#endif
-                                       cairo_arc (cr,
-                                               x_pos+0.5,
-                                               y_pos+0.5,
-                                               (gdouble)io->pixels_per_tick/2,
-                                               0,
-                                               2 * G_PI);
-                                       gdk_cairo_set_source_color (cr, &io->graphs[i].color);
-                                       cairo_fill (cr);
-                                       cairo_destroy (cr);
-                               }
-                               break;
-                       }
-
-                       prev_y_pos=y_pos;
-                       prev_x_pos=x_pos;
-               }
-       }
+        guint64 val;
+        guint32 interval, x_pos, y_pos, prev_x_pos, prev_y_pos;
+        /* Moving average variables */
+        guint32 mavg_in_average_count = 0, mavg_left = 0, mavg_right = 0;
+        guint64 mavg_cumulated = 0;
+        guint64 mavg_to_remove = 0, mavg_to_add = 0;
+
+        if(!io->graphs[i].display){
+            continue;
+        }
+
+        if(io->filter_type == MOVING_AVERAGE_FILTER){
+            /* "Warm-up phase" - calculate average on some data not displayed;
+            just to make sure average on leftmost and rightmost displayed
+            values is as reliable as possible
+            */
+            guint64 warmup_interval;
+
+            if(first_interval/io->interval > io->filter_order/2){
+                warmup_interval = first_interval/io->interval - io->filter_order/2;
+                warmup_interval *= io->interval;
+            } else {
+                warmup_interval = 0;
+            }
+            mavg_to_remove = warmup_interval;
+            for(;warmup_interval<first_interval;warmup_interval+=io->interval){
+                mavg_cumulated += get_it_value(io, i, (int)warmup_interval/io->interval);
+                mavg_in_average_count++;
+                mavg_left++;
+            }
+            mavg_cumulated += get_it_value(io, i, (int)warmup_interval/io->interval);
+            mavg_in_average_count++;
+            for(warmup_interval += io->interval;
+                ((warmup_interval < (first_interval + (io->filter_order/2) * (guint64)io->interval)) &&
+                (warmup_interval <= (io->num_items * (guint64)io->interval)));
+            warmup_interval += io->interval) {
+
+                mavg_cumulated += get_it_value(io, i, (int)warmup_interval / io->interval);
+                mavg_in_average_count++;
+                mavg_right++;
+            }
+            mavg_to_add = warmup_interval;
+        }
+
+        /* initialize prev x/y to the value of the first interval */
+        prev_x_pos = draw_width-1 -
+            io->pixels_per_tick * ((last_interval - first_interval) / io->interval) +
+            io->left_x_border;
+        val = get_it_value(io, i, first_interval / io->interval);
+
+        if(io->filter_type==MOVING_AVERAGE_FILTER
+            && mavg_in_average_count > 0) {
+                val = mavg_cumulated / mavg_in_average_count;
+        }
+
+        if(val>max_y){
+            prev_y_pos=0;
+        } else if (io->max_y_units==LOGARITHMIC_YSCALE){
+            if (val==0) {
+                prev_y_pos = (guint32)(draw_height - 1 + top_y_border);
+            } else {
+                prev_y_pos = (guint32) (
+                    (draw_height - ystart)-1 -
+                    ((log10((double)((gint64)val)) * (draw_height - ystart)) / log10((double)max_y)) +
+                    top_y_border
+                    );
+            }
+        } else {
+            prev_y_pos=(guint32)(draw_height-1-(val*draw_height)/max_y+top_y_border);
+        }
+
+        for(interval = first_interval;
+            interval < last_interval;
+            interval += io->interval) {
+                x_pos=draw_width-1-io->pixels_per_tick*((last_interval-interval)/io->interval)+io->left_x_border;
+
+                val = get_it_value(io, i, interval/io->interval);
+                /* Moving average calculation */
+                if (io->filter_type==MOVING_AVERAGE_FILTER) {
+                    if (interval != first_interval){
+                        mavg_left++;
+                        if (mavg_left > io->filter_order/2) {
+                            mavg_left--;
+                            mavg_in_average_count--;
+                            mavg_cumulated -= get_it_value(io, i, (int)mavg_to_remove/io->interval);
+                            mavg_to_remove += io->interval;
+                        }
+                        if (mavg_to_add<=(guint64)io->num_items*io->interval){
+                            mavg_in_average_count++;
+                            mavg_cumulated += get_it_value(io, i, (int)mavg_to_add/io->interval);
+                            mavg_to_add += io->interval;
+                        } else {
+                            mavg_right--;
+                        }
+                    }
+                    if (mavg_in_average_count > 0) {
+                        val = mavg_cumulated / mavg_in_average_count;
+                    }
+                }
+
+                if (val>max_y) {
+                    y_pos=0;
+                } else if (io->max_y_units==LOGARITHMIC_YSCALE) {
+                    if (val==0) {
+                        y_pos=(guint32)(draw_height-1+top_y_border);
+                    } else {
+                        y_pos = (guint32) (
+                            (draw_height - ystart) - 1 -
+                            (log10((double)(gint64)val) * (draw_height - ystart)) / log10((double)max_y) +
+                            top_y_border
+                            );
+                    }
+                } else {
+                    y_pos = (guint32)(draw_height - 1 -
+                        ((val * draw_height) / max_y) +
+                        top_y_border);
+                }
+
+                switch(io->graphs[i].plot_style){
+                case PLOT_STYLE_LINE:
+                    /* Dont draw anything if the segment entirely above the top of the graph
+                    */
+                    if( (prev_y_pos!=0) || (y_pos!=0) ){
+                        cairo_move_to(cr, prev_x_pos+0.5, prev_y_pos+0.5);
+                        cairo_line_to(cr, x_pos+0.5, y_pos+0.5);
+                                               gdk_cairo_set_source_color (cr, &io->graphs[i].color);
+                        cairo_stroke(cr);
+                    }
+                    break;
+                case PLOT_STYLE_IMPULSE:
+                    if(val){
+                        cairo_move_to(cr, x_pos+0.5, draw_height-1+top_y_border+0.5);
+                        cairo_line_to(cr, x_pos+0.5, y_pos+0.5);
+                                               gdk_cairo_set_source_color (cr, &io->graphs[i].color);
+                        cairo_stroke(cr);
+                    }
+                    break;
+                case PLOT_STYLE_FILLED_BAR:
+                    if(val){
+                        cairo_rectangle (cr,
+                            x_pos-(gdouble)io->pixels_per_tick/2+0.5,
+                            y_pos+0.5,
+                            io->pixels_per_tick,
+                            draw_height-1+top_y_border-y_pos);
+                                               gdk_cairo_set_source_color (cr, &io->graphs[i].color);
+                        cairo_fill (cr);
+                    }
+                    break;
+                case PLOT_STYLE_DOT:
+                    if(val){
+                        cairo_arc (cr,
+                            x_pos+0.5,
+                            y_pos+0.5,
+                            (gdouble)io->pixels_per_tick/2,
+                            0,
+                            2 * G_PI);
+                                               gdk_cairo_set_source_color (cr, &io->graphs[i].color);
+                        cairo_fill (cr);
+                    }
+                    break;
+                }
+
+                prev_y_pos=y_pos;
+                prev_x_pos=x_pos;
+        }
+    }
+       cairo_destroy (cr);
 
-       cr = gdk_cairo_create (gtk_widget_get_window(io->draw_area));
+    cr = gdk_cairo_create (gtk_widget_get_window(io->draw_area));
 
 #if GTK_CHECK_VERSION(2,22,0)
-       cairo_set_source_surface (cr, io->surface, 0, 0);
+    cairo_set_source_surface (cr, io->surface, 0, 0);
 #else
-       gdk_cairo_set_source_pixmap (cr, io->pixmap, 0, 0);
+    gdk_cairo_set_source_pixmap (cr, io->pixmap, 0, 0);
 #endif
-       cairo_rectangle (cr, 0, 0, io->pixmap_width, io->pixmap_height);
-       cairo_fill (cr);
-
-       cairo_destroy (cr);
-
-       /* update the scrollbar */
-       if (io->max_interval == 0) {
-               gtk_adjustment_set_upper(io->scrollbar_adjustment, (gfloat) io->interval);
-               gtk_adjustment_set_step_increment(io->scrollbar_adjustment, (gfloat) (io->interval/10));
-               gtk_adjustment_set_page_increment(io->scrollbar_adjustment, (gfloat) io->interval);
-       } else {
-               gtk_adjustment_set_upper(io->scrollbar_adjustment, (gfloat) io->max_interval);
-               gtk_adjustment_set_step_increment(io->scrollbar_adjustment, (gfloat) ((last_interval-first_interval)/10));
-               gtk_adjustment_set_page_increment(io->scrollbar_adjustment, (gfloat) (last_interval-first_interval));
-       }
-       gtk_adjustment_set_page_size(io->scrollbar_adjustment, gtk_adjustment_get_page_increment(io->scrollbar_adjustment));
-       gtk_adjustment_set_value(io->scrollbar_adjustment, (gfloat)first_interval);
-       gtk_adjustment_changed(io->scrollbar_adjustment);
-       gtk_adjustment_value_changed(io->scrollbar_adjustment);
+    cairo_rectangle (cr, 0, 0, io->surface_width, io->surface_height);
+    cairo_fill (cr);
+
+    cairo_destroy (cr);
+
+    /* update the scrollbar */
+    if (io->max_interval == 0) {
+        gtk_adjustment_set_upper(io->scrollbar_adjustment, (gfloat) io->interval);
+        gtk_adjustment_set_step_increment(io->scrollbar_adjustment, (gfloat) (io->interval/10));
+        gtk_adjustment_set_page_increment(io->scrollbar_adjustment, (gfloat) io->interval);
+    } else {
+        gtk_adjustment_set_upper(io->scrollbar_adjustment, (gfloat) io->max_interval);
+        gtk_adjustment_set_step_increment(io->scrollbar_adjustment, (gfloat) ((last_interval-first_interval)/10));
+        gtk_adjustment_set_page_increment(io->scrollbar_adjustment, (gfloat) (last_interval-first_interval));
+    }
+    gtk_adjustment_set_page_size(io->scrollbar_adjustment, gtk_adjustment_get_page_increment(io->scrollbar_adjustment));
+    gtk_adjustment_set_value(io->scrollbar_adjustment, (gfloat)first_interval);
+    gtk_adjustment_changed(io->scrollbar_adjustment);
+    gtk_adjustment_value_changed(io->scrollbar_adjustment);
 
 }
 
@@ -1377,19 +1307,17 @@ disable_graph(io_stat_graph_t *gio)
 {
        if (gio->display) {
                gio->display=FALSE;
-               protect_thread_critical_region();
                remove_tap_listener(gio);
-               unprotect_thread_critical_region();
                gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gio->display_button),
                    FALSE);
        }
 }
 
 static void
-iostat_init(const char *optarg _U_, void* userdata _U_)
+iostat_init(const char *opt_arg _U_, void* userdata _U_)
 {
        io_stat_t *io;
-       int i=0;
+       int i=0, j=0;
        static GdkColor col[MAX_GRAPHS] = {
                {0,     0x0000, 0x0000, 0x0000}, /* Black */
                {0,     0xffff, 0x0000, 0x0000}, /* Red */
@@ -1408,7 +1336,7 @@ iostat_init(const char *optarg _U_, void* userdata _U_)
 #endif
        GString *error_string;
 
-       io=g_malloc(sizeof(io_stat_t));
+       io=g_new(io_stat_t,1);
        io->needs_redraw=TRUE;
        io->interval=tick_interval_values[DEFAULT_TICK_VALUE_INDEX];
        io->window=NULL;
@@ -1420,8 +1348,8 @@ iostat_init(const char *optarg _U_, void* userdata _U_)
 #endif
        io->scrollbar=NULL;
        io->scrollbar_adjustment=NULL;
-       io->pixmap_width=500;
-       io->pixmap_height=200;
+       io->surface_width=500;
+       io->surface_height=200;
        io->pixels_per_tick=pixels_per_tick[DEFAULT_PIXELS_PER_TICK_INDEX];
        io->max_y_units=AUTO_MAX_YSCALE;
        io->count_type=0;
@@ -1451,18 +1379,23 @@ iostat_init(const char *optarg _U_, void* userdata _U_)
                io->graphs[i].advanced_buttons=NULL;
                io->graphs[i].io=io;
 
-               io->graphs[i].args=g_malloc(sizeof(construct_args_t));
+               io->graphs[i].args=g_new(construct_args_t,1);
                io->graphs[i].args->title = NULL;
                io->graphs[i].args->wants_apply_button=TRUE;
                io->graphs[i].args->activate_on_ok=TRUE;
                io->graphs[i].args->modal_and_transient=FALSE;
 
                io->graphs[i].filter_bt=NULL;
+
+               for(j=0;j<NUM_IO_ITEMS;j++){
+                       io->graphs[i].items[j] = g_new(io_item_t,1);
+               }
        }
        io_stat_reset(io);
 
        error_string=enable_graph(&io->graphs[0], NULL, NULL);
-       g_assert((error_string == NULL) && "Can't attach io_stat tap !");
+       /* Can't attach io_stat tap ! */
+       g_assert(error_string == NULL);
 #if 0
        if(error_string){
 
@@ -1488,7 +1421,7 @@ static void
 draw_area_destroy_cb(GtkWidget *widget _U_, gpointer user_data)
 {
        io_stat_t *io = user_data;
-       int i;
+       int i,j;
        GtkWidget *save_bt = g_object_get_data(G_OBJECT(io->window), "save_bt");
        surface_info_t *surface_info = g_object_get_data(G_OBJECT(save_bt), "surface-info");
 
@@ -1496,15 +1429,17 @@ draw_area_destroy_cb(GtkWidget *widget _U_, gpointer user_data)
 
        for(i=0;i<MAX_GRAPHS;i++){
                if(io->graphs[i].display){
-                       protect_thread_critical_region();
                        remove_tap_listener(&io->graphs[i]);
-                       unprotect_thread_critical_region();
 
                        g_free( (gpointer) (io->graphs[i].args->title) );
                        io->graphs[i].args->title=NULL;
 
                        g_free(io->graphs[i].args);
                        io->graphs[i].args=NULL;
+                       for(j=0;j<NUM_IO_ITEMS;j++){
+                               g_free(io->graphs[i].items[j]);
+                               io->graphs[i].items[j]=NULL;
+                       }
                }
        }
        g_free(io);
@@ -1522,7 +1457,7 @@ pixmap_clicked_event(GtkWidget *widget _U_, GdkEventButton *event, gpointer g)
        int i;
        gboolean load=FALSE, outstanding_call=FALSE;
 
-       draw_width = io->pixmap_width - io->right_x_border - io->left_x_border;
+       draw_width = io->surface_width - io->right_x_border - io->left_x_border;
 
        if ((event->x <= (draw_width+io->left_x_border+1-(draw_width/io->pixels_per_tick)*io->pixels_per_tick)) ||
            (event->x >= (draw_width+io->left_x_border-io->pixels_per_tick/2))) {
@@ -1545,17 +1480,24 @@ pixmap_clicked_event(GtkWidget *widget _U_, GdkEventButton *event, gpointer g)
                        last_interval = io->last_interval;
 
                /* Get the interval that was clicked */
-               interval = (guint32) (
-                                     (last_interval / io->interval) -
-                                     ((draw_width + io->left_x_border - event->x-io->pixels_per_tick / 2 - 1) / io->pixels_per_tick)
-                                    );
+               if ((last_interval / io->interval) <
+                               ((draw_width + io->left_x_border - event->x -
+                                 io->pixels_per_tick / 2 - 1) / io->pixels_per_tick)) {
+                       interval = 0;
+               }
+               else {
+                       interval = (guint32) (
+                                       (last_interval / io->interval) -
+                                       ((draw_width + io->left_x_border - event->x -
+                                         io->pixels_per_tick / 2 - 1) / io->pixels_per_tick));
+               }
 
                /* Determine the lowest or highest frame number depending on whether button 1 or 3 was clicked,
                 *  respectively, among the up to 5 currently displayed graphs. */
                for(i=0; i<MAX_GRAPHS; i++) {
                        graph = &io->graphs[i];
                        if(graph->display) {
-                               it = &graph->items[interval];
+                               it = graph->items[interval];
                                if (event->button==1) {
                                        if(frame_num==0 || (it->first_frame_in_invl < frame_num))
                                                frame_num = it->first_frame_in_invl;
@@ -1623,8 +1565,8 @@ draw_area_configure_event(GtkWidget *widget, GdkEventConfigure *event _U_, gpoin
                        widget_alloc.height,
                        -1);
 #endif
-       io->pixmap_width=widget_alloc.width;
-       io->pixmap_height=widget_alloc.height;
+       io->surface_width=widget_alloc.width;
+       io->surface_height=widget_alloc.height;
 
        save_bt = g_object_get_data(G_OBJECT(io->window), "save_bt");
 #if GTK_CHECK_VERSION(2,22,0)
@@ -1707,7 +1649,7 @@ create_draw_area(io_stat_t *io, GtkWidget *box)
        io->draw_area=gtk_drawing_area_new();
        g_signal_connect(io->draw_area, "destroy", G_CALLBACK(draw_area_destroy_cb), io);
 
-       gtk_widget_set_size_request(io->draw_area, io->pixmap_width, io->pixmap_height);
+       gtk_widget_set_size_request(io->draw_area, io->surface_width, io->surface_height);
 
        /* signals needed to handle backing pixmap */
 #if GTK_CHECK_VERSION(3,0,0)
@@ -2132,9 +2074,7 @@ filter_callback(GtkWidget *widget, gpointer user_data)
           first just try to delete any previous settings and then apply
           the new ones.
        */
-       protect_thread_critical_region();
        remove_tap_listener(gio);
-       unprotect_thread_critical_region();
 
        io_stat_reset(gio->io);
        enable_graph(gio, filter, field);
@@ -2261,7 +2201,8 @@ create_filter_box(io_stat_graph_t *gio, GtkWidget *box, int num)
        gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
 
 #if GTK_CHECK_VERSION(3,0,0)
-       gtk_widget_override_color(label, GTK_STATE_NORMAL, &gio->rgba_color);
+       gtk_widget_override_color(label, GTK_STATE_FLAG_NORMAL, &gio->rgba_color);
+       /* XXX gtk_widget_override_color() takes flags not state */
        gtk_widget_override_color(label, GTK_STATE_ACTIVE, &gio->rgba_color);
        gtk_widget_override_color(label, GTK_STATE_PRELIGHT, &gio->rgba_color);
        gtk_widget_override_color(label, GTK_STATE_SELECTED, &gio->rgba_color);
@@ -2408,7 +2349,7 @@ init_io_stat_window(io_stat_t *io)
        create_draw_area(io, vbox);
 
        hbox=ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
-       gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
+       gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
        gtk_container_set_border_width(GTK_CONTAINER(hbox), 3);
        gtk_box_set_child_packing(GTK_BOX(vbox), hbox, FALSE, FALSE, 0, GTK_PACK_START);
        gtk_widget_show(hbox);