TweetFollow Us on Twitter

MACINTOSH C CARBON

Demonstration Program GWorldPicCursIcn

Goto Contents

// *******************************************************************************************
// GWorldPicCursIcon.c                                                     CLASSIC EVENT MODEL
// *******************************************************************************************
// 
// This program demonstrates offscreen graphics world, picture, cursor, cursor shape change,
// animated cursor, and icon operations as a result of the user choosing items from a 
// Demonstration menu.  It also demonstrates a modal dialog-based About. box containing a 
// picture.
//
// To keep the non-demonstration code to a minimum, the program contains no functions for
// updating the window or for responding to activate and operating system events.
//
// The program utilises the following resources:
//
// o  A 'plst' resource.
//
// o  An 'MBAR' resource and associated 'MENU' resources (preload, non-purgeable).
//
// o  A 'WIND' resource (purgeable) (initially visible). 
//
// o  An 'acur' resource (purgeable).
//
// o  'CURS' resources associated with the 'acur' resource (preload, purgeable).
//
// o  Two 'cicn' resources (purgeable), one for the Icons menu item and one for drawing in the
//    window.
//
// o  Two icon family resources (purgeable), both for drawing in the window.
//
// o  A 'DLOG' resource (purgeable) and an associated 'DITL' resource (purgeable) and 'PICT'
//    resource for an About GWorldPicCursIcon. dialog box.
//
// o  A 'STR#' resource (purgeable) containing transform constants.
//
// o  A 'SIZE' resource with the acceptSuspendResumeEvents, canBackground, 
//    doesActivateOnFGSwitch, and isHighLevelEventAware flags set.
//
// *******************************************************************************************

// .................................................................................. includes

#include <Carbon.h>

// ................................................................................... defines

#define rMenubar                  128
#define rWindow                   128
#define mAppleApplication         128
#define  iAbout                   1
#define mFile                     129
#define  iQuit                    12
#define mDemonstration            131
#define  iOffScreenGWorld1        1
#define  iOffScreenGWorld2        2
#define  iPicture                 3
#define  iCursor                  4
#define  iAnimatedCursor1         5
#define  iAnimatedCursor2         6
#define  iAnimatedCursorOSX       7
#define  iIcon                    8
#define rBeachBallCursor          128
#define rPicture                  128
#define rTransformStrings         128
#define rIconFamily1              128
#define rIconFamily2              129
#define rColourIcon               128
#define rAboutDialog              128
#define kSleepTime                1
#define kBeachBallTickInterval    5
#define kCountingHandTickInterval 30
#define MAX_UINT32                0xFFFFFFFF
#define topLeft(r)                (((Point *) &(r))[0])
#define botRight(r)               (((Point *) &(r))[1])

// .................................................................................. typedefs

typedef struct
{
  SInt16     numberOfFrames;
  SInt16     whichFrame;
  CursHandle frame[];
} animCurs, *animCursPtr, **animCursHandle;

// .......................................................................... global variables

Boolean        gRunningOnX = false;
WindowRef      gWindowRef;
Boolean        gDone;
SInt32         gSleepTime;
RgnHandle      gCursorRegion;
Boolean        gCursorRegionsActive     = false;
Boolean        gAnimatedCursor1Active   = false;
Boolean        gAnimatedCursor2Active   = false;
Boolean        gAnimatedCursorOSXActive = false;
animCursHandle gAnimCursHdl;
SInt16         gAnimCursTickInterval;
SInt32         gAnimCursLastTick;
RGBColor       gBlackColour = { 0x0000, 0x0000, 0x0000 };
RGBColor       gWhiteColour = { 0xFFFF, 0xFFFF, 0xFFFF };
RGBColor       gBeigeColour = { 0xF000, 0xE300, 0xC200 };
RGBColor       gBlueColour  = { 0x4444, 0x4444, 0x9999 };

// ....................................................................... function prototypes

void    main                  (void);
void    doPreliminaries       (void);
OSErr   quitAppEventHandler   (AppleEvent *,AppleEvent *,SInt32);
void    eventLoop             (void);
void    doIdle                (void);
void    doEvents              (EventRecord *);
void    doMenuChoice          (SInt32);
void    doOffScreenGWorld1    (void);
void    doOffScreenGWorld2    (void);
void    doPicture             (void);
void    doCursor              (void);
void    doChangeCursor        (WindowRef,RgnHandle);
void    doAnimatedCursor1     (void);
void    doAnimatedCursor2     (void);
Boolean doGetAnimCursor       (SInt16,SInt16);
void    doIncrementAnimCursor (void);
void    doReleaseAnimCursor   (void);
void    doAnimatedCursorOSX   (void);
void    doIcon                (void);
void    doAboutDialog         (void);
void    doDrawStuff           (void);
UInt16  doRandomNumber        (UInt16,UInt16);

// ************************************************************************************** main

void  main(void)
{
  UInt32        seconds;
  MenuBarHandle menubarHdl;
  SInt32        response;
  MenuRef       menuRef;

  // ..................................................................... initialise managers

  doPreliminaries();

  // ............................................................ seed random number generator
  
  GetDateTime(&seconds);
  SetQDGlobalsRandomSeed(seconds);

  // ............................................................... set up menu bar and menus
  
  menubarHdl = GetNewMBar(rMenubar);
  if(menubarHdl == NULL)
    ExitToShell();
  SetMenuBar(menubarHdl);
  DrawMenuBar();

  Gestalt(gestaltMenuMgrAttr,&response);
  if(response & gestaltMenuMgrAquaLayoutMask)
  {
    menuRef = GetMenuRef(mFile);
    if(menuRef != NULL)
    {
      DeleteMenuItem(menuRef,iQuit);
      DeleteMenuItem(menuRef,iQuit - 1);
      DisableMenuItem(menuRef,0);
    }
  
    menuRef = GetMenuRef(mDemonstration);
    if(menuRef != NULL)
      EnableMenuItem(menuRef,iAnimatedCursorOSX);

    gRunningOnX = true;
  }

  // ............................................................................. open window

  if(!(gWindowRef = GetNewCWindow(rWindow,NULL,(WindowRef)-1)))
    ExitToShell();

  SetPortWindowPort(gWindowRef);
  TextSize(10);

  // ........................................................................ enter event loop

  eventLoop();
}

// ************************************************************************** do preliminaries

void  doPreliminaries(void)
{
  OSErr osError;

  MoreMasterPointers(64);
  InitCursor();
  FlushEvents(everyEvent,0);

  osError = AEInstallEventHandler(kCoreEventClass,kAEQuitApplication,
                            NewAEEventHandlerUPP((AEEventHandlerProcPtr) quitAppEventHandler),
                            0L,false);
  if(osError != noErr)
    ExitToShell();
}

// **************************************************************************** doQuitAppEvent

OSErr  quitAppEventHandler(AppleEvent *appEvent,AppleEvent *reply,SInt32 handlerRefcon)
{
  OSErr    osError;
  DescType returnedType;
  Size     actualSize;

  osError = AEGetAttributePtr(appEvent,keyMissedKeywordAttr,typeWildCard,&returnedType,NULL,0,
                              &actualSize);

  if(osError == errAEDescNotFound)
  {
    gDone = true;
    osError = noErr;
  } 
  else if(osError == noErr)
    osError = errAEParamMissed;

  return osError;
}

// ********************************************************************************* eventLoop

void  eventLoop(void)
{
  EventRecord eventStructure;
  Boolean     gotEvent;

  gDone = false;
  gSleepTime = MAX_UINT32;
  gCursorRegion = NULL;
  
  while(!gDone)
  {
    gotEvent = WaitNextEvent(everyEvent,&eventStructure,gSleepTime,gCursorRegion);
    if(gotEvent)
      doEvents(&eventStructure);
    else
    {
      if(eventStructure.what == nullEvent)
        doIdle();
    }
  }
}

// ************************************************************************************ doIdle

void  doIdle(void)
{
  if(gAnimatedCursor1Active || gAnimatedCursor2Active)
    doIncrementAnimCursor();
}

// ********************************************************************************** doEvents

