*******************************************************************************
*
* off-screen port routines -- Version 3.0
*
* Copyright (c)
* Apple Computer, Inc.  1989-1990
* All Rights Reserved.
*
* Written by Eric Soldan.
*
* Developer Technical Support Apple II Sample Code
*
* The purpose of this code is to make creating and disposing of off-screen
* grafPorts more convenient.
*
*******************************************************************************
	case on

	INCLUDE 'm16.util2'
	INCLUDE 'e16.types'

	INCLUDE 'm16.intmath'
	INCLUDE 'e16.memory'
	INCLUDE 'm16.memory'
	INCLUDE 'e16.quickdraw'
	INCLUDE 'm16.quickdraw'

	longi on
	longa on

***********************************************************************

	export newPort
newPort	PROC
	import killPort

	DefineStack

keepPort	long	;Must be at 1,s.
portPtr	long	;Pass NULL if mem needed for port.
portHndl	long
bitMapPtr	long	;Pass NULL if mem needed for bitMap.
bitMapHndl	long
bitMapAttr	word	;Memory attributes for bitMap.
portRect	block 8
bitMapRect	block 8
endDesc	block 0	;Descriptor locals end here.

portInfo	block oportRect-oportInfo
bitMapHeight	word
bmPtr	long	;Pointer to bitMap, if we made one.
tempPtr	long	;Temporary bitMap work pointer.

sizeLocals	EndLocals

saveDPage	word
returnAddr	block 3

	BegParms
portDescPtr	long	;Pointer to port descriptor.
sizeParms	EndParms

retval	long	;We will return the new grafPortPtr.

***

	phd	;Save directPage register.
	tsc	;Make space for locals.
	sec
	sbc #sizeLocals
	tcd	;Set directPage register.
	tcs

	_GetPort	;keepPort is result space.

	ldy #endDesc-portPtr-2
@a	tyx	;Copy descriptor data into directPage.
	lda [portDescPtr],y
	sta portPtr,x
	dey
	dey	
	bpl @a

	stz portHndl	;Flag that we don't have handles yet.
	stz portHndl+2
	stz bitMapHndl
	stz bitMapHndl+2

	stz retval	;Assume we fail.
	stz retval+2

	lda portPtr+1	;See if we were passed a port pointer.
	bne @givenPortMem	;We were.

	pha	;Result space.
	pha
	pea portSize>>16	;Size of handle.
	pea portSize
	pha
	_MMStartUp	;userID.
	pea attrLocked+attrFixed+attrNoCross
	lda #0	;No specific address.
	pha
	pha
	_NewHandle
	plx
	ply
	bcc @havePortHndl	;We succeeded at creating a port handle.
	brl @exit	;Failed because we couldn't get memory.

@havePortHndl	stx portHndl	;We succeeded, so save the handle.
	sty portHndl+2

	ldy #2	;Dereference the handle to a grafPortPtr.
	lda [portHndl]
	sta portPtr
	lda [portHndl],y
	sta portPtr+2

@givenPortMem	pei portPtr+2	;Now that we have grafPort mem, in either
	pei portPtr	;case, try opening the port.
	_OpenPort
	bcc @portOpened	;Hey, it worked!

	tay	;Keep error code.
	lda #$8000	;This flag indicates that the _OpenPort
	tsb portHndl+2	;failed.  If it failed, we should not
		;do a _ClosePort.
	tya	;Restore error code.
	brl @exit	;Failed because we couldn't get memory.

@portOpened	pha	;Push parms to make visRgn rectangular.
	pha
	_GetVisHandle
	pea 0
	tdc
	clc
	adc #portRect
	pha

	pha	;Push parms to make clipRgn rectangular.
	pha
	pea 0
	pha
	_GetClipHandle

	_RectRgn
	_RectRgn

	pea 0	;Get the new port's locInfo structure.
	tdc
	clc
	adc #portInfo
	pha
	_GetPortLoc

	lda bitMapRect+oh2	;Get width of bitMap rectangle.
	sec
	sbc bitMapRect+oh1
	ldx portInfo+oportSCB-1
		;Check bit 7 of the portSCB.
	bmi @b	;The -1 is so we can bmi test.
	asl a	;Pretend it is 640 for below math.

@b	clc	;Convert 640 width into rowBytes.
	adc #3
	lsr a
	lsr a
	clc
	adc #7
	and #$FFF8
	sta portInfo+owidth

	ldx bitMapPtr+1	;See if we need to make a bitMap.
	bne @givenBitMapMem	;We don't need to.

	pha	;Result space for _NewHandle
	pha
	pha	;Result space for _Multiply
	pha
	pha	;_Multiply param 1 (acc is still width).
	lda bitMapRect+ov2
	sec
	sbc bitMapRect+ov1
	sta bitMapHeight
	pha	;_Multiply param 2
	_Multiply
	pha
	_MMStartUp	;userID.
	pei bitMapAttr	;Memory attributes for bitMap.
	lda #0	;No special memory location.
	pha
	pha
	_NewHandle
	plx
	ply
	bcs @exit	;Failed because we couldn't get memory.
	stx bitMapHndl
	sty bitMapHndl+2

	ldy #2	;Dereference bit Map handle.
	lda [bitMapHndl]
	sta bmPtr
	sta tempPtr
	lda [bitMapHndl],y
	sta bmPtr+2
	sta tempPtr+2

	ldx bitMapHeight	;Fill bitMap with white.
