;*DDK*************************************************************************/
;
; COPYRIGHT (C) Microsoft Corporation, 1989
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
;/*****************************************************************************
;*
;* SOURCE FILE NAME = CURSOR2.ASM
;*
;* DESCRIPTIVE NAME = Cursor functions.
;*
;*
;* VERSION      V2.0
;*
;* DATE         10/19/91
;*
;* DESCRIPTION  Cursor functions.
;*
;* FUNCTIONS    DeviceSetCursor
;*              SetColorCursor
;*              SetDeviceCursor
;*              far_exclude
;*              far_unexclude
;*              SetScreenBusy
;*              CursorInit
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*
;*****************************************************************************/

        PAGE     60,132
        TITLE    Cursor Functions
        SUBTITLE Header
.386
.MODEL FLAT,SYSCALL

INCL_DDIMISC       EQU 1
INCL_GPIERRORS     EQU 1
INCL_GPIPRIMITIVES EQU 1
INCL_NOBASEAPI     EQU 1
INCL_SAADEFS       EQU 1
INCL_WINERRORS     EQU 1
INCL_WINPOINTERS   EQU 1
OS2_NOBASEAPI      EQU 1
OS2_NOPMAPI        EQU 1
        INCLUDE PMGRE.INC

DINCL_BITMAP     EQU 1
DINCL_ENABLE     EQU 1
        INCLUDE DRIVER.INC
        INCLUDE EXTERN.INC
        INCLUDE PROTOS.INC

        INCLUDE ASSERT.MAC
        include cursors.inc
        include pointer.inc
        include curstrc.inc

InnerExcludeTest PROTO SYSCALL

;/*
;** Prototypes for private functions
;*/

.DATA
EXTERNDEF CurData:CURSORSTRUCT

.CODE
        SUBTITLE DeviceSetCursor Function
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = DeviceSetCursor
;*
;* DESCRIPTION   = This function is called from the PDI dispatch table as the
;*                 GreDeviceSetCursor function.  The given pointer shape is
;*                 saved in local storage to be used as the current pointer
;*                 shape.  If the pointer to the pointer shape is NULL, then no
;*                 pointer is to be drawn.  The given pointer shape will have
;*                 been converted from generic form into the dimensions
;*                 requested by this driver.  Any pointer on the screen will be
;*                 removed before the new pointer shape is set.  The drawing of
;*                 the new pointer will be delayed until the check_pointer
;*                 routine is called (check_pointer is the only routine that
;*                 can make the pointer become visible).  If this routine is
;*                 reentered, the request will be ignored.
;*
;*                 Registers Preserved:
;*                       SI,DI,DS,BP
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,ES,FLAGS
;*
;* INPUT         = C Prototype:
;*                   BOOL SYSCALL DeviceSetCursor (HDC hdc,
;*                                                 PPOINTL pptHotspot,
;*                                                 ULONG hbm,
;*                                                 PVOID pInstance,
;*                                                 ULONG lFunction);
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = TRUE
;* RETURN-ERROR  = FALSE
;*
;**************************************************************************/


DeviceSetCursor PROC SYSCALL PUBLIC uses EBX ECX EDX,
                hdc       :HDC,
                pptHotspot:PPOINTL,
                hbm       :ULONG,
                pInstance :PVOID,
                lFunction :ULONG

        INVOKE  enter_driver_sem        ; Acquire screen semaphore

IFDEF FIREWALLS
        MOV     EBX,hbm                 ; They must have passed us a valid
        CMP     EBX,0                   ; bitmap handle else the Engine
        JE      @F                      ; screwed up

        CMP     [EBX].BITMAP.bm_sd.sd_usId,SURFACE_IDENT
        JNE     DSCNotBitmap
        TEST    [EBX].BITMAP.bm_sd.sd_fb,SD_DEVICE
        JZ      @F

DSCNotBitmap:
        rip        text,<DeviceSetCursor was given an invalid bitmap>

@@:

