// DisplayIOSubrs.bcpl - Subrs which deal with display
// Last change May 12, 1981  12:47 AM by Beau Sheil
// Last change March 1, 1981  8:56 PM by Beau Sheil
// Trill change February 24, 1981  1:58 PM by Beau Sheil
// Last change February 3, 1981  4:03 PM by Beau Sheil
// More XBitBlt changes January 28, 1981  6:14 PM by Beau Sheil
// XBitBlt change December 16, 1980  10:04 AM by Alan Bell

	get "AltoDefs.d"
	get "LispBcpl.decl"
	get "KbdDefs.d"
	get "Streams.d"

external [		//  procedures defined here
	Wc; Ws; DSPBOUT; FlashScreen; SETSCREENCOLOR; SHOWDISPLAY
    	SetScreenColor; BcplDisplay; StealFromBcplDisplay; AddToBcplDisplay
			//  statics defined here
	@dlispDsp; @DisplayAddrHi; @dspStartAddr; @dspArea
	@DLispDCB; @dspScanLines
	]

external [		//  procedures used
	CallSwat; RAIDCode; Zero; CreateDisplayStream; ShowDisplayStream
	Dismiss; LockPages; UnlockPages
	SmallUnbox; EqNIL; MkSmallPosSubrRes; Version
	Puts; Closes; CharWidth; EraseBits; GetBitPos; GetLmarg
	]

external [		//  statics used
	dsp; sysFont; EmulatorSpace; @RMSK; VMDisplay
	]

static [
	@dlispDsp; @DisplayAddrHi=0; DisplayPages=0; @dspStartAddr; @DLispDCB
	@dspArea; @dspScanLines
	]

structure EDCB: [			// Extended DCB
	@DCB = [ blank bit offset DCB.height
                 LongPtrFlg bit 1	// Overlaid on DCB.height
                 nScanLines bit 15
               ]
	AddrLo word			// to be D0 compatible
	AddrHi word
 		]

// The following hack allows us to fetch the number of lines from a display
// stream.  The complete declaration from which this is cribbed is in the OS
// source file DspStreamsB.bcpl

structure DispStrm [ blank word 29; nl word  ]

manifest [ sourceGray = 3
	   LongDCBSeal = #177423	// checked by display ucode
	 ]

let Ws(str) be for i = 1 to str>>String.length do Puts(dsp,str>>String.char↑i)

and Wc(ch) be Puts(dsp,ch)

and DSPBOUT(lvByte) = valof
  [
    let char = SmallUnbox(lvByte)&RMSK
    test char eq ERASECHARCODE		// Is char an eraser?
      ifnot Puts(dsp, char)
      ifso  unless GetBitPos(dsp) le GetLmarg(dsp)
               do EraseBits(dsp, -CharWidth(sysFont, $A), 0)
    resultis lvByte
  ]

and FlashScreen() be
  [
    SetScreenColor(true)
    Dismiss(60)				// 60 x 10msec = .6 secs
    SetScreenColor(false)
  ]

and SETSCREENCOLOR(lvVal) = valof
  [		// was in Lisp but Lisp shouldnt know where bcpl core is
   SetScreenColor(not EqNIL(lvVal))
   resultis lvVal
  ]

and SetScreenColor(flg) be
   [
   let AdrDCB = @displayListHead	// change to black/white   
   while AdrDCB do			// else end of DCB chain
      [ AdrDCB>>DCB.background = flg; AdrDCB = AdrDCB>>DCB.next ]
   ]

and SHOWDISPLAY(lvBlk, lvRasterWidth) = valof
   [
   if EqNIL(lvBlk) then			// give all the space to dsp
     [ BcplDisplay(808)			// this turns off Lisp Display
       DisplayAddrHi = 0		// this records that
       resultis lvBlk
     ]
   DisplayAddrHi = lvBlk>>VA.vahi
// fix up dcb for DLispDisplay - other fields are OK already
   DLispDCB>>EDCB.width = SmallUnbox(lvRasterWidth)
   DLispDCB>>EDCB.LongPtrFlg = true
   DLispDCB>>EDCB.bitmap = LongDCBSeal
   DLispDCB>>EDCB.nScanLines = 404
   DLispDCB>>EDCB.AddrHi = lvBlk>>VA.vahi
   DLispDCB>>EDCB.AddrLo = lvBlk>>VA.valo
   ShowDisplayStream(dlispDsp, DSalone)
   resultis lvBlk
   ]

and BcplDisplay(nScanLines) be
  [
// Turns on dsp, giving it nScanLines of display space. If it is running,
// the DLisp display is turned off, because we are about to show dsp alone.
   if DisplayAddrHi then ShowDisplayStream(dlispDsp, DSdelete)

   dspScanLines = nScanLines
   let nlines = (nScanLines/(sysFont!-2)) - 1

   if (dsp ne 0) & (dsp>>DispStrm.nl ne nlines) then
      [ ShowDisplayStream(dsp, DSdelete); Closes(dsp); dsp=0 ]

   if (dsp eq 0) & (nlines gr 0) then
     [ dsp = CreateDisplayStream(nlines, dspStartAddr, dspArea, sysFont)
       ShowDisplayStream(dsp, DSalone)
     ]
  ]

and AddToBcplDisplay(ptr, N, S) be
  [
//  Add N words and S scanlines to dspArea if ptr is at end of dspArea
    if ptr eq (dspStartAddr + dspArea) then dspArea = dspArea + N
    BcplDisplay(dspScanLines + S)
    if DisplayAddrHi then ShowDisplayStream(dlispDsp, DSbelow, dsp)
    if VMDisplay then ShowDisplayStream(VMDisplay, DSabove, dsp)
  ]

and StealFromBcplDisplay(N, S) = valof
  [
//  Take N words and S scanlines from dspArea, if dspArea is bigger than N
    if N ge dspArea then CallSwat("Too greedy")
    dspArea = dspArea - N
    BcplDisplay(dspScanLines - S)
    if DisplayAddrHi then ShowDisplayStream(dlispDsp, DSbelow, dsp)
    if VMDisplay then ShowDisplayStream(VMDisplay, DSabove, dsp)
    let ptr = dspStartAddr + dspArea
    Zero(ptr, N)
    resultis ptr
  ]