void  doEvents(EventRecord *eventStrucPtr)
{    
  WindowRef      windowRef;
  WindowPartCode partCode;

  switch(eventStrucPtr->what)
  {
    case kHighLevelEvent:
      AEProcessAppleEvent(eventStrucPtr);
      break;

    case mouseDown:
      partCode = FindWindow(eventStrucPtr->where,&windowRef);
      switch(partCode)
      {
        case inMenuBar:
          doMenuChoice(MenuSelect(eventStrucPtr->where));
          break;

        case inContent:
          if(windowRef != FrontWindow())
            SelectWindow(windowRef);
          break;

        case inDrag:
          DragWindow(windowRef,eventStrucPtr->where,NULL);
          if(gCursorRegionsActive)
            doChangeCursor(windowRef,gCursorRegion);
          break;
      }
      break;

    case keyDown:
      if((eventStrucPtr->modifiers & cmdKey) != 0)
        doMenuChoice(MenuEvent(eventStrucPtr));
      break;

    case updateEvt:
      BeginUpdate((WindowRef) eventStrucPtr->message);
      EndUpdate((WindowRef) eventStrucPtr->message);
      break;

    case osEvt:
      switch((eventStrucPtr->message >> 24) & 0x000000FF)
      {
        case suspendResumeMessage:
          if((eventStrucPtr->message & resumeFlag) == 1)
            SetThemeCursor(kThemeArrowCursor);
          break;
        
        case mouseMovedMessage:
          if(gCursorRegionsActive)
            doChangeCursor(FrontWindow(),gCursorRegion);
          break;
      }
      break;
  }
}

// ****************************************************************************** doMenuChoice

void  doMenuChoice(SInt32 menuChoice)
{
  MenuID        menuID;
  MenuItemIndex menuItem;

  menuID = HiWord(menuChoice);
  menuItem = LoWord(menuChoice);

  if(menuID == 0)
    return;

  if(gAnimatedCursor1Active || gAnimatedCursor2Active)
  {
    if(gAnimatedCursor2Active)
      doReleaseAnimCursor();

    SetThemeCursor(kThemeArrowCursor);
    gSleepTime = MAX_UINT32;

    gAnimatedCursor1Active = false;
    gAnimatedCursor2Active = false;
  }
  
  if(gAnimatedCursorOSXActive)
    doAnimatedCursorOSX();

  if(gCursorRegionsActive == true)
  {
    gCursorRegionsActive = false;
    DisposeRgn(gCursorRegion);
    gCursorRegion = NULL;
  }

  switch(menuID)
  {
    case mAppleApplication:
      if(menuItem == iAbout)
        doAboutDialog();
      break;

    case mFile:
      if(menuItem == iQuit)
        gDone = true;
      break;

    case mDemonstration:
      switch(menuItem)
      {
        case iOffScreenGWorld1:
          doOffScreenGWorld1();
          break;      

        case iOffScreenGWorld2:
          doOffScreenGWorld2();
          break;

        case iPicture:
          doPicture();
          break;

        case iCursor:
          doCursor();
          break;

        case iAnimatedCursor1:
          doAnimatedCursor1();
          break;

        case iAnimatedCursor2:
          doAnimatedCursor2();
          break;

        case iAnimatedCursorOSX:
          doAnimatedCursorOSX();
          break;

        case iIcon:
          doIcon();
          break;
      }
      break;
  }

  HiliteMenu(0);
}

// ************************************************************************ doOffScreenGWorld1

void  doOffScreenGWorld1(void)
{
  Rect         portRect, sourceRect, destRect;  
  GrafPtr      windowPortPtr;
  GDHandle     deviceHdl;
  QDErr        qdErr;
  GWorldPtr    gworldPortPtr;
  PixMapHandle gworldPixMapHdl, windowPixMapHdl;
  Boolean      lockPixResult;

  // .......................................................................... draw in window

  SetWTitle(gWindowRef,"\pTime-consuming drawing operation");

  if(!gRunningOnX)
    SetThemeCursor(kThemeWatchCursor);

  doDrawStuff();

  if(!gRunningOnX)
    SetThemeCursor(kThemeArrowCursor);
  
  SetWTitle(gWindowRef,"\pClick mouse to repeat in offscreen graphics port");
  QDFlushPortBuffer(GetWindowPort(gWindowRef),NULL);

  while(!Button()) ;

  if(!gRunningOnX)
    SetThemeCursor(kThemeWatchCursor);
  
  GetWindowPortBounds(gWindowRef,&portRect);

  RGBBackColor(&gBlueColour);
  EraseRect(&portRect);
  RGBForeColor(&gWhiteColour);
  MoveTo(190,180);
  DrawString("\pPlease Wait.  Drawing in offscreen graphics port.");  

  // ...................................... draw in offscreen graphics port and copy to window

  // ......................... save current graphics world and create offscreen graphics world

  GetGWorld(&windowPortPtr,&deviceHdl);

  qdErr = NewGWorld(&gworldPortPtr,0,&portRect,NULL,NULL,0);
  if(gworldPortPtr == NULL || qdErr != noErr)
  {
    SysBeep(10);
    return;
  }

  SetGWorld(gworldPortPtr,NULL);

  // ................... lock pixel image for duration of drawing and erase offscreen to white

  gworldPixMapHdl = GetGWorldPixMap(gworldPortPtr);
  if(!(lockPixResult = LockPixels(gworldPixMapHdl)))
  {
    SysBeep(10);
    return;
  }

  EraseRect(&portRect);  

  // ................................................... draw into the offscreen graphics port

  doDrawStuff();

  // ............................................................ restore saved graphics world

  SetGWorld(windowPortPtr,deviceHdl);

  // ................................................... set source and destination rectangles

  GetPortBounds(gworldPortPtr,&sourceRect);
  GetPortBounds(windowPortPtr,&destRect);

  // ............................................................. get window port's pixel map

  windowPixMapHdl = GetGWorldPixMap(windowPortPtr);

  // ............. ensure background colour is white and foreground colour in black, then copy

  RGBBackColor(&gWhiteColour);
  RGBForeColor(&gBlackColour);

  CopyBits((BitMap *) *gworldPixMapHdl,
           (BitMap *) *windowPixMapHdl,
           &sourceRect,&destRect,srcCopy,NULL);

  if(QDError() != noErr)
    SysBeep(10);

  // ................................................................................ clean up 

  UnlockPixels(gworldPixMapHdl);
  DisposeGWorld(gworldPortPtr);  

  if(!gRunningOnX)
    SetThemeCursor(kThemeArrowCursor);

  SetWTitle(gWindowRef,"\pOffscreen Graphics Worlds, Pictures,  Cursors and Icons");
  QDFlushPortBuffer(GetWindowPort(gWindowRef),NULL);
}

// ************************************************************************ doOffScreenGWorld2

