CLUTSampleMisc.a

*
*   Apple Macintosh Developer Technical Support
*
*   CLUTSample
*
*   CLUTSampleMisc.a    -   Assembler Source
*
*
*       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.
 
*   Copyright © 1990 Apple Computer, Inc.
*   All rights reserved.
 
 
* ================================================
* -------------- 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 USAGE  ---------------
* ================================================
        IMPORT  QD:QDGlobals
        IMPORT  G:AppGlobals
 
 
* ================================================
* FUNCTION TrapAvailable(tNumber: INTEGER): BOOLEAN;
* ================================================
        SEG 'Initialize'        ; case sensitive
TrapAvailable   FUNC    EXPORT          ; any source file can use this routine
 
StackFrame  RECORD  {A6Link},DECR       ; build a stack frame record
Result      DS.W    1           ; function's result returned to caller
ParamBegin  EQU *           ; start parameters after this point
tNumber     DS.W    1           ; the trap number passed by caller
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
TrapAddress DS.L    1           ; local copy of trap address
LocalSize   EQU     *           ; size of all the local variables
        ENDR
 
        WITH    StackFrame      ; cover our local stack frame
        LINK    A6,#LocalSize       ; allocate our local stack frame
 
        MOVE.W  #False,Result(A6)   ; initialize function's result
 
        MOVE.W  tNumber(A6),D0      ; get trap word into D0
        BTST    #ToolTrapBit,D0     ; test if number is Tool trap
        BEQ.S   GetOSTrap       ; off means a new OS trap number
        
        MOVE.W  G.Mac.machineType,D1    ; get the machine type we're running
        CMPI.W  #envMachUnknown,D1  ; are we on a future machine?
        BEQ.S   GetToolTrap     ; yes, go ahead and test for a new Tool trap
        
        CMPI.W  #envMacII,D1        ; are we on a Mac II or better?
        BGE.S   GetToolTrap     ; yes, go ahead and test for a new Tool trap
 
* ------------- TEST FOR EXCEEDING TRAP TABLE -------------
* At this point we know we're on a Mac 512E, Plus, or SE and need to
* test the trap number for being in the range of < $0200
 
        AND.W   #$03FF,D0       ; mask off the ToolTrap bits
        CMPI.W  #$01FF,D0       ; is this trap in our trap table?
        BLE.S   GetToolTrap     ; yes, go ahead and test for a new Tool trap
        BRA.S   Exit            ; no, then this trap cannot be present
        
* ------------- TEST FOR NEW TOOL TRAP -------------
 
GetToolTrap _GetTrapAddress ,NewTool    ; NewTool trap macro, trap is in D0
        MOVE.L  A0,TrapAddress(A6)  ; save a copy of the trap address
        BRA.S   TestUnimp       ; test against Unimplemented trap
        
* ------------- TEST FOR NEW OS TRAP -------------
 
GetOSTrap   _GetTrapAddress ,NewOS      ; NewOS trap macro, trap is in D0
        MOVE.L  A0,TrapAddress(A6)  ; save a copy of the trap address
TestUnimp   MOVE.W  #Unimplemented,D0   ; get address of Unimplemented trap
        _GetTrapAddress
        CMPA.L  TrapAddress(A6),A0  ; see if trap is implemented
        BEQ.S   Exit            ; nope, they're the same
        MOVE.W  #True,Result(A6)    ; yes, we've got the trap
 
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 TrapAval        ; this name will appear in the debugger
        ENDF
 
* ================================================
* FUNCTION GoGetRect(rectID: INTEGER; VAR theRect: Rect) : BOOLEAN;
* ================================================
* This utility loads the global rectangles that are used by the window
* drawing routines. It shows how the resource manager can be used to hold
* values in a convenient manner. These values are then easily altered without
* having to re-compile the source code. GoGetRect will return a BOOLEAN that
* indicates if it was successful in getting the rectangle.
 
* A0 is being used for resource handle.
 
        SEG 'Initialize'        ; case sensitive
GoGetRect   FUNC    EXPORT          ; any source file can use this routine
 
