Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
CLUTSample.a
* |
* Apple Macintosh Developer Technical Support |
* |
* |
* CLUTSample |
* |
* |
* Loosely based in the sample SAMPLE this program shows |
* how to create a window and display on it the colors of the CLUT |
* associated with the device the window sits on top of. |
* |
* Left to the curious reader are some improvements such as, remembering the |
* positions of each open window, so if you use this program to monitor your |
* color tables it will position the windows in the last place you opened them. |
* The treatment of direct devices is kind of 'casual' a better color display may |
* be appropriate. Last, it may be desireable to change the size of the color |
* rectangles depending on the depth of the color table. |
* Check Sample sources for more detailed documentation. |
* ================================================ |
* -------------- INCLUDES SECTION ---------------- |
* ================================================ |
PRINT PUSH,OFF ; don't print any of this stuff |
INCLUDE 'ToolEqu.a' |
INCLUDE 'Traps.a' |
INCLUDE 'PackMacs.a' |
INCLUDE 'QuickEqu.a' |
INCLUDE 'SysEqu.a' |
INCLUDE 'CLUTSample.inc1.a' ; all our macros and data templates |
PRINT POP ; restore the PRINT options |
* ================================================ |
* --------- DATA STORAGE ALLOCATION ------------ |
* ================================================ |
* Global data storage. All global memory is allocated here. The |
* Linker will load all global data offset from A5, and the Asm knows this. |
* Therefore, no reference to (A5) is required in the code. Hooray! |
* Here we declare two data structures using our templates defined previously. |
* They must be EXPORTed here for other files that need to IMPORT them. |
EXPORT (QD,G):DATA |
QD DS MyQDGlobals ; QuickDraw's globals |
G DS AppGlobals ; application's globals |
* ================================================ |
* --------- INITIALIZATION PROC ------------ |
* ================================================ |
SEG 'Initialize' ; case sensitive |
Initialize PROC ; Initialize everything |
CountReg EQU D4 ; temporary registor to count loops |
StackFrame RECORD {A6Link},DECR ; build a stack frame record |
ParamBegin EQU * ; start parameters after this point |
ParamSize EQU ParamBegin-* ; size of all the passed parameters |
RetAddr DS.L 1 ; place holder for return address |
A6Link DS.L 1 ; place holder for A6 link |
CurMBar DS.L 1 ; local handle to our menubar |
TheEvent DS EventRecord ; local copy of the event record |
LocalSize EQU * ; size of all the local variables |
ENDR |
IMPORT GoGetRect,AlertUser,SysEnvirons, \ |
OpenClutWind, \ |
TrapAvailable ; linked in with Interface.o |
WITH StackFrame ; cover our local stack frame |
LINK A6,#LocalSize ; allocate our local stack frame |
MOVEM.L CountReg,-(SP) ; save the current registor values |
MOVE.W #False,G.InBackground ; we start out in the foreground |
MOVE.W #True,G.Stopped ; we'll start with the red light on |
* ------------- INITIALIZE MANAGERS ------------- |
@1 PEA QD.thePort ; initialize all of the Managers |
_InitGraf ; please don't flush my events |
_InitFonts |
_InitWindows |
_InitMenus |
_TEInit |
CLR.L -(SP) |
_InitDialogs |
_InitCursor |
* Call MPPOpen and ATPLoad at this point to initialize AppleTalk, if you are using it. |
* NOTE -- It is no longer necessary, and actually unhealthy, to check PortBUse and |
* SPConfig before opening AppleTalk. The drivers are capable of checking for port |
* availability themselves. This next bit of code is necessary to allow the default |
* button of our alert be outlined. |
* ------------- WASTE THREE EVENTS ------------- |
MOVE.W #2,CountReg ; set register value to loop 3 times |
Loop CLR.W -(SP) ; space for result |
MOVE.W #EveryEvent,-(SP) ; the events we want |
PEA TheEvent(A6) ; pass a pointer to our event |
_EventAvail |
MOVE.W (SP)+,D0 ; result code |
DBF CountReg,Loop ; decrement count, if count < 0 then continue |
* ------------- GET THE ENVIRONMENT ------------- |
CLR.W -(SP) ; create space for result |
MOVE.W #EnvironsVersion,-(SP) ; version of SysEnvirons we want |
PEA G.Mac ; the global environment record |
JSR SysEnvirons ; we can ignore any errors here, |
MOVE.W (SP)+,D0 ; SysEnvirons will fill in regardless |
MOVE.W G.Mac.MachineType,D0 ; negitive value means old ROMs |
BPL.S @2 ; 128k ROMs or better, continue on |
JMP AlertUser ; we don't want to run on 64k ROMs |
* ------------- TEST FOR WAITNEXTEVENT ------------- |
* 1.02 - Move TrapAvailable call to after SysEnvirons so that |
* we can tell in TrapAvailable if a tool trap value is out of range. |
@2 CLR.W -(SP) ; space for result of trap test |
MOVE.W #WaitNextEvent,-(SP) ; pass the trap number of WaitNextEvent trap |
BSR TrapAvailable ; test for this trap |
MOVE.W (SP)+,G.HasWNEvent ; put the result in our global flag |
MOVE.L applLimit,D1 ; get pointer to ApplLimit |
MOVE.L applZone,D0 ; get pointer to ApplicZone |
SUB.L D0,D1 ; subtract the ApplicZone from ApplLimit |
CMPI.L #MinHeap,D1 ; do we have enough memory? |
BPL.S @3 ; yes we do, continue on |
JMP AlertUser ; no, report the error |
@3 _PurgeSpace ; results will be in A0 and D0 |
CMPI.L #MinSpace,D0 ; do we have enough purgeable space? |
BPL.S @4 |
JMP AlertUser ; no, report the error |
* ------------- SET UP THE MENUS ------------- |
@4 CLR.L -(SP) ; space for MenuBar handle |
MOVE.W #rMenuBar,-(SP) ; our MenuBar resource |
_GetNewMBar ; the modern way, get a MenuBar |
MOVE.L (SP),CurMBar(A6) |
_SetMenuBar |
MOVEA.L CurMBar(A6),A0 ; we're done with that handle |
_DisposHandle ; there is a result in D0 |
CLR.L -(SP) |
MOVE.W #AppleMenu,-(SP) |
_GetMHandle ; put Apple menu handle on stack |
MOVE.L #'DRVR',-(SP) ; get all the DAs |
_AddResMenu |
_DrawMenuBar |
Exit MOVEM.L (SP)+,CountReg ; restore the registors |
UNLK A6 ; destroy the link |
MOVEA.L (SP)+,A0 ; pull off the return address |
ADDA.L #ParamSize,SP ; strip all of the caller's parameters |
JMP (A0) ; return to the caller |
DbgInfo Initialz ; this name will appear in the debugger |
ENDP |
* ================================================ |
* PROCEDURE OpenClutWind(); |
* ================================================ |
SEG 'Main' ; case sensitive |
OpenClutWind PROC |
StackFrame RECORD {A6Link},DECR ; build a stack frame record |
ParamBegin EQU * ; passed parameter of the window pointer |
ParamSize EQU ParamBegin-* ; size of all the passed parameters |
RetAddr DS.L 1 ; place holder for return address |
A6Link DS.L 1 ; place holder for A6 link |
LocalSize EQU * ; size of all the local variables |
ENDR |
IMPORT DrawClut,NulMouse,OpenWindow |
WITH StackFrame,ClutWData ; cover our local stack frame |
LINK A6,#LocalSize ; allocate our local stack frame |
Clr.l -(SP) |
Move.W #rWindow,-(SP) |
Move.L #ClutWDataSize,-(SP) |
PEA DrawClut |
PEA NulMouse |
JSR OpenWindow |
MOVE.L (SP)+,A0 |
Exit |
UNLK A6 ; destroy the link |
MOVEA.L (SP)+,A0 ; pull off the return address |
ADDA.L #ParamSize,SP ; strip all of the caller's parameters |
JMP (A0) ; return to the caller |
DbgInfo OpenClutWind |
ENDP |
* ================================================ |
* PROCEDURE DoUpdate(window: WindowPtr); |
* ================================================ |
* This is called when an update event is received for a window. |
* It calls DrawWindow to draw the contents of an application window. |
* As an efficiency measure that does not have to be followed, it |
* calls the drawing routine only if the visRgn is non-empty. This |
* will handle situations where calculations for drawing or drawing |
* itself is very time-consuming. |
SEG 'Main' ; case sensitive |
DoUpdate PROC |
StackFrame RECORD {A6Link},DECR ; build a stack frame record |
ParamBegin EQU * ; start parameters after this point |
WindowPtr DS.L 1 ; passed parameter of the window pointer |
ParamSize EQU ParamBegin-* ; size of all the passed parameters |
RetAddr DS.L 1 ; place holder for return address |
A6Link DS.L 1 ; place holder for A6 link |
LocalSize EQU * ; size of all the local variables |
ENDR |
IMPORT IsAppWindow,DrawWindow |
WITH StackFrame ; cover our local stack frame |
LINK A6,#LocalSize ; allocate our local stack frame |
CLR.W -(SP) ; space for result of IsAppWindow |
MOVE.L WindowPtr(A6),-(SP) ; pass the window pointer |
BSR IsAppWindow ; test if this window was ours |
MOVE.W (SP)+,D0 |
CMPI.W #True,D0 ; it must be our window |
BNE.S Exit ; it wasn't our window |
MOVE.L WindowPtr(A6),-(SP) ; update only the visible region |
_BeginUpDate ; region of the window |
CLR.W -(SP) ; space for result |
MOVEA.L WindowPtr(A6),A0 ; the window pointer |
MOVE.L visRgn(A0),-(SP) ; the window's visRgn handle |
_EmptyRgn |
MOVE.W (SP)+,D0 ; result of EmptyRgn |
CMPI.W #True,D0 ; was the visRgn empty? |
BEQ.S @1 ; yes, then no update is needed |
Clr.l -(SP) |
MOVE.L WindowPtr(A6),-(SP) |
_GetWRefCon |
Move.l (SP)+,A2 ; Retrieve handle |
Move.l (A2),A0 ; Deref Handle |
Move.l (A0),A0 ; Get ProcPtr |
MOVE.L WindowPtr(A6),-(SP) |
JSR (A0) ; draw the window |
@1 MOVE.L WindowPtr(A6),-(SP) ; get pointer to window |
_EndUpdate |
Exit UNLK A6 ; destroy the link |
MOVEA.L (SP)+,A0 ; pull off the return address |
ADDA.L #ParamSize,SP ; strip all of the caller's parameters |
JMP (A0) ; return to the caller |
DbgInfo DoUpdate ; this name will appear in the debugger |
ENDP |
* ================================================ |
* PROCEDURE DoActivate(window: WindowPtr; becomingActive: BOOLEAN); |
* ================================================ |
* In this sample there is no other processing necessary other than what |
* the Window Manager has already done for us. This would be the place to |
* perform an activate on TextEdit records, controls, lists, update GrowIcon, etc. |
SEG 'Main' ; case sensitive |
DoActivate PROC |
StackFrame RECORD {A6Link},DECR ; build a stack frame record |
ParamBegin EQU * ; start parameters after this point |
WindowPtr DS.L 1 ; passed parameter of the window pointer |
Active DS.W 1 ; modifiers from the event record |
ParamSize EQU ParamBegin-* ; size of all the passed parameters |
RetAddr DS.L 1 ; place holder for return address |
A6Link DS.L 1 ; place holder for A6 link |
LocalSize EQU * ; size of all the local variables |
ENDR |
IMPORT IsAppWindow |
WITH StackFrame ; cover our local stack frame |
LINK A6,#LocalSize ; allocate our local stack frame |
CLR.W -(SP) ; space for result of IsAppWindow |
MOVE.L WindowPtr(A6),-(SP) ; pass the window pointer |
BSR IsAppWindow ; test if this window was ours |
MOVE.W (SP)+,D0 ; get the result |
CMPI.W #True,D0 ; it must be our window |
BNE.S Exit ; it wasn't our window |
CMPI.W #True,Active(A6) ; was it an Activate? |
BNE.S DeActivate ; no, perform a Deactivate |
* do the activate event processing here, then "BRA.S Exit" |
DeActivate ; do the deactivate event |
* do the deactivate event processing here, then fall through to Exit |
Exit UNLK A6 ; destroy the link |
MOVEA.L (SP)+,A0 ; pull off the return address |
ADDA.L #ParamSize,SP ; strip all of the caller's parameters |
JMP (A0) ; return to the caller |
DbgInfo Activate ; this name will appear in the debugger |
ENDP |
* ================================================ |
* PROCEDURE DoMenuCommand(menuResult: LONGINT); |
* ================================================ |
* This is called when an item is chosen from the menu bar (after calling |
* MenuSelect or MenuKey). It performs the right operation for each command. |
* It is good to have both the result of MenuSelect and MenuKey go to |
* one routine like this to keep everything organized. |
SEG 'Main' ; case sensitive |
DoMenuCommand PROC |
StackFrame RECORD {A6Link},DECR ; build a stack frame record |
ParamBegin EQU * ; start parameters after this point |
MenuItem DS.W 1 ; result from _MenuKey or _MenuSelect |
MenuID DS.W 1 ; caller passed a long word, ID + Item |
ParamSize EQU ParamBegin-* ; size of all the passed parameters |
RetAddr DS.L 1 ; place holder for return address |
A6Link DS.L 1 ; place holder for A6 link |
Deskname DS.B 256 ; local storage for Desk Accs name |
TempPort DS.L 1 ; local storage for the current port |
LocalSize EQU * ; size of all the local variables |
ENDR |
IMPORT SetLight,DoCloseWindow,Terminate |
WITH StackFrame ; cover our local stack frame |
LINK A6,#LocalSize ; allocate our local stack frame |
MOVE.W MenuID(A6),D0 ; a nifty Pascal case-like macro |
CASE#.W (D0,IF), \ |
(AppleMenu, DoAppleMenu), \ |
(FileMenu, DoFileMenu) |
; add additional Menus would go here |
BRA.W Exit ; otherwise we will exit this procedure |
* ------------- THE APPLE MENU ROUTINES ------------- |
DoAppleMenu |
CMPI.W #AboutItem,MenuItem(A6) ; was it the about item? |
BNE.S @1 ; no, must be a Desk Acc |
CLR.W -(SP) ; show the About dialog |
MOVE.W #rAboutAlert,-(SP) ; resource for alert dialog |
CLR.L -(SP) ; no filter procedure used here |
_Alert ; read the resource and display it |
MOVE.W (SP)+,D0 ; I don't care which item is was |
BRA.W Exit ; all done with with Apple menu |
@1 PEA TempPort(A6) ; open a desk accessory |
_GetPort ; save the current port |
CLR.L -(SP) ; space for result of GetMHandle |
MOVE.W #AppleMenu,-(SP) |
_GetMHandle ; put Apple menu on stack |
MOVE.W MenuItem(A6),-(SP) ; and here's the MenuItem |
PEA DeskName(A6) ; now tell me the DA's name |
_GetItem |
CLR.W -(SP) ; space for OpenDeskAcc result |
PEA DeskName(A6) |
_OpenDeskAcc ; open that puppy |
MOVE.W (SP)+,D0 ; result |
MOVE.L TempPort(A6),-(SP) ; restore the port |
_SetPort |
BRA.S Exit |
* ------------- THE FILE MENU ROUTINES ------------- |
DoFileMenu |
MOVE.W MenuItem(A6),D0 ; test the MenuItem |
Case#.W (D0,IF), \ |
(NewItem, FileNew), \ |
(CloseItem, FileClose), \ |
(QuitItem, FileQuit) |
BRA.S Exit ; add additional menus here |
FileNew: |
BSR OpenClutWind |
BRA.S Exit |
FileClose |
CLR.L -(SP) ; bug fix, didn't clear space for result -JDR 2/27/89 |
_FrontWindow |
BSR DoCloseWindow ; close the window |
BRA.S Exit |
FileQuit BSR Terminate ; let's get out of here |
Exit CLR.W -(SP) |
_HiLiteMenu ; unhilite all Menus |
UNLK A6 ; destroy the link |
MOVEA.L (SP)+,A0 ; pull off the return address |
ADDA.L #ParamSize,SP ; strip all of the caller's parameters |
JMP (A0) ; return to the caller |
DbgInfo DoMenuCm ; this name will appear in the debugger |
ENDP |
* ================================================ |
* PROCEDURE OpenWindow(WINDid:Integer,WDataSize:Long,UpdateRtn:ProcPtr,MouseRtn:ProcPtr):WindowPtr |
* ================================================ |
SEG 'Main' ; case sensitive |
OpenWindow PROC EXPORT |
StackFrame RECORD {A6Link},DECR ; build a stack frame record |
Result1 DS.L 1 |
ParamBegin EQU * ; start parameters after this point |
rWindow DS.W 1 ; Id of WIND resource to use |
WDataSize DS.L 1 ; Size of window data record to allocate |
ProcPtr DS.L 1 ; Pointer to update routine for this window |
MouseRtn DS.L 1 |
ParamSize EQU ParamBegin-* ; size of all the passed parameters |
RetAddr DS.L 1 ; place holder for return address |
A6Link DS.L 1 ; place holder for A6 link |
* insert locals here |
TempWord DS.W 1 |
TempLong DS.L 1 |
LocalSize EQU * ; size of all the local variables |
ENDR |
IMPORT AlertUser |
WITH StackFrame ; cover our local stack frame |
LINK A6,#LocalSize ; allocate our local stack frame |
MOVE.L #windowSize,D0 |
_NewPtr ,Clear ; create a pointer in A0 and clear memory |
CMPA.L #NIL,A0 ; check for NIL pointer (result in D0) |
BNE.S @1 ; must have been a valid pointer |
Move.w #25,-(SP) ; Error # |
Pea #'OpenWindow1' ; Routine Name |
Pea #'No Memory for Window Record' ; Message |
JMP AlertUser ; couldn't get memory, report error |
@1 CLR.L -(SP) ; create space for result |
MOVE.W rWindow(A6),-(SP) ; out window resource definition |
MOVE.L A0,-(SP) ; our window record storage |
MOVE.L #-1,-(SP) ; make it on top |
_GetNewCWindow ; create the window |
Move.l (SP)+,Result1(A6) |
MOVE.L WDataSize(A6),D0 |
_NewHandle ,Clear ; create a pointer in A0 and clear memory |
CMPA.L #NIL,A0 ; check for NIL pointer (result in D0) |
BNE.S @2 ; must have been a valid pointer |
Move.w #25,-(SP) ; Error # |
Pea #'OpenWindow2' ; Routine Name |
Pea #'No Memory for Window Record' ; Message |
JMP AlertUser ; couldn't get memory, report error |
@2 Move.l A0,-(SP) ; Save address |
Move.l Result1(A6),-(SP) |
Move.l A0,-(SP) |
_SetWRefCon |
Move.l (SP)+,A0 ; restore address |
Move.l (A0),A0 |
WITH ClutWData |
Move.l ProcPtr(A6),UpdateRtn(A0) ; Update routine |
Move.l MouseRtn(A6),MouseDnRtn(A0) ; Mouse down routine |
ENDWITH |
Exit UNLK A6 ; destroy the link |
MOVEA.L (SP)+,A0 ; pull off the return address |
ADDA.L #ParamSize,SP ; strip all of the caller's parameters |
JMP (A0) ; return to the caller |
DbgInfo OpenWindow |
ENDP |
* ================================================ |
* PROCEDURE DoMouseDown(Event: EventRecord); |
* ================================================ |
* Handle all of the MouseDown events. |
SEG 'Main' ; case sensitive |
DoMouseDown PROC |
StackFrame RECORD {A6Link},DECR ; build a stack frame record |
ParamBegin EQU * ; start parameters after this point |
EventPtr DS.L 1 ; pointer to current event |
ParamSize EQU ParamBegin-* ; size of all the passed parameters |
RetAddr DS.L 1 ; place holder for return address |
A6Link DS.L 1 ; place holder for A6 link |
WindowPtr DS.L 1 ; local Window pointer variable |
Where DS.L 1 ; local variable where the click was |
NewGrowRect DS Rect ; local rect variable for SizeWindow |
LocalSize EQU * ; size of all the local variables |
ENDR |
IMPORT AdjustMenus,DoContentClick |
WITH StackFrame ; cover our local stack frame |
LINK A6,#LocalSize ; allocate our local stack frame |
MOVEA.L EventPtr(A6),A0 ; event record only needed by SystemClick |
MOVE.L evtMouse(A0),Where(A6) ; make a local copy of the mouse location |
CLR.W -(SP) ; space for FindWindow result |
MOVE.L Where(A6),-(SP) ; the mouse point |
PEA WindowPtr(A6) ; a local variable |
_FindWindow ; put the result in a register |
MOVE.W (SP)+,D0 ; a nifty Pascal case-like macro |
Case#.W (D0,IF), \ |
(InMenuBar, MenuEvent), \ |
(InSysWindow, SystemEvent), \ |
(InContent, Content), \ |
(InDrag, Drag) |
; add additional routines here |
BRA.S Exit ; otherwise we will exit this procedure |
* ------------- THE DESK ACCS EVENT ------------- |
MenuEvent |
BSR.W AdjustMenus |
CLR.L -(SP) ; space for MenuSelect |
MOVE.L Where(A6),-(SP) ; Mouse coordinates |
_MenuSelect ; pass MenuSelect's result |
BSR DoMenuCommand ; go do the menu and return |
BRA.S Exit |
* ------------- THE DESK ACCS EVENT ------------- |
SystemEvent |
MOVE.L EventPtr(A6),-(SP) ; get EventRecord and WindowPtr |
MOVE.L WindowPtr(A6),-(SP) ; pass the window pointer and... |
_SystemClick ; let the system handle it |
BRA.S Exit |
* ------------- THE CONTENT EVENT ------------- |
Content |
CLR.L -(SP) ; was our window in front? |
_FrontWindow ; get front window's pointer |
MOVE.L (SP)+,D0 |
CMP.L WindowPtr(A6),D0 ; was it in the front window? |
BNE.S @1 ; no, then just select window |
Clr.l -(SP) |
MOVE.L WindowPtr(A6),-(SP) |
_GetWRefCon |
Move.l (SP)+,A2 ; Retrieve handle |
Move.l (A2),A0 ; Deref Handle |
WITH ClutWData |
Move.l MouseDnRtn(A0),A0 ; Get ProcPtr |
ENDWITH |
MOVE.L WindowPtr(A6),-(SP) ; pass the window pointer |
MOVE.L EventPtr(A6),-(SP) ; pass a pointer to the event |
JSR (A0) |
BRA.S Exit |
@1 MOVE.L WindowPtr(A6),-(SP) ; only select this window |
_SelectWindow ; and take no further action |
BRA.S Exit |
* ------------- THE DRAG A WINDOW EVENT ------------- |
Drag |
MOVE.L WindowPtr(A6),-(SP) ; pass Window Pointer |
MOVE.L Where(A6),-(SP) ; Mouse coordinates and boundary |
PEA QD.Screenbits.bounds |
_DragWindow ; drag it the screen's boundary |
Exit |
UNLK A6 ; destroy the link |
MOVEA.L (SP)+,A0 ; pull off the return address |
ADDA.L #ParamSize,SP ; strip all of the caller's parameters |
JMP (A0) ; return to the caller |
DbgInfo MouseDwn ; this name will appear in the debugger |
ENDP |
* ================================================ |
* PROCEDURE DoEvent(event: EventRecord); |
* ================================================ |
* Do the right thing for an event. Determine what kind of event it is, |
* and call the appropriate routines. |
SEG 'Main' ; case sensitive |
DoEvent PROC |
ModifyReg EQU D4 ; we'll use this register locally |
StackFrame RECORD {A6Link},DECR ; build a stack frame record |
ParamBegin EQU * ; start listing parameters here |
EventPtr DS.L 1 ; pointer to current event |
ParamSize EQU ParamBegin-* ; size of all the passed parameters |
RetAddr DS.L 1 ; place holder for return address |
A6Link DS.L 1 ; place holder for A6 link |
TheEvent DS EventRecord ; local copy of the event record |
LocalSize EQU * ; size of all the local variables |
ENDR |
IMPORT DoMouseDown,DrawWindow, \ |
AdjustMenus,IsAppWindow,\ |
DoUpdate,DoActivate |
WITH StackFrame,TheEvent ; cover our local stack frame |
LINK A6,#LocalSize ; allocate our local stack frame |
MOVEM.L ModifyReg,-(SP) ; save this register before using it |
MOVEA.L EventPtr(A6),A0 ; pointer of event passed by caller |
LEA TheEvent(A6),A1 ; pointer to local variable TheEvent |
MOVE.L #evtBlkSize,D0 ; size of an event record |
_BlockMove ; we now have a local copy of the event |
MOVE.W Modify(A6),ModifyReg ; a nifty Pascal case-like macro |
MOVE.W What(A6),D0 ; get the event number |
Case# (D0,Exit), \ ; if not an event we support, then exit |
, \ ; 0 Null (not used) |
MouseDown, \ ; 1 Mouse down |
, \ ; 2 Mouse up (not used) |
KeyDown, \ ; 3 Key down |
, \ ; 4 Key up (not used) |
KeyDown, \ ; 5 Auto key |
Update, \ ; 6 Update |
Disk, \ ; 7 Disk inserted |
Activate, \ ; 8 Activate/Deactivate |
, \ ; 9 (not used) |
, \ ; 10 Network (not used) |
, \ ; 11 I/O Driver (not used) |
, \ ; 12 App1 (not used) |
, \ ; 13 App2 (not used) |
, \ ; 14 App3 (not used) |
OSEvent, ; 15 OS Event or Suspend/Resume |
* ------------- THE MOUSEDOWN EVENT ------------- |
MouseDown |
PEA TheEvent(A6) ; pass Event pointer in case of SystemClick |
BSR DoMouseDown |
BRA Exit |
* ------------- THE KEYDOWN EVENT ------------- |
KeyDown |
BTST #CmdKey,ModifyReg ; command key? |
BEQ Exit ; no, then we're done |
BSR.W AdjustMenus ; first, adjust the menus |
CLR.L -(SP) ; space for MenuKey |
MOVE.W 2+Message(A6),-(SP) ; get the character |
_MenuKey ; is it a command? |
BSR DoMenuCommand ; handle the command and return |
BRA.S Exit |
* ------------- THE UPDATE EVENT ------------- |
Update |
MOVE.L Message(A6),-(SP) ; pass the window pointer |
BSR DoUpdate ; do the update |
BRA.S Exit |
* ------------- THE DISK EVENT ------------- |
Disk |
TST.W Message(A6) ; check for error |
BEQ.S @1 ; if none, skip |
CLR.W -(SP) |
MOVE.L #DITopLeft,-(SP) |
MOVE.L Message(A6),-(SP) |
MOVE.W #diBadMount,-(SP) |
_Pack2 ; go through disk init package |
ADDQ #2,SP ; throw away result |
@1 BRA.S Exit |
* ------------- THE ACTIVATE/DEACTIVATE EVENT ------------- |
Activate |
BTST #ActiveFlag,ModifyReg ; was it an Activate? |
BEQ.S @1 ; no, perform a Deactivate |
MOVE.L Message(A6),-(SP) ; pass the current window pointer |
MOVE.W #True,-(SP) ; set up for an Activate event |
BSR DoActivate ; do the activate routine |
BRA.S Exit ; we're done |
@1 MOVE.L Message(A6),-(SP) ; pass current window pointer |
MOVE.W #False,-(SP) ; set up for an Deactivate event |
BSR DoActivate ; go do the activate routine |
BRA.S Exit ; we're done |
* ------------- THE SUSPEND/RESUME EVENT ------------- |
* OSEvent is the event number of the suspend/resume and mouse-moved events sent |
* by MultiFinder. Once we determine that an event is an osEvent, we look at the |
* high byte of the message sent to determine which kind it is. To differentiate |
* suspend and resume events we check the resumeMask bit. |
OSEvent MOVE.B Message(A6),D1 ; get high byte of Message in reg |
CMPI.B #SuspendResume,D1 ; test for message event type |
BNE.S Exit ; not a suspend/resume event |
BTST #0,3+Message(A6) ; test bit zero in low byte of Message |
BNE.S @1 ; this is a resume event |
MOVE.W #True,G.InBackground ; a suspend event |
CLR.L -(SP) ; bug fix, was passing Message to DoActivate -JDR 2/27/89 |
_FrontWindow ; pass the front window to DoActivate -JDR 2/27/89 |
MOVE.W #False,-(SP) ; pass false to cause deactivate |
BSR DoActivate ; go do the activate routine |
BRA.S Exit |
@1 MOVE.W #False,G.InBackground ; a resume event |
CLR.L -(SP) ; bug fix, was passing Message to DoActivate -JDR 2/27/89 |
_FrontWindow ; pass the front window to DoActivate -JDR 2/27/89 |
MOVE.W #True,-(SP) ; pass false to cause activate |
BSR DoActivate ; go do the activate routine |
Exit |
MOVEM.L (SP)+,ModifyReg ; restore this register after use |
UNLK A6 |
MOVEA.L (SP)+,A0 ; save the caller's address |
ADDA.L #ParamSize,SP ; strip the caller's parameters |
JMP (A0) |
DbgInfo DoEvent ; this name will appear in the debugger |
ENDP |
* ================================================ |
* PROCEDURE EventLoop; |
* ================================================ |
* Get the events by calling WaitNextEvent, if it's available, otherwise |
* by calling GetNextEvent. Also call AdjustCursor before doing the event. |
* After returning from handling the event, we have to make sure the cursor |
* is still adjusted proper ONLY because this application can "sleep" forever. |
* An event record is allocated on the stack. A pointer to this event is |
* passed to "DoEvent". We loop until the user has selects "Quit" in the |
* file menu. This program will exit through the DoMenuCommand routine. |
* 1.02 made adjustments to the event loop logic. There was a bug in calling |
* AdjustCursor at the wrong time. (it crashed under _GetNextEvent too!) |
* If you are using modeless dialogs that have editText items, |
* you will want to call IsDialogEvent to give the caret a chance |
* to blink, even if WNE/GNE returned FALSE. However, check FrontWindow |
* for a non-NIL value before calling IsDialogEvent. |
SEG 'Main' ; case sensitive |
EventLoop PROC ; any source file can use this routine |
StackFrame RECORD {A6Link},DECR ; build a stack frame record |
ParamBegin EQU * ; start listing parameters here |
ParamSize EQU ParamBegin-* ; size of all the passed parameters |
RetAddr DS.L 1 ; place holder for return address |
A6Link DS.L 1 ; place holder for A6 link |
TheEvent DS EventRecord ; local copy of the event record |
MouseMvdRgn DS.L 1 ; local region for MouseMoved events |
MousePos DS.L 1 ; local point for mouse position |
LocalSize EQU * ; size of all the local variables |
ENDR |
IMPORT AdjustCursor,GetGlobalMouse |
WITH StackFrame ; cover our local stack frame |
LINK A6,#LocalSize ; allocate our local stack frame |
CLR.L -(SP) |
_NewRgn ; create region for AdjustCursor |
MOVE.L (SP)+,MouseMvdRgn(A6) ; save the handle to this region |
* ------------- GET NEXT EVENT LOOP ------------- |
NextEvent |
CMPI.W #True,G.HasWNEvent ; see if we can call WaitNextEvent |
BNE.S @1 ; nope, old time events |
PEA MousePos(A6) ; here's the mouse |
BSR GetGlobalMouse ; get global coordinate |
MOVE.L MousePos(A6),-(SP) ; here's the mouse |
MOVE.L MouseMvdRgn(A6),-(SP) ; the region to change |
BSR AdjustCursor ; adjust the cursor and region |
CLR.W -(SP) ; space for result |
MOVE.W #EveryEvent,-(SP) ; the events we want |
PEA TheEvent(A6) ; pointer to the event record |
MOVE.L #SleepValue,-(SP) ; the sleeping time value |
MOVE.L MouseMvdRgn(A6),-(SP) ; the current MouseRgn |
_WaitNextEvent |
BRA.S @2 ; got an event to handle? |
; no WaitNextEvent trap available |
@1 _SystemTask ; call SystemTask for drivers and DAs |
CLR.W -(SP) ; space for result |
MOVE.W #EveryEvent,-(SP) ; the events we want |
PEA TheEvent(A6) ; pass a pointer to our event |
_GetNextEvent |
@2 MOVE.W (SP)+,D0 ; result code |
BEQ.S NextEvent ; no event, get another one |
GotEvent MOVE.L TheEvent.where(A6),-(SP); the mouse location |
MOVE.L MouseMvdRgn(A6),-(SP) ; the region to change |
BSR AdjustCursor ; adjust cursor BEFORE doing event |
PEA TheEvent(A6) ; pass the pointer to our event |
BSR DoEvent ; do the event and return |
BRA.S NextEvent ; done with that event, get the next |
Exit UNLK A6 ; destroy the link |
MOVEA.L (SP)+,A0 ; pull off the return address |
ADDA.L #ParamSize,SP ; strip all of the caller's parameters |
JMP (A0) ; return to the caller |
DbgInfo EvntLoop ; this name will appear in the debugger |
ENDP |
* ================================================ |
* --------------- MAIN ENTRY POINT --------------- |
* ================================================ |
* This is the entry point of the program. We start with data initializing |
* and then to get the System environment (SysEnvirons). We unload the |
* initialization code segment and finally get started with the EventLoop. |
SEG 'Main' ; case sensitive |
StartUp MAIN ; entry point of the program |
IMPORT _DataInit,Initialize, \ |
ForceEnvirons,EventLoop |
JSR _DataInit ; initialize those constants |
PEA _DataInit ; get rid of that segment |
_UnloadSeg |
* If you have stack requirements that differ from the default, then you could |
* use SetApplLimit to increase StackSpace at this point, before calling MaxApplZone. |
_MaxApplZone ; result in D0 |
JSR Initialize ; get things the program set up |
PEA Initialize |
_UnloadSeg ; we're done this that segment too |
* ------------- SET UP THE CLUT WINDOW ------------- |
BSR OpenClutWind |
LEA EventLoop,A0 ; on your mark, get set,... |
JMP (A0) ; go into the event loop |
ENDP |
END ; end of this source file |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14