ENDIF ; FIREWALLS

        CMP     hbm,0                   ; Look for null pointer
        JZ      DSCLookingGood
        MOV     EBX,pptHotspot          ; Validate hotspot offsets

        MOV     EAX,[EBX].POINTL.ptl_x
        MOVSX   EDX,AX
        cmp     EDX,EAX
        JNE     DSCInvCoordinate
        MOV     ECX,EAX
        MOV     EAX,[EBX].POINTL.ptl_y
        MOVSX   EDX,AX
        cmp     EDX,EAX
        JE      DSCLookingGood

DSCInvCoordinate:
        MOV     EAX,PMERR_INV_COORDINATE
        save_error_code
        XOR     EAX,EAX
        JMP     DSCExit

DSCLookingGood:
        INVOKE  SetDeviceCursor,ECX,EAX,hbm,0,0,pInstance

DSCExit:
        INVOKE  leave_driver
        fw_zero <ECX>

        RET

DeviceSetCursor ENDP

        SUBTITLE SetColorCursor Function
        PAGE +


;/***************************************************************************
;*
;* FUNCTION NAME = SetColorCursor
;*
;* DESCRIPTION   = This function is equivalent to SetCursor except that it
;*                 takes a color bitmap handle.  This function is called from
;*                 the PDI dispatch table as the GreSetColorCursor function.
;*                 The given pointer shape is saved in local storage to be
;*                 used as the current pointer shape.  If pPointerInfo is
;*                 NULL, the pointer is to be removed.  The given pointer
;*                 shape will have been converted from generic form into the
;*                 dimensions requested by this driver.  Any pointer on the
;*                 screen will be removed before the new pointer shape is set.
;*                 The drawing of the new pointer will be delayed until the
;*                 check_pointer routine is called (check_pointer is the only
;*                 routine that can make the pointer become visible).
;*
;*                 Registers Preserved:
;*                       SI,DI,DS,BP
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,ES,FLAGS
;*
;* INPUT         = C Prototype:
;*                   BOOL SYSCALL SetColorCursor (HDC          hdc,
;*                                                PPOINTERINFO pPointerInfo,
;*                                                PVOID        pInstance,
;*                                                ULONG        lFunction);
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = TRUE
;* RETURN-ERROR  = FALSE
;*
;**************************************************************************/

SetColorCursor PROC SYSCALL PUBLIC uses EBX ECX EDX EDI ESI,
                hdc         :HDC,
                pPointerInfo:DWORD,
                pInstance   :PVOID,
                lFunction   :ULONG

        INVOKE  enter_driver_sem                ; Acquire screen semaphore
        MOV     EBX,pPointerInfo
        CMP     EBX,0                           ; Removing cursor from screen?
        JZ      SCCNullCursor                   ;  Y - Go do it
        MOV     EDI,[EBX].POINTERINFO.ptri_hbmColor

        assert  EDI,NE,0                        ; Must be non null bitmaps
        assert  [EBX].POINTERINFO.ptri_hbmPointer,NE,0

        INVOKE  GetDriverInfo,
                [EBX].POINTERINFO.ptri_hbmPointer,
                DI_HBITMAP,
                hdc                             ; EAX = Translated hbmPointer

        CMP     EAX,GPI_ALTERROR
        JZ      SCCInvCursor                    ; Return error

IFDEF FIREWALLS
        CMP     [EAX].BITMAP.bm_sd.sd_usId,SURFACE_IDENT
        JNE     SCCNotBM
        TEST    [EAX].BITMAP.bm_sd.sd_fb,SD_DEVICE
        JZ      @F
SCCNotBM:
        rip        text,<SetColorCursor was given an invalid bitmap>
@@:

ENDIF ; FIREWALLS

        XCHG    EDI,EAX                         ; EDI = Translated hbmPointer
                                                ; EAX = Original hbmColor
        INVOKE  GetDriverInfo,
                EAX,
                DI_HBITMAP,
                hdc                             ; EAX = Translated hbmColor

        CMP     EAX,GPI_ALTERROR                ; Error?
        JNZ     SCCGoodColorCursor              ;  N - Continue