StackFrame  RECORD  {A6Link},DECR       ; build a stack frame record
Result      DS.W    1           ; function's result returned to caller
ParamBegin  EQU *           ; start parameters after this point
RectID      DS.W    1           ; resource ID of rect passed by caller
TheRect     DS.L    1           ; the rect's pointer passed by caller
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
 
        WITH    StackFrame      ; cover our local stack frame
        LINK    A6,#LocalSize       ; allocate our local stack frame
 
        MOVE.W  #False,Result(A6)   ; initialize function's result
 
        CLR.L   -(SP)           ; create space for result
        MOVE.L  #'RECT',-(SP)
        MOVE.W  RectID(A6),-(SP)    ; get the stop light's rect
        _GetResource
        MOVEA.L (SP)+,A0        ; handle to RECT resource in A0
        CMPA.L  #NIL,A0         ; test for NIL handle
        BEQ.S   Exit            ; didn't get resource, exit this procedure
 
 
* -------- COPY THE RESOURCE TO THE RECT --------
 
        MOVE.W  #True,Result(A6)    ; we got the resource, return true
        MOVEA.L (A0),A0         ; pointer to RECT resource in A0
        MOVEA.L TheRect(A6),A1      ; pointer to the dest. RECT in A1
        MOVE.L  topLeft(A0),topLeft(A1) ; copy to the rect passed to us
        MOVE.L  botRight(A0),botRight(A1)
 
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 GetRect         ; this name will appear in the debugger
        ENDF
 
* ================================================
* FUNCTION IsDAWindow(window: WindowPtr): BOOLEAN;
* ================================================
* Check if a window belongs to a desk accessory.  DA window has a negitive kind.
 
        SEG 'Main'
IsDAWindow  FUNC    EXPORT          ; any source file can use this routine
 
StackFrame  RECORD  {A6Link},DECR       ; build a stack frame record
Result      DS.W    1           ; function's result returned to caller
ParamBegin  EQU *           ; start parameters after this point
TheWindow   DS.L    1           ; a window's pointer passed by caller
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
 
        WITH    StackFrame      ; cover our local stack frame
        LINK    A6,#LocalSize       ; allocate our local stack frame
 
        MOVE.W  #False,Result(A6)   ; first, initialize the result
        CMPI.L  #NIL,TheWindow(A6)  ; valid pointer?
        BEQ.S   Exit            ; it was NIL, look out!
 
        MOVEA.L TheWindow(A6),A0    ; get the window pointer
        MOVE.W  WindowKind(A0),D0   ; what kind of window was it?
        BPL.S   Exit            ; DA windows are negitive
 
        MOVE.W  #True,Result(A6)    ; return true to the caller
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 IsDAWind        ; this name will appear in the debugger
        ENDF
 
* ================================================
* FUNCTION IsAppWindow(window: WindowPtr): BOOLEAN;
* ================================================
* Check to see if a window belongs to the application. If the window pointer
* passed was NIL, then it could not be an application window. WindowKinds
* that are negative belong to the system and windowKinds less than userKind
* are reserved by Apple except for windowKinds equal to dialogKind, which
* means it is a dialog.
* In order to reduce the chance of accidentally treating some window
* as an AppWindow that shouldn't be, we'll only return true if the windowkind
* is userKind. If you add different kinds of windows to Sample you'll need
* to change how this all works.
 
        SEG 'Main'
IsAppWindow FUNC    EXPORT          ; any source file can use this routine
 
StackFrame  RECORD  {A6Link},DECR       ; build a stack frame record
Result      DS.W    1           ; function's result returned to caller
ParamBegin  EQU *           ; start parameters after this point
TheWindow   DS.L    1           ; a window's pointer passed by caller
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
 
        WITH    StackFrame      ; cover our local stack frame
        LINK    A6,#LocalSize       ; allocate our local stack frame
 
        MOVE.W  #False,Result(A6)   ; first, initialize the result
        CMPI.L  #NIL,TheWindow(A6)  ; valid pointer?
        BEQ.S   Exit            ; it was NIL, look out!
 
        MOVEA.L TheWindow(A6),A0    ; get the window pointer
        MOVE.W  WindowKind(A0),D0   ; what kind of window was it?
        CMPI.W  #UserKind,D0        ; was it an application window?
        BNE.S   Exit            ; no, result is going to be false
 
        MOVE.W  #True,Result(A6)    ; return true to the caller
 
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 IsAppWin        ; this name will appear in the debugger
        ENDF
 
* ================================================
* PROCEDURE AlertUser;
* ================================================
* Display an alert that tells the user an error occurred, then exit the program.
* This routine is used as an ultimate bail-out for serious errors that prohibit
* the continuation of the application. Errors that do not require the termination
* of the application should be handled in a different manner. Error checking and
* reporting has a place even in the simplest application. For simplicity, the alert
* displayed here only says that an error occurred, but not what it was. There are
* various methods available for being more specific.
 
        SEG 'Main'      ; case sensitive
