*******************************************************************************
*
* 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
                    longi on
                    longa on

                    copy 2/ainclude/e16.types

                    copy 2/ainclude/e16.memory
                    copy 2/ainclude/e16.quickdraw
                    mcopy offscreen.mac

                    trace on

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

*                   Export newPort
newPort             start
*                   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

startParms          BegParms
portDescPtr         long                ;Pointer to port descriptor.
sizeParms           EndParms startParams

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
aa                  tyx                 ;Copy descriptor data into directPage.
                    lda [portDescPtr],y
                    sta portPtr,x
                    dey
                    dey                 
                    bpl aa

                    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

                    _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 ab              ;The -1 is so we can bmi test.
                    asl a               ;Pretend it is 640 for below math.

ab                  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
ac                  tyx                 ;Update the port descriptor.
                    lda portPtr,x
                    sta [portDescPtr],y
                    dey
                    dey
                    bpl ac

                    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

                    end

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

*                   Export killPort
killPort            start

                    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

startParms          BegParms
portDescPtr         long                ;Pointer to port descriptor.
sizeParms2          EndParms startParms

***

                    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
ba                  tyx                 ;Copy descriptor data into directPage.
                    lda [portDescPtr],y
                    sta portPtr,x
                    dey
                    dey                 
                    bpl ba

                    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+sizeParms2,s
                    lda 2,s
                    sta <2+sizeParms2,s
                    tsc                 ;Get rid of passed parameters.
                    adc #sizeParms2
                    tcs

                    lda #0              ;return no error.
                    clc
                    rtl

                    end

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

                    END