SCCInvCursor:
        MOV     EAX,PMERR_INV_CURSOR_BITMAP
        save_error_code
        XOR     EAX,EAX
        JMP     SCCExit

SCCGoodColorCursor:

IFDEF FIREWALLS
        CMP     [EAX].BITMAP.bm_sd.sd_usId,SURFACE_IDENT
        JNE     SCCNotBitmap
        TEST    [EAX].BITMAP.bm_sd.sd_fb,SD_DEVICE
        JZ      @F
SCCNotBitmap:
        rip        text,<SetColorCursor was given an invalid bitmap>
@@:
ENDIF ; FIREWALLS

        MOV     EDX,EDI                         ; EDX = translated hbmPointer
        MOV     EDI,pPointerInfo
        MOV     EBX,[EDI].POINTERINFO.ptri_xHotspot
        MOV     ECX,[EDI].POINTERINFO.ptri_yHotspot

;/*
;** EDX = translated hbmPointer
;** EAX = translated hbmColor
;** EBX = x hotspot if cursor non null
;** ECX = y hotspot if cursor non null
;*/


        assert  EAX,NE,0         ; a NULL near ptr means no color bitmap

SCCNullCursor:
        INVOKE  SetDeviceCursor,
                EBX,
                ECX,
                EDX,
                EAX,
                [EDI].POINTERINFO.ptri_fPointer,
                pInstance

SCCExit:
        INVOKE  leave_driver
        fw_zero <ECX>
        RET
SetColorCursor ENDP

        SUBTITLE SetDeviceCursor
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = SetDeviceCursor
;*
;* DESCRIPTION   = Common routine for DeviceSetCursor and SetColorCursor.  The
;*                 given pointer shape is saved in local storage to be used as
;*                 the current pointer shape.  If the pointer to the pointer
;*                 shape (pbmPointer) is NULL, then no pointer is to be drawn.
;*                 The given pointer shape will have been converted from
;*                 generic form into the dimensions requested by this driver.
;*                 Any pointer on the screen will be removed before the new
;*                 pointer shape is set.  The drawing of the new pointer will
;*                 be delayed until the check_pointer routine is called
;*                 (check_pointer is the only routine that can make the
;*                 pointer become visible).
;*
;* INPUT         = C Prototype:
;*                   BOOL SYSCALL SetDeviceCursor (LONG sHotX,
;*                                                 LONG sHotY,
;*                                                 HBITMAP pbmPointer,
;*                                                 HBITMAP pbmColor,
;*                                                 ULONG   fwFlags,
;*                                                 PDDC pDDC);
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = TRUE
;* RETURN-ERROR  = FALSE
;*
;**************************************************************************/

SetDeviceCursor PROC SYSCALL PRIVATE uses EBX ECX EDX ESI EDI,
                sHotX     :SDWORD,
                sHotY     :SDWORD,
                pbmPointer:HBITMAP,
                pbmColor  :HBITMAP,
                fwFlags   :DWORD,
                pDDC      :PDDC

        LOCAL   pBitsAndXor :DWORD,     ; Pointer to AND/XOR mask bits
                pBitsColor  :DWORD,     ; Pointer to color mask bits
                tmpcxPointer:DWORD,
                tmpcyPointer:DWORD
        LOCAL   pBitsAndXorTmp :DWORD,  ;Pointer to AND/XOR mask bits
                pBitsColorTmp  :DWORD,  ;Pointer to color mask bits
                fSpecial       :DWORD   ;TRUE if special case, else FALSE

        PUSHFD                          ; Save flags
        CLD

;/*
;** Validate the incoming pointer shape.  If they passed us a NULL, then the
;** old cursor is to be removed, and no new cursor defined.  If they passed
;** anything else, validate it to be a bitmap in the correct format for us.
;*/


        MOV     pBitsAndXor,0           ; Initialize pointers for null bitmaps
        MOV     pBitsColor,0

        mov     pBitsAndXorTmp,0
        mov     pBitsColorTmp,0
        mov     fSpecial,0              ;Initialize to FALSE