void  doOffScreenGWorld2(void)
{
  PicHandle    picture1Hdl,picture2Hdl;
  Rect         portRect;
  Rect         sourceRect, maskRect, maskDisplayRect, dest1Rect, dest2Rect, destRect;
  GrafPtr      windowPortPtr;  
  GDHandle     deviceHdl;
  QDErr        qdErr;
  GWorldPtr    gworldPortPtr;
  PixMapHandle gworldPixMapHdl, windowPixMapHdl;
  RgnHandle    region1Hdl, region2Hdl, regionHdl;
  SInt16       a, sourceMode;

  RGBBackColor(&gBeigeColour);
  GetWindowPortBounds(gWindowRef,&portRect);  
  EraseRect(&portRect);

  // ........................................ get the source picture and draw it in the window

  if(!(picture1Hdl = GetPicture(rPicture)))
    ExitToShell();
  HNoPurge((Handle) picture1Hdl);
  SetRect(&sourceRect,116,35,273,147);
  DrawPicture(picture1Hdl,&sourceRect);
  HPurge((Handle) picture1Hdl);
  MoveTo(116,32);
  DrawString("\pSource image");

  // ......................... save current graphics world and create offscreen graphics world

  GetGWorld(&windowPortPtr,&deviceHdl);  

  SetRect(&maskRect,0,0,157,112);

  qdErr = NewGWorld(&gworldPortPtr,0,&maskRect,NULL,NULL,0);  
  if(gworldPortPtr == NULL || qdErr != noErr)
  {
    SysBeep(10);
    return;
  }

  SetGWorld(gworldPortPtr,NULL);

  // ................... lock pixel image for duration of drawing and erase offscreen to white

  gworldPixMapHdl = GetGWorldPixMap(gworldPortPtr);

  if(!(LockPixels(gworldPixMapHdl)))
  {
    SysBeep(10);
    return;
  }

  GetPortBounds(gworldPortPtr,&portRect);  
  EraseRect(&portRect);

  // ................................. get mask picture and draw it in offscreen graphics port

  if(!(picture2Hdl = GetPicture(rPicture + 1)))
    ExitToShell();
  HNoPurge((Handle) picture2Hdl);
  DrawPicture(picture2Hdl,&maskRect);

  // .............................................................. also draw it in the window

  SetGWorld(windowPortPtr,deviceHdl);
  SetRect(&maskDisplayRect,329,35,485,146);
  DrawPicture(picture2Hdl,&maskDisplayRect);
  HPurge((Handle) picture2Hdl);
  MoveTo(329,32);
  DrawString("\pCopy of offscreen mask");

  // ........................ define an oval-shaped region and a round rectangle-shaped region
  
  SetRect(&dest1Rect,22,171,296,366);
  region1Hdl = NewRgn();
  OpenRgn();
  FrameOval(&dest1Rect);
  CloseRgn(region1Hdl);

  SetRect(&dest2Rect,308,171,582,366);
  region2Hdl = NewRgn();
  OpenRgn();
  FrameRoundRect(&dest2Rect,100,100);
  CloseRgn(region2Hdl);

  SetWTitle(GetWindowFromPort(windowPortPtr),"\pClick mouse to copy");
  QDFlushPortBuffer(GetWindowPort(gWindowRef),NULL);
  while(!Button()) ;

  // ............................................................. get window port's pixel map

  windowPixMapHdl = GetGWorldPixMap(windowPortPtr);

  // ........ set background and foreground colour, then copy source to destination using mask

  RGBForeColor(&gBlackColour);
  RGBBackColor(&gWhiteColour);

  for(a=0;a<2;a++)
  {
    if(a == 0)
    {
      regionHdl = region1Hdl;
      destRect = dest1Rect;
      sourceMode = srcCopy;
      MoveTo(22,168);
      DrawString("\pBoolean source mode srcCopy");
    }
    else
    {
      regionHdl = region2Hdl;
      destRect = dest2Rect;
      sourceMode = srcXor;
      MoveTo(308,168);
      DrawString("\pBoolean source mode srcXor");
    }

    CopyDeepMask((BitMap *) *windowPixMapHdl,
                 (BitMap *) *gworldPixMapHdl,
                 (BitMap *) *windowPixMapHdl,
                 &sourceRect,&maskRect,&destRect,sourceMode + ditherCopy,regionHdl);

    if(QDError() != noErr)
      SysBeep(10);
  }

  // ................................................................................ clean up

  UnlockPixels(gworldPixMapHdl);
  DisposeGWorld(gworldPortPtr);  

  ReleaseResource((Handle) picture1Hdl);
  ReleaseResource((Handle) picture2Hdl);
  DisposeRgn(region1Hdl);
  DisposeRgn(region2Hdl);

  SetWTitle(gWindowRef,"\pOffscreen Graphics Worlds, Pictures,  Cursors and Icons");
  QDFlushPortBuffer(GetWindowPort(gWindowRef),NULL);
}

// ********************************************************************************* doPicture

void  doPicture(void)
{
  Rect           portRect, pictureRect, theRect;  
  OpenCPicParams picParams;
  RgnHandle      oldClipRgn;
  PicHandle      pictureHdl;
  SInt16         a, left, top, right, bottom, random;
  RGBColor       theColour;
  PictInfo       pictInfo;
  Str255         theString;

  RGBBackColor(&gWhiteColour);
  GetWindowPortBounds(gWindowRef,&portRect);
  EraseRect(&portRect);

  // ................................................................ define picture rectangle

  pictureRect = portRect;
  pictureRect.right = (portRect.right - portRect.left) / 2;
  InsetRect(&pictureRect,10,10);

  // ..................................................................... set clipping region

  oldClipRgn = NewRgn();
  GetClip(oldClipRgn);
  ClipRect(&pictureRect);

  // ......................................................... set up OpenCPicParams structure

  picParams.srcRect  = pictureRect;
  picParams.hRes    = 0x00480000;
  picParams.vRes    = 0x00480000;
  picParams.version = -2;

  // .......................................................................... record picture

  pictureHdl = OpenCPicture(&picParams);

  RGBBackColor(&gBlueColour);
  EraseRect(&pictureRect);

  for(a=0;a<300;a++)
  {
    theRect = pictureRect;

    theColour.red   = doRandomNumber(0,65535);
    theColour.green = doRandomNumber(0,65535);
    theColour.blue  = doRandomNumber(0,65535);
    RGBForeColor(&theColour);

    left = doRandomNumber(10,theRect.right);  
    top = doRandomNumber(10,theRect.bottom);
    right = doRandomNumber(left,theRect.right);  
    bottom = doRandomNumber(top,theRect.bottom);    
    SetRect(&theRect,left,top,right,bottom);

    PenMode(doRandomNumber(addOver,adMin));
    
    random = doRandomNumber(0,5);

    if(random == 0)
    {
      MoveTo(left,top);
      LineTo(right - 1,bottom - 1);
    }
    else if(random == 1)
      PaintRect(&theRect);
    else if(random == 2)
      PaintRoundRect(&theRect,30,30);
    else if(random == 3)
      PaintOval(&theRect);
    else if(random == 4)
      PaintArc(&theRect,0,300);
    else if(random == 5)
    {
      TextSize(doRandomNumber(10,70));
      MoveTo(left,right);
      DrawString("\pPICTURE");
    }
  }

  // ............................. stop recording, draw picture, restore saved clipping region

  ClosePicture();

  DrawPicture(pictureHdl,&pictureRect);

  SetClip(oldClipRgn);
  DisposeRgn(oldClipRgn);

  // .................................... display some information from the PictInfo structure

  RGBForeColor(&gBlueColour);
  RGBBackColor(&gBeigeColour);
  PenMode(patCopy);
  OffsetRect(&pictureRect,300,0);
  EraseRect(&pictureRect);
  FrameRect(&pictureRect);
  TextSize(10);

  if(GetPictInfo(pictureHdl,&pictInfo,recordFontInfo + returnColorTable,1,systemMethod,0))
    SysBeep(10);

  MoveTo(380,70);
  DrawString("\pSome Picture Information:");

  MoveTo(380,100);
  DrawString("\pLines: ");
  NumToString(pictInfo.lineCount,theString);
  DrawString(theString);

  MoveTo(380,115);
  DrawString("\pRectangles: ");
  NumToString((long) pictInfo.rectCount,theString);
  DrawString(theString);

  MoveTo(380,130);
  DrawString("\pRound rectangles: ");
  NumToString(pictInfo.rRectCount,theString);
  DrawString(theString);

  MoveTo(380,145);
  DrawString("\pOvals: ");
  NumToString(pictInfo.ovalCount,theString);
  DrawString(theString);

  MoveTo(380,160);
  DrawString("\pArcs: ");
  NumToString(pictInfo.arcCount,theString);
  DrawString(theString);

  MoveTo(380,175);
  DrawString("\pPolygons: ");
  NumToString(pictInfo.polyCount,theString);
  DrawString(theString);

  MoveTo(380,190);
  DrawString("\pRegions: ");
  NumToString(pictInfo.regionCount,theString);
  DrawString(theString);

  MoveTo(380,205);
  DrawString("\pText strings: ");
  NumToString(pictInfo.textCount,theString);
  DrawString(theString);

  MoveTo(380,220);
  DrawString("\pUnique fonts: ");
  NumToString(pictInfo.uniqueFonts,theString);
  DrawString(theString);

  MoveTo(380,235);
  DrawString("\pUnique colours: ");
  NumToString(pictInfo.uniqueColors,theString);
  DrawString(theString);

  MoveTo(380,250);
  DrawString("\pFrame rectangle left: ");
  NumToString(pictInfo.sourceRect.left,theString);
  DrawString(theString);

  MoveTo(380,265);
  DrawString("\pFrame rectangle top: ");
  NumToString(pictInfo.sourceRect.top,theString);
  DrawString(theString);

  MoveTo(380,280);
  DrawString("\pFrame rectangle right: ");
  NumToString(pictInfo.sourceRect.right,theString);
  DrawString(theString);

  MoveTo(380,295);
  DrawString("\pFrame rectangle bottom: ");
  NumToString(pictInfo.sourceRect.bottom,theString);
  DrawString(theString);

  QDFlushPortBuffer(GetWindowPort(gWindowRef),NULL);

  // ............................................ release memory occupied by Picture structure

  KillPicture(pictureHdl);
}

