[net.micro.amiga] GfxMem.c - graphical memory usage

louie@trantor.UMD.EDU (11/29/85)

From: Louis A. Mamakos <louie@trantor.UMD.EDU>

Here's a new and much improved version of my GfxMem.c program.  It has been
heavily revised since the last version that was distributed over the 
info-amiga@red.rutgers.edu mailing list and net.micro.amiga newsgroup.  The
display updating is now much more crisp, and I'm now using the timer.device
rather than the AmigaDOS Delay() subroutine.  There was a note that the
previous version could trash a disk while running the READ program.  I 
tested the new version while downloading a copy of GfxMem.c (to make sure
it got to our VAX ok), and things seemed to run just fine.  Just compile
with the Lattice C compiler and go.  You should see two compilation warnings;
these can be ignored.

**** Soapbox time ****
As one of the few folks that posted any amiga programs so far, let me cast
my vote to SOURCE POSTINGS of programs rather than BINHEXed versions.  We
can learn a lot from each other, and hopefully avoid making the same
stupid errors or inventing the same wheels over and over again.
**** End Soapbox ****

The program displays two bar graphics, one for "CHIP" memory, and one for
"FAST" memory.  Each bar graph is split into two colors; part for memory in
use and part for memory free.  As the window is resized, the graphics are
rescaled to the sized of the window.  If you find any bugs or have any 
neat features that you'd like to see, let me know. 

Louis A. Mamakos  WA3YMH    Internet: louie@TRANTOR.UMD.EDU
  University of Maryland, Computer Science Center - Systems Programming

Anyway, here it is:
------------------------------------ gfxmem.c -----------------------
/*
 *  gfxmem.c  - graphically display available memory.  Quick program
 *     that's a freebie.  Give it to anyone you please, just don't sell it.
 *
 *       Version 0.0 - initial version, released on INFO-AMIGA.
 *       Version 0.1 - added numeric indication of available and used memory
 *                     in bar graphs.
 *       Version 0.2 - added condition compilation for timer.device code.  If
 *                     I can figure out how to make it create timer signals,
 *                     then I can define USE_TIMER for much more prompt
 *                     response to window sizing attempts.  Oh well.
 *       Version 0.3 - removed conditional compilation for timer.device
 *                     code.  We now use the timer, and all seems well.
 *       Version 0.4 - calculate character data placement according to
 *                     display preferences.  Check for updated preferences
 *                     while running.
 *  TODO:
 *       Add menu selection package to display Kbytes or percent of memory
 *       used and free.
 *
 *       Add requestor to display statistics like min and max for free and
 *       avail, time running, etc..
 *
 *
 *                 Copyright (C) 1985,
 *                 Louis A. Mamakos
 *                 Software & Stuff
 */

#define  PROG_VER "GfxMem 0.4 "

#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/exec.h>
#include <exec/execbase.h>
#include <exec/ports.h>
#include <exec/devices.h>
#include <exec/memory.h>
#include <devices/timer.h>
#include <hardware/blit.h>
#include <graphics/copper.h>
#include <graphics/regions.h>
#include <graphics/rastport.h>
#include <graphics/gfxbase.h>
#include <graphics/gfxmacros.h>
#include <graphics/gels.h>
#include <intuition/intuition.h>

extern struct ExecBase *SysBase;
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct MsgPort *timerport, *CreatePort();
struct timerequest timereq;

struct NewWindow NewWindow = {
   10, 10, 450, 50,           /* sizes */
   -1, -1,                    /* pens */
   CLOSEWINDOW | ACTIVEWINDOW | SIZEVERIFY |
                 NEWSIZE | NEWPREFS | REFRESHWINDOW,   /* IDCMP flags */
   WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE | WINDOWSIZING | SIMPLE_REFRESH,
   NULL, NULL,                /* gadget, checkmark */
   PROG_VER,                  /* title */
   NULL, NULL,                /* screen, bitmap */
   100, 30, 640, 100,         /* min and max sizing */
   WBENCHSCREEN               /* on the workbench screen */
};

ULONG    AvailMem ();
ULONG    ChipMax, FastMax, ChipFree, FastFree;
ULONG    ChipLargest, FastLargest;
int      dont_draw, char_size;

/*
 *  maxsize -- determine the total maximum size for all regions
 *   of the given type.  This code must be executed while
 *   FORBIDDEN (it accesses shared system structures).
 */