;/*
;** pbmPointer must be a monochrome bitmap, of the correct width and height.
;** It is actually a double bitmap containing both the AND and XOR masks.
;** Therefore, the height given must be twice the actual image height.
;*/

        MOV     ESI,pbmPointer          ; We have confirmed that it's a bitmap
        OR      ESI,ESI
        JZ      SDCNullBitmap
        MOV     EAX,[ESI].BITMAP.bm_sd.sd_pBits
        MOV     pBitsAndXor,EAX
        MOV     EAX,PMERR_INV_CURSOR_BITMAP
        TEST    [ESI].BITMAP.bm_sd.sd_fb,SD_COLOR
        JNZ     SDCLogError

;/*
;** The driver may allow more than one pointer size.  Check that the given
;** bitmap has allowed dimensions.
;*/

        MOV     EBX,[ESI].BITMAP.bm_sd.sd_cx
        MOV     EDX,[ESI].BITMAP.bm_sd.sd_cy    ; Should be double-height
        SHR     EDX,1                           ; because it has both the AND
                                                ; and XOR masks.
        JC      SDCLogError
        MOV     ESI,[offset PtrSizes]
        MOV     ECX,[ESI][-(sizeof cPtrSizes)]  ; ECX = Ct. of valid ptr sizes
        assert  ECX,NE,0                        ; ESI -> list of valid ptr
                                                ; sizes
PtrSizeLoop:
        CMP     EBX,[ESI]                       ; Valid cxPtr?
        JNE     WrongCX
        CMP     EDX,[ESI].PTRSIZE.PtrHeight
        JE      BitmapSizeIsValid
WrongCX:
        cmp     ebx,40                          ;Check for special case (40x40)
        jnz     @f                              ;If cx == 40, check cy
        cmp     edx,40                          ;else continue as not special
        jnz     @f                              ;If cy == 40, treat as special
        mov     fSpecial,1                      ;Flag as special

;/*
;** Scale X and Y hot spots
;*/

        push    eax
        mov     eax,sHotX
        mov     ebx,4
        mul     ebx
        div     ebx
        mov     sHotX,eax
        mov     eax,sHotY
        mov     ebx,4
        mul     ebx
        mov     ebx,5
        div     ebx
        mov     sHotY,eax
        pop     eax
        mov     ebx,32
        mov     edx,32
        jmp     BitmapSizeIsValid
@@:
        ADD     ESI,sizeof PTRSIZE              ; Point to next size
        LOOP    PtrSizeLoop
        JMP     SDCLogError                     ; Oops

BitmapSizeIsValid:                              ; EBX:EDX = validated pointer
                                                ;           width:height
        MOV     tmpcxPointer,EBX                ; We don't dare change the
                                                ; actual pointer size until
        MOV     tmpcyPointer,EDX                ; we've called pointer_off

;/*
;** Validate pbmColor only if pbmPointer is not null.  pbmColor must be a color
;** bitmap of the correct width and height.
;*/

        MOV     EDI,pbmColor
        OR      EDI,EDI
        JZ      SDCLookingGood
        MOV     ESI,[EDI].BITMAP.bm_sd.sd_pBits
        MOV     pBitsColor,ESI
        assert  EAX,E,PMERR_INV_CURSOR_BITMAP
        TEST    [EDI].BITMAP.bm_sd.sd_fb,SD_COLOR
        JZ      SDCLogError
        cmp     fSpecial,1
        jz      SDCLookingGood
        CMP     [EDI].BITMAP.bm_sd.sd_cx,EBX
        JNE     SDCLogError
        CMP     [EDI].BITMAP.bm_sd.sd_cy,EDX
        JE      SDCLookingGood

SDCLogError:
        save_error_code
        XOR     EAX,EAX
        JMP     SDCExit

SDCLookingGood:
        DEC     EDX                             ; Map the Y into our hardware
        SUB     EDX,sHotY                       ; coordinate system.  (invert
        MOV     sHotY,EDX                       ; it)