// ********************************************************************************** doCursor

void  doCursor(void)
{
  Rect   portRect, cursorRect;
  SInt16 a;

  RGBBackColor(&gBlueColour);
  GetWindowPortBounds(gWindowRef,&portRect);
  EraseRect(&portRect);

  cursorRect = portRect;

  for(a=0;a<3;a++)
  {
    InsetRect(&cursorRect,40,40);

    if(a == 0 || a == 2)
      RGBBackColor(&gBeigeColour);
    else
      RGBBackColor(&gBlueColour);

    EraseRect(&cursorRect);
  }

  RGBForeColor(&gBeigeColour);
  MoveTo(10,20);
  DrawString("\pArrow cursor region");
  RGBForeColor(&gBlueColour);
  MoveTo(50,60);
  DrawString("\pIBeam cursor region");
  RGBForeColor(&gBeigeColour);
  MoveTo(90,100);
  DrawString("\pCross cursor region");
  RGBForeColor(&gBlueColour);
  MoveTo(130,140);
  DrawString("\pPlus cursor region");

  gCursorRegion = NewRgn();
  doChangeCursor(gWindowRef,gCursorRegion);

  gCursorRegionsActive = true;
}

// **************************************************************************** doChangeCursor

void  doChangeCursor(WindowRef windowRef,RgnHandle cursorRegion)
{
  RgnHandle arrowCursorRgn;
  RgnHandle ibeamCursorRgn;
  RgnHandle crossCursorRgn;
  RgnHandle plusCursorRgn;
  Rect      cursorRect;
  GrafPtr   oldPort;  
  Point     mousePosition;

  arrowCursorRgn = NewRgn();
  ibeamCursorRgn = NewRgn();  
  crossCursorRgn = NewRgn();
  plusCursorRgn   = NewRgn();

  SetRectRgn(arrowCursorRgn,-32768,-32768,32766,32766);

  GetPort(&oldPort);
  SetPortWindowPort(windowRef);

  GetWindowPortBounds(windowRef,&cursorRect);
  LocalToGlobal(&topLeft(cursorRect));
  LocalToGlobal(&botRight(cursorRect));  

  InsetRect(&cursorRect,40,40);
  RectRgn(ibeamCursorRgn,&cursorRect);
  DiffRgn(arrowCursorRgn,ibeamCursorRgn,arrowCursorRgn);

  InsetRect(&cursorRect,40,40);
  RectRgn(crossCursorRgn,&cursorRect);
  DiffRgn(ibeamCursorRgn,crossCursorRgn,ibeamCursorRgn);

  InsetRect(&cursorRect,40,40);
  RectRgn(plusCursorRgn,&cursorRect);
  DiffRgn(crossCursorRgn,plusCursorRgn,crossCursorRgn);

  GetGlobalMouse(&mousePosition);

  if(PtInRgn(mousePosition,ibeamCursorRgn))
  {
    SetThemeCursor(kThemeIBeamCursor);
    CopyRgn(ibeamCursorRgn,cursorRegion);
  }
  else if(PtInRgn(mousePosition,crossCursorRgn))
  {
    SetThemeCursor(kThemeCrossCursor);
    CopyRgn(crossCursorRgn,cursorRegion);
  }
  else if(PtInRgn(mousePosition,plusCursorRgn))
  {
    SetThemeCursor(kThemePlusCursor);
    CopyRgn(plusCursorRgn,cursorRegion);
  }
  else
  {
    SetThemeCursor(kThemeArrowCursor);
    CopyRgn(arrowCursorRgn,cursorRegion);
  }

  DisposeRgn(arrowCursorRgn);
  DisposeRgn(ibeamCursorRgn);
  DisposeRgn(crossCursorRgn);
  DisposeRgn(plusCursorRgn);

  SetPort(oldPort);
}

// ************************************************************************* doAnimatedCursor1

void  doAnimatedCursor1(void)
{
  Rect    portRect;
  Pattern whitePattern;

  BackColor(whiteColor);
  GetWindowPortBounds(gWindowRef,&portRect);
  FillRect(&portRect,GetQDGlobalsWhite(&whitePattern));

  gAnimCursTickInterval = kCountingHandTickInterval;
  gSleepTime = gAnimCursTickInterval;
  gAnimatedCursor1Active = true;

}

// ************************************************************************* doAnimatedCursor2

void  doAnimatedCursor2(void)
{
  Rect    portRect;
  Pattern whitePattern;
  SInt16  animCursResourceID, animCursTickInterval;

  BackColor(whiteColor);
  GetWindowPortBounds(gWindowRef,&portRect);
  FillRect(&portRect,GetQDGlobalsWhite(&whitePattern));

  animCursResourceID   = rBeachBallCursor;
  animCursTickInterval = kBeachBallTickInterval;

  if(doGetAnimCursor(animCursResourceID,animCursTickInterval))
  {
    gSleepTime = animCursTickInterval;
    gAnimatedCursor2Active = true;
  }  
  else
    SysBeep(10);
}

// *************************************************************************** doGetAnimCursor

Boolean  doGetAnimCursor(SInt16 resourceID,SInt16 tickInterval)
{
  SInt16  cursorID, a = 0;
  Boolean noError = false;

  if((gAnimCursHdl = (animCursHandle) GetResource('acur',resourceID)))
  {
    noError = true;
    while((a < (*gAnimCursHdl)->numberOfFrames)  && noError)
    {
      cursorID = (SInt16) HiWord((SInt32) (*gAnimCursHdl)->frame[a]);
      (*gAnimCursHdl)->frame[a] = GetCursor(cursorID);
      if((*gAnimCursHdl)->frame[a])
        a++;
      else
        noError = false;
    }
  }

  if(noError)
  {
    gAnimCursTickInterval = tickInterval;
    gAnimCursLastTick = TickCount();
    (*gAnimCursHdl)->whichFrame = 0;
  }

  return noError;
}

// ********************************************************************* doIncrementAnimCursor

void  doIncrementAnimCursor(void)
{
  SInt32        newTick;
  static UInt32 animationStep;

  newTick = TickCount();
  if(newTick < (gAnimCursLastTick + gAnimCursTickInterval))
    return;

  if(gAnimatedCursor1Active)
  {
    SetAnimatedThemeCursor(kThemeCountingUpAndDownHandCursor,animationStep);
      animationStep++;
  }
  else if(gAnimatedCursor2Active)
  {
    SetCursor(*((*gAnimCursHdl)->frame[(*gAnimCursHdl)->whichFrame++]));
    if((*gAnimCursHdl)->whichFrame == (*gAnimCursHdl)->numberOfFrames)
      (*gAnimCursHdl)->whichFrame = 0;
  }

  gAnimCursLastTick = newTick;
}

// *********************************************************************** doReleaseAnimCursor

void  doReleaseAnimCursor(void)
{
  SInt16 a;

  for(a=0;a<(*gAnimCursHdl)->numberOfFrames;a++)
    ReleaseResource((Handle) (*gAnimCursHdl)->frame[a]);

  ReleaseResource((Handle) gAnimCursHdl);
}

// *********************************************************************** doAnimatedCursorOSX

void  doAnimatedCursorOSX(void)
{
  if(!gAnimatedCursorOSXActive)
  {
    QDDisplayWaitCursor(true);
    gAnimatedCursorOSXActive = true;
  }
  else
  {
    QDDisplayWaitCursor(false);
    gAnimatedCursorOSXActive = false;
  }
}

