Listing 2: Etch.c

#include <PalmOS.h>
#include "EtchRes.h"

#define EtchID       'ETCH'
#define EtchDataType 'DATA'
#define EtchDBName   "EtchDB"

MenuBarPtr currentMenu;
PointType lastPenPos;
Coord maxX, maxY;
Boolean erase = false;

BitmapPtr CaptureScreen()
{
   WinHandle offscreen;
   Err err;
   BitmapPtr bitmap = BmpCreate(maxX, maxY, 1, NULL, &err);
   RectangleType rect;

   RctSetRectangle(&rect, 0, 0, maxX, maxY);

   if (!err)
   {  
      offscreen = WinCreateBitmapWindow(bitmap, &err);

      if (!err)
      {
         WinCopyRectangle(WinGetDrawWindow(), offscreen,
                                      &rect, 0, 0, winPaint);
         WinDeleteWindow(offscreen, false);
      }
   }

   return bitmap;
}

Boolean MainFormHandleEvent(EventPtr event)
{
   FormPtr frm;
   
   switch (event->eType)
   {
      case penDownEvent:
         lastPenPos.x = event->screenX;
         lastPenPos.y = event->screenY;
         // Don't break; fall through
         
      case penMoveEvent:

         if (event->screenY > maxY) event->screenY = maxY-1;

         if (erase)
         {
            RectangleType rect;
            RctSetRectangle(&rect, event->screenX-5,
                                  event->screenY-5, 10, 10);
            WinEraseRectangle(&rect, 0);
         }
         else
            WinDrawLine(lastPenPos.x, lastPenPos.y,
                            event->screenX, event->screenY);

         lastPenPos.x = event->screenX;
         lastPenPos.y = event->screenY;
         
         return true;
         
      case keyDownEvent:
         if (event->data.keyDown.chr == 'c')
         {
            WinEraseWindow();
            return true;
         }
         else if (event->data.keyDown.chr == vchrPageDown)
         {
            erase = !erase;
            return true;
         }
         break;
         
      case menuEvent:
         if (event->data.menu.itemID == AboutCmd)
         {
            frm = FrmInitForm(AboutForm);
            FrmDoDialog(frm);
            FrmDeleteForm(frm);
            return true;
         }
         else if (event->data.menu.itemID == ToggleEraseCmd)
         {
            erase = !erase;
            return true;
         }
         else if (event->data.menu.itemID == ClearCmd)
         {
            WinEraseWindow();
            return true;
         }
         break;
   }

   return false;
}

Boolean ApplicationHandleEvent(EventPtr event)
{
   FormPtr frm;
   
   switch (event->eType)
   {
      case frmLoadEvent:         
         if (event->data.frmLoad.formID == EtchForm)
         {
            frm = FrmInitForm(EtchForm);
            FrmSetActiveForm(frm);
            FrmSetEventHandler(frm, MainFormHandleEvent);
            return true;
         }
         break;
   }
   
   return false;
}

void EventLoop()
{
   UInt16 error;
   EventType event;

   do
   {
      EvtGetEvent(&event, evtWaitForever);

      if (!SysHandleEvent(&event))
      
         if (!MenuHandleEvent(currentMenu, &event, &error))

            if (!ApplicationHandleEvent(&event))

               FrmDispatchEvent(&event); 
   }
   while (event.eType != appStopEvent);
}

void StartApplication()
{
   DmOpenRef dbRef;
   
   WinGetDisplayExtent(&maxX, &maxY);
   
   lastPenPos.x = -1;
   lastPenPos.y = -1;
   
   dbRef = DmOpenDatabaseByTypeCreator(EtchDataType, EtchID,
                                               dmModeReadOnly);
   if (dbRef)
   {
      MemHandle rec = DmQueryRecord(dbRef, 0);
      
      if (rec)
      {
         BitmapPtr bitmap = (BitmapPtr) MemHandleLock(rec);
         if (bitmap)
         {
            WinDrawBitmap(bitmap, 0, 0);
            MemHandleUnlock(rec);
         }
      }
      
      DmCloseDatabase(dbRef);
   }  
}

void StopApplication()
{
   BitmapPtr bitmap = CaptureScreen();
   UInt16 bmpSize;
   MemHandle record;
   UInt16 recIndex = 0;
   DmOpenRef dbRef;
      
   BmpCompress(bitmap, BitmapCompressionTypeRLE);
   bmpSize = BmpSize(bitmap);
   
   dbRef = DmOpenDatabaseByTypeCreator(EtchDataType, EtchID,
                                                  dmModeWrite);
   if (!dbRef)
   {
      if (DmCreateDatabase(0, EtchDBName, EtchID,
                                        EtchDataType, false))
         return;

      dbRef = DmOpenDatabaseByTypeCreator(EtchDataType,
                                         EtchID, dmModeWrite);
      if (!dbRef) return;
      record = DmNewRecord(dbRef, &recIndex, bmpSize);
   }
   else
   {
      record = DmResizeRecord(dbRef, 0, bmpSize);
   }

   if (record)
   {
      MemPtr recordPtr = MemHandleLock(record);
      DmWrite(recordPtr, 0, bitmap, bmpSize);
      MemHandleUnlock(record);
      DmReleaseRecord(dbRef, 0, false);
   }

   DmCloseDatabase(dbRef);
   BmpDelete(bitmap);
}

UInt32 PilotMain(UInt16 cmd, void* cmdPBP, UInt16 launchFlags)
{
   if (cmd == sysAppLaunchCmdNormalLaunch)
   {
      StartApplication();
      
      FrmGotoForm(EtchForm);
      EventLoop();
      StopApplication();
   }

   return errNone;
}
— End of Listing —