ULONG
maxsize (t)
    unsigned long t;
{
    /* THIS CODE MUST ALWAYS BE CALLED WHILE FORBIDDEN */
    ULONG size = 0;
    struct MemHeader *mem;
    struct ExecBase *eb = SysBase;

    for (mem = (struct MemHeader *) eb->MemList.lh_Head;
                        mem->mh_Node.ln_Succ; mem = mem->mh_Node.ln_Succ)
       if (mem -> mh_Attributes & t)
          size += ((ULONG) mem->mh_Upper - (ULONG) mem->mh_Lower);
    return size;
}

getsizes()
{
   if (ChipMax == 0) {  /* only do this once */
      Forbid ();
      ChipMax = maxsize (MEMF_CHIP);
      FastMax = maxsize (MEMF_FAST);
      Permit();
   }
   ChipFree = AvailMem (MEMF_CHIP);
   ChipLargest = AvailMem (MEMF_CHIP | MEMF_LARGEST);
   FastFree = AvailMem (MEMF_FAST);
   FastLargest = AvailMem (MEMF_FAST | MEMF_LARGEST);
}

starttimer()
{
   timereq.tr_time.tv_secs = 1;
   timereq.tr_time.tv_micro = 0;
   timereq.tr_node.io_Command = TR_ADDREQUEST;
   timereq.tr_node.io_Flags = 0;
   timereq.tr_node.io_Error = 0;
   timereq.tr_node.io_Message.mn_ReplyPort = timerport;
   SendIO((char *) &timereq.tr_node);
}

/*
 *  This function is called during startup and when new preferences are
 *  selected.  Get the font size from the Preferences structure.
 */
newprefs()
{
   char FontHeight;

   GetPrefs(&FontHeight, sizeof (FontHeight));
   switch (FontHeight) {
   case TOPAZ_SIXTY:
      char_size = 11;
      break;

   case TOPAZ_EIGHTY:
      char_size = 8;
      break;

   default:
      char_size = 12;
   }
}


/*
 *  Main function.  Call intution to create a new window for us on the
 *  screen.  Go from there.
 */
main(argc, argv)
   int argc;
   char **argv;
{
   struct Window *w;
   struct IntuiMessage *msg, *GetMsg();
   int waitmask;

   timerport = NULL;
   IntuitionBase = (struct IntuitionBase *)
                   OpenLibrary("intuition.library", 0);
   if (IntuitionBase == NULL)
      exit(1);
   GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", 0);
   if (GfxBase == NULL) {
      CloseLibrary(IntuitionBase);
      exit(2);
   }

   if ((w = (struct Window *) OpenWindow(&NewWindow)) == NULL) {
      CloseLibrary(GfxBase);
      CloseLibrary(IntuitionBase);
      exit(3);
   }
   if ((timerport = CreatePort("Timer Port", 0)) == NULL) {
      CloseWindow(w);
      CloseLibrary(GfxBase);
      CloseLibrary(IntuitionBase);
      exit(5);
   }
   if (OpenDevice(TIMERNAME, UNIT_VBLANK, (char *) &timereq, 0) != 0) {
      DeletePort(timerport);
      CloseWindow(w);
      CloseLibrary(GfxBase);
      CloseLibrary(IntuitionBase);
      exit(4);
   }

   newprefs();
   redraw(w, TRUE);
   starttimer();
   waitmask = (1 << w->UserPort->mp_SigBit) |
              (1 << timerport->mp_SigBit);
   for(;;) {
      Wait(waitmask);
      while (msg = GetMsg(w->UserPort)) {
         switch (msg->Class) {
         case CLOSEWINDOW:
            ReplyMsg(msg);
            AbortIO(&timereq);
            CloseDevice(&timereq);
            DeletePort(timerport);
            CloseWindow(w);
            CloseLibrary(GfxBase);
            CloseLibrary(IntuitionBase);
            exit(0);

         case REFRESHWINDOW:
            BeginRefresh(w);
            dont_draw = 0;
            redraw(w, TRUE);
            EndRefresh(w, TRUE);

         case ACTIVEWINDOW:
            /* when window is active, display version */
            SetWindowTitles(w, -1, 
			    "Graphical memory display by Louis A. Mamakos");
            break;

         case NEWSIZE:
            dont_draw = 0;
            redraw(w, TRUE);
            break;

         case SIZEVERIFY:
            dont_draw = 1;
            break;

         case NEWPREFS:
            newprefs();
            redraw(w, TRUE);
            break;
         }
         ReplyMsg(msg);
      } /* while */

      if (GetMsg(timerport)) {
         redraw(w, FALSE);
         starttimer();
      }
   } /* for */
}


