-- ColorCursorImpl.mesa
-- Last changed by Maureen Stone, June 9, 1982 4:47 pm

DIRECTORY
  ColorDisplay USING[width,height,curmode, Coordinate, CursorArray, Mode, CursorMode, disconnected, baseA, wplA, baseB, wplB],
  DriverStartChain USING [Start],
  BitBlt USING [BBTableSpace, BitBltTablePtr, AlignedBBTable, SrcFunc, DstFunc, BITBLT, BitAddress],
  ColorDisplayFace USING [displayType],
  SpecialSpace USING [MakeResident],
  Space USING[Create, defaultBase, virtualMemory, Handle, Map, nullHandle,defaultWindow,LongPointer];

ColorCursorImpl: MONITOR
IMPORTS SpecialSpace, Space, BitBlt, ColorDisplay, ColorDisplayFace, OtherDrivers: DriverStartChain
EXPORTS DriverStartChain, ColorDisplay = {
OPEN ColorDisplay; 

--like UserTerminal.mesa

cursorPosition: PUBLIC LONG POINTER TO Coordinate=@currentCursor;
currentCursor: Coordinate;
cursorWidth: PUBLIC INTEGER←16;	--defined as 16 for now
cursorHeight: PUBLIC INTEGER←16;	--defined as 16 for now

template: CursorArray ← ALL[0];

bbspace: BitBlt.BBTableSpace;
bb: BitBlt.BitBltTablePtr ← BitBlt.AlignedBBTable[@bbspace];

space: Space.Handle ← Space.nullHandle;
sourceA: LONG POINTER ← NIL;
backupA: LONG POINTER ← NIL;
sourceB: LONG POINTER ← NIL;
backupB: LONG POINTER ← NIL;
wplSrcA: CARDINAL = 16;
wplSrcB: CARDINAL = 8;

ppw,bpp: CARDINAL;
srcfunc: BitBlt.SrcFunc ← complement;
dstfunc: BitBlt.DstFunc ← and;
xMax,yMax: INTEGER ← 0;
bltX,bltY: INT ← 0;
bltW,bltH: CARDINAL ← 0;

setupMode: Mode ← disconnected;

validBackup: BOOLEAN ← FALSE;
lock: BOOLEAN ← FALSE;

  
NotifyCursor: PUBLIC ENTRY PROC = {Setup[]};

SetCursorMode: PUBLIC ENTRY PROC [mode: CursorMode] = {
    IF mode = zeros THEN {srcfunc ← complement; dstfunc ← and}
    ELSE {srcfunc ← null; dstfunc ← or};
    IF curmode=disconnected THEN RETURN;
    SetCursorInternal[cursorPosition↑];
    };

SetCursorPattern: PUBLIC ENTRY PROC [cursorPattern: CursorArray] = {
    template ← cursorPattern;
    Setup[];
    };

GetCursorPattern: PUBLIC ENTRY PROCEDURE RETURNS [cursorPattern: CursorArray] = {
    RETURN[template];
    };

SetCursorPosition: PUBLIC ENTRY PROCEDURE [newMousePosition: Coordinate] = {
    IF curmode=disconnected THEN RETURN;
    IF newMousePosition=cursorPosition↑ THEN RETURN;	--will not display unless mouse has moved
    SetCursorInternal[newMousePosition];
    };
    
SetCursorInternal: INTERNAL PROCEDURE [newMousePosition: Coordinate] = {
    x: INTEGER ← newMousePosition.x;
    y: INTEGER ← newMousePosition.y;
    xoff,yoff: INTEGER ← 0;
    HideInternal[];  --restore the display
    cursorPosition↑ ← newMousePosition;
    IF lock THEN RETURN;	--cursor is locked during a scanline write 
    IF x<=-cursorWidth OR y<=-cursorHeight OR x>xMax OR y>yMax THEN RETURN; --way off the screen
    
    bltX ←x; bltY ← y;
    bltW ← cursorWidth; bltH ← cursorHeight;
    IF x<0 THEN {xoff ← ABS[x]; bltW ← cursorWidth-xoff;  bltX ← 0};
    IF y<0 THEN {yoff ← ABS[y]; bltH ← cursorHeight-yoff; bltY ← 0};
    IF x>xMax-cursorWidth THEN bltW ← xMax-x;
    IF y>yMax-cursorWidth THEN bltH ← yMax-y;
    bb.flags.srcFunc ← null;
    bb.flags.dstFunc ← null;
    ToA[backupA];  --save the bits under the cursor
    IF curmode.full THEN ToB[backupB];  --save the bits under the cursor
    validBackup ← TRUE;
    bb.flags.srcFunc ← srcfunc;
    bb.flags.dstFunc ← dstfunc;
    FromA[sourceA,xoff,yoff];    --Put the cursor in
    IF curmode.full THEN
        FromB[sourceB,xoff,yoff];    --Put the cursor in
    };

HideCursor: PUBLIC ENTRY PROC = {
    IF curmode=disconnected THEN RETURN;
    HideInternal[];
    };

HideInternal: INTERNAL PROC = {
    IF ~validBackup THEN RETURN;
    validBackup ← FALSE;	--conventional to invalidate the backup cache
    bb.flags.srcFunc ← null;
    bb.flags.dstFunc ← null;
    FromA[backupA];	--restore the bits under the cursor
    IF curmode.full THEN FromB[backupB];
   };

RestoreCursor: PUBLIC ENTRY PROC = {
--assume if the backup cache is valid, the cursor is actually already showing
    IF curmode=disconnected THEN RETURN;
    IF ~validBackup THEN SetCursorInternal[cursorPosition↑];
    };

SetLock: PUBLIC ENTRY PROC = {lock ← TRUE};
ClearLock: PUBLIC ENTRY PROC = {lock ← FALSE};
    
FromA: INTERNAL PROC [buffer: LONG POINTER, xoff,yoff: CARDINAL ← 0] = INLINE {
    bb.dst.word ← baseA + bltY*wplA + bltX/ppw;
    bb.dst.bit ← (bltX MOD ppw)*bpp;
    bb.dstBpl ← wplA*16;
    bb.src.word ← buffer + yoff*wplSrcA + xoff/ppw;
    bb.src.bit ← (xoff MOD ppw)*bpp;
    bb.srcDesc.srcBpl ← wplSrcA*16;
    bb.width ← bltW*bpp;
    bb.height ← bltH;
    BitBlt.BITBLT[bb];	--from an A Buffer to the framebuffer 
    };	
    
ToA: INTERNAL PROC [buffer: LONG POINTER] = INLINE {
    bb.dst ← [word: buffer, bit: 0];
    bb.dstBpl ← wplSrcA*16;
    bb.src.word ← baseA + bltY*wplA + bltX/ppw;
    bb.src.bit ← (bltX MOD ppw)*bpp;
    bb.srcDesc.srcBpl ← wplA*16;
    bb.width ← bltW*bpp;
    bb.height ← bltH;
    BitBlt.BITBLT[bb];  --from the framebuffer to an A buffer
    };

FromB: INTERNAL PROC [buffer: LONG POINTER, xoff,yoff: CARDINAL ← 0] = INLINE {
    bb.dst.word ← baseB + bltY*wplB + bltX/2;
    bb.dst.bit ← (bltX MOD 2)*8;
    bb.dstBpl ← wplB*16;
    bb.src.word ← buffer + yoff*wplSrcB + xoff/2;
    bb.src.bit ← (xoff MOD 2)*8;
    bb.srcDesc.srcBpl ← wplSrcB*16;
    bb.width ← bltW*8;
    bb.height ← bltH;
    BitBlt.BITBLT[bb];	--from a B buffer to the framebuffer
    };
    
ToB: INTERNAL PROC [buffer: LONG POINTER] = INLINE {
    bb.src.word ← baseB + bltY*wplB + bltX/2;
    bb.src.bit ← (bltX MOD 2)*8;
    bb.srcDesc.srcBpl ← wplB*16;
    bb.dst ← [word: buffer, bit: 0];
    bb.dstBpl ← wplSrcB*16;
    bb.width ← bltW*8;
    bb.height ← bltH;
    BitBlt.BITBLT[bb];	--from the framebuffer to a B buffer
    };
    
Setup: INTERNAL PROC = {
    IF curmode=disconnected THEN RETURN;
    HideInternal[];
    xMax ← ColorDisplay.width;
    yMax ← ColorDisplay.height;
    setupMode ← curmode;
    IF curmode.full THEN {
        bpp ← 8; ppw ← 2;
        ExpandBitmap[sourceB,wplSrcB];
        bpp ← 16; ppw ← 1;
        }
    ELSE {bpp ← curmode.bitsPerPixelA; ppw ← 16/bpp};
 --need to convert the 1 bit/pixel template to a bpp source
    ExpandBitmap[sourceA,wplSrcA];
    validBackup ← FALSE;	--invalidate the caches
    };

ExpandBitmap: INTERNAL PROC [buffer: LONG POINTER, wpl: CARDINAL] = {
    bb.src.word ← BASE[template];
    bb.src.bit ← 0;
    bb.srcDesc.srcBpl ← 16;
    bb.dst.word ← buffer;
    bb.dst.bit ← 0;
    bb.dstBpl ← wpl*16;
    bb.width ← 1;
    bb.height ← 16;
    bb.flags.srcFunc ← null;
    bb.flags.dstFunc ← null;
    FOR i: NAT IN [0..16) DO
        FOR j: NAT IN [0..bpp) DO
            BitBlt.BITBLT[bb];	--write one column
            bb.dst ← AddOne[bb.dst];
            ENDLOOP;   
        bb.src ← AddOne[bb.src];
        ENDLOOP;
    };

AddOne: INTERNAL PROC[address: BitBlt.BitAddress] RETURNS[BitBlt.BitAddress] = {
    IF address.bit<15 THEN address.bit ← address.bit+1
    ELSE {address.bit ← 0; address.word ← address.word+1};
    RETURN[address];
    };
    
Init: PROC = {
  space ← Space.Create[size: 3, parent: Space.virtualMemory, base: Space.defaultBase];
  Space.Map[space: space, window: Space.defaultWindow];
  SpecialSpace.MakeResident[space];
  sourceA ← Space.LongPointer[space];  --page 1
  backupA ← sourceA+256;  --page 2
  sourceB ← backupA+256;  --first half of page 3
  backupB ← sourceB+128;  --second half of page 3
  
  bb↑ ← [dst: [word: NIL, bit: 0], dstBpl: 0, src: [word: NIL, bit: 0],
      srcDesc: [srcBpl[0]], width: 0, height: 16,
      flags: [disjoint: TRUE, gray: FALSE, srcFunc: complement, dstFunc: and]];
  };
  
Start: PUBLIC PROCEDURE = {OtherDrivers.Start[]};
  
IF ColorDisplayFace.displayType#0 THEN Init[];

}.