"Fossies" - the Fresh Open Source Software Archive

Member "procmeter3-3.6+svn387/gtk3/widgets/PMGraph.c" (7 Jan 2012, 20147 Bytes) of package /linux/misc/procmeter3-3.6+svn387.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "PMGraph.c" see the Fossies "Dox" file reference documentation.

    1 /***************************************
    2   ProcMeter Graph Widget Source file (for ProcMeter3 3.6).
    3   ******************/ /******************
    4   Written by Andrew M. Bishop
    5 
    6   This file Copyright 1996-2012 Andrew M. Bishop
    7   It may be distributed under the GNU Public License, version 2, or
    8   any higher version.  See section COPYING of the GNU Public license
    9   for conditions under which this file may be redistributed.
   10   ***************************************/
   11 
   12 
   13 #include <stdlib.h>
   14 #include <string.h>
   15 
   16 #include "PMGeneric.h"
   17 #include "PMGraph.h"
   18 
   19 #include "procmeter.h"
   20 
   21 static void procmetergraph_class_init(ProcMeterGraphClass *class);
   22 static void procmetergraph_init(ProcMeterGraph *pmw);
   23 static void destroy(GtkWidget *widget);
   24 static void realize(GtkWidget *widget);
   25 static void get_preferred_width(GtkWidget *widget,gint *minimal_width,gint *natural_width);
   26 static void get_preferred_height(GtkWidget *widget,gint *minimal_height,gint *natural_height);
   27 static void size_allocate(GtkWidget *widget,GtkAllocation *allocation);
   28 static gboolean draw(GtkWidget *widget,cairo_t *cr);
   29 
   30 static void GraphResize(ProcMeterGraph *pmw);
   31 static void GraphUpdate(ProcMeterGraph *pmw,gboolean all);
   32 
   33 static char *empty_string="";
   34 
   35 static ProcMeterGenericClass *parent_class=NULL;
   36 
   37 
   38 /*++++++++++++++++++++++++++++++++++++++
   39   Returns the type of a Widget.
   40 
   41   guint gtk_procmetergraph_get_type Returns a unique pointer to the Widget type.
   42   ++++++++++++++++++++++++++++++++++++++*/
   43 
   44 guint gtk_procmetergraph_get_type(void)
   45 {
   46  static guint pmw_type = 0;
   47 
   48  if(!pmw_type)
   49    {
   50     GTypeInfo pmw_info={sizeof(ProcMeterGraphClass),
   51                         NULL,
   52                         NULL,
   53                         (GClassInitFunc) procmetergraph_class_init,
   54                         NULL,
   55                         NULL,
   56                         sizeof(ProcMeterGraph),
   57                         0,
   58                         (GInstanceInitFunc) procmetergraph_init,
   59                         NULL};
   60 
   61     pmw_type=g_type_register_static(gtk_procmetergeneric_get_type(),"ProcMeterGraph",&pmw_info,0);
   62    }
   63 
   64  return(pmw_type);
   65 }
   66 
   67 
   68 /*++++++++++++++++++++++++++++++++++++++
   69   Initialise the Widget class
   70 
   71   ProcMeterGraphClass *class The class of widget to initialise.
   72   ++++++++++++++++++++++++++++++++++++++*/
   73 
   74 static void procmetergraph_class_init(ProcMeterGraphClass *class)
   75 {
   76  GtkWidgetClass *widget_class;
   77 
   78  g_return_if_fail(class!=NULL);
   79 
   80  widget_class=(GtkWidgetClass*)class;
   81 
   82  class->resize=GraphResize;
   83  class->update=GraphUpdate;
   84 
   85  parent_class=g_type_class_ref(gtk_procmetergeneric_get_type());
   86 
   87  widget_class->destroy=destroy;
   88  widget_class->realize=realize;
   89  widget_class->draw=draw;
   90  widget_class->get_preferred_width=get_preferred_width;
   91  widget_class->get_preferred_height=get_preferred_height;
   92  widget_class->size_allocate=size_allocate;
   93 }
   94 
   95 
   96 /*++++++++++++++++++++++++++++++++++++++
   97   Initialise an instance of the Widget
   98 
   99   ProcMeterGraph *pmw The Widget to initialise.
  100   ++++++++++++++++++++++++++++++++++++++*/
  101 
  102 static void procmetergraph_init(ProcMeterGraph *pmw)
  103 {
  104  g_return_if_fail(pmw!=NULL);
  105 
  106  /* The grid parts. */
  107 
  108  pmw->grid_units=empty_string;
  109 
  110  gtk_style_context_get_color(gtk_widget_get_style_context(&pmw->generic.widget),GTK_STATE_FLAG_NORMAL,&pmw->grid_color);
  111 
  112  pmw->grid_drawn=1;
  113  pmw->grid_min=1;
  114 
  115  pmw->grid_max=0;
  116 
  117  pmw->grid_num=pmw->grid_min;
  118 
  119  /* The data parts. */
  120 
  121  pmw->data_num=10;
  122  pmw->data=(gushort*)calloc(pmw->data_num,sizeof(gushort));
  123  pmw->data_max=0;
  124  pmw->data_index=0;
  125 
  126  /* The rest of the sizing. */
  127 
  128  GraphResize(pmw);
  129 }
  130 
  131 
  132 /*++++++++++++++++++++++++++++++++++++++
  133   Create a new Widget.
  134 
  135   GtkWidget* gtk_procmetergraph_new Returns the new widgets.
  136   ++++++++++++++++++++++++++++++++++++++*/
  137 
  138 GtkWidget* gtk_procmetergraph_new(void)
  139 {
  140  ProcMeterGraph *pmw;
  141 
  142  pmw=g_object_new(gtk_procmetergraph_get_type(),NULL);
  143 
  144  return(GTK_WIDGET(pmw));
  145 }
  146 
  147 
  148 /*++++++++++++++++++++++++++++++++++++++
  149   Destroy a Widget
  150 
  151   GtkWidget *widget The widget to destroy.
  152   ++++++++++++++++++++++++++++++++++++++*/
  153 
  154 static void destroy(GtkWidget *widget)
  155 {
  156  ProcMeterGraph *pmw;
  157 
  158  g_return_if_fail(widget!=NULL);
  159  g_return_if_fail(GTK_IS_PROCMETERGRAPH(widget));
  160 
  161  pmw=GTK_PROCMETERGRAPH(widget);
  162 
  163  if(pmw->grid_units!=empty_string)
  164    {
  165     free(pmw->grid_units);
  166     pmw->grid_units=empty_string;
  167    }
  168  if(pmw->data)
  169    {
  170     free(pmw->data);
  171     pmw->data=NULL;
  172    }
  173 
  174  if(GTK_WIDGET_CLASS(parent_class)->destroy)
  175     (*GTK_WIDGET_CLASS(parent_class)->destroy)(widget);
  176 }
  177 
  178 
  179 /*++++++++++++++++++++++++++++++++++++++
  180   Realize a widget.
  181 
  182   GtkWidget *widget The widget to realize.
  183   ++++++++++++++++++++++++++++++++++++++*/
  184 
  185 static void realize(GtkWidget *widget)
  186 {
  187  ProcMeterGraph *pmw;
  188  GdkWindowAttr attributes;
  189  GtkAllocation allocation;
  190  gint attributes_mask;
  191 
  192  g_return_if_fail(widget!=NULL);
  193  g_return_if_fail(GTK_IS_PROCMETERGRAPH(widget));
  194 
  195  gtk_widget_set_realized(widget,TRUE);
  196  pmw=GTK_PROCMETERGRAPH(widget);
  197 
  198  gtk_widget_get_allocation(widget,&allocation);
  199 
  200  attributes.x=allocation.x;
  201  attributes.y=allocation.y;
  202  attributes.width=allocation.width;
  203  attributes.height=allocation.height;
  204  attributes.wclass=GDK_INPUT_OUTPUT;
  205  attributes.window_type=GDK_WINDOW_CHILD;
  206  attributes.event_mask=gtk_widget_get_events(widget)|GDK_EXPOSURE_MASK|GDK_BUTTON_PRESS_MASK;
  207  attributes.visual=gtk_widget_get_visual(widget);
  208 
  209  attributes_mask=GDK_WA_X|GDK_WA_Y|GDK_WA_VISUAL;
  210  gtk_widget_set_window(widget,gdk_window_new(gtk_widget_get_parent_window(widget),&attributes,attributes_mask));
  211 
  212  gdk_window_set_user_data(gtk_widget_get_window(widget),widget);
  213 
  214  GraphUpdate(pmw,TRUE);
  215 }
  216 
  217 
  218 /*++++++++++++++++++++++++++++++++++++++
  219   Return the preferred width of the widget
  220 
  221   GtkWidget *widget The widget whose width is requested.
  222 
  223   gint *minimal_width Returns the minimal width.
  224 
  225   gint *natural_width Returns the preferred width.
  226   ++++++++++++++++++++++++++++++++++++++*/
  227 
  228 static void get_preferred_width(GtkWidget *widget,gint *minimal_width,gint *natural_width)
  229 {
  230  g_return_if_fail(widget!=NULL);
  231  g_return_if_fail(GTK_IS_PROCMETERGRAPH(widget));
  232  g_return_if_fail(minimal_width!=NULL);
  233  g_return_if_fail(natural_width!=NULL);
  234 
  235  *minimal_width=*natural_width=50; /* arbitrary */
  236 }
  237 
  238 
  239 /*++++++++++++++++++++++++++++++++++++++
  240   Return the preferred height of the widget
  241 
  242   GtkWidget *widget The widget whose height is requested.
  243 
  244   gint *minimal_height Returns the minimal height.
  245 
  246   gint *natural_height Returns the preferred height.
  247   ++++++++++++++++++++++++++++++++++++++*/
  248 
  249 static void get_preferred_height(GtkWidget *widget,gint *minimal_height,gint *natural_height)
  250 {
  251  ProcMeterGraph *pmw;
  252 
  253  g_return_if_fail(widget!=NULL);
  254  g_return_if_fail(GTK_IS_PROCMETERGRAPH(widget));
  255  g_return_if_fail(minimal_height!=NULL);
  256  g_return_if_fail(natural_height!=NULL);
  257 
  258  pmw=GTK_PROCMETERGRAPH(widget);
  259 
  260  *minimal_height=*natural_height=20+pmw->generic.label_height;
  261 }
  262 
  263 
  264 /*++++++++++++++++++++++++++++++++++++++
  265   Change to the size that has been specified by the container.
  266 
  267   GtkWidget *widget The widget that has been resized.
  268 
  269   GtkAllocation *allocation The size information.
  270   ++++++++++++++++++++++++++++++++++++++*/
  271 
  272 static void size_allocate(GtkWidget *widget,GtkAllocation *allocation)
  273 {
  274  g_return_if_fail(widget!=NULL);
  275  g_return_if_fail(GTK_IS_PROCMETERGRAPH(widget));
  276  g_return_if_fail(allocation!=NULL);
  277 
  278  gtk_widget_set_allocation(widget,allocation);
  279  if(gtk_widget_get_realized(widget))
  280    {
  281     ProcMeterGraph *pmw=GTK_PROCMETERGRAPH(widget);
  282 
  283     gdk_window_move_resize(gtk_widget_get_window(widget),
  284                            allocation->x,allocation->y,
  285                            allocation->width,allocation->height);
  286 
  287     GraphResize(pmw);
  288    }
  289 }
  290 
  291 
  292 /*++++++++++++++++++++++++++++++++++++++
  293   Redisplay the ProcMeter Graph Widget.
  294 
  295   gboolean draw Returns false
  296 
  297   GtkWidget *widget The Widget to redisplay.
  298 
  299   cairo_t *cr A cairo object describing the position to draw.
  300   ++++++++++++++++++++++++++++++++++++++*/
  301 
  302 static gboolean draw(GtkWidget *widget,cairo_t *cr)
  303 {
  304  ProcMeterGraph *pmw;
  305 
  306  g_return_val_if_fail(widget!=NULL,FALSE);
  307  g_return_val_if_fail(GTK_IS_PROCMETERGRAPH(widget),FALSE);
  308 
  309  pmw=GTK_PROCMETERGRAPH(widget);
  310 
  311  GraphUpdate(pmw,TRUE);
  312 
  313  return(FALSE);
  314 }
  315 
  316 
  317 /*++++++++++++++++++++++++++++++++++++++
  318   Perform all of the sizing on the Widget when it is created/resized.
  319 
  320   ProcMeterGraph *pmw The Widget to resize.
  321   ++++++++++++++++++++++++++++++++++++++*/
  322 
  323 static void GraphResize(ProcMeterGraph *pmw)
  324 {
  325  int allocation_width;
  326  cairo_t *cr;
  327  PangoLayout *layout;
  328  int width,height;
  329 
  330  g_return_if_fail(pmw!=NULL);
  331 
  332  if(parent_class->resize)
  333     parent_class->resize(&pmw->generic);
  334 
  335  allocation_width=gtk_widget_get_allocated_width(&pmw->generic.widget);
  336 
  337  if(pmw->data_num!=allocation_width)
  338    {
  339     int i,old_num=pmw->data_num;
  340     gushort* old_data=pmw->data;
  341 
  342     pmw->data_num=allocation_width;
  343     pmw->data=(gushort*)calloc(pmw->data_num,sizeof(gushort));
  344 
  345     if(pmw->data_num<old_num)
  346        i=pmw->data_num;
  347     else
  348        i=old_num;
  349 
  350     for(;i>0;i--)
  351        pmw->data[(-i+pmw->data_num)%pmw->data_num]=old_data[(pmw->data_index-i+old_num)%old_num];
  352 
  353     pmw->data_index=0;
  354 
  355     free(old_data);
  356 
  357     for(i=pmw->data_max=0;i<pmw->data_num;i++)
  358        if(pmw->data[i]>pmw->data_max)
  359           pmw->data_max=pmw->data[i];
  360 
  361     pmw->grid_num=(pmw->data_max+(PROCMETER_GRAPH_SCALE-1))/PROCMETER_GRAPH_SCALE;
  362 
  363     if(pmw->grid_num<pmw->grid_min)
  364        pmw->grid_num=pmw->grid_min;
  365     if(pmw->grid_max && pmw->grid_num>pmw->grid_max)
  366        pmw->grid_num=pmw->grid_max;
  367    }
  368 
  369  pmw->generic.label_x=2;
  370 
  371  /* The grid parts. */
  372 
  373  cr=gdk_cairo_create(gtk_widget_get_root_window(&pmw->generic.widget));
  374 
  375  layout=pango_cairo_create_layout(cr);
  376  if(pmw->generic.label_font)
  377     pango_layout_set_font_description(layout,pmw->generic.label_font);
  378  else
  379     pango_layout_set_font_description(layout,gtk_style_context_get_font(gtk_widget_get_style_context(&pmw->generic.widget),GTK_STATE_FLAG_NORMAL));
  380 
  381  pango_layout_set_text(layout,pmw->grid_units,-1);
  382  pango_layout_get_pixel_size(layout,&width,&height);
  383 
  384  cairo_destroy(cr);
  385 
  386  pmw->grid_units_x=allocation_width-width-2;
  387 
  388  pmw->grid_maxvis=pmw->generic.body_height/3;
  389 
  390  if(pmw->generic.label_pos==ProcMeterLabelTop)
  391     pmw->generic.body_start=pmw->generic.label_height;
  392  else
  393     pmw->generic.body_start=0;
  394 
  395  if(pmw->grid_num>pmw->grid_maxvis && pmw->grid_drawn)
  396     pmw->grid_drawn=-1;
  397  if(pmw->grid_num<=pmw->grid_maxvis && pmw->grid_drawn)
  398     pmw->grid_drawn=1;
  399 }
  400 
  401 
  402 /*++++++++++++++++++++++++++++++++++++++
  403   Update the display.
  404 
  405   ProcMeterGraph *pmw The Widget to update.
  406 
  407   gboolean all Indicates if the whole widget is to be updated.
  408   ++++++++++++++++++++++++++++++++++++++*/
  409 
  410 static void GraphUpdate(ProcMeterGraph *pmw,gboolean all)
  411 {
  412  g_return_if_fail(pmw!=NULL);
  413 
  414  if(gtk_widget_get_visible(&pmw->generic.widget))
  415    {
  416     int allocation_width;
  417     cairo_t *cr;
  418     int i;
  419     int scale=PROCMETER_GRAPH_SCALE*pmw->grid_num;
  420     gushort val;
  421     gshort pos;
  422 
  423     cr=gdk_cairo_create(gtk_widget_get_window(&pmw->generic.widget));
  424     cairo_set_line_width(cr,1.0);
  425 
  426     allocation_width=gtk_widget_get_allocated_width(&pmw->generic.widget);
  427 
  428     if(all)
  429       {
  430        if(parent_class->update)
  431           parent_class->update(&pmw->generic);
  432 
  433        if(pmw->generic.label_pos!=ProcMeterLabelNone)
  434          {
  435           PangoLayout *layout;
  436 
  437           cairo_set_source_rgb(cr,pmw->generic.label_color.red,pmw->generic.label_color.green,pmw->generic.label_color.blue);
  438 
  439           layout=pango_cairo_create_layout(cr);
  440           if(pmw->generic.label_font)
  441              pango_layout_set_font_description(layout,pmw->generic.label_font);
  442           else
  443              pango_layout_set_font_description(layout,gtk_style_context_get_font(gtk_widget_get_style_context(&pmw->generic.widget),GTK_STATE_FLAG_NORMAL));
  444 
  445           cairo_move_to(cr,pmw->grid_units_x,pmw->generic.label_y);
  446           pango_layout_set_text(layout,pmw->grid_units,-1);
  447           pango_cairo_show_layout(cr,layout);
  448          }
  449 
  450        cairo_set_source_rgb(cr,pmw->generic.body_fg_color.red,pmw->generic.body_fg_color.green,pmw->generic.body_fg_color.blue);
  451 
  452        for(i=0;i<pmw->data_num;i++)
  453          {
  454           val=pmw->data[(i+pmw->data_index)%pmw->data_num];
  455           pos=val*pmw->generic.body_height/scale;
  456 
  457           if(pmw->line_solid)
  458             {
  459              cairo_move_to(cr,i+0.5,pmw->generic.body_height+pmw->generic.body_start);
  460              cairo_line_to(cr,i+0.5,pmw->generic.body_height+pmw->generic.body_start-pos);
  461              cairo_stroke(cr);
  462             }
  463           else if(i)
  464             {
  465              gushort oldval=pmw->data[(i-1+pmw->data_index)%pmw->data_num];
  466              gshort oldpos=oldval*pmw->generic.body_height/scale;
  467 
  468              cairo_move_to(cr,i+0.5,pmw->generic.body_height+pmw->generic.body_start-oldpos);
  469              cairo_line_to(cr,i+0.5,pmw->generic.body_height+pmw->generic.body_start-pos);
  470              cairo_stroke(cr);
  471             }
  472          }
  473 
  474        cairo_set_source_rgb(cr,pmw->grid_color.red,pmw->grid_color.green,pmw->grid_color.blue);
  475 
  476        if(pmw->grid_drawn==1)
  477           for(i=1;i<pmw->grid_num;i++)
  478             {
  479              pos=i*pmw->generic.body_height/pmw->grid_num;
  480              cairo_move_to(cr,0               ,pmw->generic.body_height+pmw->generic.body_start-pos+0.5);
  481              cairo_line_to(cr,allocation_width,pmw->generic.body_height+pmw->generic.body_start-pos+0.5);
  482              cairo_stroke(cr);
  483             }
  484        else
  485           if(pmw->grid_drawn==-1)
  486             {
  487              pos=pmw->grid_maxvis*pmw->generic.body_height/pmw->grid_num;
  488              cairo_move_to(cr,0               ,pmw->generic.body_height+pmw->generic.body_start-pos+0.5);
  489              cairo_line_to(cr,allocation_width,pmw->generic.body_height+pmw->generic.body_start-pos+0.5);
  490              cairo_stroke(cr);
  491             }
  492       }
  493     else
  494       {
  495        val=pmw->data[(pmw->data_num-1+pmw->data_index)%pmw->data_num];
  496        pos=val*pmw->generic.body_height/scale;
  497 
  498        cairo_save(cr);
  499 
  500        cairo_push_group(cr);
  501        gdk_cairo_set_source_window(cr,gtk_widget_get_window(&pmw->generic.widget),-1,0);
  502        cairo_rectangle(cr,0,pmw->generic.body_start,allocation_width,pmw->generic.body_height);
  503        cairo_clip(cr);
  504        cairo_paint(cr);
  505        cairo_pop_group_to_source(cr);
  506        cairo_paint(cr);
  507 
  508        cairo_restore(cr);
  509 
  510        cairo_set_source_rgb(cr,pmw->generic.body_bg_color.red,pmw->generic.body_bg_color.green,pmw->generic.body_bg_color.blue);
  511 
  512        cairo_move_to(cr,allocation_width-1+0.5,pmw->generic.body_start);
  513        cairo_line_to(cr,allocation_width-1+0.5,pmw->generic.body_start+pmw->generic.body_height);
  514        cairo_stroke(cr);
  515 
  516        cairo_set_source_rgb(cr,pmw->generic.body_fg_color.red,pmw->generic.body_fg_color.green,pmw->generic.body_fg_color.blue);
  517 
  518        if(pmw->line_solid)
  519          {
  520           cairo_move_to(cr,(pmw->data_num-1)+0.5,pmw->generic.body_height+pmw->generic.body_start);
  521           cairo_line_to(cr,(pmw->data_num-1)+0.5,pmw->generic.body_height+pmw->generic.body_start-pos);
  522           cairo_stroke(cr);
  523          }
  524        else
  525          {
  526           gushort oldval=pmw->data[(pmw->data_num-2+pmw->data_index)%pmw->data_num];
  527           gshort oldpos=oldval*pmw->generic.body_height/scale;
  528 
  529           cairo_move_to(cr,(pmw->data_num-1)+0.5,pmw->generic.body_height+pmw->generic.body_start-oldpos);
  530           cairo_line_to(cr,(pmw->data_num-1)+0.5,pmw->generic.body_height+pmw->generic.body_start-pos);
  531           cairo_stroke(cr);
  532          }
  533 
  534        cairo_set_source_rgb(cr,pmw->grid_color.red,pmw->grid_color.green,pmw->grid_color.blue);
  535 
  536        if(pmw->grid_drawn==1)
  537           for(i=1;i<pmw->grid_num;i++)
  538             {
  539              pos=i*pmw->generic.body_height/pmw->grid_num;
  540              cairo_move_to(cr,allocation_width-1,pmw->generic.body_height+pmw->generic.body_start-pos+0.5);
  541              cairo_line_to(cr,allocation_width  ,pmw->generic.body_height+pmw->generic.body_start-pos+0.5);
  542              cairo_stroke(cr);
  543             }
  544        else
  545           if(pmw->grid_drawn==-1)
  546             {
  547              pos=pmw->grid_maxvis*pmw->generic.body_height/pmw->grid_num;
  548              cairo_move_to(cr,allocation_width-1,pmw->generic.body_height+pmw->generic.body_start-pos+0.5);
  549              cairo_line_to(cr,allocation_width  ,pmw->generic.body_height+pmw->generic.body_start-pos+0.5);
  550              cairo_stroke(cr);
  551             }
  552       }
  553 
  554     cairo_destroy(cr);
  555    }
  556 }
  557 
  558 
  559 /*++++++++++++++++++++++++++++++++++++++
  560   Set the grid colour of the Widget.
  561 
  562   ProcMeterGraph *pmw The widget to set.
  563 
  564   GdkRGBA *grid_color The grid.
  565   ++++++++++++++++++++++++++++++++++++++*/
  566 
  567 void ProcMeterGraphSetGridColour(ProcMeterGraph *pmw,GdkRGBA *grid_color)
  568 {
  569  pmw->grid_color=*grid_color;
  570 
  571  GraphUpdate(pmw,TRUE);
  572 }
  573 
  574 
  575 /*++++++++++++++++++++++++++++++++++++++
  576   Set the minimum number of grid lines in the Widget.
  577 
  578   ProcMeterGraph *pmw The Widget to set.
  579 
  580   gint grid_min The minimum number of lines.
  581   ++++++++++++++++++++++++++++++++++++++*/
  582 
  583 void ProcMeterGraphSetGridMin(ProcMeterGraph *pmw,gint grid_min)
  584 {
  585  if(grid_min<0)
  586    {
  587     pmw->grid_min=-grid_min;
  588     pmw->grid_drawn=0;
  589    }
  590  else if(grid_min>0)
  591    {
  592     pmw->grid_min=grid_min;
  593     pmw->grid_drawn=1;
  594    }
  595  else /* if(grid_min==0) */
  596    {
  597     pmw->grid_min=1;
  598     pmw->grid_drawn=1;
  599    }
  600 
  601  if(grid_min>pmw->grid_max && pmw->grid_max)
  602     pmw->grid_min=pmw->grid_max;
  603 
  604  if(pmw->grid_min>=pmw->grid_num)
  605     pmw->grid_num=pmw->grid_min;
  606 
  607  GraphResize(pmw);
  608 
  609  GraphUpdate(pmw,TRUE);
  610 }
  611 
  612 
  613 /*++++++++++++++++++++++++++++++++++++++
  614   Set the maximum number of grid lines in the Widget.
  615 
  616   ProcMeterGraph *pmw The Widget to set.
  617 
  618   gint grid_max The maximum number of lines.
  619   ++++++++++++++++++++++++++++++++++++++*/
  620 
  621 void ProcMeterGraphSetGridMax(ProcMeterGraph *pmw,gint grid_max)
  622 {
  623  if(grid_max<0)
  624     pmw->grid_max=0;
  625  else
  626     pmw->grid_max=grid_max;
  627 
  628  if(grid_max && grid_max<pmw->grid_min)
  629     pmw->grid_max=pmw->grid_min;
  630 
  631  GraphResize(pmw);
  632 
  633  GraphUpdate(pmw,TRUE);
  634 }
  635 
  636 
  637 /*++++++++++++++++++++++++++++++++++++++
  638   Set the graph to solid or line.
  639 
  640   ProcMeterGraph *pmw The Widget to set.
  641 
  642   gboolean solid The solidity of the graph.
  643   ++++++++++++++++++++++++++++++++++++++*/
  644 
  645 void ProcMeterGraphSetSolid(ProcMeterGraph *pmw,gboolean solid)
  646 {
  647  pmw->line_solid=solid;
  648 
  649  GraphUpdate(pmw,TRUE);
  650 }
  651 
  652 
  653 /*++++++++++++++++++++++++++++++++++++++
  654   Set the grid units for the widget
  655 
  656   ProcMeterGraph *pmw The widget to set.
  657 
  658   gchar *units The grid units.
  659   ++++++++++++++++++++++++++++++++++++++*/
  660 
  661 void ProcMeterGraphSetGridUnits(ProcMeterGraph *pmw,gchar *units)
  662 {
  663  if(pmw->grid_units!=empty_string)
  664     free(pmw->grid_units);
  665  pmw->grid_units=(char*)malloc(strlen(units)+1);
  666  strcpy(pmw->grid_units,units);
  667 
  668  GraphResize(pmw);
  669 
  670  GraphUpdate(pmw,TRUE);
  671 }
  672 
  673 
  674 /*++++++++++++++++++++++++++++++++++++++
  675   Add a data point to the ProcMeter Graph Widget.
  676 
  677   ProcMeterGraph *pmw The ProcMeter Graph Widget.
  678 
  679   gushort datum The data point to add.
  680   ++++++++++++++++++++++++++++++++++++++*/
  681 
  682 void ProcMeterGraphAddDatum(ProcMeterGraph *pmw,gushort datum)
  683 {
  684  gushort old_datum,new_data_max=pmw->data_max;
  685  int i;
  686 
  687  old_datum=pmw->data[pmw->data_index];
  688  pmw->data[pmw->data_index]=datum;
  689 
  690  pmw->data_index=(pmw->data_index+1)%pmw->data_num;
  691 
  692  if(datum>new_data_max)
  693     new_data_max=datum;
  694  else
  695     if(old_datum==new_data_max)
  696        for(i=new_data_max=0;i<pmw->data_num;i++)
  697           if(pmw->data[i]>new_data_max)
  698              new_data_max=pmw->data[i];
  699 
  700  if(new_data_max!=pmw->data_max)
  701    {
  702     int new_grid_num=(new_data_max+(PROCMETER_GRAPH_SCALE-1))/PROCMETER_GRAPH_SCALE;
  703 
  704     if(new_grid_num<pmw->grid_min)
  705        new_grid_num=pmw->grid_min;
  706     if(pmw->grid_max && new_grid_num>pmw->grid_max)
  707        new_grid_num=pmw->grid_max;
  708 
  709     pmw->data_max=new_data_max;
  710 
  711     if(new_grid_num!=pmw->grid_num)
  712       {
  713        pmw->grid_num=new_grid_num;
  714 
  715        if(pmw->grid_num>pmw->grid_maxvis && pmw->grid_drawn)
  716           pmw->grid_drawn=-1;
  717        if(pmw->grid_num<=pmw->grid_maxvis && pmw->grid_drawn)
  718           pmw->grid_drawn=1;
  719 
  720        GraphUpdate(pmw,TRUE);
  721       }
  722    }
  723 
  724  GraphUpdate(pmw,FALSE);
  725 }