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