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