// ************************************************************************************ doIcon

void  doIcon(void)
{
  Rect              portRect, theRect;
  SInt16            a, b, stringIndex = 1;
  IconTransformType transform = 0;
  Str255            theString;
  Handle            iconSuiteHdl;
  CIconHandle       ciconHdl;

  RGBForeColor(&gBlueColour);
  RGBBackColor(&gBeigeColour);
  GetWindowPortBounds(gWindowRef,&portRect);
  EraseRect(&portRect);

  // .............................................................. PlotIconID with transforms

  MoveTo(50,28);
  DrawString("\pPlotIconID with transforms");

  for(a=50;a<471;a+=140)
  { 
    if(a == 190)
      transform = 16384;
    if(a == 330)
      transform = 256;

    for(b=0;b<4;b++)
    {
      if(a == 470 && b == 3)
        continue;

      GetIndString(theString,rTransformStrings,stringIndex++);
      MoveTo(a,b * 60 + 47);
      DrawString(theString);
      
      SetRect(&theRect,a,b * 60 + 50,a + 32,b * 60 + 82);
      PlotIconID(&theRect,0,transform,rIconFamily1);
      SetRect(&theRect,a + 40,b * 60 + 50,a + 56,b * 60 + 66);
      PlotIconID(&theRect,0,transform,rIconFamily1);
      SetRect(&theRect,a + 64,b * 60 + 50,a + 80,b * 60 + 62);
      PlotIconID(&theRect,0,transform,rIconFamily1);

      if(a >= 330)
        transform += 256;
      else
        transform ++;
    }
  }

  // .......................................................... GetIconSuite and PlotIconSuite

  MoveTo(50,275);
  LineTo(550,275);
  MoveTo(50,299);
  DrawString("\pGetIconSuite and PlotIconSuite");

  GetIconSuite(&iconSuiteHdl,rIconFamily2,kSelectorAllLargeData);

  SetRect(&theRect,50,324,82,356);
  PlotIconSuite(&theRect,kAlignNone,kTransformNone,iconSuiteHdl);
  SetRect(&theRect,118,316,166,364);
  PlotIconSuite(&theRect,kAlignNone,kTransformNone,iconSuiteHdl);
  SetRect(&theRect,202,308,266,372);
  PlotIconSuite(&theRect,kAlignNone,kTransformNone,iconSuiteHdl);

  // .................................................................. GetCIcon and PlotCIcon

  MoveTo(330,299);
  DrawString("\pGetCIcon and PlotCIcon");

  ciconHdl = GetCIcon(rColourIcon);

  SetRect(&theRect,330,324,362,356);
  PlotCIcon(&theRect,ciconHdl);
  SetRect(&theRect,398,316,446,364);
  PlotCIcon(&theRect,ciconHdl);
  SetRect(&theRect,482,308,546,372);
  PlotCIcon(&theRect,ciconHdl);
}

// ***************************************************************************** doAboutDialog

void  doAboutDialog(void)
{
  DialogPtr dialogPtr;
  SInt16    itemHit;

  dialogPtr = GetNewDialog(rAboutDialog,NULL,(WindowRef)-1);
  ModalDialog(NULL,&itemHit);
  DisposeDialog(dialogPtr);
}

// ******************************************************************************* doDrawStuff

void  doDrawStuff(void)
{
  Rect     portRect, theRect;
  RGBColor theColour;
  SInt16   a, left, top, right, bottom, random;

  RGBBackColor(&gBlueColour);
  GetWindowPortBounds(gWindowRef,&portRect);
  EraseRect(&portRect);

  for(a=0;a<900;a++)
  {
    theRect = portRect;

    theColour.red   = doRandomNumber(0,65535);
    theColour.green = doRandomNumber(0,65535);
    theColour.blue  = doRandomNumber(0,65535);
    RGBForeColor(&theColour);

    left = doRandomNumber(0,theRect.right);  
    top = doRandomNumber(0,theRect.bottom);
    right = doRandomNumber(left,theRect.right);  
    bottom = doRandomNumber(top,theRect.bottom);    
    SetRect(&theRect,left,top,right,bottom);

    PenMode(doRandomNumber(addOver,adMin));
    
    random = doRandomNumber(0,3);

    if(random == 0)
      PaintRect(&theRect);
    else if(random == 1)
      PaintRoundRect(&theRect,doRandomNumber(10,100),doRandomNumber(10,100));
    else if(random == 2)
      PaintOval(&theRect);
    else if(random == 3)
      PaintArc(&theRect,0,doRandomNumber(5,330));

    QDFlushPortBuffer(GetWindowPort(gWindowRef),NULL);
  }
}

// **************************************************************************** doRandomNumber

UInt16  doRandomNumber(UInt16 minimum, UInt16 maximum)
{
  UInt16 randomNumber;
  SInt32 range, t;

  randomNumber = Random();
  range = maximum - minimum + 1;
  t = (randomNumber * range) / 65536;
  return (t + minimum);
}

// *******************************************************************************************

Demonstration Program GWorldPicCursIcn Comments

When this program is run, the user should:

o Invoke the demonstrations by choosing items from the Demonstration menu, clicking the mouse
  when instructed to do so by the text in the window's title bar.

o Click outside and inside the window when the animated cursor demonstrations have been
  invoked.

o Choose the About item in the Apple menu to display the About dialog.

o Note that the Icons item in the Demonstration menu contains an icon.

On Mac OS 8/9, if the first offscreen graphics world demonstration does not work when the
monitor colour depth is set to Millions, increase the Minimum Heap Size set in the CodeWarrior
project.

defines

Constants are established for the resource IDs of 'acur', 'PICT', 'STR#', icon family, and
'cicn' resources, and a 'DLOG' resource.

kSleeptime and MAX_UINT32 will be assigned to WaitNextEvent's sleep parameter at various points
in the program.  kBeachBallTickInterval represents the interval between frame changes for the
first of three animated cursors.  kCountingHandTickInterval represents the interval between
frame changes for the second animated cursor.

typedefs

The data type anumCurs is identical to the structure of an 'acur' resource.

Global Variables

In this program, the sleep and cursor region parameters in the WaitNextEvent call will be
changed during program execution, hence the global variables gSleepTime and gCursorRegion. 
gCursorRegion will be assigned a reference to a region which will passed in the mouseRgn
parameter of the WaitNextEvent call.  This relates to the cursor shape changing demonstration.

gAnimCursHdl will be assigned a handle to the animCurs structure used during the first animated
cursor demonstration.  gAnimCursTickInterval and gAnimCursLastTick also relate to the animated
cursor demonstration.

main

Random numbers will be used in the function doPicture.  The call to SetQDGlobalsRandomSeed
seeds the random number generator with the value returned by the call to GetDateTime.

Note that error handling here and in other areas of the program is somewhat rudimentary: the
program simply terminates, sometimes with a call to SysBeep().

eventLoop

Before the event loop is entered, gSleepTime is set to MAX_UINT32.  Initially, therefore, the
sleep parameter in the WaitNextEvent call is set to the maximum possible UInt32 value.

The global variable passed in the mouseRgn parameter of the WaitNextEvent call is assigned NULL
so as to defeat the generation of mouse-moved events.

When WaitNextEvent returns 0 with a null event, the function doIdle is called.

doIdle

doIdle is called from the main event loop when WaitNextEvent returns 0 with a null event.  If
the active demonstration is one of the first two animated cursor demonstrations, the function
doIncrementAnimCursor is called.

doEvents

In the inDrag case, after the call to DragWindow, and provided the cursor shape changing
demonstration is currently under way, the function doChangeCursor is called.

The regions controlling the generation of mouse-moved events are defined in global coordinates,
and are based on the window's port rectangle.  Accordingly, when the window is moved, the new
location of the port rectangle, in global coordinates, must be re-calculated so that the
various cursor regions may be re-defined.  The call to doChangeCursor re-defines these regions
for the new window location and copies the reference to one of them, depending on the current
location of the mouse cursor, to the global variable gCursorRegion.  (Note that this call to
doChangeCursor is also required, for the same reason, when a window is re-sized or zoomed.)

