title	Exported cursor functions Windows 3.1 VGA/EGA Display drivers
.286c

.xlist
include CMACROS.INC
include WINDEFS.INC
include MFLAGS.INC
include CURSOR.INC
.list

subttl	Data Area for Set Cursor Routines
page +
sBegin	Data
globalW CURSOR_X_COORDINATE,0
globalW CURSOR_Y_COORDINATE,0
globalW UNDONE_X_COORDINATE,0
globalW UNDONE_Y_COORDINATE,0
globalB CURSOR_STATUS,IS_VISIBLE+IS_NULL
globalW CURSOR_X_SIZE,0
globalW CURSOR_Y_SIZE,0
globalW X_HOT_SPOT,0
globalW Y_HOT_SPOT,0
globalW wInhibitCount,0
externW Qsize				;MouseBlur Queue size.
sEnd	Data

IS_EXCLUDED	equ 000000001b		;Cursor is excluded.
IS_BUSY      	equ 000000010b		;Critical section.
IS_NULL	    	equ 000000100b		;Cursor is null.
HAS_MOVED	equ 000001000b		;Cursor has moved.
IS_VISIBLE   	equ 000010000b		;Cursor is visible.

subttl  The SetCursor Code
page +
sBegin	Code
assumes cs,Code
assumes ds,Data

externNP	CursorOff
externNP	LoadCursor
externNP	DrawCursor
externNP	ExcludeTest
externNP	EraseTail
externNP	unexclude

;--------------------------------------------------------------------------
; SetCursor
;--------------------------------------------------------------------------
cProc	SetCursor, <PUBLIC, FAR>, <si, di>
        parmD   lpCursorShape
	localB	bStatus

        org     $+1
_cstods label   word
        org     $-1
        public  _cstods

cBegin
	mov	cl,IS_BUSY		;Tell MoveCursor and CheckCursor
	xchg	CURSOR_STATUS,cl	;to not do anything.
	mov	bStatus,cl

	cmp	seg_lpCursorShape,0	;is this a null pointer?
	jne	short SC_DrawACursor	;no, go load and draw a cursor.
	test	bStatus,IS_NULL		;is cursor already null?
	jnz	short SC_End		;yep, we're done.
	or	bStatus,IS_NULL		;Indicate cursor is null.
	call	CursorOff		;erase the old cursor.
	and	bStatus,not IS_VISIBLE	;Show the cursor is not visible.
	jmp	short SC_End 		;and we're done.

SC_DrawACursor:
	mov	ax,Qsize		;If multiple trails are on 
	cmp	ax,1			;the screen, then turn them
	jz	short @f		;off before redefining the cursor.
	call	CursorOff
@@:	and	bStatus,not IS_NULL	;Show non-null cursor.
	push	ds			;save DS = Data
	mov	ax,ds			;make ES --> Data
	mov	es,ax			
	lds	si,lpCursorShape	;DS:SI points at our cursor
	lodsw				;get the X-hotspot
	mov	es:X_HOT_SPOT,ax	;save it.
	lodsw				;get the Y-hotspot 
	mov	es:Y_HOT_SPOT,ax	;save it.
	lodsw				;get the size in X
	mov	es:CURSOR_X_SIZE,ax	;save it
	lodsw				;get the size in Y
	mov	es:CURSOR_Y_SIZE,ax	;save it
	mov	di,ax			;this is size of our cursor
	add	si,4			;point at the cursor bits
@@:	call	LoadCursor		;Load the new cursor image.
	pop	ds
	test	bStatus,IS_EXCLUDED	;don't draw the cursor if 
	jnz	short SC_End		;excluded.
	call	DrawCursor		;Draw the new cursor.	
	or	bStatus,IS_VISIBLE	;Show the cursor is visible.
SC_End:                                          
	mov	cl,bStatus
	xchg	cl, CURSOR_STATUS
	mov	ax,1			;return success code
cEnd     

;--------------------------------------------------------------------------
; CheckCursor
;--------------------------------------------------------------------------
cProc	CheckCursor, <FAR,PUBLIC>, <si,di>
cBegin   
	mov	cl, IS_BUSY
	xchg	CURSOR_STATUS, cl	;get the state of the flag
					;upon entry to this routine, and
					;disable MoveCursor activity.

	;Should we try to bring the cursor back?

	test	cl,IS_BUSY 		;Are we exclusive?
	jnz	short CC_Exit		;no, get out.

	test	cl,HAS_MOVED			;Has the cursor moved?
	jz	short @f			;If so, 
	mov	ax,UNDONE_X_COORDINATE		;update with the most
	mov	CURSOR_X_COORDINATE,ax		;recent position.
	mov	ax,UNDONE_Y_COORDINATE
	mov	CURSOR_Y_COORDINATE,ax
	and	cl,not HAS_MOVED