AlertUser   PROC    EXPORT          ; any source file can use this routine
 
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
LocalSize   EQU     *           ; size of all the local variables
        ENDR
 
        WITH    StackFrame      ; cover our local stack frame
        LINK    A6,#LocalSize       ; allocate our local stack frame
 
        CLR.W   -(SP)           ; space for result of Alert
        MOVE.W  #rUserAlert,-(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
        _ExitToShell            ; we're out of here, no error recovery
 
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 AlrtUser        ; this name will appear in the debugger
        ENDP
 
* ================================================
* FUNCTION DoCloseWindow(window: WindowPtr) : BOOLEAN;
* ================================================
* At this point, if there was a document associated with a window, you could
* do any document saving processing if it is 'dirty'.  DoCloseWindow would
* return TRUE if the window actually closes, i.e., the user does not cancel
* from a save dialog. This result is handy when the user quits an application,
* but then cancels a save of a document associated with a window. We also added
* code to close the application window since otherwise, the termination routines
* would never stop looping, waiting for FrontWindow to return NIL.
 
        SEG 'Main'          ; case sensitive
DoCloseWindow   FUNC    EXPORT          ; any source file can use this routine
 
StackFrame  RECORD  {A6Link},DECR       ; build a stack frame record
Result      DS.W    1           ; function's result returned to caller
ParamBegin  EQU *           ; start parameters after this point
WindowPtr   DS.L    1           ; passed window pointer parameter
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
 
        WITH    StackFrame      ; cover our local stack frame
        LINK    A6,#LocalSize       ; allocate our local stack frame
 
        MOVE.W  #True,Result(A6);   ; initialize the function's result
 
        CLR.W   -(SP)           ; space for result of IsDAWindow
        MOVE.L  WindowPtr(A6),-(SP) ; pass the window pointer
        BSR IsDAWindow
        MOVE.W  (SP)+,D0        ; result of IsDAWindow
        CMPI.W  #True,D0
        BNE.S   @1          ; this wasn't a DA window
 
        MOVEA.L WindowPtr(A6),A0    ; get window pointer
        MOVE.W  WindowKind(A0),-(SP)    ; pass the refNum of DA
        _CloseDeskAcc
        BRA.S   Exit            ; all done
 
@1      CLR.W   -(SP)           ; space for result of IsAppWindow
        MOVE.L  WindowPtr(A6),-(SP) ; pass a the window pointer
        BSR IsAppWindow
        MOVE.W  (SP)+,D0        ; result of IsAppWindow
        CMPI.W  #True,D0
        BNE.S   Exit            ; it wasn't our application's window
 
        MOVE.L  WindowPtr(A6),-(SP) ; close window, it shouldn't be a dialog
        _CloseWindow            ; close the application window
 
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 ClosWind        ; this name will appear in the debugger
        ENDF
 
* ================================================
* PROCEDURE Terminate;
* ================================================
* Clean up the application and exit. We close all of the windows so that
* they can update their documents, if any.  We don't have much to do here.
* Just close our windows and then exit.  If we find out that a Cancel has
* occurred (DoCloseWindow will return False) we won't exit to the shell,
* but will simply exit this procedure.
 
        SEG 'Main'          ; case sensitive
Terminate   PROC    EXPORT
 
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
WindowPtr   DS.L    1           ; local variable for a window pointer
Closed      DS.W    1           ; local variable for looping
LocalSize   EQU     *           ; size of all the local variables
        ENDR
 
        IMPORT  DoCloseWindow
 
        WITH    StackFrame      ; cover our local stack frame
        LINK    A6,#LocalSize       ; allocate our local stack frame
 
        MOVE.W  #True,Closed(A6)    ; initialize local variable
 
Loop        CLR.L   -(SP)           ; space for front window pointer
        _FrontWindow
        MOVE.L  (SP)+,WindowPtr(A6) ; get the front window pointer
        CMPI.L  #NIL,WindowPtr(A6)  ; is there a front window?
        BEQ.S   @1          ; there are no more windows
 
        CLR.W   -(SP)           ; space for result of DoCloseWindow
        MOVE.L  WindowPtr(A6),-(SP) ; pass the window pointer
        BSR DoCloseWindow       ; close all our windows
        MOVE.W  (SP)+,Closed(A6)    ; get result of DoCloseWindow
        CMPI.W  #True,Closed(A6)    ; what's the result of DoCloseWindow?
        BNE.S   Exit            ; user didn't want to close that window
 
        BRA.S   Loop            ; loop again and close the next window
 