;/*
;** All the bitmap stuff looks real good.  Take down the old pointer and then
;** see about setting this as the new one.
;*/


SDCNullBitmap:
        XOR     ECX,ECX                         ; Set screen busy
        XCHG    CurData.screen_busy,CL                  ; and get current status
        assert  ECX,NE,0                        ; Walt says it should never
                                                ; happen
        .ERRNZ  IS_BUSY

;/*
;** Remove any old pointer.
;**
;** cxReal and cyReal are kept as the upper left corner of where the pointer is
;** to be drawn.  Since the hot spot might change with the pointer shape, the
;** hot spot must be added back into these locations.  After the new pointer
;** has been set, the hot spot can be subtracted out for it.
;*/


        MOV     CL,CurData.fbPtrFlags                   ; Need old value for later
        OR      CL,CL                           ; Cursor on?
        JS      SDCCursorIsOff                  ;  N - Don't bother
        .ERRNZ  PTR_OFF-80h
        CLI                                     ;  Y - Don't want cxReal,
                                                ;      cyReal changing
        XOR     EAX,EAX                         ; Zero old hot spot and add
        XCHG    EAX,CurData.cxHot                       ; it back to real [X,Y]
        ADD     CurData.cxReal,EAX                      ; coordinate
        XOR     EAX,EAX
        XCHG    EAX,CurData.cyHot
        ADD     CurData.cyReal,EAX
        STI                                     ; Allow interrupts
        TEST    CurData.fwPrevFlags,PTRI_ANIMATE        ; Only skip if last pointer
        JZ      SDCRemoveCursor                 ; also was animated (full
                                                ; sized)
        TEST    fwFlags,PTRI_ANIMATE            ; Animating?
        JNZ     SDCCursorIsOff                  ;  Y - Don't clear old cursor

SDCRemoveCursor:
        LEA     EDI,CurData
        INVOKE  pointer_off,0,0                 ; Remove old ptr from screen
        MOV     CurData.fbPtrFlags,PTR_OFF

SDCCursorIsOff:
        MOV     EAX,fwFlags
        MOV     CurData.fwPrevFlags,AX
        CMP     pBitsAndXor,0                   ; pBitsAndXor was set to zero
        JZ      SDCGoodExit                     ; if a null bitmap was passed
                                                ; in
;/*
;** move_pointers saves the new ptr (AND/XOR masks and COLOR bm) in off-screen
;** memory (on most devices).  If any edges of the new pointer are transparent
;** then move_pointers may simply reduce the size of the stored bitmap and
;** associated exclusion rect.
;*/


        cmp     fSpecial,0            ;Special case (40x40) ?
        jz      not_special           ;if not, continue as normal (32x32)
        mov     eax,PTR_HEIGHT*PTR_WIDTH*2 ;EAX = size of allocated buffer 256
        lea     ebx,pBitsAndXorTmp    ;EBX = address of allocated buffer
        INVOKE  private_alloc
        jecxz   @f                    ;ECX = 0 if successful
        jmp     not_special
@@:
        cmp     pBitsColor,0
        jz      @f
        mov     eax,PTR_HEIGHT*PTR_WIDTH*8 ;EAX = size of allocated buffer 1024
        lea     ebx,pBitsColorTmp     ;EBX = address of allocated buffer
        INVOKE  private_alloc
        jecxz   @f                    ;ECX = 0 if successful
        mov     ecx,pBitsAndXorTmp    ;ECX = address of allocated buffer
        INVOKE  private_free
        jmp     not_special
@@:
        mov     esi,pBitsAndXor
        mov     edi,pBitsAndXorTmp

;/*
;** Clip 40x40 to 32x32
;*/


        mov     ecx,16
AndXor_loop:
        mov     ebx,4
next_row:

        lodsb
        shl     eax,8
        lodsb
        shl     eax,8
        lodsb
        shl     eax,8
        lodsb

        mov     edx,eax
        shld    eax,edx,4
        shl     edx,5
        jnc     @f
        or      eax,1