#define TOP w->BorderTop
#define BOTTOM w->Height - w->BorderBottom
#define LEFT w->BorderLeft
#define RIGHT w->Width - w->BorderRight
#define GUTTER 3        /* pixels of veritical spacing between bars */

/*
 *  Redraw all of the stuff in the window.
 */
redraw(w, refresh)
   struct Window *w;
   int refresh;
{
   register struct RastPort *rp = w->RPort;
   register short x_min, y_min, x_max, y_max;
   static short AvailWidth, AvailHeight, HorizSpace, Thickness, Scale;
   static long old_chipfree, old_fastfree;
   char txt[10];

   if (dont_draw)
      return 0;
   getsizes();
   if (refresh) {
      SetAPen(rp, 2);
      SetBPen(rp, 2);
      SetOPen(rp, 2);
      RectFill(rp, LEFT, TOP, RIGHT, BOTTOM);
      /*  recalculate the spacing paramters for this sized window */
      AvailWidth = w->Width - w->BorderRight - w->BorderLeft;
      AvailHeight = w->Height - w->BorderTop - w->BorderBottom;
      HorizSpace = AvailWidth/20; /* use 5% of available space as margin */
      AvailWidth -= HorizSpace * 2;
      Thickness = (AvailHeight - GUTTER*3) / 2;
      if (ChipMax > FastMax)
         Scale = ChipMax/AvailWidth;
      else
         Scale = FastMax/AvailWidth;
   } else
      if (old_chipfree == ChipFree && old_fastfree == FastFree)
         return 0;
   old_chipfree = ChipFree;
   old_fastfree = FastFree;
   SetAPen(rp, 3);
   SetOPen(rp, 1);
   SetBPen(rp, 2);
   x_min = HorizSpace;
   y_min = TOP + GUTTER;
   x_max = x_min + (ChipMax - ChipFree)/Scale;
   y_max = y_min + Thickness;
   RectFill(rp, x_min, y_min, x_max, y_max);
   if ((Thickness > char_size) && (x_max - x_min > 6 * char_size)) {
      sprintf(txt, "%4dK", (ChipMax - ChipFree) >> 10);
      SetAPen(rp, 1);
      SetBPen(rp, 3);
      Move(rp, x_max - 5*char_size - 6, y_min + Thickness/2 + 3);
      Text(rp, txt, 5);
   }
   x_min = x_max;
   x_max = x_min + ChipFree/Scale;
   SetAPen(rp, 0);
   RectFill(rp, x_min, y_min, x_max, y_max);
   if ((Thickness > char_size) && (x_max - x_min > 6 * char_size)) {
      sprintf(txt, "%4dK", ChipFree>>10);
      SetAPen(rp, 1);
      SetBPen(rp, 0);
      Move(rp,x_min + 5, y_min + Thickness/2 + 3);
      Text(rp, txt, 5);
   }
   if ((HorizSpace > char_size + 5) && Thickness > char_size + 1) {
      SetAPen(rp, 1);
      SetBPen(rp, 2);
      Move(rp, HorizSpace - char_size - 1, y_min + Thickness/2 + 4);
      Text(rp, "C", 1);
   }
   x_min = HorizSpace;
   x_max = x_min + (FastMax - FastFree)/Scale;
   y_min = y_max + GUTTER;
   y_max = y_min + Thickness;
   SetAPen(rp, 3);
   RectFill(rp, x_min, y_min, x_max, y_max);
   if ((Thickness > char_size) && (x_max - x_min > 6 * char_size)) {
      sprintf(txt, "%4dK", (FastMax - FastFree) >> 10);
      SetAPen(rp, 1);
      SetBPen(rp, 3);
      Move(rp, x_max - 5*char_size - 6, y_min + Thickness/2 + 3);
      Text(rp, txt, 5);
   }
   x_min = x_max;
   x_max = x_min + FastFree/Scale;
   SetAPen(rp, 0);
   RectFill(rp, x_min, y_min, x_max, y_max);
   if ((Thickness > char_size) && (x_max - x_min > 6 * char_size)) {
      sprintf(txt, "%4dK", FastFree>>10);
      SetAPen(rp, 1);
      SetBPen(rp, 0);
      Move(rp,x_min + 5, y_min + Thickness/2 + 3);
      Text(rp, txt, 5);
   }
   if ((HorizSpace > char_size + 5) && Thickness > char_size + 1) {
      SetAPen(rp, 1);
      SetBPen(rp, 2);
      Move(rp, HorizSpace - char_size - 1, y_min + Thickness/2 + 3);
      Text(rp, "F", 1);
   }
}