@white1	lda #$FFFF
	ldy portInfo+owidth
@white2	dey
	dey
	sta [tempPtr],y
	bne @white2
	lda tempPtr
	clc
	adc portInfo+owidth
	sta tempPtr
	bcc @ok
	inc tempPtr+2
@ok	dex
	bne @white1

@givenBitMapMem	ldx #6	;Copy the bounds rect into locInfo.
@moveBounds	lda bitMapRect,x
	sta portInfo+oboundsRect,x
	dex
	dex
	bpl @moveBounds

	lda bitMapPtr+2
	bmi @defaultBitMap	;Use QuickDraw default bitMap pointer.

	ldx bitMapPtr
	ldy bitMapPtr+2
	lda bitMapPtr+1
	bne @passedBitMap	;Use bitMap pointer declared by application.

	ldx bmPtr	;Use pointer to bitMap we made.
	ldy bmPtr+2

@passedBitMap	stx portInfo+optrToPixImage
	sty portInfo+optrToPixImage+2

@defaultBitMap	pea 0	;Set the portLoc, now that we have
	tdc	;finished setting it up.
	clc
	adc #portInfo
	pha
	_SetPortLoc

	pea 0	;Set the portRect to the passed rect.
	tdc
	clc
	adc #portRect
	pha
	_SetPortRect

	lda portPtr	;Everything worked, so pass back the
	sta retval	;new grafPort pointer, instead of NULL.
	lda portPtr+2
	sta retval+2

	clc	;We had no error.

@exit	ldy #0	;Assume no error.
	bcc @noError	;Hey, we were right!

@error	pha	;Keep error code.
	pei portDescPtr+2
	pei portDescPtr
	jsl killPort	;Dispose everything that was created.
	ply	;Restore error code.

@noError	phy	;Keep error code (if any).

	pei keepPort+2	;Restore the port.
	pei keepPort
	_SetPort

	ldy #endDesc-portPtr-2
@c	tyx	;Update the port descriptor.
	lda portPtr,x
	sta [portDescPtr],y
	dey
	dey
	bpl @c

	ply	;Restore error code (if any).

	tsc	;Get rid of local variables.
	clc
	adc #sizeLocals
	tcs
	pld	;Restore directPage register.
	lda 1,s	;Move return address.
	sta 1+sizeParms,s
	lda 2,s
	sta 2+sizeParms,s
	tsc	;Get rid of passed parameters.
	adc #sizeParms
	tcs
	tya
	cmp #1	;Set error status correctly.
	rtl

	ENDP

********************

	export killPort
killPort	PROC

	DefineStack

portPtr	long	;Pass NULL if mem needed for port.
portHndl	long
bitMapPtr	long	;Pass NULL if mem needed for bitMap.
bitMapHndl	long
endDesc	block 0	;Descriptor locals end here.
		;We don't need the entire descriptor.

sizeLocals	EndLocals

saveDPage	word
returnAddr	block 3

	BegParms
portDescPtr	long	;Pointer to port descriptor.
sizeParms	EndParms

***

	phd	;Save directPage register.
	tsc	;Make space for locals.
	sec
	sbc #sizeLocals
	tcd	;Set directPage register.
	tcs	;Allow us to use 0 as directPage address.

	ldy #endDesc-portPtr-2
@a	tyx	;Copy descriptor data into directPage.
	lda [portDescPtr],y
	sta portPtr,x
	dey
	dey	
	bpl @a

	lda bitMapHndl+1
	beq @notOurBitMap
	pei bitMapHndl+2
	pei bitMapHndl
	_DisposeHandle

@notOurBitMap	lda portHndl+2
	bmi @openPortFailed	;This is our flag that the _OpenPort
		;in newPort failed.  If it failed, then
		;we don't want to do a _ClosePort on it.

	pei portPtr+2	;Close the port, since it opened okay.
	pei portPtr
	_ClosePort

@openPortFailed	lda portHndl+1
	beq @notOurPortMem
	lda portHndl+2
	and #$7FFF
	pha
	pei portHndl
	_DisposeHandle
	ldy #2	;If we created a handle for the grafPort
	lda #0	;memory, we did this because the portPtr
	sta [portDescPtr]	;field was NULL.  If this is the case, we
	sta [portDescPtr],y	;need to return it to it's original value.
	
@notOurPortMem	tsc	;Get rid of local variables.
	clc
	adc #sizeLocals
	tcs
	pld	;Restore directPage register.

	lda 1,s	;Move return address.
	sta 1+sizeParms,s
	lda 2,s
	sta 2+sizeParms,s
	tsc	;Get rid of passed parameters.
	adc #sizeParms
	tcs

	lda #0	;return no error.
	clc
	rtl

	ENDP

********************

	END