@@:
        shld    eax,edx,4
        shl     edx,5
        jnc     @f
        or      eax,1
@@:
        shld    eax,edx,4
        shl     edx,5
        jnc     @f
        or      eax,1
@@:
        shld    eax,edx,4
        shl     edx,5
        jnc     @f
        or      eax,1
@@:
        shld    eax,edx,4
        shl     edx,5
        jnc     @f
        or      eax,1
@@:
        shld    eax,edx,4
        shl     edx,5
        jnc     @f
        or      eax,1
@@:
        push    ecx
        movzx   ecx,byte ptr[esi]
        shl     ecx,22
        or      edx,ecx
        pop     ecx
        shld    eax,edx,4
        shl     edx,5
        jnc     @f
        or      eax,1
@@:
        shld    eax,edx,4
        shl     edx,5
        jnc     @f
        or      eax,1
@@:
        rol     eax,8
        stosb
        rol     eax,8
        stosb
        rol     eax,8
        stosb
        rol     eax,8
        stosb

        add     esi,4
        dec     ebx
        jnz     next_row

        lodsb
        shl     eax,8
        lodsb
        shl     eax,8
        lodsb
        shl     eax,8
        lodsb

        mov     edx,eax
        shld    eax,edx,4
        shl     edx,5
        jnc     @f
        or      eax,1
@@:
        shld    eax,edx,4
        shl     edx,5
        jnc     @f
        or      eax,1
@@:
        shld    eax,edx,4
        shl     edx,5
        jnc     @f
        or      eax,1
@@:
        shld    eax,edx,4
        shl     edx,5
        jnc     @f
        or      eax,1
@@:
        shld    eax,edx,4
        shl     edx,5
        jnc     @f
        or      eax,1
@@:
        shld    eax,edx,4
        shl     edx,5
        jnc     @f
        or      eax,1
@@:
        push    ecx
        movzx   ecx,byte ptr[esi]
        shl     ecx,22
        or      edx,ecx
        pop     ecx
        shld    eax,edx,4
        shl     edx,5
        jnc     @f
        or      eax,1
@@:
        shld    eax,edx,4
        shl     edx,5
        jnc     @f
        or      eax,1
@@:
        sub     edi,4

        rol     eax,8
        or      [edi],al
        inc     edi

        rol     eax,8
        or      [edi],al
        inc     edi

        rol     eax,8
        or      [edi],al
        inc     edi

        rol     eax,8
        or      [edi],al
        inc     edi

        add     esi,4

        dec     ecx
        jnz     AndXor_loop

        cmp     pBitsColorTmp,0
        jz      Color_done

        mov     esi,pBitsColor
        mov     edi,pBitsColorTmp

        mov     ecx,8
Color_loop:
        mov     ebx,4
next_color_row:
        movsd
        inc     esi
        movsd
        inc     esi
        movsd
        inc     esi
        movsd
        inc     esi
        movsd
        inc     esi
        movsd
        inc     esi
        movsd
        inc     esi
        movsd
        inc     esi
        dec     ebx
        jnz     next_color_row
        add     esi,40
        loop    Color_loop
Color_done:

        mov     ebx,tmpcxPointer
        mov     edx,tmpcyPointer
        INVOKE  move_pointers,pBitsAndXorTmp,pBitsColorTmp,fwFlags
        push    eax
        mov     ecx,pBitsAndXorTmp    ;ECX = address of allocated buffer
        INVOKE  private_free
        cmp     pBitsColorTmp,0
        jz      @f
        mov     ecx,pBitsColorTmp     ;ECX = address of allocated buffer
        INVOKE  private_free
@@:
        pop     eax
        jmp     check_return
not_special:

        MOV     EBX,tmpcxPointer                ; Not used by CGA/EGA/VGA
        MOV     EDX,tmpcyPointer

;/*
;** internal to this file
;*/

        INVOKE  move_pointers,pBitsAndXor,pBitsColor,fwFlags

