home *** CD-ROM | disk | FTP | other *** search
Text File | 1989-01-11 | 46.1 KB | 1,658 lines | [TEXT/MPS ] |
- (*--------------------------------------------------------------------------+
- | |
- | Spinning Globe Graphics Demo |
- | |
- | GlobeFrames (bitmaps) from an unsuspecting Sun 3 |
- | |
- | Copyright (C) 1987, 1988 Paul Mercer |
- | All rights reserved |
- | Non-commercial distribution only |
- | |
- | Created: pm 05/24/87 new today |
- | Modified: pm 06/03/87 v1.0 release |
- | pm 06/19/87 v1.1 fixed shading bug in mono pixmaps |
- | use pixmaps only if depth > 1 |
- | pm 06/30/87 v1.2 works around Juggler b2 bug with |
- | video slot VBL task switching |
- | pm 01/28/88 v1.3 revved for MPW 3.0D3, misc changes |
- | pm 03/06/88 v1.4 added support for lsr's round WDEF, |
- | rolled 'GlobeFrames64' file into app, |
- | now boots in background, fixed a5 |
- | bug under Juggler, all user settings |
- | are now saved along with window |
- | position |
- | pm 06/18/88 v1.41 now with 'improved' slot VBLs' |
- | pm 12/26/88 v1.5 added PICT resources, imaging to target |
- | window device; tweaked alignment; |
- | improved shading; fixed cursors; |
- | added palette, Palette Mgr. support; |
- | plus lots more changes; |
- | thanx to Bruce and Darin |
- | |
- | Globe was written as an exercise in learning Color QuickDraw. |
- | The goal was to write a decent demo completely in Pascal using |
- | only Apple documented and approved techniques. A bit of assembler |
- | was neccessitated by the need to do VBL synchronization on the |
- | Macintosh II. There is also a bit of experimentation with Juggler. |
- | Globe's heavy CPU usage makes it useful for investigating |
- | QuickDraw (CopyBits) performance under different conditions such as |
- | window placement and clipping. The sadistic will no doubt change |
- | the depth of the screen at runtime to watch QuickDraw sweat. |
- | |
- | Special thanx to Larry Rosenstein for the round WDEF. |
- | |
- | Things worth investigating include: |
- | - this code is a mess!! |
- | - add dithered transfer mode option for Full Color QuickDraw |
- | + convert the data files to PICTs to give PackBits some work |
- | + improve shading by stealing system colors (palette manager) |
- | + improve shading by checking for higher resolution/depth devices |
- | ╨ be smart about bit depth changes (window moving, control panel) |
- | ╨ regeneration of pixmaps to match changing screen depth |
- | ╨ use temporary memory calls |
- | ╨ speed up CopyBits when shading and blitting (how?) |
- | ╨ anti-alias the pixmaps (scale down big bitmaps) |
- | ╨ improve resolution by using more frames |
- | ╨ alleviate timing interaction while being juggled |
- | |
- | Please send your enhnancements, comments and/or questions to: |
- | Paul Mercer |
- | P.O. Box 160165 |
- | Cupertino, CA 95016-0165 |
- | |
- | If you really like this program (and/or this source), |
- | please send $10 to your favorite charity. |
- | |
- | AppleLink: MERCER1 |
- | UUCP: {nsc,dual,sun}!apple!pmercer |
- | MCI: SOL |
- | |
- +--------------------------------------------------------------------------*)
-
- PROGRAM Globe;
-
- USES
- MemTypes, QuickDraw, Palettes, OSIntf, ToolIntf, MacPrint, PackIntf, CursorCtl;
-
- {$R-} {$OV-} {we don't need no stinkin' range or overflow checking}
- {$D+} { cuz we've got TMON/MacsBug}
-
- CONST
- {$SETC Debug := True}
-
- {System stuff}
- WaitNextEventTrap = $60;
- SlotVInstallTrap = $6f;
- UnImplentedTrap = $9f;
- PaintWhite = $9dc; {window manager white erase}
- Ticks = $16a; {tick counter in low mem}
- {$IFC Debug}
- MonkeyLives = $100;
- {$ENDC}
- kOptionKeyCode = 58;
- CurAppName = $910;
- CurApRefNum = $900;
- GrayRgn = $9ee;
-
- {Program stuff}
- dataID = 128;
-
- {Resource IDs}
- kFirstPICT = 128; {PICT}
- kPalette = 256; {pltt}
-
- appleID = 128; {MENU}
- fileID = 129;
- editID = 130;
- controlID = 131;
-
- loadingID = 128; {DLOG}
- coloringID = 129;
- noMemoryID = 130;
- ioErrorID = 131;
- aboutID = 132;
- kOK = 1; {ok button}
-
- rectID = 128; {WIND}
- roundID = 129;
-
- {Menu stuff}
- appleM = 1; {menu handle array indices}
- fileM = 2;
- editM = 3;
- controlM = 4;
- menuCount = 4;
-
- aboutCommand = 1; {Apple menu commands}
-
- closeCommand = 1; {File}
- quitCommand = 3;
-
- undoCommand = 1; {Edit}
- cutCommand = 3;
- copyCommand = 4;
- pasteCommand = 5;
- clearCommand = 6;
-
- slowerCommand = 1; {Control}
- stepCommand = 2;
- fasterCommand = 3;
- syncCommand = 5;
- alignCommand = 7;
- timeCommand = 9;
- roundCommand = 10;
- paletteCommand = 12;
-
- TYPE
- LongIntPtr = ^LongInt; {for accessing Ticks in WaitVBL}
- IntegerPtr = ^Integer;
- BooleanPtr = ^Boolean; {for accessing PaintWhite in Initialize}
- BitMapPtr = ^BitMap; {for type coercion in CopyBits}
- RgnHandlePtr = ^RgnHandle; {for getting at GrayRgn in bounds checking}
- Str31Ptr = ^Str31;
-
- DataRec = RECORD {Data resource format}
- width: Integer; {bitmap width}
- height: Integer; {bitmap height}
- count: Integer; {frame count including mask}
- sync: Integer; {0/1 VBL syncing}
- round: Integer; {0/1 round window}
- time: Integer; {0/1 frames/sec display}
- top: Integer; {window position}
- left: Integer;
- speed: Integer; {speed}
- palette: Integer; {use custom palette}
- END; {DataRec}
-
-
- VAR
- {$Z+} {exported for assembler access}
- parisTicks: LongInt; {main video device tick count on Mac II}
- {$Z-}
-
- appRefNum: Integer; {refNum of the application's resource fork}
- frameFile: Str255;
- myData: DataRec; {config structure stored in as resource in data file}
- frameWidth,
- frameHeight,
- frameCount: Integer;
- border: Integer; {border of gray space}
- windLeft,
- windTop: Integer; {saved default window position}
-
- curFrame, {current frame (2 - frameCount)}
- speed, {frame advance delay or yieldtime w/ Juggler}
- delayCount: Integer; {count remaining to delay}
- syncVBL, {sync to vbl command switch}
- displayTime, {display frames/sec command switch}
- roundWindow, {using Larry's round WDEF}
- usePalette, {using green and blue ramped palette}
- doneFlag: Boolean; {MEL quit flag}
-
- timeRect: Rect; {rect for drawing frames/sec}
- framesDone: Integer; {frames/sec display vars}
- targTime: LongInt; {time to target 'next second' used to write frames/sec}
-
- frameSize: LongInt; {size of frame bitmap}
- frameBounds, {rect of source frame}
- destBounds: Rect; {centered dest rect}
- pixDepth: Integer; {depth of PixMap}
- bitMaps: ARRAY[0..100] OF BitMap; {the bitmaps themselves ***cheezewhiz}
- pixMaps: ARRAY[0..100] OF PixMapHandle; {handles to pixmaps for cqd}
- { 0 = scratch, 1 = mask, 2 - frameCount = bitmaps}
- bigPixBlock: Ptr; {pointer to big pixmap bit data}
-
- theWorld: SysEnvRec; {the world according to SysEnvirons}
- usePixMaps, {use pixel maps on screens deeper than 1 b/p}
- useColor, {only use color if 4 or more 4 bits/pix}
- useShading, {shade only if 8 or more bits/pix}
- juggler: Boolean; {twitcher lives flag}
- slotVBL: Boolean; {has slot interrupts}
-
- landColor, {pretty colors}
- waterColor,
- spaceColor,
- shadeColor,
- myForeColor,
- myBackColor: RGBColor;
- myColors: CTabHandle; {my color table}
-
- dragRect: Rect; {rectangle used to mark bounds for dragging window}
- myMenus: ARRAY [1..menuCount] OF MenuHandle; {array of handles to the menus}
- myWindow: WindowPtr;
- myPal: PaletteHandle;
- myEvent: EventRecord; {information about an event}
-
-
- PROCEDURE _DataInit; EXTERNAL;
- PROCEDURE InstallVBLSync; EXTERNAL;
- PROCEDURE RemoveVBLSync; EXTERNAL;
- PROCEDURE AlignWindow; FORWARD; {used by Initialize}
- PROCEDURE UpdateWindow; FORWARD; {used by DrawFrame}
- PROCEDURE GetDefaults; FORWARD;
- PROCEDURE SaveDefaults; FORWARD;
- PROCEDURE ChangeWindow; FORWARD;
- PROCEDURE ChangePalette; FORWARD;
- FUNCTION GetMyDevice: GDHandle; FORWARD;
- FUNCTION GetMyDialog(id: Integer): DialogPtr; FORWARD;
-
- {$S Initialize} {this segment is dumped after initialization}
-
- {+--------------------------------------------------------------------------+
- | simplistic fatal error handler with nice centering |
- +--------------------------------------------------------------------------+}
- PROCEDURE FatalError(id: Integer);
-
- VAR
- deviceRect: Rect;
- width: Integer;
- theDialog: DialogPtr;
- iType: Integer;
- iHandle: Handle;
- iBox: Rect;
-
- BEGIN
- SetCursor(arrow);
- {open this window on the target device so the Palette Manager gets
- to set the clut up properly for the offscreen pixmaps }
- theDialog := GetNewDialog(id, Nil, WindowPtr( -1));
- deviceRect := GetMyDevice^^.gdRect;
- width := theDialog^.portRect.right - theDialog^.portRect.left;
- MoveWindow(theDialog, (((deviceRect.right - deviceRect.left) - width) DIV 2) + deviceRect.left,
- deviceRect.top + ((deviceRect.bottom - deviceRect.top) DIV 6), False);
- ShowWindow(theDialog);
-
- GetDItem(theDialog, kOK, iType, iHandle, iBox);
- SetPort(theDialog);
- BeginUpdate(theDialog);
- DrawDialog(theDialog);
- PenSize(3, 3);
- InsetRect(iBox, -4, -4);
- FrameRoundRect(iBox, 16, 16);
- EndUpdate(theDialog);
-
- SysBeep(10);
- ModalDialog(Nil, width);
-
- ExitToShell;
- END; {FatalError}
-
-
- {+--------------------------------------------------------------------------+
- | is the trap available? |
- +--------------------------------------------------------------------------+}
- FUNCTION TrapExist(t: Integer): Boolean;
-
- BEGIN
- IF GetTrapAddress(t) <> GetTrapAddress(UnImplentedTrap) THEN
- TrapExist := True
- ELSE
- TrapExist := False;
- END; {TrapExist}
-
- FUNCTION NewOSTrapExist(t: Integer): Boolean;
-
- BEGIN
- IF NGetTrapAddress(t, OSTrap) <> GetTrapAddress(UnImplentedTrap) THEN
- NewOSTrapExist := True
- ELSE
- NewOSTrapExist := False;
- END; {NewOSTrapExist}
-
-
- {+--------------------------------------------------------------------------+
- | return a RGBColor record |
- +--------------------------------------------------------------------------+}
- FUNCTION MakeRGBColor(r, g, b: Integer): RGBColor;
-
- VAR
- color: RGBColor;
-
- BEGIN
- WITH color DO
- BEGIN
- red := r;
- green := g;
- blue := b;
- END;
- MakeRGBColor := color;
- END; {MakeRGBColor}
-
-
- {+--------------------------------------------------------------------------+
- | Get a 'STR ' Resource |
- +--------------------------------------------------------------------------+}
- FUNCTION GetSTR(theID: Integer): Str255;
-
- VAR
- aHandle: Handle;
- s: Str255;
-
- BEGIN
- aHandle := GetResource('STR ', theID);
- HLock(aHandle);
- BlockMove(aHandle^, @s, SizeResource(aHandle));
- HUnlock(aHandle);
- ReleaseResource(aHandle);
- GetSTR := s;
- END; {GetSTR}
-
-
- {+--------------------------------------------------------------------------+
- | give time to other apps and handle updates of 'loading' dialog |
- +--------------------------------------------------------------------------+}
- PROCEDURE BeNiceToJuggler;
-
- VAR
- savePort: GrafPtr;
- w: WindowPtr;
-
- BEGIN
- IF GetNextEvent(everyEvent, myEvent) THEN
- IF myEvent.what = updateEvt THEN
- BEGIN
- w := FrontWindow;
- GetPort(savePort);
- SetPort(w);
- BeginUpdate(w);
- UpdtDialog(w, w^.visRgn);
- EndUpdate(w);
- SetPort(savePort);
- END;
- END; {BeNiceToJuggler}
-
-
- {+------------------------------------------------------------------------+
- | load frames off disk |
- +------------------------------------------------------------------------+}
- PROCEDURE LoadFrames;
-
- VAR
- i, j, refNum: Integer;
- dataForkSize: longint;
- myPort: GrafPort;
- oldResource: Handle;
- myPICT: PicHandle;
-
- PROCEDURE IOError(err: OSErr);
-
- BEGIN
- IF err <> noErr THEN
- BEGIN
- i := FSClose(refNum); {close file, just in case}
- FatalError(ioErrorID);
- END;
- END; {IOError}
-
- BEGIN
- IOError(FSOpen(frameFile, 0, refNum));
- IOError(GetEOF(refNum, dataForkSize));
-
- IF dataForkSize <> 0 THEN
- FOR i := 1 TO frameCount DO
- BEGIN
- IOError(FSRead(refNum, frameSize, bitMaps[i].baseAddr));
- BeNiceToJuggler;
- SpinCursor(32); {spin my beachball}
- END;
-
- IOError(SetEOF(refNum, 0)); {truncate the data file}
- IOError(FSClose(refNum));
-
- OpenPort(@myPort);
- refNum := OpenResFile(frameFile);
- UseResFile(refNum);
-
- j := 1;
- IF dataForkSize = 0 THEN
- FOR i := 1 TO frameCount DO
- BEGIN
- REPEAT {this little ditty allows for sparse PICT numbering}
- myPict := PicHandle(Get1Resource('PICT', kFirstPICT + j - 1));
- IF myPICT = Nil THEN
- j := j + 1;
- UNTIL ((myPict <> Nil) OR (j = 1000));
-
- j := j + 1;
- SetPortBits(bitMaps[i]);
- myPort.portRect := bitMaps[i].bounds;
- EraseRect(thePort^.portRect);
- DrawPicture(myPICT, thePort^.portRect);
- BeNiceToJuggler;
- SpinCursor(32); {spin my beachball}
- END
- ELSE
- FOR i := 1 TO frameCount DO
- BEGIN
- ClipRect(bitMaps[i].bounds);
- myPict := OpenPicture(bitMaps[i].bounds);
- CopyBits(bitMaps[i], thePort^.portBits, bitMaps[i].bounds, bitMaps[i].bounds, srcCopy, nil);
- ClosePicture;
-
- REPEAT
- SetResLoad(False);
- oldResource := Get1Resource('PICT', kFirstPICT + i - 1);
- SetResLoad(True);
- RmveResource(oldResource);
- DisposHandle(oldResource);
- UNTIL oldResource = Nil;
-
- AddResource(Handle(myPICT), 'PICT', kFirstPICT + i - 1, '');
- SetResAttrs(Handle(myPICT), resPurgeable + resChanged);
-
- BeNiceToJuggler;
- SpinCursor(32); {spin my beachball}
- END;
-
- UpdateResFile(refNum);
- IF refNum <> appRefNum THEN
- CloseResFile(refNum);
- END; {LoadFrames}
-
-
- {+--------------------------------------------------------------------------+
- | process mono bitmaps |
- +--------------------------------------------------------------------------+}
- PROCEDURE ProcessBitMaps;
-
- VAR
- tPort: GrafPort;
- i: Integer;
-
- BEGIN
- OpenPort(@tPort);
- SetPortBits(bitMaps[0]); {scratch map}
- PenPat(ltGray);
- PaintRect(frameBounds);
- ClosePort(@tPort);
-
- CopyBits(bitMaps[0], bitMaps[1], frameBounds, frameBounds, notSrcBic, Nil);
- FOR i := 2 TO frameCount DO
- BEGIN
- CopyBits(bitMaps[1], bitMaps[i], frameBounds, frameBounds, srcOr, Nil);
- BeNiceToJuggler;
- SpinCursor(32);
- END;
- END; {ProcessBitMaps}
-
-
- {+--------------------------------------------------------------------------+
- | process mono bitmaps into pixmaps and color them if appropriate |
- +--------------------------------------------------------------------------+}
- PROCEDURE ProcessPixMaps;
-
- CONST
- kShadeRange = $0e000; {from white-kEdgeShade}
- kEdgeShade = $01fff;
-
- VAR
- i, j, k: Integer;
- tRect: Rect;
- tCPort: CGrafPort;
- tHandle: PixMapHandle;
- shadePat: PixPatHandle;
- shadeStep, shade: Fixed;
- bigNum: LongInt;
- saveGDevice: GDHandle;
-
- BEGIN
- saveGDevice := GetGDevice;
- SetGDevice(GetMyDevice); {make sure we╒re on the target device}
- ChangePalette; {for 5 bit inverse table to be built/current}
-
- OpenCPort(@tCPort); {open this port so we can change colors}
- tHandle := tCPort.portPixMap; {save portPixMap since it's going to change}
-
- {copy bitMaps to pixMaps and let CopyBits color them in the process}
- IF useColor THEN
- BEGIN
- RGBForeColor(landColor);
- RGBBackColor(waterColor);
- END
- ELSE
- BEGIN
- RGBForeColor(myForeColor); {black and white only for 2 bits/pixel}
- RGBBackColor(myBackColor);
- END;
- FOR i := 1 To frameCount DO
- BEGIN
- CopyBits(bitMaps[i], BitMapPtr(pixMaps[i]^)^,
- frameBounds, frameBounds, srcCopy, Nil);
- BeNiceToJuggler;
- SpinCursor(32);
- END;
-
- {logically or the mask over (around) globe for background}
- RGBForeColor(spaceColor); {always try for gray}
- FOR i := 2 To frameCount DO
- BEGIN
- CopyBits(bitMaps[1], BitMapPtr(pixMaps[i]^)^, {***quicker to use pixmaps only?}
- frameBounds, frameBounds, srcOr, Nil);
- BeNiceToJuggler;
- SpinCursor(32);
- END;
-
- {shade it nicely}
- IF useShading THEN
- BEGIN
- SetPortPix(pixMaps[0]);
- RGBBackColor(myBackColor);
- EraseRect(frameBounds);
- RGBForeColor(shadeColor);
- PenMode(addOver); {smear the shades}
-
- {$IFC True}
- {draw shaded gray sphere}
- bigNum := kShadeRange * $1000;
- shadeStep := bigNum DIV (frameWidth DIV 2) * $10;
- shade := kEdgeShade * $10000;
- PenSize(1, 1);
- tRect := frameBounds;
- PenMode(srcCopy);
- FOR i := (frameWidth DIV 2) DOWNTO 1 DO {this many shades}
- BEGIN
- shadeColor := MakeRGBColor(FixRound(shade), FixRound(shade), FixRound(shade));
- RGBForeColor(shadeColor);
- shade := shade + shadeStep;
- FrameOval(tRect);
- InsetRect(tRect, 1, 1);
- BeNiceToJuggler;
- SpinCursor(32);
- END;
- {$ELSEC} {old drawing before Bruce changed the world}
- {draw shaded gray sphere}
- j := frameBounds.bottom DIV (16 * 2); {pen size}
- FOR i := 1 TO 16 - 4 DO {this many shades}
- BEGIN
- k := i * j;
- PenSize(k, k);
- FrameOval(frameBounds);
- BeNiceToJuggler;
- SpinCursor(32);
- END;
- {$ENDC}
-
- {apply the shaded sphere to the frames}
- FOR i := 2 TO frameCount DO
- BEGIN
- CopyBits(BitMapPtr(pixMaps[0]^)^, BitMapPtr(pixMaps[i]^)^,
- frameBounds, frameBounds, addMin, Nil);
- BeNiceToJuggler;
- SpinCursor(32);
- END;
- END; {IF useShading}
-
- SetPortPix(tHandle); {restore portPixMap for killing}
- ClosePort(GrafPtr(@tCPort)); {dispose its structures}
- SetGDevice(saveGDevice);
- END; {ProcessPixMaps}
-
-
- {+--------------------------------------------------------------------------+
- | initialize the frame globals |
- +--------------------------------------------------------------------------+}
- PROCEDURE InitFrameGlobals;
-
- VAR
- i, j: Integer;
- saveGDevice,
- myDevice: GDHandle;
-
- BEGIN
- frameBounds.top := 0;
- frameBounds.left := 0;
- frameBounds.bottom := frameHeight;
- frameBounds.right := frameWidth;
-
- {allocate the bitmaps}
- FOR i := 0 to frameCount DO
- BEGIN
- bitMaps[i].rowBytes := frameWidth DIV 8;
- bitMaps[i].bounds := frameBounds;
- bitMaps[i].baseAddr := NewPtr(frameSize);
- SpinCursor(32);
- IF bitMaps[i].baseAddr = Nil THEN
- FatalError(noMemoryID);
- END;
-
- {allocate the pixmaps}
- IF usePixMaps THEN
- BEGIN
- {clone the main device's color table for the pixMaps (tech note 120)}
- myDevice := GetMyDevice;
- myColors := myDevice^^.gdPMap^^.pmTable; {get the color table}
- j := HandToHand(Handle(myColors)); { and clone it}
- {now convert from device color table to screen color table - thanx DG}
- WITH myColors^^ DO
- BEGIN
- FOR i := 0 TO ctSize DO
- ctTable[i].value := i; {put in indices}
- {now clear the high bit of ctFlags to indicate it's a screen color table}
- ctFlags := BAND(ctFlags, $7fff);
- END; {WITH}
-
- bigPixBlock := NewPtr(frameSize * pixDepth * (frameCount + 1));
- IF bigPixBlock = Nil THEN
- FatalError(noMemoryID);
-
- saveGDevice := GetGDevice;
- SetGDevice(myDevice);
- FOR i := 0 to frameCount DO
- BEGIN
- pixMaps[i] := NewPixMap;
- pixMaps[i]^^.pmTable := myColors; {use my color table ***kill old color}
- pixMaps[i]^^.baseAddr := Ptr(ORD4(bigPixBlock) + (i * frameSize * pixDepth));
- pixMaps[i]^^.rowBytes := (frameWidth DIV 8) * pixDepth + $8000;
- pixMaps[i]^^.bounds := frameBounds;
- END;
- SetGDevice(saveGDevice);
- END; {IF usePixMaps}
-
- END; {InitFrameGlobals}
-
-
- {+--------------------------------------------------------------------------+
- | high level initializtion |
- +--------------------------------------------------------------------------+}
- PROCEDURE InitFrames;
-
- VAR
- savePort: GrafPtr;
- theDialog: DialogPtr;
- dID: Integer;
-
- BEGIN
- {open this window on the target device so the Palette Manager gets
- to set the clut up properly for the offscreen pixmaps }
- IF useShading THEN
- dID := coloringID
- ELSE
- dID := loadingID;
-
- theDialog := GetMyDialog(dID);
-
- GetPort(savePort); {process the bitmap data appropriately}
- InitFrameGlobals; {initialize frame data structures}
- LoadFrames; {load the bitmaps}
-
- IF usePixMaps THEN
- ProcessPixMaps
- ELSE
- ProcessBitMaps;
- SetPort(savePort);
-
- DisposDialog(theDialog);
- END; {InitFrames}
-
-
- {+--------------------------------------------------------------------------+
- | initialize applicaton globals |
- +--------------------------------------------------------------------------+}
- PROCEDURE InitGlobals;
-
- VAR
- i, j: Integer;
- tGDevice: GDHandle;
- refNum: Integer;
- tHandle: Handle;
- numFiles: Integer;
- message: Integer;
- document: AppFile;
- myName: Str31Ptr;
- appRefPtr: IntegerPtr;
-
- BEGIN
- IF SysEnvirons(1, theWorld) <> noErr THEN
- BEGIN
- SysBeep(5);
- SysBeep(5);
- SysBeep(5);
- ExitToShell; {everyone should use the latest system software!}
- END;
-
- myWindow := Nil;
- appRefPtr := IntegerPtr(CurApRefNum);
- appRefNum := appRefPtr^;
-
- IF TrapExist(WaitNextEventTrap) THEN
- juggler := True
- ELSE
- juggler := False;
-
- IF NewOSTrapExist(SlotVInstallTrap) THEN
- slotVBL := True
- ELSE
- slotVBL := False;
-
- CountAppFiles(message, numfiles); {get Finder info}
- IF numFiles = 0 THEN
- BEGIN
- myName := Str31Ptr(CurAppName);
- frameFile := myName^;
- END
- ELSE
- BEGIN
- GetAppFiles(1, document);
- frameFile := document.fName;
- IF SetVol(Nil, document.vRefNum) <> noErr THEN
- FatalError(ioErrorID);
- END;
-
- GetDefaults;
-
- IF theWorld.hasColorQD THEN
- BEGIN
- tGDevice := GetMyDevice;
- pixDepth := tGDevice^^.GDPMap^^.pixelSize;
- usePixMaps := pixDepth > 1;
- useColor := pixDepth >= 4;
- useShading := pixDepth >= 8;
- END
- ELSE
- BEGIN
- usePixMaps := False;
- useColor := False;
- pixDepth := 1;
- END;
-
- frameSize := (frameWidth DIV 8) * frameHeight;
- doneFlag := False;
- curFrame := 2;
- targTime := 0;
- framesDone := 0;
-
- WITH screenBits.bounds DO
- SetRect(dragRect, 4, 24, right - 4, bottom - 4);
-
- shadeColor := MakeRGBColor($1fff, $1fff, $1fff); {light gray for additive shading}
- landColor := MakeRGBColor(0, -1, 0); {green continents}
- waterColor := MakeRGBColor(0, 0, -1); {blue oceans}
- spaceColor := MakeRGBColor($1fff, $1fff, $1fff); {a bit lighter than neutral gray}
- myForeColor := MakeRGBColor(0, 0, 0); {black}
- myBackColor := MakeRGBColor(-1, -1, -1); {white}
-
- myPal := GetNewPalette(kPalette);
- END; {InitGlobals}
-
-
- {+--------------------------------------------------------------------------+
- | set up menus and draw menubar |
- +--------------------------------------------------------------------------+}
- PROCEDURE SetUpMenus;
-
- VAR
- i: Integer;
-
- BEGIN
- myMenus[appleM] := GetMenu(appleID);
- AddResMenu(myMenus[appleM], 'DRVR');
- myMenus[fileM] := GetMenu(fileID);
- myMenus[editM] := GetMenu(editID);
- myMenus[controlM] := GetMenu(controlID);
-
- FOR i := 1 TO menuCount DO
- InsertMenu(myMenus[i], 0);
- DrawMenuBar;
- END; {SetUpMenus}
-
-
- {+--------------------------------------------------------------------------+
- | program initialization |
- +--------------------------------------------------------------------------+}
- PROCEDURE Initialize;
-
- VAR
- x: LongInt;
- b: Boolean;
-
- BEGIN
- InitGraf(@thePort);
- InitFonts;
- FlushEvents(everyEvent, 0);
- InitWindows;
- InitMenus;
- TEInit;
- InitDialogs(Nil);
- InitCursor;
- InitCursorCtl(Nil); {bring in acur resource now}
- SetCursor(GetCursor(watchCursor)^^);
-
- InitGlobals; {initialize my globals}
- SetUpMenus; {set up menus and menu bar}
- b := GetNextEvent(everyEvent, myEvent); {***juggler hacking so windows show up on top}
- ChangePalette; {bring up palette (if option on) }
- InitFrames; {load and process frames}
- IF slotVBL THEN
- InstallVBLSync; {install custom VBL task if possible, do this last}
- Delay(30, x); {wait a bit for the load dialog to go away}
- ChangeWindow; {bring up the window invisibly}
- ShowWindow(myWindow);
- END; {Initialize}
-
-
- {+--------------------------------------------------------------------------+
- | return default top,left coords taking into account window type |
- +--------------------------------------------------------------------------+}
- PROCEDURE DefaultWindow(VAR left, top: Integer);
-
- BEGIN
- IF roundWindow THEN
- BEGIN
- top := 64;
- left := 64;
- END
- ELSE
- BEGIN
- top := 64 - 16; {account for window border}
- left := 64 - 16;
- END;
- END; {DefaultWindow}
-
-
- {+--------------------------------------------------------------------------+
- | get defaults |
- +--------------------------------------------------------------------------+}
- PROCEDURE GetDefaults;
-
- VAR
- refNum: Integer;
- tHandle: Handle;
-
- BEGIN
- refNum := OpenResFile(frameFile);
- IF refNum = -1 THEN
- FatalError(ioErrorID);
- tHandle := GetResource('Data', dataID);
- BlockMove(tHandle^, @myData, SIZEOF(dataRec));
- IF SizeResource(tHandle) <> SIZEOF(dataRec) THEN
- BEGIN
- SetHandleSize(tHandle, SIZEOF(dataRec));
- ChangedResource(tHandle);
- DefaultWindow(myData.left, myData.top);
- myData.speed := 0;
- myData.palette := 0;
- END;
-
- IF refNum <> appRefNum THEN
- CloseResFile(refNum);
-
- WITH myData DO
- BEGIN
- frameWidth := width;
- frameHeight := width;
- frameCount := count;
- syncVBL := sync = 1;
- displayTime := time = 1;
- roundWindow := round = 1;
- usePalette := palette = 1;
- windTop := top;
- windLeft := left;
- END; {WITH}
- speed := myData.speed;
- delayCount := speed;
- END; {GetDefaults}
-
-
- {$S Main} {normal stuff goes here}
-
- {+--------------------------------------------------------------------------+
- | is the Option key being held down? |
- +--------------------------------------------------------------------------+}
- FUNCTION CheckOptionKey: Boolean;
-
- VAR
- keys: KeyMap;
-
- BEGIN
- GetKeys(keys);
- CheckOptionKey := keys[kOptionKeyCode];
- END; {CheckOptionKey}
-
-
- {+--------------------------------------------------------------------------+
- | return the max device the globe window is in |
- +--------------------------------------------------------------------------+}
- FUNCTION GetMyDevice: GDHandle;
-
- VAR
- windowRect: Rect;
-
- BEGIN
- IF myWindow <> Nil THEN
- BEGIN
- windowRect := myWindow^.portRect;
- LocalToGlobal(windowRect.topLeft);
- LocalToGlobal(windowRect.botRight);
- END
- ELSE
- SetRect(windowRect, windLeft, windTop, windLeft + frameWidth, windTop + frameHeight);
- GetMyDevice := GetMaxDevice(windowRect);
- END; {GetMyDevice}
-
-
- {+--------------------------------------------------------------------------+
- | bring up a dialog centered on the target device |
- +--------------------------------------------------------------------------+}
- FUNCTION GetMyDialog(id: Integer): DialogPtr;
-
- VAR
- deviceRect: Rect;
- width: Integer;
- theDialog: DialogPtr;
-
- BEGIN
- SetCursor(arrow);
- theDialog := GetNewDialog(id, Nil, WindowPtr( -1));
- deviceRect := GetMyDevice^^.gdRect;
- width := theDialog^.portRect.right - theDialog^.portRect.left;
- MoveWindow(theDialog, (((deviceRect.right - deviceRect.left) - width) DIV 2) + deviceRect.left,
- deviceRect.top + ((deviceRect.bottom - deviceRect.top) DIV 6), False);
- ShowWindow(theDialog);
- BeginUpdate(theDialog);
- DrawDialog(theDialog);
- EndUpdate(theDialog);
-
- GetMyDialog := theDialog;
- END; {GetMyDialog}
-
-
- {+--------------------------------------------------------------------------+
- | update the 'Data' config resource |
- +--------------------------------------------------------------------------+}
- PROCEDURE SaveDefaults;
-
- VAR
- tHandle: Handle;
- refNum: Integer;
- p: Point;
-
- BEGIN
- IF NOT CheckOptionKey THEN {update the Data config resource}
- BEGIN
- refNum := OpenResFile(frameFile);
- IF refNum <> -1 THEN
- BEGIN
- p := myWindow^.portRect.topLeft;
- LocalToGlobal(p);
- WITH myData DO
- BEGIN
- IF syncVBL THEN
- sync := 1
- ELSE
- sync := 0;
- IF displayTime THEN
- time := 1
- ELSE
- time := 0;
- IF roundWindow THEN
- round := 1
- ELSE
- round := 0;
- top := p.v;
- left := p.h;
- IF usePalette THEN
- palette := 1
- ELSE
- palette := 0;
- END; {WITH}
- myData.speed := speed;
- tHandle := GetResource('Data', dataID);
- BlockMove(@myData, tHandle^, SIZEOF(dataRec));
- ChangedResource(tHandle);
- IF refNum <> appRefNum THEN
- CloseResFile(refNum)
- ELSE
- UpdateResFile(refNum);
- END;
- END;
- END; {SaveDefaults}
-
-
- {+--------------------------------------------------------------------------+
- | wait for the vertical blanking for smooth blits |
- +--------------------------------------------------------------------------+}
- PROCEDURE WaitVBL;
-
- VAR
- t: LongInt;
-
- BEGIN
- IF slotVBL THEN
- BEGIN
- t := ParisTicks;
- REPEAT UNTIL t <> ParisTicks;
- END
- ELSE
- BEGIN
- t := LongIntPtr(Ticks)^;
- REPEAT UNTIL t <> LongIntPtr(Ticks)^;
- END;
- END; {WaitVBL}
-
-
- {+--------------------------------------------------------------------------+
- | ensures the ENTIRE window is visible |
- +--------------------------------------------------------------------------+}
- PROCEDURE CheckWindowBounds(w: WindowPtr);
-
- VAR
- r: Rect;
- rgn: RgnHandlePtr;
-
- BEGIN
- rgn := RgnHandlePtr(GrayRgn);
- r := w^.portRect;
- IF NOT roundWindow THEN
- r.top := r.top - 20; {account for title bar}
- SetPort(w);
- LocalToGlobal(r.topLeft);
- LocalToGlobal(r.botRight);
- IF NOT (PtInRgn(r.topLeft, rgn^) AND PtInRgn(r.botRight, rgn^)) THEN
- BEGIN
- SysBeep(1);
- DefaultWindow(windLeft, windTop);
- MoveWindow(myWindow, windLeft, windTop, False);
- END;
- END; {CheckWindowBounds}
-
-
- {+--------------------------------------------------------------------------+
- | change ChangePalette |
- +--------------------------------------------------------------------------+}
- PROCEDURE ChangePalette;
-
- VAR
- myDevice: GDHandle;
-
- BEGIN
- IF usePalette THEN
- BEGIN
- SetPalette(WindowPtr(-1), myPal, True);
- myDevice := GetMyDevice;
- IF myDevice^^.gdPMap^^.pixelSize <= 8 THEN
- MakeITable(myDevice^^.gdPMap^^.pmTable, myDevice^^.gdITable, 5);
- END
- ELSE
- SetPalette(WindowPtr(-1), Nil, True)
- END; {ChangePalette}
-
-
- {+--------------------------------------------------------------------------+
- | change WDEF |
- +--------------------------------------------------------------------------+}
- PROCEDURE ChangeWindow;
-
- VAR
- b: Boolean;
- w: Integer;
- first: Boolean;
- p: Point;
-
- BEGIN
- IF myWindow = Nil THEN
- first := True
- ELSE
- first := False;
- IF NOT first THEN
- BEGIN
- p := myWindow^.portRect.topLeft;
- LocalToGlobal(p);
- IF roundWindow THEN {adjust for gray space border}
- BEGIN
- p.h := p.h + 16; {danger! danger, hardcoding ahead}
- p.v := p.v + 16;
- END
- ELSE
- BEGIN
- p.h := p.h - 16;
- p.v := p.v - 16;
- END;
- DisposeWindow(myWindow); {waste my window prior to change, if any}
- END;
- IF roundWindow THEN
- w := roundID
- ELSE
- w := rectID;
- IF usePixMaps THEN {bring up invisible window}
- WindowPtr(myWindow) := GetNewCWindow(w, Nil, POINTER( -1))
- ELSE
- myWindow := GetNewWindow(w, Nil, POINTER( -1));
- SetPort(myWindow);
- TextMode(srcXor);
- TextSize(9); {draw with small chars}
- BackPat(ltGray); {set erase pattern}
- IF roundWindow THEN
- border := 0
- ELSE
- border := 32;
- SizeWindow(myWindow, frameBounds.right + border, frameBounds.bottom + border, False);
- destBounds := frameBounds;
- OffSetRect(destBounds, border DIV 2, border DIV 2); {center a bit}
- IF NOT roundWindow THEN
- BEGIN
- timeRect := myWindow^.portRect;
- timeRect.bottom := timeRect.bottom - 5;
- timeRect.top := timeRect.bottom - 11;
- timeRect.left := timeRect.left + 5;
- timeRect.right := timeRect.left + 25;
- END;
- IF first THEN
- MoveWindow(myWindow, windLeft, windTop, False)
- ELSE
- BEGIN
- MoveWindow(myWindow, p.h, p.v, False);
- ShowWindow(myWindow); {window is now visible}
- END;
-
- CheckWindowBounds(myWindow);
- b := BooleanPtr(PaintWhite)^; {don't draw window in white}
- BooleanPtr(PaintWhite)^ := False; { when making it visible}
- UpdateWindow; {draw everything now}
- BooleanPtr(PaintWhite)^ := b; {restore the global}
- END; {ChangeWindow}
-
-
- {+--------------------------------------------------------------------------+
- | write the blit speed in frames per sec |
- +--------------------------------------------------------------------------+}
- PROCEDURE WriteSpeed;
-
- VAR
- outStr: Str255;
- r: Rect;
- savePort: GrafPtr;
-
- BEGIN
- IF (targTime < TickCount) THEN
- BEGIN
- {$IFC Debug}
- IntegerPtr(MonkeyLives)^ := framesDone; {*** for Bruce}
- {$ENDC}
- IF NOT roundWindow THEN
- BEGIN
- GetPort(savePort);
- SetPort(myWindow);
- NumToString (framesDone, outStr);
- FrameRect(timeRect);
- r := timeRect;
- InsetRect(r, 1, 1);
- PenPat(white);
- PaintRect(r);
- PenNormal;
- IF framesDone < 1000 THEN {don't draw if too long}
- BEGIN
- MoveTo(timeRect.left + 4, timeRect.bottom - 2);
- DrawString (outStr);
- END;
- SetPort(savePort);
- END;
- framesDone := 0;
- targTime := TickCount + 60; {1 second into the future}
- END
- ELSE
- framesDone := framesDone + 1;
- END; {WriteSpeed}
-
-
- {+------------------------------------------------------------------------+
- | change time display |
- +------------------------------------------------------------------------+}
- PROCEDURE FlipTime;
-
- VAR
- savePort: GrafPtr;
-
- BEGIN
- IF displayTime THEN
- BEGIN
- displayTime := False;
- GetPort(savePort);
- SetPort(myWindow);
- IF usePixMaps THEN
- BEGIN
- RGBForeColor(spaceColor);
- PaintRect(timeRect);
- RGBForeColor(myForeColor);
- END
- ELSE
- EraseRect(timeRect);
- SetPort(savePort);
- END
- ELSE
- BEGIN
- displayTime := True;
- targTime := 0; {draw it now}
- WriteSpeed;
- END;
- END; {FlipTime}
-
-
- {+--------------------------------------------------------------------------+
- | blit a frame - look for updates here to minimize flicker |
- +--------------------------------------------------------------------------+}
- PROCEDURE DrawFrame(i: Integer);
-
- BEGIN
- IF EmptyRgn(WindowPeek(myWindow)^.updateRgn) THEN
- BEGIN
- IF syncVBL THEN
- WaitVBL;
- IF usePixMaps THEN
- {$IFC Debug}
- IF (CheckOptionKey AND UseShading) THEN
- CopyBits(BitMapPtr(pixMaps[0]^)^,
- BitMapPtr(CGrafPtr(myWindow)^.portPixMap^)^,
- frameBounds, destBounds, srcCopy, Nil)
- ELSE
- {$ENDC}
- CopyBits(BitMapPtr(pixMaps[i]^)^,
- BitMapPtr(CGrafPtr(myWindow)^.portPixMap^)^,
- frameBounds, destBounds, srcCopy, Nil)
- ELSE
- CopyBits(bitMaps[i], myWindow^.portBits, frameBounds, destBounds, srcCopy, Nil);
- END {no update}
- ELSE
- UpdateWindow;
- END; {DrawFrame}
-
-
- {+--------------------------------------------------------------------------+
- | handle update events for my window |
- +--------------------------------------------------------------------------+}
- PROCEDURE UpdateWindow;
-
- VAR
- r: Rect;
-
- BEGIN
- targTime := 0; {force draw of time box now}
- BeginUpdate(myWindow);
- IF NOT roundWindow THEN {only need to erase/gray if border exists}
- IF usePixMaps THEN
- BEGIN
- RGBForeColor(spaceColor);
- PaintRect(myWindow^.portRect);
- RGBForeColor(myForeColor);
- END
- ELSE
- EraseRect(myWindow^.portRect);
- r := myWindow^.portRect; {draw some nice lines}
- PenSize(1, 1);
- FrameRect(r);
- InsetRect(r, 2, 2);
- FrameRect(r);
- PenPat(white);
- InsetRect(r, -1, -1);
- FrameRect(r);
- PenNormal;
- IF displayTime THEN
- WriteSpeed;
- DrawFrame(curFrame);
- EndUpdate(myWindow);
- END; {UpdateWindow}
-
-
- {+--------------------------------------------------------------------------+
- | advance a frame - called from MEL, handles delays |
- +--------------------------------------------------------------------------+}
- PROCEDURE FrameAdvance;
-
- BEGIN
- IF (delayCount = 0) AND (speed <> -1) THEN {handle stepping}
- BEGIN
- delayCount := speed;
- IF curFrame = frameCount THEN
- curFrame := 2
- ELSE
- curFrame := curFrame + 1;
-
- IF displayTime THEN
- WriteSpeed;
- DrawFrame(curFrame);
- END
- ELSE
- BEGIN
- delayCount := delayCount - 1;
- END;
- END; {FrameAdvance}
-
-
- {+--------------------------------------------------------------------------+
- | about box handler |
- +--------------------------------------------------------------------------+}
- PROCEDURE DoAbout;
-
- VAR
- theDialog: DialogPtr;
- hasEvent: Boolean;
-
- BEGIN
- theDialog := GetMyDialog(aboutID);
-
- REPEAT
- IF juggler THEN
- hasEvent := WaitNextEvent(keyDownMask + mDownMask, myEvent, 0, Nil)
- ELSE
- BEGIN
- SystemTask;
- hasEvent := GetNextEvent(keyDownMask + mDownMask, myEvent);
- END;
- FrameAdvance;
- UNTIL hasEvent;
-
- DisposDialog(theDialog);
- END; {DoAbout}
-
-
- {+--------------------------------------------------------------------------+
- | update menus |
- +--------------------------------------------------------------------------+}
- PROCEDURE AdjustMenus;
-
- VAR
- savePort: GrafPtr;
- globalRect: Rect;
- myDevice: GDHandle;
-
- BEGIN
- GetPort(savePort);
- SetPort(myWindow);
- SetPort(savePort);
- globalRect := myWindow^.portRect;
- LocalToGlobal(globalRect.topLeft);
- LocalToGlobal(globalRect.botRight);
- myDevice := GetMyDevice;
- globalRect.left := (globalRect.left + destBounds.left) * myDevice^^.gdPMap^^.pixelSize;
- IF globalRect.left MOD 32 = 0 THEN
- DisableItem(myMenus[controlM], alignCommand)
- ELSE
- EnableItem(myMenus[controlM], alignCommand);
-
- IF speed = 0 THEN
- DisableItem(myMenus[controlM], fasterCommand)
- ELSE
- EnableItem(myMenus[controlM], fasterCommand);
- IF roundWindow THEN
- DisableItem(myMenus[controlM], timeCommand)
- ELSE
- EnableItem(myMenus[controlM], timeCommand);
- CheckItem(myMenus[controlM], syncCommand, syncVBL);
- CheckItem(myMenus[controlM], timeCommand, displayTime AND NOT roundWindow);
- CheckItem(myMenus[controlM], roundCommand, roundWindow);
- CheckItem(myMenus[controlM], paletteCommand, usePalette);
-
- IF (FrontWindow = myWindow) THEN
- BEGIN
- DisableItem(myMenus[fileM], closeCommand);
- DisableItem(myMenus[editM], undoCommand);
- DisableItem(myMenus[editM], cutCommand);
- DisableItem(myMenus[editM], copyCommand);
- DisableItem(myMenus[editM], pasteCommand);
- DisableItem(myMenus[editM], clearCommand);
- END
- ELSE
- BEGIN
- EnableItem(myMenus[fileM], closeCommand);
- EnableItem(myMenus[editM], undoCommand);
- EnableItem(myMenus[editM], cutCommand);
- EnableItem(myMenus[editM], copyCommand);
- EnableItem(myMenus[editM], pasteCommand);
- EnableItem(myMenus[editM], clearCommand);
- END;
- END; {AdjustMenus}
-
-
- {+--------------------------------------------------------------------------+
- | longword align the window to help out quickdraw |
- +--------------------------------------------------------------------------+}
- PROCEDURE AlignWindow;
-
- VAR
- i: Integer;
- myDevice: GDHandle;
- grid: Integer;
- globalRect: Rect;
-
- BEGIN
- globalRect := myWindow^.portRect;
- LocalToGlobal(globalRect.topLeft);
- LocalToGlobal(globalRect.botRight);
-
- myDevice := GetMyDevice;
- grid := 32 DIV myDevice^^.gdPMap^^.pixelSize;
-
- i := (((globalRect.left + destBounds.left) + grid DIV 2) DIV grid) * grid - destBounds.left;
- MoveWindow(myWindow, i, globalRect.top, False);
- END; {AlignWindow}
-
-
- {+--------------------------------------------------------------------------+
- | handle control menu commands |
- +--------------------------------------------------------------------------+}
- PROCEDURE DoControlMenu(i: Integer);
-
- VAR
- savePort: GrafPtr;
-
- BEGIN
- CASE i OF
- slowerCommand:
- BEGIN
- IF speed = -1 THEN
- speed := 50 {magic numbers...}
- ELSE
- speed := speed + 1;
- delayCount := speed;
- END;
-
- stepCommand:
- BEGIN
- delayCount := 0; {advance frame now}
- speed := 0; {step now}
- FrameAdvance;
- speed := -1; {don't advance in loop}
- END;
-
- fasterCommand:
- BEGIN
- speed := speed - 1;
- IF speed < 0 THEN
- speed := 0;
- delayCount := speed;
- END;
-
- syncCommand:
- syncVBL := NOT syncVBL;
-
- alignCommand:
- AlignWindow;
-
- timeCommand:
- FlipTime;
-
- roundCommand:
- BEGIN
- roundWindow := NOT roundWindow;
- ChangeWindow;
- END;
-
- paletteCommand:
- BEGIN
- usePalette := NOT usePalette;
- ChangePalette;
- END;
-
- END; {CASE}
- AdjustMenus;
- END; {DoControlMenu}
-
-
- {+--------------------------------------------------------------------------+
- | handle menu and menu key commands |
- +--------------------------------------------------------------------------+}
- PROCEDURE DoCommand(mResult: LONGINT);
-
- VAR
- theItem: Integer; {menu item number from mResult low-order word}
- theMenu: Integer; {menu number from mResult high-order word}
- name: Str255; {desk accessory name}
- w: WindowPtr;
- i: Integer;
-
- BEGIN
- theItem := LoWord(mResult); {call Toolbox Utility routines to}
- theMenu := HiWord(mResult); {set menu item number and menu}
- {number}
-
- CASE theMenu OF
- appleID:
- BEGIN
- IF (theItem = aboutCommand) THEN
- DoAbout
- ELSE
- BEGIN
- GetItem(myMenus[appleM], theItem, name);
- i := OpenDeskAcc(name);
- SetPort(myWindow);
- END;
- END; {CASE appleID}
-
- fileID:
- CASE theItem OF
- closeCommand:
- BEGIN
- w := FrontWindow;
- IF WindowPeek(w)^.windowKind < 0 THEN
- CloseDeskAcc(WindowPeek(w)^.windowKind);
- END;
- quitCommand:
- doneFlag := True;
- END; {CASE fileID}
-
- editID:
- IF NOT SystemEdit(theItem - 1) THEN
- BEGIN
- END;
-
- controlID:
- DoControlMenu(theItem);
-
- END; {CASE theMenu}
-
- HiliteMenu(0);
- END; {DoCommand}
-
-
- {+--------------------------------------------------------------------------+
- | main event loop |
- +--------------------------------------------------------------------------+}
- PROCEDURE MainEventLoop;
-
- VAR
- hasEvent: Boolean;
- whichWindow: WindowPtr;
-
- BEGIN
- REPEAT
- FrameAdvance; {draw my stuff}
-
- IF juggler THEN
- hasEvent := WaitNextEvent(everyEvent, myEvent, 0, Nil)
- ELSE
- BEGIN
- SystemTask; {service DAs}
- hasEvent := GetNextEvent(everyEvent, myEvent);
- END;
-
- IF hasEvent THEN
- CASE myEvent.what OF
-
- mouseDown:
- CASE FindWindow(myEvent.where, whichWindow) OF
-
- inSysWindow:
- SystemClick(myEvent, whichWindow);
-
- inMenuBar:
- BEGIN
- AdjustMenus; {pretty up the menus}
- DoCommand(MenuSelect(myEvent.where));
- END;
-
- inDrag:
- BEGIN
- DragWindow(whichWindow, myEvent.where, dragRect);
- AdjustMenus; {align command may change}
- END;
-
- inGoAway:
- IF whichWindow = myWindow THEN
- IF TrackGoAway(myWindow, myEvent.where) THEN
- doneFlag := True;
-
- inContent:
- BEGIN
- IF whichWindow <> FrontWindow THEN
- SelectWindow(whichWindow);
- IF roundWindow THEN
- BEGIN
- DragWindow(whichWindow, myEvent.where, dragRect);
- AdjustMenus; {align command may change}
- END;
- END;
- END; {CASE mouseDown}
-
- keyDown, autoKey: {key pressed once or held down to repeat}
- IF (myWindow = frontWindow) AND
- (BAnd(myEvent.modifiers, cmdKey) <> 0) THEN
- DoCommand(MenuKey(CHR(BAnd(myEvent.message, charCodeMask))));
-
- activateEvt:
- IF (WindowPtr(myEvent.message) = myWindow) AND
- (BAnd(myEvent.modifiers, activeFlag) <> 0) THEN
- SetCursor(arrow);
-
- updateEvt:
- IF WindowPtr(myEvent.message) = myWindow THEN
- UpdateWindow;
-
- END; {CASE myEvent.what}
- UNTIL doneFlag;
- END; {MainEventLoop}
-
-
- {+--------------------------------------------------------------------------+
- | recursively chow da windows |
- +--------------------------------------------------------------------------+}
- PROCEDURE CloseAllWindows(w: WindowPtr);
-
- BEGIN
- IF WindowPeek(w)^.nextWindow <> Nil THEN
- CloseAllWindows(WindowPtr(WindowPeek(w)^.nextWindow));
- IF WindowPeek(w)^.windowKind < 0 THEN
- CloseDeskAcc(WindowPeek(w)^.windowKind);
- END; {CloseAllWindows}
-
-
- {+--------------------------------------------------------------------------+
- | Main Program |
- +--------------------------------------------------------------------------+}
- BEGIN
- UnLoadSeg(@_DataInit); {remove Pascal data initialization code}
- MaxApplZone; {fully expand the heap}
- Initialize; {run once-only code}
- UnLoadSeg(@Initialize); {remove once-only code}
-
- AdjustMenus; {adjust once now}
- MainEventLoop; {run the main loop}
-
- IF NOT juggler THEN
- SetCursor(GetCursor(watchCursor)^^);
- IF slotVBL THEN
- RemoveVBLSync; {remove custom VBL task if on Mac II}
- SaveDefaults; {save the program settings}
- DisposeWindow(myWindow);
- IF FrontWindow <> Nil THEN
- CloseAllWindows(FrontWindow);
- END. {PROGRAM Globe}
-