home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / MONITOR1.ZIP / MONITOR.C < prev    next >
Text File  |  1990-03-12  |  26KB  |  693 lines

  1. /*********************  START OF SPECIFICATIONS  ********************/
  2. /*                                                                  */
  3. /*  SOURCE FILE NAME:  monitor.c                                    */
  4. /*  DESCRIPTIVE NAME:                                               */
  5. /*      A simple minded CPU monitor (and a first attempt at a       */
  6. /*      Presentation Manager Application).                          */
  7. /*  COPYRIGHT:         IBM Corporation 1988                         */
  8. /*  STATUS:            Version 1.02                                 */
  9. /*                                                                  */
  10. /*  DESCRIPTION AND PURPOSE:                                        */
  11. /*           This program provides a windowed display of the        */
  12. /*      approximate CPU utilization.                                */
  13. /*                                                                  */
  14. /*  EXTERNAL DEPENDENCIES:                                          */
  15. /*          This function has dependencies on the following         */
  16. /*      files for compilation.                                      */
  17. /*                                                                  */
  18. /*  EXECUTION INSTRUCTIONS:                                         */
  19. /*          TBD.                                                    */
  20. /*                                                                  */
  21. /*  EXPECTED OUTPUT: A windowed graphical display of the CPU usage. */
  22. /*                                                                  */
  23. /*  PROGRAM AUTHOR:                                                 */
  24. /*      Marc L. Cohen                                               */
  25. /*                                                                  */
  26. /***********************  END OF SPECIFICATIONS  ********************/
  27.  
  28. /* These include files are standard C include files.                */
  29. #include <stdlib.h>
  30. #include <string.h>
  31.  
  32. /* These include files are OS/2 specific.                           */
  33. #define INCL_DOS
  34. #define INCL_DOSERRORS
  35. #define INCL_GPI
  36. #define INCL_WININPUT
  37. #define INCL_WINFRAMEMGR
  38. #define INCL_WINERRORS
  39. #define INCL_WINMENUS
  40. #define INCL_WINSYS
  41.  
  42. #include <os2.h>
  43. USHORT APIENTRY WinQueryProfileData ( HAB , PSZ , PSZ , PVOID , PUSHORT );
  44. USHORT APIENTRY WinWriteProfileData ( HAB , PSZ , PSZ , PVOID , USHORT );
  45.  
  46. /* Define me and local defines.                                     */
  47. #define MYNAME MONITOR
  48.  
  49. /* These include files are specific to this program.                */
  50. #include "monitor.h"
  51. #include "match.h"
  52.  
  53. #define INTERVAL  1000
  54. #define STACKSIZE 350
  55. #define MAXPOINTS 400
  56. #define MAXPOINT  151
  57. #define MINPOINTS  20
  58. #define idMyFrame 1
  59. #define NEXT_POINT 1
  60. #define MAX_BACK  15
  61. #define MAX_FORE  15
  62.  
  63.  
  64.  
  65. /********************************************************/
  66. /* Macro to issue messages to check/uncheck menu items. */
  67. /********************************************************/
  68. #define CHEKMENU(item,value) (WinSendMsg( hwndOptions,\
  69.                   MM_SETITEMATTR,\
  70.                   MPFROM2SHORT( item, TRUE),\
  71.                   MPFROM2SHORT( MIA_CHECKED,\
  72.                                 (value ?  MIA_CHECKED\
  73.                                        : ~MIA_CHECKED) ) ) )
  74.  
  75. #define MAX(a,b) (((a)>(b))?(a):(b))
  76.  
  77. static char * copyright = "(C) Copyright IBM Corporation 1988 \nIBM Internal Use Only\n";
  78.  
  79. /* These are global variables within this program                   */
  80.  
  81. static ULONG    useage[MAXPOINTS+3];   /* The usage history array.      */
  82. static SHORT    maxpoints = MAXPOINT;  /* Maximum points to use         */
  83. static SHORT    maxpoint = MAXPOINT;   /* The maximum point recorded    */
  84.                                        /*   in the useage array.        */
  85. static SHORT    breakpoint = MAXPOINT; /* Point where real data starts  */
  86. static ULONG    counter  = 0L;         /* The counter that measures the */
  87.                                        /*   idle time.                  */
  88. static BOOL     running  = TRUE;       /* Shutdown indicator.           */
  89. static ULONG    interval = INTERVAL;   /* Sampling interval in msecs.   */
  90. static HWND     hwndWindow;            /* Handle of the client window.  */
  91. static HWND     hwndFrame;             /* Handle of the frame window.   */
  92. static HWND     hwndMenuBar;
  93. static HWND     hwndOptions;
  94. static BOOL     dynamic  = FALSE;      /* Dynamic or static maximum.    */
  95. static BOOL     frozen   = FALSE;      /* Frozen/thawed display state.  */
  96. static UCHAR    *no      = "NO";       /* Move this outside later       */
  97. static ULONG    ctldata = FCF_STANDARD & ~FCF_SHELLPOSITION;
  98.                                        /* Set up for a standard window. */
  99. static char *option_names[] = {
  100.     "MENU"
  101.    ,"INTERVAL"
  102.    ,"SMOOTH"
  103.    ,"SLIDE"
  104.    ,"POINTS"
  105.    ,"FOREGROUND"
  106.    ,"BACKGROUND"
  107.    ,"FILL"
  108.    ,"ICON"
  109.    ,"DYNAMIC"
  110.    ,NULL};
  111. #define OPT_MENU      0
  112. #define OPT_INTERVAL  1
  113. #define OPT_SMOOTH    2
  114. #define OPT_SLIDE     3
  115. #define OPT_POINTS    4
  116. #define OPT_FOREG     5
  117. #define OPT_BACKG     6
  118. #define OPT_FILL      7
  119. #define OPT_ICON      8
  120. #define OPT_DYNAMIC   9
  121.  
  122. static char *color_names[] = {
  123.     "WHITE"
  124.    ,"BLACK"
  125.    ,"BACKGROUND"
  126.    ,"BLUE"
  127.    ,"RED"
  128.    ,"PINK"
  129.    ,"GREEN"
  130.    ,"CYAN"
  131.    ,"YELLOW"
  132.    ,"NEUTRAL"
  133.    ,"DARKGRAY"
  134.    ,"DARKBLUE"
  135.    ,"DARKRED"
  136.    ,"DARKPINK"
  137.    ,"DARKGREEN"
  138.    ,"DARKCYAN"
  139.    ,"BROWN"
  140.    ,"PALEGRAY"
  141.    ,"WINDOWSTATICTEXT"
  142.    ,"SCROLLBAR"
  143.    ,"SYSBACKGROUND"
  144.    ,"ACTIVETITLE"
  145.    ,"INACTIVETITLE"
  146.    ,"MENU"
  147.    ,"WINDOW"
  148.    ,"WINDOWFRAME"
  149.    ,"MENUTEXT"
  150.    ,"WINDOWTEXT"
  151.    ,"TITLETEXT"
  152.    ,"ACTIVEBORDER"
  153.    ,"INACTIVEBORDER"
  154.    ,"APPWORKSPACE"
  155.    ,"HELPBACKGROUND"
  156.    ,"HELPTEXT"
  157.    ,"HELPHILITE"
  158.    ,NULL};
  159.  
  160. static COLOR colors[] = {
  161.     CLR_WHITE
  162.    ,CLR_BLACK
  163.    ,CLR_BACKGROUND
  164.    ,CLR_BLUE
  165.    ,CLR_RED
  166.    ,CLR_PINK
  167.    ,CLR_GREEN
  168.    ,CLR_CYAN
  169.    ,CLR_YELLOW
  170.    ,CLR_NEUTRAL
  171.    ,CLR_DARKGRAY
  172.    ,CLR_DARKBLUE
  173.    ,CLR_DARKRED
  174.    ,CLR_DARKPINK
  175.    ,CLR_DARKGREEN
  176.    ,CLR_DARKCYAN
  177.    ,CLR_BROWN
  178.    ,CLR_PALEGRAY
  179.    ,SYSCLR_WINDOWSTATICTEXT
  180.    ,SYSCLR_SCROLLBAR
  181.    ,SYSCLR_BACKGROUND
  182.    ,SYSCLR_ACTIVETITLE
  183.    ,SYSCLR_INACTIVETITLE
  184.    ,SYSCLR_MENU
  185.    ,SYSCLR_WINDOW
  186.    ,SYSCLR_WINDOWFRAME
  187.    ,SYSCLR_MENUTEXT
  188.    ,SYSCLR_WINDOWTEXT
  189.    ,SYSCLR_TITLETEXT
  190.    ,SYSCLR_ACTIVEBORDER
  191.    ,SYSCLR_INACTIVEBORDER
  192.    ,SYSCLR_APPWORKSPACE
  193.    ,SYSCLR_HELPBACKGROUND
  194.    ,SYSCLR_HELPTEXT
  195.    ,SYSCLR_HELPHILITE
  196.    };
  197.  
  198.  
  199.   /*******************************************************************/
  200.   /*                                                                 */
  201.   /*  This structure holds all of the personal preference data that  */
  202.   /*  is stored across invocations of the program.                   */
  203.   /*                                                                 */
  204.   /*******************************************************************/
  205.  
  206. static struct INITDATA {
  207.        COLOR    background;            /* Background color.             */
  208.        COLOR    line_color;            /* Graph line color.             */
  209.        BOOL     smoothed;              /* Smooth/normal graph state.    */
  210.        SWP      wp;                    /* Window size/position.         */
  211.        BOOL     slide;                 /* Sliding vs. jump graph.       */
  212.        BOOL     fill;                  /* Fill below the graph.         */
  213.        } init,saveinit;
  214.  
  215.  
  216.  
  217. static UCHAR    *program_name = "CPU Utilization Monitor";
  218.  
  219.  
  220.  
  221. /* Prototypes of all function calls                             */
  222.  
  223. MRESULT EXPENTRY MyWindowProc(HWND,USHORT,MPARAM,MPARAM);
  224. void APIENTRY IdleLoopThread(void);
  225. void APIENTRY MonitorLoopThread(void);
  226. void cdecl main(int, char * *, char * *);
  227.  
  228.  
  229.   /***********************************************************************/
  230.   /*                                                                     */
  231.   /*                This is the IdleLoopThread.                          */
  232.   /*                                                                     */
  233.   /* It sets itself to an IDLE class priority and falls into a loop that */
  234.   /* counts forever.                                                     */
  235.   /*                                                                     */
  236.   /***********************************************************************/
  237.  
  238. void APIENTRY IdleLoopThread()
  239. {
  240.    if (DosSetPrty(PRTYS_THREAD,PRTYC_IDLETIME,-31,0)) {
  241.       WinPostMsg(hwndFrame,WM_CLOSE,0L,0L);
  242.    } else {
  243.       while (running) {
  244.          counter++;
  245.       } /* endwhile */
  246.    } /* endif */
  247.    DosExit(EXIT_THREAD,0);
  248. }
  249.  
  250.   /********************************************************************/
  251.   /*                                                                  */
  252.   /*                This is the MonitorLoopThread.                    */
  253.   /*                                                                  */
  254.   /* It sets a recurrent timer and then calculates statistics on each */
  255.   /* timer pop and sends the free time to the window procedure.       */
  256.   /*                                                                  */
  257.   /********************************************************************/
  258.  
  259.  
  260. void APIENTRY MonitorLoopThread()
  261. {
  262.    ULONG  last = 0L;         /* The counter value at last check         */
  263.    PGINFOSEG pgseg  = NULL;  /* A far pointer for the Global Info Seg   */
  264.                              /* We will get the time from here.         */
  265.    PLINFOSEG lgseg  = NULL;  /* A pointer to the Local Info Seg         */
  266.    ULONG  maxcount = 0L;     /* The maximum change seen so far          */
  267.    LONG   current;           /* The change in counter value this time   */
  268.    ULONG  last_msecs;        /* The millisecond value at our last check */
  269.    ULONG  current_msecs;     /* The millisec. value now.                */
  270.    ULONG  delta_msec;        /* The number of millisecs between checks  */
  271.    USHORT max_times = 0;     /* Time since maximum seen                 */
  272.    ULONG  sub_max = 0;       /* Secondary maximum                       */
  273.  
  274.    if (DosSetPrty(PRTYS_THREAD,PRTYC_TIMECRITICAL,+31,0)) {
  275.       WinPostMsg(hwndFrame,WM_CLOSE,0L,0L);
  276.    } else if (DosGetInfoSeg(&SELECTOROF(pgseg),&SELECTOROF(lgseg))) {
  277.       WinPostMsg(hwndFrame,WM_CLOSE,0L,0L);
  278.    } else {
  279.       last_msecs = pgseg->msecs;
  280.       while (running) {
  281.          DosSleep(interval);
  282.          current_msecs = pgseg->msecs;
  283.          current = counter - last;
  284.          last = counter;
  285.          delta_msec = current_msecs - last_msecs;
  286.          last_msecs = current_msecs;
  287.          current = (current * 1000) / delta_msec;
  288.          if (running) {
  289.             WinPostMsg(hwndWindow,WM_USER+NEXT_POINT
  290.                       ,MPFROMLONG(current)
  291.                       ,MPFROMLONG(pgseg->time));
  292.          } /* endif */
  293.       } /* endwhile */
  294.    } /* endif */
  295.    DosExit(EXIT_THREAD,0);
  296. }
  297.  
  298.    /*******************************************************************/
  299.    /*                                                                 */
  300.    /* This routine process the command line arguments to check for    */
  301.    /* any requests to modify the default or saved values.             */
  302.    /*                                                                 */
  303.    /*******************************************************************/
  304. void process_args(int argc, char **argv)
  305. {
  306.    USHORT option;
  307.    BOOL no;
  308.    char *arg_ptr;
  309.    int temp;
  310.  
  311.    while (--argc) {
  312.       if (strnicmp("no",arg_ptr = *++argv,2)) {
  313.          no = FALSE;
  314.       } else {
  315.          no = TRUE;
  316.          arg_ptr += 2;
  317.       }
  318.       if (NO_MATCH == (option = match(option_names,arg_ptr))) {
  319.          /* Do something good here! */
  320.          /* Until then, ignore option! */
  321.       } else {
  322.          switch (option) {
  323.             case OPT_MENU:
  324.                if (no) {
  325.                   ctldata &= ~FCF_MENU;
  326.                } else {
  327.                   ctldata |= FCF_MENU;
  328.                }
  329.                break;
  330.             case OPT_ICON:
  331.                if (no) {
  332.                   ctldata &= ~FCF_ICON;
  333.                } else {
  334.                   ctldata |= FCF_ICON;
  335.                } /* endif */
  336.                break;
  337.             case OPT_INTERVAL:
  338.                interval = atol(*++argv);
  339.                argc--;
  340.                break;
  341.             case OPT_DYNAMIC:
  342.                dynamic = !no;
  343.                break;
  344.             case OPT_SMOOTH:
  345.                init.smoothed = !no;
  346.                break;
  347.             case OPT_SLIDE:
  348.                init.slide = !no;
  349.                break;
  350.             case OPT_POINTS:
  351.                temp = atoi(*++argv);
  352.                if (temp>MINPOINTS && temp<=MAXPOINTS) {
  353.                   maxpoints = temp;
  354.                   breakpoint = temp;
  355.                   maxpoint  = maxpoints;
  356.                }
  357.                argc--;
  358.                break;
  359.             case OPT_FOREG:
  360.                if (NO_MATCH != (temp = match(color_names,*++argv))) {
  361.                   init.line_color = colors[temp];
  362.                }
  363.                argc--;
  364.                break;
  365.             case OPT_BACKG:
  366.                if (NO_MATCH != (temp = match(color_names,*++argv))) {
  367.                   init.background = colors[temp];
  368.                }
  369.                argc--;
  370.                break;
  371.             case OPT_FILL:
  372.                init.fill = !no;
  373.                break;
  374.  
  375.             default: /* This is bad, shouldn't get here! */
  376.                break;
  377.          }
  378.       }
  379.    }
  380.    return;
  381. }
  382.  
  383.  
  384.    /*******************************************************************/
  385.    /*                                                                 */
  386.    /*                  Here is the main program.                      */
  387.    /* It sets up the PM environment and enter the message loop until  */
  388.    /* terminated.                                                     */
  389.    /*                                                                 */
  390.    /*******************************************************************/
  391.  
  392. void cdecl main(argc, argv, envp)
  393.    int argc;
  394.    char **argv;
  395.    char **envp;
  396. {
  397.    UCHAR  stack1[STACKSIZE]; /* The stack for the idle loop thread.     */
  398.    UCHAR  stack2[STACKSIZE]; /* The stack for the monitor thread.       */
  399.    HMQ    hMsgQ;             /* The PM message Q handle.                */
  400.    QMSG   qMsg;              /* A message structure to hold the message */
  401.                              /*   currently being processed.            */
  402.  
  403.  
  404.    TID    IdleTID;           /* The thread ID for the idle loop thread. */
  405.    TID    MonitorTID;        /* The thread ID for the monitor thread.   */
  406.    USHORT i;                 /* Just used for clearing the storage array*/
  407.    HAB    hAB;               /* Anchor block handle.                    */
  408.    MENUITEM Mi;
  409.  
  410.  
  411.  
  412.    if (!(hAB = WinInitialize(NULL))) {  /* Initialize the PM interface.  */
  413.       exit(1);                          /* Error in WinInitialize!       */
  414.    } /* endif */
  415.                                         /* Start up the message queue    */
  416.    if (!(hMsgQ = WinCreateMsgQueue(hAB,0))) {
  417.       exit(1);                          /* Error creating message queue! */
  418.    } /* endif */
  419.  
  420.    WinRegisterClass(hAB                 /* Register the Window class     */
  421.                    ,"MonitorWindow"
  422.                    ,MyWindowProc
  423.                    ,CS_SIZEREDRAW
  424.                    ,0);
  425.  
  426.    for (i = 0; i<=maxpoints; i++) {     /* Initialize the storage array. */
  427.       useage[i] = 0xffffffffl;
  428.    } /* endfor */
  429.  
  430.    /* Get our saved profile data                */
  431.    i = sizeof init;
  432.    if (!WinQueryProfileData(hAB,program_name
  433.                 ,"Monitor window data"
  434.                 ,&init
  435.                 ,&i) ) {
  436.       init.background = CLR_DARKGREEN;  /* No data, so initialize to    */
  437.       init.line_color = CLR_BLUE;       /*   default values.            */
  438.       init.smoothed   = FALSE;
  439.       init.wp.x       = 100;
  440.       init.wp.y       = 100;
  441.       init.wp.cx      = 220;
  442.       init.wp.cy      = 134;
  443.       init.fill       = FALSE;
  444.    } else if (i < (sizeof init)) {
  445.       init.fill       = FALSE;
  446.    } /* endif */
  447.    saveinit = init;                     /* Save the initial values to   */
  448.                                         /*   check against later.       */
  449.  
  450.    process_args(argc,argv);
  451.  
  452.  
  453.  
  454.    hwndFrame = WinCreateStdWindow       /* And create the window.        */
  455.                       (HWND_DESKTOP
  456.                       ,0L
  457.                       ,&ctldata
  458.                       ,"MonitorWindow"
  459.                       ,""
  460.                       ,0L
  461.                       ,NULL
  462.                       ,ID_MONITOR
  463.                       ,&hwndWindow);
  464.  
  465.    if ((NULL == hwndFrame) || (NULL == hwndWindow)) {
  466.       /* Make sure the window was created.      */
  467.       exit(1);
  468.    } /* endif */
  469.  
  470.    WinSetWindowPos(hwndFrame            /* Position the window where it  */
  471.                   ,HWND_TOP             /* was last time.                */
  472.                   ,init.wp.x
  473.                   ,init.wp.y
  474.                   ,init.wp.cx
  475.                   ,init.wp.cy
  476.                   ,SWP_SIZE | SWP_MOVE | SWP_ACTIVATE | SWP_SHOW);
  477.  
  478.    /* Get infor for modifying menu items with check marks.      */
  479.    hwndMenuBar = WinWindowFromID( hwndFrame, FID_MENU    );
  480.    WinSendMsg( hwndMenuBar
  481.              , MM_QUERYITEM
  482.              , MPFROM2SHORT( IDMOPTIONS, FALSE)
  483.              ,(MPARAM)(PSZ)&Mi
  484.              );
  485.    hwndOptions = Mi.hwndSubMenu;
  486.    CHEKMENU(IDMSMOOTH,init.smoothed);
  487.    CHEKMENU(IDMSLIDE,init.slide);
  488.    CHEKMENU(IDMFILL,init.fill);
  489.  
  490.    /* Start the idle loop thread.            */
  491.  
  492.    if (DosCreateThread((void far *)IdleLoopThread
  493.                            ,&IdleTID
  494.                            ,stack1+STACKSIZE-2)) {
  495.       WinPostMsg(hwndWindow,WM_QUIT,0L,0L);  /* Quit if it failed.       */
  496.  
  497.  
  498.    } else if (DosCreateThread((void far *)MonitorLoopThread
  499.                            ,&MonitorTID      /* Start the monitor thread.*/
  500.                            ,stack2+STACKSIZE-2)) {
  501.       WinPostMsg(hwndWindow,WM_QUIT,0L,0L);  /* Quit if it failed.       */
  502.    } /* endif */
  503.  
  504.  
  505.    /* This is the main message loop. Stay here until told to quit       */
  506.  
  507.    while (WinGetMsg(hAB,(PQMSG)&qMsg,(HWND)NULL,0,0)) {
  508.       WinDispatchMsg(hAB,(PQMSG)&qMsg);
  509.    } /* endwhile */
  510.  
  511.  
  512.    /* If the preference data has changed, then save it. */
  513.  
  514.    WinQueryWindowPos(hwndFrame,&init.wp);
  515.    if (memcmp(&init,&saveinit,sizeof init)) {
  516.       WinWriteProfileData(hAB,program_name
  517.                          ,"Monitor window data"
  518.                          ,&init
  519.                          ,sizeof init);
  520.    } /* endif */
  521.  
  522.    WinDestroyWindow(hwndFrame);
  523.    WinDestroyMsgQueue(hMsgQ);
  524.    WinTerminate(hAB);
  525.    DosExit(EXIT_PROCESS,0);
  526. }
  527.  
  528.    /**********************************************************************/
  529.    /*                                                                    */
  530.    /*                  This is the window procedure.                     */
  531.    /* It is the heart of the user interface. All work related to the     */
  532.    /* input and output of the program are located here. All work         */
  533.    /* requests are presented as messages. Currently, this procedure only */
  534.    /* handles WM_PAINT, WM_CLOSE, WM_COMMAND and NEXT_POINT messages.    */
  535.    /*                                                                    */
  536.    /**********************************************************************/
  537.  
  538. MRESULT EXPENTRY MyWindowProc(HWND hWnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  539. {
  540.    HPS      hPS;                        /* Handle to the presentation   */
  541.                                         /*   used for PAINTing.         */
  542.    RECTL    rect;                       /* Rectangle for background     */
  543.    USHORT   shift_size;                 /* Temporary variable for       */
  544.                                         /*   shifting data in the       */
  545.                                         /*   useage array.              */
  546.    SHORT    loop_var;                   /* Temporary for loop control.  */
  547.    ULONG    xsize,ysize;                /* Use for window sizes.        */
  548. static   ULONG    max = 0;
  549. static   POINTL   points[MAXPOINTS+3];  /* Storage for data to graph.   */
  550. static   POINTL beginpt = {0,0};
  551. static   POINTL endpt = {0,0};
  552.  
  553.    switch (msg) {
  554.  
  555.    case WM_USER+NEXT_POINT:             /* This message holds the next  */
  556.                                         /*   data point to graph.       */
  557.       if (maxpoint<maxpoints) {
  558.          maxpoint++;
  559.       } else if (init.slide) {
  560.          if (breakpoint>=0) breakpoint--;
  561.          for (loop_var=0; loop_var<maxpoints; loop_var++) {
  562.             useage[loop_var] = useage[loop_var+1];
  563.          } /* endfor */
  564.       } else {
  565.          shift_size = maxpoint/3;
  566.          breakpoint -= (breakpoint>=shift_size) ? shift_size : (breakpoint+1);
  567.          for (loop_var=0; loop_var<maxpoints-shift_size; loop_var++) {
  568.             useage[loop_var] = useage[loop_var+shift_size];
  569.          } /* endfor */
  570.          maxpoint = maxpoints-shift_size;
  571.       } /* endif */
  572.       useage[maxpoint] = LONGFROMMP(mp1);
  573.       if (!frozen) {
  574.          WinInvalidateRegion(hWnd,NULL,FALSE);
  575.       } /* endif */
  576.       if (!dynamic) {
  577.          max = MAX(max,LONGFROMMP(mp1));
  578.       } /* endif */
  579.       break;
  580.  
  581.    case WM_PAINT:                       /* This message requests a      */
  582.                                         /*   re-drawing of the window.  */
  583.       hPS = WinBeginPaint(hWnd,(HPS)NULL,&rect);
  584.  
  585.       WinQueryWindowRect(hWnd,&rect);
  586.       if (dynamic) {
  587.          max = 0;
  588.          for (loop_var = breakpoint+1; loop_var<=maxpoint; loop_var++) {
  589.             max = MAX(useage[loop_var],max);
  590.          } /* endfor */
  591.       } /* endif */
  592.       if (!max) max = 1;
  593.       WinFillRect(hPS,&rect,init.background);
  594.       endpt.x = rect.xRight - rect.xLeft + 1;
  595.       xsize = endpt.x * 1000 / (maxpoints);
  596.       ysize = rect.yTop   - rect.yBottom - 1;
  597.  
  598.       for (loop_var = 0; loop_var<=maxpoint; loop_var++) {
  599.          points[loop_var].x = loop_var * xsize / 1000;
  600.          points[loop_var].y = ( (loop_var > breakpoint)
  601.                               ? ((max - useage[loop_var])* ysize /max)
  602.                               : 0);
  603.       } /* endfor */
  604.       endpt.x = points[maxpoint].x;
  605.  
  606.       GpiSetColor(hPS,init.line_color);
  607.       if (maxpoint>1) {
  608.          if (init.fill) {
  609.             GpiBeginArea(hPS,BA_BOUNDARY);
  610.             GpiMove(hPS,&beginpt);
  611.             GpiLine(hPS,points);
  612.          } else {
  613.             GpiMove(hPS,points);
  614.          }
  615.          if (init.smoothed) {
  616.             GpiPolyFillet(hPS,(ULONG)(maxpoint+1),points);
  617.          } else {
  618.             GpiPolyLine(hPS,(ULONG)(maxpoint+1),points);
  619.          } /* endif */
  620.          if (init.fill) {
  621.             GpiLine(hPS,&endpt);
  622.             GpiEndArea(hPS);
  623.          }
  624.       } /* endif */
  625.       WinEndPaint(hPS);
  626.       break;
  627.  
  628.    case WM_CLOSE:                       /* This message is a shutdown   */
  629.                                         /*   request.                   */
  630.       running = FALSE;
  631.       WinPostMsg(hWnd,WM_QUIT,0L,0L);
  632.       break;
  633.  
  634.    case WM_COMMAND:                     /* This message is a command    */
  635.                                         /*   from the menu or an        */
  636.                                         /*   accelerator key.           */
  637.       switch (SHORT1FROMMP(mp1)) {
  638.  
  639.       case IDMEXITNOW:                  /* Another request to exit.     */
  640.          WinPostMsg(hWnd,WM_CLOSE,0L,0L);
  641.          break;
  642.  
  643.       case IDMBACKG:                    /* Cycle to next background color*/
  644.          init.background++;
  645.          if (init.background>MAX_BACK) {
  646.             init.background = 0;
  647.          } /* endif */
  648.          break;
  649.  
  650.       case IDMFOREG:                    /* Cycle to next foreground color*/
  651.          init.line_color++;
  652.          if (init.line_color>MAX_FORE) {
  653.             init.line_color = 0;
  654.          } /* endif */
  655.          break;
  656.  
  657.       case IDMSMOOTH:                   /* Flip between smooth and      */
  658.                                         /*   simple graph.              */
  659.          init.smoothed = !init.smoothed;
  660.          CHEKMENU(IDMSMOOTH,init.smoothed);
  661.          break;
  662.  
  663.       case IDMSLIDE:                    /* Flip between sliding and     */
  664.                                         /*   shifting graph.            */
  665.          init.slide = !init.slide;
  666.          CHEKMENU(IDMSLIDE,init.slide);
  667.          break;
  668.  
  669.       case IDMFILL:                     /* Flip between fill and simple */
  670.                                         /*   graph.                     */
  671.          init.fill = !init.fill;
  672.          CHEKMENU(IDMFILL,init.fill);
  673.          break;
  674.  
  675.       case IDMFREEZE:                   /* Flip between frozen and      */
  676.                                         /*   thawed display.            */
  677.          frozen = !frozen;
  678.          CHEKMENU(IDMFREEZE,frozen);
  679.          break;
  680.  
  681.       default:
  682.          return ( WinDefWindowProc(hWnd,msg,mp1,mp2) );
  683.       } /* endswitch */
  684.       break;
  685.  
  686.    default:
  687.       return ( WinDefWindowProc(hWnd,msg,mp1,mp2) );
  688.    } /* endswitch */
  689.  
  690.    return FALSE;
  691. }
  692.  
  693.