check_return:

        ; Returns EDX and EAX
        OR      EAX,EAX                         ; CX=CY=0 iff xparent pointer
        JNZ     @F                              ; given
        OR      EDX,EDX
        JZ      SDCGoodExit                     ; given
@@:
        MOV     CurData.cxPointer,EAX                   ; Pointer width in bits
        MOV     CurData.cyPointer,EDX                   ; Pointer height in scans

;/*
;** Since the pointer must be drawn again (it wasn't a null pointer), we have
;** to draw it.  To do this, the pointer excluded flag will be set in
;** fbPtrFlags.  Only the timer code can bring the pointer back once it has
;** been excluded, and will do it when the next timer interrupt occurs.  This
;** minimizes the code that has to be written or duplicated in SetCursor!
;**
;** Also set up the new hot spot adjustments and adjust the pointer coordinate
;** for it.
;*/


        CLI                                     ; Don't want cxReal, cyReal
                                                ; changing
        MOV     EAX,sHotX                       ;Set X hot spot adjustment
        MOV     CurData.cxHot,EAX
        SUB     CurData.cxReal,EAX                      ; Adjust cxReal for hotspot
        MOV     EAX,sHotY                       ; Ditto for Y
        MOV     CurData.cyHot,EAX
        SUB     CurData.cyReal,EAX
        MOV     CurData.fbPtrFlags,PTR_EXCLUDED         ; Show excluded, but not
                                                ; hidden
        TEST    fwFlags,PTRI_ANIMATE
        JZ      SDCGoodExit
        MOV     CurData.fbPtrFlags,PTR_REDRAW           ; Cursor is animated type it
                                                ; needs to be redrawn
        STI
        MOV     CurData.screen_busy,NOT_BUSY
        LEA     eax,CurData
        INVOKE  MoveCursor,8000h,8000h          ; Force cursor check

;/*
;** Whatever had to be done has been.  Restore the interrupt state to whatever
;** was set by the user and free the screen and make the screen available.
;*/

SDCGoodExit:
        MOV     EAX,1
        STI
        MOV     CurData.screen_busy,NOT_BUSY

SDCExit:
        fw_zero <ECX>

        POPFD                                   ; Restore flags
        RET

SetDeviceCursor ENDP
        SUBTITLE far_exclude Function
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = far_exclude
;*
;* DESCRIPTION   =
;*
;*        This function sets the pointer exclusion rectangle.
;*
;*        The pointer exclusion area is set to the passed value.  If the pointer
;*        image is currently within the excluded area, it will be removed from the
;*        screen.
;*
;*        The given X coordinates will be rounded to the word size being used
;*        (byte, word, dword).  This removes the adjustment for word size out of
;*        the actual hit test code into the code that creates the exclusion
;*        rectangle.  The left side will be rounded down and the right side will be
;*        rounded up).
;*
;*        As an example, for bytes:
;*
;*                 top,left  ---------------------
;*                          |                     |
;*                          |                     |
;*                          |                     |
;*                          | Exclusion rectangle |
;*                          |                     |
;*                          |                     |
;*                          |                     |
;*                           ---------------------  right,bottom
;*
;*
;*               |L              |               |              R|
;*               |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|
;*
;*                  left will always be at D7
;*                  right will always be at D0
;*
;*
;*         Exclude is not called by the interrupt pointer drawing code.
;*
;*         Registers Preserved:
;*               BP
;*         Registers Destroyed:
;*               AX,BX,CX,DX,SI,DI,DS,ES,FLAGS
;*
;*
;* INPUT         = ECX = X coordinate of left edge
;*                 EDX = Y coordinate of top edge
;*                 ESI = X coordinate of right edge (inclusive)
;*                 EDI = Y coordinate of bottom edge (inclusive)
;*
;* OUTPUT        = NONE
;*                 Warning: Interrupts enables upon exit.
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

_PtrCode32 SEGMENT DWORD PUBLIC USE32 'CODE'