@1      CMPI.W  #True,Closed(A6)    ; should we really terminate?
        BNE.S   Exit            ; no, exit this procedure
 
        _ExitToShell            ; we're done, let's get out of here
 
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 Terminat        ; this name will appear in the debugger
        ENDP
 
* ================================================
* PROCEDURE AdjustMenus;
* ================================================
* Enable and disable menus based on the current state.  The user can only select
* enabled menu items. We set up all the menu items before calling MenuSelect or
* MenuKey, since these are the only times that a menu item can be selected. Note
* that MenuSelect is also the only time the user will see menu items. This
* approach to deciding what enable/disable state a menu item has the advantage
* of concentrating all the decision making in one routine, as opposed to being
* spread throughout the application.  Other application designs may take a
* different approach that are just as valid.
 
        SEG 'Main'          ; case sensitive
AdjustMenus PROC    EXPORT          ; any source file can use this routine
 
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
FrontMost   DS.L    1           ; local copy of the front window
Menu        DS.L    1           ; local copy of the menu handle
LocalSize   EQU     *           ; size of all the local variables
        ENDR
 
        WITH    StackFrame      ; cover our local stack frame
        LINK    A6,#LocalSize       ; allocate our local stack frame
 
        CLR.L   -(SP)           ; space for result
        _FrontWindow
        MOVE.L  (SP)+,FrontMost(A6) ; save the front window
 
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 AdjstMnu        ; this name will appear in the debugger
        ENDP
 
* ================================================
* PROCEDURE GetGlobalMouse(VAR mouse: Point);
* ================================================
* Get the global coordinates of the mouse. When you call OSEventAvail
* it will return either a pending event or a null event. In either case,
* the where field of the event record will contain the current position
* of the mouse in global coordinates and the modifiers field will reflect
* the current state of the modifiers. Another way to get the global
* coordinates is to call GetMouse and LocalToGlobal, but that requires
* being sure that thePort is set to a valid port.}
 
        SEG 'Main'          ; case sensitive
GetGlobalMouse  PROC    EXPORT          ; any source file can use this routine
 
StackFrame  RECORD  {A6Link},DECR       ; build a stack frame record
ParamBegin  EQU *           ; start parameters after this point
Mouse       DS.L    1           ; passed reference to mouse position
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
 
        WITH    StackFrame      ; cover our local stack frame
        LINK    A6,#LocalSize       ; allocate our local stack frame
 
        MOVE.W  #NoEvents,D0        ; we aren't interested in any events
        LEA TheEvent(A6),A0     ; point to event record
        _OSEventAvail           ; just the mouse position
        MOVE.L  Mouse(A6),A0        ; deref address of mouse
        MOVE.L  TheEvent.Where(A6),(A0) ; stuff new value
 
        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 GetGlobalMouse      ; this name will appear in the debugger
        ENDP
 
* ================================================
* PROCEDURE DrawClut(window: WindowPtr);
* ================================================
*
* This procedure finds the max depth device for the window port and uses that
* device to draw the colors in the window.
 
        SEG 'Main'          ; case sensitive
DrawClut    PROC    EXPORT          ; any source file can use this routine
 
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
Color       DS.W    3
OldGDev     DS.l    1           ; save current GDevice
wRectBR     DS.L    1           ; 
wRectTL     DS.L    1           ; local storage for rect
LocalSize   EQU     *           ; size of all the local variables
        ENDR
 
        WITH    StackFrame,ClutWData    ; cover our local stack frame
        LINK    A6,#LocalSize       ; allocate our local stack frame
 
        MOVE.L  WindowPtr(A6),-(SP)
        _SetPort            ; set the current port to use
        
        MOVE.L  theGDevice,OldGDev(a6)  ; save current device
        
; Now we want to check the max device the window is on in order to use its color table
; to display colors. 
 
        move.l  WindowPtr(a6), A0   ; get pointer to port
        ADD.L   #$10,A0         ; point to rectangle
        LEA wRectTL(a6),a1
        MOVE.L  (a0)+,(a1)+     ; copy topleft
        MOVE.L  (a0)+,(a1)+     ; copy bottomright
        PEA wRectTL(a6)     ; push rect
        _LocalToGlobal          ; globalize topleft
        PEA wRectBR(a6)     ; push rect
        _LocalToGlobal          ; globalize bottomright
 
        clr.l   -(sp)           ; make room for result 
        PEA wRectTL(a6)     ; push rect
        _GetMaxDevice           ; don't touch result
        
        CMP.L   #0,(sp)         ; check result
        BEQ @1          ; if nil use current device
        
        _SetGDevice         ; the max dev is in the stack
        