In the case of a resume event, SetThemeCursor is called to ensure that the cursor is set to the
arrow shape.

In the case of a mouse-moved event (which occurs when the mouse cursor has moved outside the
region whose reference is currently being passed in WaitNextEvent's mouseRgn parameter),
doChangeCursor is called to change the region passed in the mouseRgn parameter according to the
current location of the mouse.

doMenuChoice

The purpose of the code prior to the switch is to cancel any cursor demonstrations that may be
currently under way.

If the second of the first two animated cursor demonstrations is currently under way,
doReleaseAnimCursor is called to release the memory associated with that animated cursor.

If either of the first two animated cursor demonstrations is currently under way,
SetThemeCursor is called to set the cursor shape to the arrow shape and WaitNextEvent's sleep
parameter is then set to the maximum possible value.

if the third animated cursor demonstration is currently under way, the function
doAnimatedCursorOSX is called to terminate the Mac OS X wait cursor.

If the cursor shape changing demonstration is currently under way, gCursorRegionsActive is set
to false, the region containing the current cursor region is disposed of and the associated
global variable is set to NULL, thus defeating the generation of mouse-moved events.

Note that, if the user chooses the About... item in the Mac OS 8/9Apple or Mac OS X Application
menu, doAboutDialog is called.

doOffScreenGWorld1

doWithoutOffScreenGWorld is the first demonstration.
Draw in Window
As a prelude for what is to come, the function doDrawStuff is called to repeatedly paint some
shapes in the window.
Draw in Offscreen Graphics Port and Copy to Window
The call to GetGWorld saves the current graphics world, that is, the current graphics port and
the current device.

The call to NewGWorld creates an offscreen graphics world.  The gworldPortPtr parameter
receives a pointer to the offscreen graphics world's graphics port.  0 in the pixelDepth
parameter means that the offscreen world's pixel depth will be set to the deepest device
intersecting the rectangle passed as the boundsRect parameter.  This rectangle becomes the
offscreen port's port port rectangle, the offscreen pixel map's bounding rectangle, and the
offscreen device's bounding rectangle.  NULL in the cTable parameter causes the default colour
table for the pixel depth to be used.  The aGDevice parameter is set to NULL because the
noNewDevice flag is not set.  0 in the flags parameter means that no flags are set.

The call to SetGWorld sets the graphics port pointed to by gworldPortPtr as the current
graphics port.  (When the first parameter is a GWorldPtr, the current device is set to the
device attached to the offscreen world and the second parameter is ignored.)

GetGWorldPixMap gets a handle to the offscreen pixel map and LockPixels is called to prevent
the base address of the pixel image from being moved when the pixel image is drawn into or
copied from.

The call to EraseRect clears the offscreen graphics port before the function doGWorldDrawing is
called to draw some graphics in the offscreen port.

With the drawing complete, the call to SetGWorld sets the (saved) window's graphics port as the
current port and the saved device as the current device.

The next two lines establish the source and destination rectangles (required by the forthcoming
call to CopyBits) as equivalent to the offscreen graphics world and window port rectangles
respectively.  The calls to RGBForeColor and RGBBackColor set the foreground and background
colours to black and white respectively, which is required to ensure that the CopyBits call
will produce predictable results in the colour sense.

The CopyBits call copies the image from the offscreen world to the window.  The call to QDError
checks for any error resulting from the last QuickDraw call (in this case, CopyBits).

UnlockPixels unlocks the offscreen pixel image buffer and DisposeGWorld deallocates all of the
memory previously allocated for the offscreen graphics world.

doOffScreenGWorld2

doWithoutOffScreenGWorld demonstrates the use of CopyDeepMask to copy a source pixel map to a
destination pixel map using a pixel map as a mask, and clipping the copying operation to a
designated region.  Because mask pixel maps cannot come from the screen, an offscreen graphics
world is created for the mask.

The first block loads a 'PICT' resource and draws the picture in the window.

The current graphics world is then saved and an offscreen graphics world the same size as the
drawn picture is created.  The offscreen graphics port is set as the current port, the pixel
map is locked, and the offscreen port is erased.

The second call to GetPicture loads the 'PICT' resource representing the mask and DrawPicture
is called to draw the mask in the offscreen port.

SetGWorld is then called again to make the window's graphics port the current port.  The mask
is then also drawn in the window next to the source image so that the user can see a copy of
the mask in the offscreen graphics port.

The next two blocks define two regions, one containing an oval and one a rounded rectangle. 
The references to these regions will be passed in the maskRgn parameter of two separate calls
to CopyDeepMask.

Before the calls to CopyDeepMask, the foreground and background colours are set to black and
white respectively so that the results of the copying operation, in terms of colour, will be
predictable.

The for loop causes the source image to be copied to two locations in the window using a
different mask region and Boolean source mode for each copy.  The first time CopyDeepMask is
called, the oval-shaped region is passed in the maskRgn parameter and the source mode srcCopy
is passed in the mode parameter.  The second time CopyDeepMask is called, the round
rectangle-shaped region and srcOr are passed.

QDError checks for any error resulting from the last QuickDraw call (in this case,
CopyDeepMask).

In the clean-up, UnlockPixels unlocks the offscreen pixel image buffer, DisposeGWorld
deallocates all of the memory previously allocated for the offscreen graphics world, and the
memory allocated for the picture resources and regions is released.  Note that, because the
pictures are resources obtained via GetPicture, ReleaseResource, rather than KillPicture, is
used.

doPicture

doPicture demonstrates the recording and playing back of a picture.
Define Picture Rectangle and Set Clipping Region
The window's port rectangle is copied to a local Rect variable.  This rectangle is then made
equal to the left half of the port rectangle, and then inset by 10 pixels all round.  This is
the picture rectangle

The clipping region is then set to be the equivalent of this rectangle.  (Before this call, the
clipping region is very large.  In fact, it is as large as the coordinate plane.  If the
clipping region is very large and you scale a picture while drawing it, the clipping region can
become invalid when DrawPicture scales the clipping region - in which case the picture will not
be drawn.)
Set up OpenCPicParams Structure
This block assigns values to the fields of an OpenCPicParams structure.  These specify the
previously defined rectangle as the bounding rectangle, and 72 pixels per inch resolution both
horizontally and vertically.  The version field should always be set to -2.  
Record Picture
OpenCPicture initiates the recording of the picture definition.  The address of the
OpenCPicParams structure is passed in the newHeader parameter.

The picture is then drawn.  Lines, rectangles, round rectangles, ovals, wedges, and text are
drawn in random colours, and sizes.
Stop Recording, Draw Picture, Restore Saved Clipping Region
The call to ClosePicture terminates picture recording and the call to DrawPicture draws the
picture by "playing back" the "recording" stored in the specified Picture structure.

The call to SetClip restores the saved clipping region and DisposeRgn frees the memory
associated with the saved region.
Display Some Information From The Pictinfo Structure
The call to GetPictInfo  returns information about the picture in a picture information
structure.  Information in some of the fields of this structure is then drawn in the right side
of the window.
Release Memory Occupied By Picture Structure
The call to KillPicture releases the memory occupied by the Picture structure.

doCursor

doCursor's chief purpose is to assign true to the global variable gCursorRegionsActive, which
will cause the function doChangeCursor to be called from within the main event loop provided
the application is not in the background.  In addition, it draws some rectangles in the window
which visually represent to the user some cursor regions which will later be established by the
doChangeCursor function.

The last two lines sets the gCursorRegionsActive flag to true and create an empty region for
the last parameter of the WaitNextEvent call in the main event loop.  A reference to a cursor
region will be copied to gCursorRegion in the function doChangeCursor.

doChangeCursor

doChangeCursor is called whenever a mouse-moved event is received and after the window is
dragged.

The first four lines create new empty regions to serve as the regions within which the cursor
shape will be changed to, respectively, the arrow, I-beam, cross, and plus shapes.

The SetRectRgn call sets the arrow cursor region to, initially, the boundaries of the
coordinate plane.  The next five lines establish a rectangle equivalent to the window's port
rectangle and change this rectangle's coordinates from local to global coordinates so that the
regions calculated from it will be in the required global coordinates.  The call to InsetRect
insets this rectangle by 40 pixels all round and the call to RectRgn establishes this as the
I-beam region.  The call to DiffRgn, in effect, cuts the rectangle represented by the I-beam
region from the arrow region, leaving a hollow arrow region.

The next six lines use the same procedure to establish a rectangular hollow region for the
cross cursor and an interior rectangular region for the plus cursor.  The result of all this is
a rectangular plus cursor region in the centre of the window, surrounded by (but not overlapped
by) a hollow rectangular cross cursor region, this surrounded by (but not overlapped by) a
hollow rectangular I-beam cursor region, this surrounded by (but not overlapped by) a hollow
rectangular arrow cursor region the outside of which equates to the boundaries of the
coordinate plane.

The call to GetGlobalMouse gets the point, in global coordinates, representing the mouse's
current position.

The next task is to determine the region in which the cursor is currently located.  The calls
to PtInRgn are made for that purpose.  Depending on which region is established as the region
in which the cursor in currently located, the cursor is set to the appropriate shape and the
reference to that region is copied to the global variable passed in WaitNextEvent's mouseRgn
parameter.

That accomplished, the last four lines deallocate the memory associated with the regions
created earlier in the function.

doAnimatedCursor1

doAnimatedCursor1 responds to the user's selection of the Animated Cursor 1 item in the
Demonstration menu.

In this first animated cursor demonstration, the Appearance Manager function
SetAnimatedThemeCursor will be used in the function doIncrementAnimCursor to increment the
cursor frame.  As preparatory measures, an appropriate frame change tick interval is assigned
to gAnimCursTickInterval, the sleep parameter in the WaitNextEvent call is set to the same
value (causing null events to be generated at that tick interval), and gAnimCurs1Active is set
to true so that doIncrementAnimCursor will be called from the doIdle function.

doAnimatedCursor2

doAnimatedCursor2 responds to the user's selection of the Animated Cursor 2 item in the
Demonstration menu.

In this second animated cursor demonstration, functions are utilised to retrieve 'acur' and
'CURS' resources, animate the cursor, and deallocate the memory associated with the animated
cursor when the cursor is no longer required.  DoAnimatedCursor2's major role is simply to call
doGetAnimCursor with a "beach-ball" 'acur' resource as a parameter.

After the screen has been cleared, the resource ID of the "beach-ball" 'acur' resource is
assigned to the variable used as the first parameter in the later call to doGetAnimCursor.  The
next line assigns a value to the second parameter in the doGetAnimCursor call.  This value
controls the frame rate of the cursor, that is, the number of ticks which must elapse before
the next frame (cursor) is displayed.  (The best frame rate depends on the type of animated
cursor used.)

If the call to doGetAnimCursor is successful, the sleep parameter in the WaitNextEvent call is
set to the same ticks value as that used to control the cursor's frame rate (causing null
events to be generated at that tick interval), and the flag gAnimCurs2Active is set to true so
that doIncrementAnimCursor will be called from the doIdle function.