@@:	test	cl,IS_NULL		;is cursor null?
	jnz	short CC_Exit		;No need to draw it.

	test	cl,IS_VISIBLE		;Have we drawn the cursor before?
	jnz	short CC_CheckTail	;Yes, maybe remove the tail.

	or	cl,IS_VISIBLE		;Indicate it is visible.
	push	cx
	call	DrawCursor		;Bring the cursor back.	
	pop	cx

	test	cl,IS_EXCLUDED		;Is cursor excluded?
	jz	short CC_Exit		;no. Get out.
	call	ExcludeTest		;Did we draw in the cursor exclusion
	jnc	short CC_Exit		;region?
	push	cx			;Yes, remove the cursor.
	call	CursorOff	
	pop	cx
	and	cl,not IS_VISIBLE	;Show that it is not visible.	
CC_Exit:
	xchg	cl,CURSOR_STATUS	;get back the original state of
					;the draw busy flag
cEnd

CC_CheckTail:
	mov	ax,Qsize		;Nothing special happens
	cmp	ax,1			;when the queue size is 1.
	je	short CC_Exit
	push	cx
	call	EraseTail
	pop	cx
	jmp	short CC_Exit

;--------------------------------------------------------------------------
; MoveCursor
;--------------------------------------------------------------------------
cProc	MoveCursor, <PUBLIC, FAR>, <si, di>
        parmW   absX
        parmW   absY
cBegin
	mov	cl,IS_BUSY		;set draw busy and get current
	xchg	cl,CURSOR_STATUS	;status into CL
	mov	ax,absX	 		;get X-coordinate
	mov	bx,absY			;get Y-coordinate
	or	ax,ax			;exceeding low X-limit?
	jg	MC_CHECK_HIGH_X_LIMIT	;nope, go on
	xor	ax,ax			;fix cursor position to 0

MC_CHECK_HIGH_X_LIMIT:
	cmp	ax,SCREEN_WIDTH		;exceeding high X-limit?
	jb	MC_CHECK_LOW_Y_LIMIT	;nope, go on
	mov	ax,SCREEN_WIDTH-1	;fix cursor position

MC_CHECK_LOW_Y_LIMIT:
	or	bx,bx			;exceeding low Y-limit?
	jg	MC_CHECK_HIGH_Y_LIMIT	;nope, go on
	mov	bx,1			;fix cursor position

MC_CHECK_HIGH_Y_LIMIT:
	cmp	bx,SCREEN_HEIGHT	;exceeding high Y-limit?
	jb	MC_MOVE_CURSOR		;nope, go do the cursor
	mov	bx,SCREEN_HEIGHT-1	;fix cursor position

MC_MOVE_CURSOR:                  
	test	cl,IS_BUSY		;is it safe to move the cursor?
	jnz	DONT_MOVE_CURSOR	;no, get out.

	mov	CURSOR_X_COORDINATE,ax	;save this location
	mov	CURSOR_Y_COORDINATE,bx

	test	cl,IS_NULL		;Is the cursor null?
	jnz	MOVE_CURSOR_EXIT	;yes, nothing to draw.

	push	cx			;Preserve status across the call.
	call	DrawCursor
	pop	cx
	or	cl,IS_VISIBLE		;Show we have drawn the cursor.

	test	cl,IS_EXCLUDED
	jz	short MOVE_CURSOR_EXIT

	call	ExcludeTest		;Have we drawn in the exclusion region?
	jnc	short @f		;No, we are done.
	push	cx			;Yes, remove the cursor.
	call	CursorOff	
	pop	cx
	and	cl,not IS_VISIBLE	;Show that it is not visible.
@@:	jmp	short MOVE_CURSOR_EXIT

DONT_MOVE_CURSOR:
	or	cl,HAS_MOVED		;Indicate the cursor has moved.
	mov	UNDONE_X_COORDINATE,ax	;save this location
	mov	UNDONE_Y_COORDINATE,bx

MOVE_CURSOR_EXIT:                                                       
	xchg	cl,CURSOR_STATUS	;restore the original state of
					;the cursor status flag
cEnd

if 0
;--------------------------------------------------------------------------
; October 31, 1991 - Removed this code because it causes the cursor to
; disapper (and/or blink) during GP fault recovery.  This code does 
; give a bit of a performance win, however, not a big win.
;--------------------------------------------------------------------------
; ORDINAL 105.
; InhibitCursorRedraw  -- User calls this when it expects that several
; back-to-back driver operations are going to occur.  If the driver
; has to exclude the cursor, it won't bring it back unless wInhibitCount is
; zero. 
; >0: Inhibit the cursor
;  0: UnInhibit the cursor
; <0: Reset the cursor
;--------------------------------------------------------------------------
cProc	InhibitCursorRedraw, <FAR,PUBLIC>
	parmW	wInhibit
cBegin   
	cmp	wInhibit,0	;Is the command to Uninhibit the cursor?
	jz	short ICR_Uninhibit ;Zero means yes. 
	jl	short ICR_Reset	;negative means reset.
ICR_Inhibit:
	inc	wInhibitCount	;Positive...Just increment wInhibitCount.
	jmp	ICR_Exit

ICR_Reset:
	xor	ax,ax
	mov	wInhibitCount,ax
	jmp	short @f
ICR_Uninhibit:
	dec	wInhibitCount	;no. Decrement wInhibitCount and if we
	jnz	short ICR_Exit	;go to zero, go unexclude the cursor.
@@:	cCall	unexclude
ICR_Exit:
cEnd	
endif

sEnd            Code
end