@1      Move.L  #255,D3
        Move.w  #4,-(SP)
        Move.w  #4,-(SP)
        _PenSize
ClutLoop:
        Move.L  D3,-(SP)
        Pea Color(A6)
        _Index2Color
        Pea Color(A6)
        _RGBForeColor
                        ; Build 16*16 array = 256 colors
        Move.w  D3,D0           ; Current color index
        And.w   #$000F,D0       ; mod 16 (16 colors per row)
        ASL.w   #2,D0           ; times 4 (pen width)
        Move.w  D0,-(SP)        ; set ÔleftÕ for MoveTo
        Move.w  D3,D0           ; Current index
        LSR.w   #4,D0           ; divided by 16 (and lose low order bits)
        ASL.w   #2,D0           ; times 4 (pen width)
        Move.w  D0,-(SP)        ; set ÔtopÕ for MoveTo
        _MoveTo
        Clr.l   -(SP)
        _Line               ; Line length of zero ÔstampsÕ in pen
        DBRA    D3,ClutLoop
 
Exit        MOVE.L  OldGDev(a6),theGDevice  ; restore current device
 
        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 DrawClut
        ENDP
        
* ================================================
* PROCEDURE NulMouse(window: WindowPtr; event: EventRecord);
* ================================================
        SEG 'Main'          ; case sensitive
NulMouse    PROC    EXPORT
 
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
EventPtr    DS.L    1           ; pointer to 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
* insert locals here
LocalSize   EQU     *           ; size of all the local variables
        ENDR
;       IMPORT  
 
        WITH    StackFrame      ; cover our local stack frame
        LINK    A6,#LocalSize       ; allocate our local stack frame
        
 
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 NulMouse
        ENDP
 
* ================================================
* PROCEDURE AdjustCursor(mouse: Point; region: RgnHandle);
* ================================================
* Change the cursor's shape, depending on its position. This also calculates the
* region where the current cursor resides (for WaitNextEvent). If the mouse is
* ever outside of that region, an event would be generated, causing this routine
* to be called, allowing us to change the region to the region the mouse is
* currently in. If there is more to the event than just the mouse moved, we
* get called before the event is processed to make sure the cursor is the right
* one. In any (ahem) event, this is called again before we fall back into WNE.
* 1.02 - Removed the mouse position parameter and instead use the current position
* of the mouse by calling GetMouse and LocalToGlobal.
 
        SEG 'Main'          ; case sensitive
AdjustCursor    PROC    EXPORT
 
StackFrame  RECORD  {A6Link},DECR       ; build a stack frame record
ParamBegin  EQU *           ; start parameters after this point
Where       DS.L    1           ; the mouse location passed to us
MouseRegion DS.L    1           ; passed pointer to current region
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
FrontMost   DS.L    1           ; local pointer to the front window
ArrowRgn    DS.L    1           ; local handle to the arrow cursor region
PlusRgn     DS.L    1           ; local handle to the plus cursor region
LocalSize   EQU     *           ; size of all the local variables
        ENDR
 
        IMPORT  IsDAWindow,IsAppWindow
 
        WITH    StackFrame      ; cover our local stack frame
        LINK    A6,#LocalSize       ; allocate our local stack frame
 
        CLR.W   -(SP)           ; space for result of IsAppWindow
        CLR.L   -(SP)           ; space for result of FrontWindow
        _FrontWindow            ; push front window pointer
        MOVE.L  (SP),FrontMost(A6)  ; copy pointer and keep it on stack
        BSR IsDAWindow      ; is this an application window?
        MOVE.W  (SP)+,D0
        CMPI.W  #True,D0
        BEQ.W   Exit            ; not our window, don't adjust the cursor
        CMPI.W  #True,G.InBackground
        BEQ.W   Exit            ; and do nothing if we're in the background
 