If the call to getAnimCursor fails, doAnimCursor simply plays the system alert sound and
returns.

doGetAnimCursor

doGetAnimCursor retrieves the data in the specified 'acur' resource and stores it in an
animCurs structure, retrieves the 'CURS' resources specified in the 'acur' resource and assigns
the reference s to the resulting Cursor structures to elements in an array in the animCurs
structure, establishes the frame rate for the cursor, and sets the starting frame number.

GetResource is called to read the 'acur' resource into memory and return a handle to the
resource.  The handle is cast to type animCursHandle and assigned to the global variable
gAnimCursHdl (a handle to a structure of type animCurs, which is identical to the structure of
an 'acur' resource).  If this call is not successful (that is, GetResource returns NULL), the
function will simply exit, returning false.  If the call is successful, noError is set to true
before a while loop is entered.  This loop will cycle once for each of the 'CURS' resources
specified in the 'acur' resource, assuming that noError is not set to false at some time during
this process.

The ID of each cursor is stored in the high word of the specified element of the frame[] field
of the animCurs structure.  This is retrieved.  The cursor ID is then used in the call to
GetCursor to read in the resource (if necessary) and assign the handle to the resulting 68-byte
Cursor structure to the specified element of the frame[] field of the animCurs structure.  If
this pass through the loop was successful, the array index is incremented; otherwise, noError
is set to false, causing the loop and the function to exit.

The first line within the if block assigns the ticks value passed to doGetAnimCursor to a
global variable that will be utilised in the function doIncrementAnimCursor.  The next line
assigns the number of ticks since system startup to another variable which will also be
utilised in the function doIncrementAnimCursor.  The third line sets the starting frame number.

At this stage, the animated cursor has been initialised and doIdle will call
doIncrementAnimCursor whenever null events are received.

doIncrementAnimCursor

doIncrementAnimCursor is called whenever null events are received.

The first line assigns the number of ticks since system startup to newTick.  The next line
checks whether the specified number of ticks have elapsed since the previous call to
doIncrementAnimCursor.  If the specified number of ticks have not elapsed, the function simply
returns.  Otherwise, the following occurs:

o If the first animated cursor demonstration is under way, the Appearance Manager function
  SetThemeAnimatedCursor is called to increment the theme-compliant cursor frame.

o If the second animated cursor demonstration is under way, SetCursor sets the cursor shape to
  that represented by the handle stored in the specified element of the frame[] field of the
  animCurs structure.  This line also increments the frame counter field (whichFrame) of the
  animCurs structure.  If whichFrame has been incremented to the last cursor in the series, the
  frame counter is re-set to 0.

The last line retrieves and stores the tick count at exit for use at the first line the next
time the function is called.

doReleaseAnimCursor

doReleaseAnimCursor deallocates the memory occupied by the Cursor structures and the 'acur'
resource.

Recall that doReleaseAnimCursor is called when the user clicks in the menu bar and that, at the
same time, the gAnimatedCursor1Active and gAnimatedCursor2Active flags are set to false, the
cursor is reset to the standard arrow shape, and WaitNextEvent's sleep parameter is reset to
the maximum possible value.

doAnimatedCursorOSX

doAnimatedCursorOSX utilises the function QDDisplayWaitCursor to turn the Mac OS X "spinning
wheel" cursor on and off.  This function is only available on OS X, so the stub library
CarbonFrameworkLib has been added to the CodeWarrior project.

doIcon

doIcon demonstrates the drawing of icons in a window using PlotIconID, PlotIconSuite, and
PlotCIcon.
PlotIconID With Transforms
This block uses the function PlotIconID to draw an icon from an icon family with the specified
ID fifteen times, once for each of the fifteen available transform types.  PlotIconID
automatically chooses the appropriate icon resource from the icon suite depending on the
specified destination rectangle and the bit depth of the current device.
GetIconSuite and PlotIconSuite
This block uses GetIconSuite to get an icon suite comprising only the 'ICN#', 'icl4', and
'icl8' resources from the icon family with the specified resource ID.  PlotIconSuite is then
called three times to draw the appropriate icon within destination rectangles of three
different sizes.  PlotIconSuite automatically chooses the appropriate icon resource from the
icon suite depending on the specified destination rectangle and the bit depth of the current
device.  PlotIconSuite also expands the icon to fit the last two destination rectangles.
GetCIcon and PlotCIcon
This block uses GetCIcon to load the specified 'cicn' resource and PlotCIcon to draw the colour
icon within destination rectangles of three different sizes.  PlotCIcon expands the 32 by 32
pixel icon to fit the last two destination rectangles.

doAboutDialog

doAboutDialog is called when the user chooses the About... item in the Apple menu.

GetNewDialog creates a modal dialog. The dialog's item list contains a picture item, which
fills the entire dialog window.

The call to ModalDialog means that the dialog will remain displayed until the user clicks
somewhere within the dialog, at which time DisposeDialog is called to dismiss the dialog and
free the associated memory.  A dialog rather than an alert is used to obviate the need for a
button for dismissing the dialog.
 
AAPL
$116.47
Apple Inc.
+0.16
MSFT
$47.98
Microsoft Corpora
-0.72
GOOG
$537.50
Google Inc.
+2.67