far_exclude PROC SYSCALL PUBLIC USES EDI
        LOCAL   dwVdm:DWORD

        mov     dwVdm,ebx               ; if EBX == 055555555h then this is VDM call

        AND     ECX,PTR_ROUND_LEFT      ; Round left coordinate down
        OR      ESI,PTR_ROUND_RIGHT     ; Round right coordinate up
        MOV     EBX,8000h               ; Make any negative top/lefts 0
        CMP     ECX,EBX                 ; 'C' if positive number
        SBB     EAX,EAX
        AND     ECX,EAX
        CMP     EDX,EBX
        SBB     EAX,EAX
        AND     EDX,EAX
        MOV     CurData.ExcludeRect.rcl_xLeft,ECX       ; Set up exclusion rectangle
        MOV     CurData.ExcludeRect.rcl_yTop,EDX
        MOV     CurData.ExcludeRect.rcl_xRight,ESI
        MOV     CurData.ExcludeRect.rcl_yBottom,EDI
        MOV     CurData.ExcludeCt,RECT_PRES
        MOV     CL,PTR_OFF+PTR_EXCLUDED ; Set test mask for ExcludeTest

;/*
;** Inside the critical section, we'll jump to ExcludeTest rather than call,
;** thus avoiding a stack reference (the push of the return address).
;** Currently (1 Mar 89) the ring 2 stack is 4K bytes and is locked down in
;** memory.  If the stack size is ever increased without locking down more than
;** the first page, then we will still be protected from stack page faults.
;*/

        cmp     dwVdm,55555555h
        je      @F
        CLI                                     ; Hit test is critical code
@@:
        MOV     EAX,CurData.cxCell                      ; Get current pointer x,y
        MOV     EBX,CurData.cyCell                      ; location
        MOV     EDX,offset HitTestReturn        ; Load return address
        lea     edi,CurData
        JMP     InnerExcludeTest

HitTestReturn:
        JNC     NoExcludeNeeded ; Hidden or already excluded
        JZ      NoExcludeNeeded ; Don't need to exclude

;/*
;** The pointer needs to be removed from the screen.  Show that the screen is
;** busy and then take the pointer down.  Since this is a pointer drawing
;** operation which will take some time, do it with interrupts enabled.
;*/

        XOR     ECX,ECX
        XCHG    CurData.screen_busy,CL          ; Set screen busy and save old state
        .ERRNZ  IS_BUSY
        MOV     CurData.fbPtrFlags,PTR_EXCLUDED ; Show pointer excluded
        cmp     dwVdm,55555555h
        je      @F
        STI                             ; Allow interrupts
@@:
        LEA     EDI,CurData
        PUSH    ECX
        INVOKE  pointer_off,0,0         ; Remove pointer
        POP     EAX                     ; Restore screen busy state
        MOV     CurData.screen_busy,AL

NoExcludeNeeded:
        cmp     dwVdm,55555555h
        je      @F
        STI
@@:

        RET

far_exclude ENDP
        SUBTITLE far_unexclude Function
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = far_unexclude
;*
;* DESCRIPTION   = The exclusion rectangle is removed.  The pointer will not
;*                 be redrawn since it might have to be taken down for the
;*                 next call.  Redrawing the pointer will be left to the
;*                 CheckCursor routine.
;*
;*                 Registers Preserved:
;*                       AX,BX,CX,DX,Si,DI,BP
;*                 Registers Destroyed:
;*                       DS
;*
;* INPUT         = C Prototype:
;*                   void SYSCALL far_unexclude (void)
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

far_unexclude PROC SYSCALL PUBLIC
        MOV     CurData.ExcludeCt,RECT_NOT_PRES

        RET

far_unexclude ENDP

SetScreenBusy PROC SYSCALL,
        ulState:BYTE
        MOV     AL,ulState
        MOV     CurData.screen_busy,AL
        RET
SetScreenBusy ENDP

_PtrCode32 ENDS

CursorInit PROC SYSCALL
        CALL    GetVRAMR0Pointer
        MOV     CurData.pVRAMRing0,EAX
        RET
CursorInit ENDP


END