* ------------- INITIALIZE SOME REGION DATA -------------
 
        CLR.L   -(SP)
        _NewRgn             ; create an empty plus region
        MOVE.L  (SP)+,PlusRgn(A6)
        CLR.L   -(SP)
        _NewRgn             ; create an empty arrow region
        MOVE.L  (SP)+,ArrowRgn(A6)
        MOVE.L  ArrowRgn(A6),-(SP)  ; arrow region handle
        MOVE.W  #ExtremeNeg,-(SP)   ; big left corner
        MOVE.W  #ExtremeNeg,-(SP)   ; big top corner
        MOVE.W  #ExtremePos,-(SP)   ; big right corner
        MOVE.W  #ExtremePos,-(SP)   ; big bottom corner
        _SetRecRgn          ; really big rectangular region
 
        CLR.W   -(SP)
        MOVE.L  FrontMost(A6),-(SP)
        BSR IsAppWindow     ; is this an application window?
        MOVE.W  (SP)+,D0
        CMPI.W  #True,D0
        BNE.S   @1          ; our window isn't in front?
 
* ------------- CALCULATE THE PLUS REGION -------------
 
        MOVE.L  FrontMost(A6),-(SP)
        _SetPort            ; set the current port to us
        MOVEA.L FrontMost(A6),A0
        MOVE.W  portBits+bounds+left(A0),D0
        NEG.W   D0          ; offset window's left edge...
        MOVE.W  D0,-(SP)        ; to the screen's left edge
        MOVEA.L FrontMost(A6),A0
        MOVE.W  portBits+bounds+top(A0),D0
        NEG.W   D0          ; offset window's top edge...
        MOVE.W  D0,-(SP)        ; to the screen's top edge
        _SetOrigin          ; make window rect global
        MOVE.L  PlusRgn(A6),-(SP)   ; handle to empty plus region
        MOVEA.L FrontMost(A6),A0    ; pointer to our window
        PEA portRect(A0)        ; window rect's global coordinates
        _RectRgn            ; make global window rect into region
        MOVE.L  PlusRgn(A6),-(SP)   ; get intersection of plus and window region
        MOVEA.L FrontMost(A6),A0
        MOVE.L  visRgn(A0),-(SP)    ; get front window's visRgn
        MOVE.L  PlusRgn(A6),-(SP)   ; resulting region will be in PlusRgn
        _SectRgn            ; intersection the two regions
        CLR.L   -(SP)           ; reset the origin of our window to 0,0
        _SetOrigin
 
@1      MOVE.L  ArrowRgn(A6),-(SP)  ; the really big rectangular region
        MOVE.L  PlusRgn(A6),-(SP)   ; the region of our window
        MOVE.L  ArrowRgn(A6),-(SP)  ; intersetion of the Arrow and Plus region
        _DiffRgn            ; this is the region where the Arrow shows
        CLR.W   -(SP)           ; space for result of PtInRect
        MOVE.L  Where(A6),-(SP)     ; here's the mouse
        MOVE.L  PlusRgn(A6),-(SP)   ; where the arrow should show up
        _PtInRgn            ; was cursor in the arrow region?
        MOVE.W  (SP)+,D0
        CMPI.W  #True,D0
        BNE.S   @2          ; cursor was in arrow region
 
* ------------- SET THE CURSOR AND NEW MOUSE REGION -------------
 
        CLR.L   -(SP)           ; space for result
        MOVE.W  #plusCursor,-(SP)   ; I want the plus cursor now!
        _GetCursor
        MOVEA.L (SP)+,A0        ; get the handle
        CMPA.L  #NIL,A0
        BEQ.S   Exit            ; check for NIL like a good boy
        MOVE.L  (A0),-(SP)      ; got the plus cursor
        _SetCursor          ; set cursor to plus
        MOVE.L  PlusRgn(A6),-(SP)   ; current region containing cursor
        MOVE.L  MouseRegion(A6),-(SP)   ; set it to the new region
        _CopyRgn
        BRA.S   @3          ; we're done, get out of here
 
@2      PEA QD.Arrow        ; got arrow cursor at InitGraf
        _SetCursor          ; set cursor to the Arrow
        MOVE.L  ArrowRgn(A6),-(SP)  ; current region containing cursor
        MOVE.L  MouseRegion(A6),-(SP)   ; set it to the new region
        _CopyRgn
 
@3      MOVE.L  PlusRgn(A6),-(SP)   ; dispose of our two temporary regions
        _DisposRgn
        MOVE.L  ArrowRgn(A6),-(SP)
        _DisposRgn
 
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 AdjstCur        ; this name will appear in the debugger
        ENDP
 
        END             ; end of this source file