MacTech Search:
Community Search:

Software Updates via MacUpdate

Cobook 3.0.7 - Intelligent address book....
Cobook Contacts is an intuitive, engaging address book. Solve the problem of contact management with Cobook Contacts and its simple interface and powerful syncing and integration possibilities.... Read more
StatsBar 1.9 - Monitor system processes...
StatsBar gives you a comprehensive and detailed analysis of the following areas of your Mac: CPU usage Memory usage Disk usage Network and bandwidth usage Battery power and health (MacBooks only)... Read more
Cyberduck 4.6 - FTP and SFTP browser. (F...
Cyberduck is a robust FTP/FTP-TLS/SFTP browser for the Mac whose lack of visual clutter and cleverly intuitive features make it easy to use. Support for external editors and system technologies such... Read more
Maya 2015 - Professional 3D modeling and...
Maya is an award-winning software and powerful, integrated 3D modeling, animation, visual effects, and rendering solution. Because Maya is based on an open architecture, all your work can be scripted... Read more
Evernote 6.0.1 - Create searchable notes...
Evernote allows you to easily capture information in any environment using whatever device or platform you find most convenient, and makes this information accessible and searchable at anytime, from... Read more
calibre 2.11 - Complete e-library manage...
Calibre is a complete e-book library manager. Organize your collection, convert your books to multiple formats, and sync with all of your devices. Let Calibre be your multi-tasking digital... Read more
Herald 5.0.1 - Notification plugin for M...
Note: Versions 2.1.3 (for OS X 10.7), 3.0.6 (for OS X 10.8), and 4.0.8 (for OS X 10.9) are no longer supported by the developer. Herald is a notification plugin for Mail.app, Apple's Mac OS X email... Read more
Firetask 3.7 - Innovative task managemen...
Firetask uniquely combines the advantages of classical priority-and-due-date-based task management with GTD. Stay focused and on top of your commitments - Firetask's "Today" view shows all relevant... Read more
TechTool Pro 7.0.6 - Hard drive and syst...
TechTool Pro is now 7, and this is the most advanced version of the acclaimed Macintosh troubleshooting utility created in its 20-year history. Micromat has redeveloped TechTool Pro 7 to be fully 64... Read more
PhotoDesk 3.0.1 - Instagram client for p...
PhotoDesk lets you view, like, comment, and download Instagram pictures/videos! (NO Uploads! / Image Posting! Instagram forbids that! AND you *need* an *existing* Instagram account). But you can do... Read more

Latest Forum Discussions

See All

Ubisoft Gives Everyone Two New Ways to E...
Ubisoft Gives Everyone Two New Ways to Earn In-Game Stuff for Far Cry 4 Posted by Jessica Fisher on November 21st, 2014 [ permalink ] | Read more »
Golfinity – Tips, Tricks, Strategies, an...
Dig this: Would you like to know what we thought of being an infinite golfer? Check out our Golfinity review! Golfinity offers unlimited ways to test your skills at golf. Here are a few ways to make sure your score doesn’t get too high and your... | Read more »
Dark Hearts, The Sequel to Haunting Meli...
Dark Hearts, The Sequel to Haunting Melissa, is Available Now Posted by Jessica Fisher on November 21st, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Meowza! Toyze Brings Talking Tom to Life...
Meowza! | Read more »
Square Enix Announces New Tactical RPG f...
Square Enix Announces New Tactical RPG for Mobile, Heavenstrike Rivals. Posted by Jessica Fisher on November 21st, 2014 [ permalink ] With their epic stories and gorgeous graphics, | Read more »
Quest for Revenge (Games)
Quest for Revenge 1.0.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.0 (iTunes) Description: The great Kingdom of the west has fallen. The gods ignore the prayers of the desperate. A dark warlord has extinguished... | Read more »
Threadz is a New Writing Adventure for Y...
Threadz is a New Writing Adventure for You and Your Friends Posted by Jessica Fisher on November 21st, 2014 [ permalink ] In the tradition of round-robin storytelling, | Read more »
SteelSeries Stratus XL Hardware Review
Made by: SteelSeries Price: $59.99 Hardware/iOS Integration Rating: 4 out of 5 stars Usability Rating: 4.5 out of 5 stars Reuse Value Rating: 4.25 out of 5 stars Build Quality Rating: 4.5 out of 5 stars Overall Rating: 4.31 out of 5 stars | Read more »
ACDSee (Photography)
ACDSee 1.0.0 Device: iOS iPhone Category: Photography Price: $1.99, Version: 1.0.0 (iTunes) Description: Capture, perfect, and share your photos with ACDSee. The ACDSee iPhone app combines an innovative camera, a powerful photo... | Read more »
ProTube for YouTube (Entertainment)
ProTube for YouTube 2.0.2 Device: iOS Universal Category: Entertainment Price: $1.99, Version: 2.0.2 (iTunes) Description: ProTube is the ultimate, fully featured YouTube app. With it's highly polished design, ProTube offers ad-free... | Read more »

Price Scanner via MacPrices.net

15″ 2.2GHz Retina MacBook Pro on sale for $17...
 B&H Photo has the 2014 15″ 2.2GHz Retina MacBook Pro on sale today for $1749. Shipping is free, and B&H charges NY sales tax only. B&H will also include free copies of Parallels Desktop... Read more
27-inch 3.5GHz 5K iMac in stock today and on...
 B&H Photo has the new 27″ 3.5GHz 5K iMac in stock today and on sale for $2299 including free shipping plus NY sales tax only. Their price is $200 off MSRP, and it’s the lowest price available... Read more
21-inch 1.4GHz iMac on sale for $979, save $1...
B&H Photo has the new 21″ 1.4GHz iMac on sale for $979.99 including free shipping plus NY sales tax only. Their price is $120 off MSRP. B&H will also include free copies of Parallels Desktop... Read more
13-inch 1.4GHz/256GB MacBook Air on sale for...
B&H Photo has lowered their price on the 13″ 1.4GHz/256GB MacBook Air to $1059.99 including free shipping plus NY sales tax only. Their price is $140 off MSRP, and it’s the lowest price for this... Read more
Save up to $400 with Apple refurbished 2014 1...
The Apple Store has restocked Apple Certified Refurbished 2014 15″ Retina MacBook Pros for up to $400 off the cost of new models. An Apple one-year warranty is included with each model, and shipping... Read more
New 13-inch 1.4GHz MacBook Air on sale for $8...
 Adorama has the 2014 13″ 1.4GHz/128GB MacBook Air on sale for $899.99 including free shipping plus NY & NJ tax only. Their price is $100 off MSRP. B&H Photo has the 13″ 1.4GHz/128GB MacBook... Read more
Apple Expected to Reverse Nine-Month Tablet S...
Apple and Samsung combined accounted for 62 percent of the nearly 36 million branded tablets shipped in 3Q 2014, according to early vendor shipment share estimates from market intelligence firm ABI... Read more
Stratos: 30 Percent of US Smartphone Owners t...
Stratos, Inc., creator of the Bluetooth Connected Card Platform, has announced results from its 2014 Holiday Mobile Payments Survey. The consumer survey found that nearly one out of three (30 percent... Read more
2014 1.4GHz Mac mini on sale for $449, save $...
 B&H Photo has lowered their price on the new 1.4GHz Mac mini to $449.99 including free shipping plus NY tax only. Their price is $50 off MSRP, and it’s the lowest price available for this new... Read more
Check Apple prices on any device with the iTr...
MacPrices is proud to offer readers a free iOS app (iPhones, iPads, & iPod touch) and Android app (Google Play and Amazon App Store) called iTracx, which allows you to glance at today’s lowest... Read more

Jobs Board

*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
*Apple* Solutions Consultant (ASC)- Retail S...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
Project Manager, *Apple* Financial Services...
**Job Summary** Apple Financial Services (AFS) offers consumers, businesses and educational institutions ways to finance Apple purchases. We work with national and Read more
*Apple* Store Leader Program - College Gradu...
Job Description: Job Summary As an Apple Store Leader Program agent, you can continue your education as you major in the art of leadership at the Apple Store. You'll Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.