-- NXDisplay.mesa; edited by Gobbel; March 11, 1981 5:44 PM -- Last modified October 18, 1983 3:22 PM by Taft DIRECTORY AltoDefs USING [PageSize, wordlength], AltoDisplay USING [DCB, DCBchainHead, DCBHandle, DCBnil], BitBltDefs USING [BBptr, BBTable, BITBLT], DisplayDefs USING [Background], FontDefs USING [BitmapState, FontHandle], FrameDefs USING [GlobalFrame, SwapInCode], MMOps USING [MMFont], ImageDefs USING [ AddCleanupProcedure, CleanupItem, CleanupMask, CleanupProcedure], InlineDefs USING [BITAND, BITOR, BITSHIFT, BITXOR, COPY], NXDefs USING [debug], ProcessDefs USING [MsecToTicks, SetTimeout], SegmentDefs USING [ DataSegmentAddress, DataSegmentHandle, DefaultBase, DeleteDataSegment, NewDataSegment], SystemDefs USING [AllocateResidentPages], StreamDefs USING [DisplayHandle, StreamError, StreamHandle, StreamObject]; NXDisplay: MONITOR IMPORTS BitBltDefs, FrameDefs, ImageDefs, InlineDefs, NXDefs, ProcessDefs, SegmentDefs, SystemDefs, StreamDefs, MMOps EXPORTS DisplayDefs, NXDefs, StreamDefs SHARES StreamDefs = BEGIN OPEN AltoDisplay; heraldStr: STRING = " XEROX Cedar Net Executive 6.0c "L; displayLines: PUBLIC CARDINAL; BitsPerWord: CARDINAL = AltoDefs.wordlength; BitmapState: TYPE = FontDefs.BitmapState; StreamHandle: TYPE = StreamDefs.StreamHandle; OrderedPOINTER: TYPE = ORDERED POINTER; OrderedNIL: OrderedPOINTER = LOOPHOLE[NIL]; TAB: CHARACTER = 11C; CR: CHARACTER = 15C; NUL: CHARACTER = 0C; SP: CHARACTER = ' ; LeftIndent: CARDINAL; LeftMargin: CARDINAL; RightMargin: CARDINAL; WordsPerLine: CARDINAL; MaxWordsPerLine: CARDINAL = 38; hostPos: CARDINAL = 18; timePos: CARDINAL = 45; statusPos: CARDINAL = 3; DSP: Display StreamDefs.StreamObject ← StreamDefs.StreamObject [ reset: ClearDS, get: GetNop, put: DPutChar, putback: PutbackNop, endof: EndofNop, destroy: DestroyNop, link: NIL, body: Display[ clearCurrentLine: ClearCurrentLine, clearLine: CLNop, clearChar: ClearDisplayChar, type: 0, data: NIL]]; systemDS: StreamDefs.DisplayHandle = @DSP; displayOn: BOOLEAN ← FALSE; lineHeight: CARDINAL; TABindex: CARDINAL; TABs: ARRAY [0..10) OF CARDINAL; bmSegment: SegmentDefs.DataSegmentHandle; bmFirst, bmTail, bmNext, bmLastLine: OrderedPOINTER; lastLineSize: CARDINAL ← 0; spacerDCB, clockSpareDCB, clockDCB, hostDCB, dummyDCB: DCBHandle; firstDCB, lastDCB, currentDCB: DCBHandle ← DCBnil; -- layout of bitmap is: -- DCBs: ARRAY [firstDCB..lastDCB] OF DCB, -- bmFirst: ARRAY OF UNSPECIFIED, -- bmLastLine: ARRAY [0..lineHeight*WordsPerLine) OF UNSPECIFIED, -- bmNext points to next word to allocate, -- bmTail points to oldest allocated bitmap. bmState: FontDefs.BitmapState; tabWidth: CARDINAL; -- Typescript data GetDefaultDisplayStream: PUBLIC PROC RETURNS[StreamDefs.DisplayHandle] = {RETURN[systemDS]}; NotEnoughSpaceForDisplay: PUBLIC SIGNAL = CODE; SetupBitmap: PROC [bitmap: POINTER, nLines, nWords: CARDINAL] = BEGIN dcb: DCBHandle; WHILE nLines*SIZE[DCB] + lastLineSize > nWords DO IF nLines > 1 THEN nLines ← nLines - 1 ELSE BEGIN IF WordsPerLine = 2 THEN ERROR NotEnoughSpaceForDisplay; WordsPerLine ← WordsPerLine - 2; RightMargin ← WordsPerLine * BitsPerWord; lastLineSize ← lineHeight*WordsPerLine; END; ENDLOOP; currentLines ← nLines; firstDCB ← dcb ← bitmap; THROUGH [0..nLines) DO dcb.next ← dcb + SIZE[DCB]; dcb.height ← lineHeight/2; dcb ← dcb.next; ENDLOOP; lastDCB ← dcb-SIZE[DCB]; lastDCB.next ← DCBnil; bmFirst ← LOOPHOLE[dcb, OrderedPOINTER]; bmLastLine ← LOOPHOLE[bitmap+nWords-lastLineSize, OrderedPOINTER]; bmState ← [origin: bmLastLine, wordsPerLine: WordsPerLine, x:, y:0]; END; currentPages, currentLines, currentDummySize: CARDINAL; DisplayOff: PUBLIC PROC [color: DisplayDefs.Background] = BEGIN IF ~displayOn THEN RETURN; SetSystemDisplaySize[0,0]; spacerDCB.background ← color; END; DisplayOn: PUBLIC PROC = BEGIN IF displayOn THEN RETURN; spacerDCB.background ← white; SetDummyDisplaySize[currentDummySize]; SetSystemDisplaySize[currentLines, currentPages]; END; SetSystemDisplaySize: PUBLIC PROC [nTextLines, nPages: CARDINAL] = BEGIN OPEN SegmentDefs; IF displayOn THEN BEGIN firstDCB.next ← lastDCB.next; spacerDCB.next ← NIL; firstDCB ← lastDCB ← currentDCB ← DCBnil; DeleteDataSegment[bmSegment]; blinkOn ← displayOn ← FALSE; END; IF nPages = 0 THEN RETURN; currentPages ← nPages; -- for Display Off/On currentLines ← nTextLines; -- for Display Off/On bmSegment ← NewDataSegment[DefaultBase, nPages]; SetupBitmap[ DataSegmentAddress[bmSegment], nTextLines, nPages*AltoDefs.PageSize]; displayOn ← TRUE; ClearDS[systemDS]; spacerDCB.next ← firstDCB; RETURN END; SetSystemDisplayWidth: PUBLIC PROC [indent, width: CARDINAL] = BEGIN max: CARDINAL; LeftMargin ← indent MOD BitsPerWord; LeftIndent ← indent / BitsPerWord; max ← Even[MaxWordsPerLine-1-LeftIndent]; WordsPerLine ← MIN[Even[width/BitsPerWord],max]; RightMargin ← WordsPerLine * BitsPerWord; IF displayOn THEN SetSystemDisplaySize[currentLines, currentPages]; RETURN END; FillWithDashes: PROC [dcb: DCBHandle] = BEGIN bmState: BitmapState ← [dcb.bitmap, WordsPerLine, 0, 0]; THROUGH [0..RightMargin/CharWidth['X]) DO PaintChar['-, @bmState] ENDLOOP; END; SetupHeader: PROC = BEGIN lineSize: CARDINAL = lineHeight*WordsPerLine; heraldPos: CARDINAL = 3; headerBitmap: POINTER ← SystemDefs.AllocateResidentPages[(3*lineSize+255)/256]; charWidth: CARDINAL ← CharWidth['X]; bmState: BitmapState ← [NIL, WordsPerLine, 0, 0]; headerBitmap↑ ← 0; InlineDefs.COPY[ from: headerBitmap, nwords: 3*lineSize-1, to: headerBitmap+1]; clockDCB.bitmap ← headerBitmap; clockSpareDCB.bitmap ← clockDCB.bitmap+lineSize; hostDCB.bitmap ← clockSpareDCB.bitmap+lineSize; clockDCB.next ← clockSpareDCB.next ← hostDCB; clockDCB.height ← clockSpareDCB.height ← hostDCB.height ← lineHeight/2; clockDCB.width ← clockSpareDCB.width ← hostDCB.width ← WordsPerLine; clockDCB.indenting ← clockSpareDCB.indenting ← hostDCB.indenting ← LeftIndent; spacerDCB.height ← 20; hostDCB.next ← spacerDCB; FillWithDashes[clockDCB]; FillWithDashes[hostDCB]; bmState.origin ← clockDCB.bitmap; bmState.x ← heraldPos*charWidth; SetString[heraldStr, @bmState]; bmState.x ← heraldPos*charWidth+1; PaintString[" XEROX"L, @bmState]; bmState.x ← timePos*charWidth; SetString[" Date and time unknown "L, @bmState]; InlineDefs.COPY[clockDCB.bitmap, lineSize, clockSpareDCB.bitmap]; dummyDCB.next ← clockDCB; END; SetIntoTime: PUBLIC PROC [str: STRING] = BEGIN bmState: BitmapState ← [clockSpareDCB.bitmap, WordsPerLine, 0, 0]; tempDCB: DCBHandle; IF NXDefs.debug THEN RETURN; bmState.x ← timePos*CharWidth['X]; SetString[str, @bmState]; dummyDCB.next ← clockSpareDCB; tempDCB ← clockDCB; clockDCB ← clockSpareDCB; clockSpareDCB ← tempDCB; END; SetIntoHost: PUBLIC PROC [str: STRING] = BEGIN bmState: BitmapState ← [hostDCB.bitmap, WordsPerLine, 0, 0]; IF NXDefs.debug THEN RETURN; bmState.x ← hostPos*CharWidth['X]; SetString[str, @bmState]; END; SetIntoStatus: PUBLIC PROC [str: STRING] = BEGIN bmState: BitmapState ← [hostDCB.bitmap, WordsPerLine, 0, 0]; IF NXDefs.debug THEN RETURN; bmState.x ← statusPos*CharWidth['X]; SetString[str, @bmState]; END; SetDummyDisplaySize: PUBLIC PROC [nScanLines: CARDINAL] = BEGIN currentDummySize ← nScanLines; -- for Display Off/On IF nScanLines/2 = dummyDCB.height THEN RETURN; IF dummyDCB.height # 0 THEN DCBchainHead↑ ← DCBnil; dummyDCB.height ← nScanLines/2; IF dummyDCB.height # 0 THEN DCBchainHead↑ ← dummyDCB; RETURN END; ClearDS: ENTRY PROC [stream: StreamHandle] = BEGIN dcb: DCBHandle; IF stream # systemDS THEN SIGNAL StreamDefs.StreamError[stream,StreamType]; IF ~displayOn THEN RETURN; FOR dcb ← firstDCB, dcb.next DO dcb.resolution ← high; dcb.background ← white; dcb.indenting ← dcb.width ← 0; dcb.bitmap ← bmLastLine; IF dcb = lastDCB THEN EXIT; ENDLOOP; bmNext ← bmFirst; bmTail ← bmLastLine; currentDCB ← firstDCB; ClearCurrentLineInternal[stream]; RETURN END; -- back up n characters Erase: PUBLIC PROC [n: CARDINAL, str: STRING] = BEGIN IF NXDefs.debug THEN RETURN; THROUGH [0..n) DO IF str.length=0 THEN RETURN; str.length ← str.length-1; ClearDisplayChar[systemDS, str[str.length]] ENDLOOP; END; ResetTo: PUBLIC ENTRY PROC [n: CARDINAL] = BEGIN oldX: CARDINAL = bmState.x; charWidth: CARDINAL = CharWidth['X]; i: CARDINAL; IF NXDefs.debug THEN RETURN; IF blinkOn THEN [] ← BlinkCursorInternal[]; bmState.x ← n*charWidth+LeftMargin; FOR i IN [n..oldX/charWidth) DO BlankChar[@bmState]; ENDLOOP; bmState.x ← n*charWidth+LeftMargin; END; ClearLine: PUBLIC PROC = {IF ~NXDefs.debug THEN ClearCurrentLine[systemDS]}; ClearCurrentLine: PUBLIC ENTRY PROC [stream: StreamHandle] = {ClearCurrentLineInternal[stream]}; ClearCurrentLineInternal: INTERNAL PROC [stream: StreamHandle] = BEGIN IF stream # systemDS THEN SIGNAL StreamDefs.StreamError[stream,StreamType]; IF ~displayOn THEN RETURN; bmLastLine↑ ← 0; InlineDefs.COPY[ from: bmLastLine, to: bmLastLine+1, nwords: lastLineSize-1]; currentDCB.indenting ← LeftIndent; currentDCB.bitmap ← bmLastLine; currentDCB.width ← WordsPerLine; bmState.x ← LeftMargin; blinkOn ← FALSE; TABindex ← 0; RETURN END; CLNop: PUBLIC PROC [stream: StreamHandle, line: CARDINAL] = {}; Scroll: INTERNAL PROC [char: CHARACTER] = BEGIN OPEN BitBltDefs; bbt: ARRAY [0..SIZE[BBTable]] OF WORD; bbp: BBptr ← Even[BASE[bbt]]; pos: CARDINAL; SELECT char FROM CR => NULL; TAB => BEGIN TABs[TABindex] ← bmState.x; TABindex ← TABindex + 1; pos ← (LOOPHOLE[bmState.x-LeftMargin,CARDINAL]/tabWidth+1) * tabWidth+LeftMargin; IF pos < RightMargin THEN bmState.x ← pos ELSE DPutCharInternal[systemDS, SP]; RETURN END; NUL => RETURN; ENDCASE => IF char < 40C THEN BEGIN DPutCharInternal[systemDS, '↑]; DPutCharInternal[systemDS, LOOPHOLE[LOOPHOLE[char,CARDINAL]+100B,CHARACTER]]; RETURN END; -- Do the scroll, assuming last (current) line is in bmLastLine. -- scroll all others by BLTing their DCBs. move old last line to -- new bitmap and free bmLastLine for reuse. UNTIL Compact[currentDCB,bmState.x] DO IF ~DeleteTopLine[] THEN RETURN; -- not enough space ENDLOOP; IF currentDCB # lastDCB THEN currentDCB ← currentDCB.next ELSE BEGIN IF firstDCB.width # 0 THEN [] ← DeleteTopLine[]; bbp↑ ← [ pad: 0, sourcealt: FALSE, destalt: FALSE, sourcetype: block, function: replace, dbca: firstDCB, dbmr: SIZE[DCB], dlx: 16, dty: 0, dw: 16*(SIZE[DCB]-1), dh: currentLines-1, sbca: firstDCB, sbmr: SIZE[DCB], slx: 16, sty: 1, unused:, gray0:, gray1:, gray2:, gray3:]; IF firstDCB # lastDCB THEN BITBLT[bbp]; END; ClearCurrentLineInternal[systemDS]; IF char # CR THEN DPutChar[systemDS, char]; END; DeleteTopLine: PROC RETURNS [BOOLEAN] = BEGIN dcb: DCBHandle; -- find first line with bitmap allocated FOR dcb ← firstDCB, dcb.next DO IF dcb.width # 0 THEN EXIT; IF dcb = lastDCB THEN RETURN[FALSE]; -- found no top line to delete ENDLOOP; dcb.width ← dcb.indenting ← 0; -- find next line with bitmap allocated UNTIL dcb = lastDCB DO dcb ← dcb.next; IF dcb.width # 0 THEN {bmTail ← LOOPHOLE[dcb.bitmap]; EXIT}; REPEAT FINISHED => -- all linex deleted {bmTail ← bmLastLine; bmNext ← bmFirst}; ENDLOOP; RETURN[TRUE]; END; Compact: PROC [dcb: DCBHandle, x: CARDINAL] RETURNS [BOOLEAN] = BEGIN newWidth: CARDINAL ← (x+15)/16; oldWidth: CARDINAL ← dcb.width; old: OrderedPOINTER ← LOOPHOLE[dcb.bitmap]; lineHeight: CARDINAL ← dcb.height*2; d: CARDINAL; IF x <= LeftMargin THEN d ← 0 ELSE FOR d IN [0..newWidth) DO BEGIN p: OrderedPOINTER; p ← old + d; THROUGH [0..lineHeight) DO IF p↑ # 0 THEN GO TO foundit; p ← p + oldWidth; ENDLOOP; END; REPEAT foundit => NULL; ENDLOOP; newWidth ← Even[newWidth-d]; IF newWidth > 0 THEN BEGIN OPEN BitBltDefs; bbt: ARRAY [0..SIZE[BBTable]] OF WORD; bbp: BBptr ← Even[BASE[bbt]]; new: OrderedPOINTER; IF (new ← GetMapSpace[newWidth*lineHeight]) = OrderedNIL THEN RETURN[FALSE]; dcb.width ← 0; bbp↑ ← [ pad: 0, sourcealt: FALSE, destalt: FALSE, sourcetype: block, function: replace, dbca: new, dbmr: newWidth, dlx: 0, dty: 0, dw: newWidth*16, dh: lineHeight, sbca: old, sbmr: oldWidth, slx: d*16, sty: 0, unused:, gray0:, gray1:, gray2:, gray3:]; BITBLT[bbp]; dcb.indenting ← LeftIndent + d; dcb.bitmap ← new; dcb.width ← newWidth; END ELSE dcb.indenting ← dcb.width ← 0; RETURN [ TRUE ]; END; GetMapSpace: PROC [nwords: [0..77777B]] RETURNS [p: OrderedPOINTER] = BEGIN DO t: INTEGER = bmTail - bmNext; IF t < 0 THEN IF bmLastLine >= bmNext+nwords THEN EXIT ELSE bmNext ← bmFirst ELSE IF t >= nwords THEN EXIT ELSE RETURN[OrderedNIL]; ENDLOOP; p ← bmNext; bmNext ← bmNext + nwords; RETURN END; DPutChar: ENTRY PROC [stream: StreamHandle, char: UNSPECIFIED] = {DPutCharInternal[stream, char]}; DPutCharInternal: INTERNAL PROC [stream: StreamHandle, char: UNSPECIFIED] = BEGIN IF stream # systemDS THEN SIGNAL StreamDefs.StreamError[stream,StreamType]; IF ~displayOn THEN RETURN; IF char > 377B THEN RETURN; IF blinkOn THEN [] ← BlinkCursorInternal[]; IF char < 40B OR CharWidth[char] + bmState.x > RightMargin THEN Scroll[char] ELSE PaintChar[char,@bmState]; RETURN END; ClearDisplayChar: PUBLIC ENTRY PROC [ stream: StreamHandle, char: UNSPECIFIED] = {ClearDisplayCharInternal[stream, char]}; ClearDisplayCharInternal: INTERNAL PROC [ stream: StreamHandle, char: UNSPECIFIED] = BEGIN IF stream # systemDS THEN SIGNAL StreamDefs.StreamError[stream,StreamType]; IF displayOn THEN BEGIN IF blinkOn THEN [] ← BlinkCursorInternal[]; SELECT char FROM NUL, CR, > 377B => RETURN; TAB => BEGIN IF TABindex > 0 THEN BEGIN TABindex ← TABindex -1; bmState.x ← TABs[TABindex]; END; RETURN END; < 40B => BEGIN ClearDisplayCharInternal[stream, char+100B]; char ← '↑; END; ENDCASE => NULL; ClearChar[char,@bmState]; END; RETURN END; GetNop: PROC [stream: StreamHandle] RETURNS [UNSPECIFIED] = {ERROR StreamDefs.StreamError[stream,StreamAccess]}; PutbackNop: PROC [stream: StreamHandle, char: UNSPECIFIED] = {ERROR StreamDefs.StreamError[stream,StreamAccess]}; EndofNop: PROC [stream: StreamHandle] RETURNS [BOOLEAN] = BEGIN IF stream # systemDS THEN SIGNAL StreamDefs.StreamError[stream,StreamType]; RETURN[FALSE] END; DestroyNop: PROC [stream: StreamHandle] = {ERROR StreamDefs.StreamError[stream,StreamAccess]}; ddarray: ARRAY [0..SIZE[DCB]*5] OF UNSPECIFIED; Even: PROC [a: UNSPECIFIED] RETURNS [UNSPECIFIED] = {RETURN[a + CARDINAL[a] MOD 2]}; blinkOn: BOOLEAN ← FALSE; BlinkCursor: PUBLIC ENTRY PROC RETURNS [BOOLEAN] = {RETURN[BlinkCursorInternal[]]}; BlinkCursorInternal: INTERNAL PROC RETURNS [BOOLEAN] = BEGIN OPEN InlineDefs; mask: WORD; p: POINTER; IF ~displayOn THEN RETURN[blinkOn]; mask ← BITSHIFT[3, 14 - CARDINAL[bmState.x+1] MOD 16]; p ← bmState.origin + (bmState.x+1)/16 + bmState.wordsPerLine; THROUGH [2..lineHeight) DO p↑ ← BITXOR[p↑, mask]; IF mask = 1 THEN (p+1)↑ ← BITXOR[(p+1)↑, 100000B]; p ← p + bmState.wordsPerLine; ENDLOOP; RETURN[blinkOn ← ~blinkOn] END; InitDisplay: PUBLIC PROC [ dummySize, textLines, nPages: CARDINAL, f: FontDefs.FontHandle] = BEGIN lineHeight ← Even[CharHeight['A]]; lastLineSize ← lineHeight*WordsPerLine; tabWidth ← CharWidth[SP]*8; SetDummyDisplaySize[dummySize]; SetupHeader[]; SetSystemDisplaySize[textLines, nPages]; RETURN END; CleanupDisplay: ImageDefs.CleanupItem ← [ link:, proc: Cleanup, mask: ImageDefs.CleanupMask[Finish] + ImageDefs.CleanupMask[Abort]]; Cleanup: ImageDefs.CleanupProcedure = BEGIN SELECT why FROM Finish, Abort => DCBchainHead.next ← DCBnil; ENDCASE; END; font: Fptr; FHptr: TYPE = POINTER TO FontHeader; Fptr: TYPE = POINTER TO Font; FCDptr: TYPE = POINTER TO FCD; FAptr: TYPE = POINTER TO FontArray; FontArray: TYPE = ARRAY [0..255] OF FCDptr; Font: TYPE = MACHINE DEPENDENT RECORD [ header: FontHeader, FCDptrs: FontArray, -- array of self-relative pointers to -- FCD's. Indexed by char value. -- font pointer points hear! extFCDptrs: FontArray -- array of self-relative pointers to -- FCD's for extentions. As large an -- array as needed. ]; FontHeader: TYPE = MACHINE DEPENDENT RECORD [ maxHeight: CARDINAL, -- height of tallest char in font (scan lines) variableWidth: BOOLEAN, -- IF TRUE, proportionally spaced font blank: [0..177B], -- not used maxWidth: [0..377B] -- width of widest char in font (raster units). ]; FCD: TYPE = MACHINE DEPENDENT RECORD [ widthORext: [0..77777B], -- width or extention index hasNoExtension: BOOLEAN, -- TRUE=> no ext.;prevfield=width height: [0..377B], -- # scan lines to skip for char displacement: [0..377B] -- displacement back to char bitmap ]; CharWidth: PUBLIC PROC [char: CHARACTER] RETURNS [w: CARDINAL] = BEGIN code: CARDINAL; cw: FCDptr; fontdesc: FAptr; -- checkfor control characters IF char = CR THEN char ← SP; IF char < SP THEN RETURN[CharWidth['↑] + CharWidth[LOOPHOLE[LOOPHOLE[char,CARDINAL]+100B,CHARACTER]]]; w ← 0; fontdesc ← @font.FCDptrs; code ← LOOPHOLE[char]; DO cw ← LOOPHOLE[fontdesc[code]+LOOPHOLE[fontdesc,CARDINAL]+code]; IF cw.hasNoExtension THEN EXIT; w ← w+16; code ← cw.widthORext; ENDLOOP; w ← w+cw.widthORext; RETURN END; CharHeight: PUBLIC PROC [CHARACTER] RETURNS [CARDINAL] = {RETURN[font.header.maxHeight]}; PaintString: PROC [s: STRING, bmState: POINTER TO BitmapState] = BEGIN FOR i: CARDINAL IN [0..s.length) DO PaintChar[s[i], bmState]; ENDLOOP; END; SetString: PROC [s: STRING, bmState: POINTER TO BitmapState] = BEGIN i: CARDINAL; saveX: CARDINAL ← bmState.x; FOR i IN [0..s.length) DO BlankChar[bmState]; ENDLOOP; bmState.x ← saveX; FOR i IN [0..s.length) DO PaintChar[s[i], bmState]; ENDLOOP; END; BlankChar: PROC [bmState: POINTER TO BitmapState] = BEGIN OPEN BitBltDefs, bmState; bba: ARRAY [0..SIZE[BBTable]] OF UNSPECIFIED; bbt: BBptr = LOOPHOLE[BASE[bba] + LOOPHOLE[BASE[bba],CARDINAL] MOD 2]; bbt↑ ← [pad: 0, sourcealt: FALSE, destalt: FALSE, sourcetype: gray, function: replace, unused:, dbca: origin, dbmr: wordsPerLine, dlx: x, dty: 0, dw: CharWidth['X], dh: lineHeight, sbca:, sbmr: 1, slx: 0, sty: 0, gray0: 0, gray1: 0, gray2: 0, gray3: 0]; x ← x + CharWidth['X]; BITBLT[bbt]; RETURN END; PaintChar: PROC [char: CHARACTER, bmState: POINTER TO BitmapState] = BEGIN OPEN BitBltDefs, bmState; bba: ARRAY [0..SIZE[BBTable]] OF UNSPECIFIED; bbt: BBptr = LOOPHOLE[BASE[bba] + LOOPHOLE[BASE[bba],CARDINAL] MOD 2]; cw: FCDptr; fontdesc: FAptr = @font.FCDptrs; code: CARDINAL ← LOOPHOLE[char]; bbt↑ ← [pad: 0, sourcealt: FALSE, destalt: FALSE, sourcetype: block, function: paint, unused:, dbca: origin, dbmr: wordsPerLine, dlx: x, dty:, dw: 16, dh:, sbca:, sbmr: 1, slx: 0, sty: 0, gray0:, gray1:, gray2:, gray3:]; DO cw ← LOOPHOLE[fontdesc[code]+LOOPHOLE[fontdesc,CARDINAL]+code]; bbt.dty ← y + cw.height; bbt.dh ← cw.displacement; bbt.sbca ← cw - (bbt.dh ← cw.displacement); IF cw.hasNoExtension THEN BEGIN x ← x + (bbt.dw ← cw.widthORext); BITBLT[bbt]; EXIT END ELSE BEGIN BITBLT[bbt]; bbt.dlx ← x ← x + 16 END; code ← cw.widthORext; ENDLOOP; RETURN END; ClearChar: PROC [char: CHARACTER, bmState: POINTER TO BitmapState] = BEGIN OPEN bmState, InlineDefs; bit: [0..15]; xword: CARDINAL; scanLines: CARDINAL = font.header.maxHeight; start,p: POINTER; cwidth: INTEGER ← CharWidth[char]; mask: WORD; ones: WORD = 177777B; IF x < cwidth THEN BEGIN cwidth ← x; x ← 0 END ELSE x ← x - cwidth; xword ← x/16; bit ← x MOD 16; mask ← BITOR[BITSHIFT[ones, 16-bit],BITSHIFT[ones,-(bit+cwidth)]]; start ← origin + xword + y*wordsPerLine-1; cwidth ← cwidth + bit; DO p ← start ← start + 1; THROUGH [0..scanLines) DO p↑ ← BITAND[p↑,mask]; p ← p + wordsPerLine; ENDLOOP; IF (cwidth ← cwidth - 16) <= 0 THEN EXIT; mask ← BITSHIFT[ones,-cwidth]; ENDLOOP; RETURN END; Cursor: ENTRY PROC = BEGIN wait: CONDITION; timer: POINTER TO INTEGER ← LOOPHOLE[430B]; blinktime: INTEGER; ProcessDefs.SetTimeout[@wait, ProcessDefs.MsecToTicks[450]]; DO -- forever IF blinktime-timer↑ ~IN[0..13] THEN BEGIN [] ← BlinkCursorInternal[]; blinktime ← timer↑+13 END; IF stopCursor THEN EXIT; WAIT wait; ENDLOOP; RETURN END; stopCursor: BOOLEAN ← TRUE; CursorProcess: PUBLIC PROCESS; StartCursor: PUBLIC PROC = BEGIN IF stopCursor THEN {stopCursor ← FALSE; CursorProcess ← FORK Cursor[]}; RETURN END; StopCursor: PUBLIC PROC = BEGIN IF ~stopCursor THEN {stopCursor ← TRUE; JOIN CursorProcess}; RETURN END; Init: PROC = BEGIN FrameDefs.SwapInCode[LOOPHOLE[MMOps.MMFont]]; font ← FrameDefs.GlobalFrame[MMOps.MMFont].code.shortbase; ImageDefs.AddCleanupProcedure[@CleanupDisplay]; dummyDCB ← Even[BASE[ddarray]]; dummyDCB↑ ← [DCBnil,high,white,0,0,LOOPHOLE[0,OrderedPOINTER],0]; clockDCB ← dummyDCB+SIZE[DCB]; clockDCB↑ ← [DCBnil,high,white,0,0,LOOPHOLE[0,OrderedPOINTER],0]; clockSpareDCB ← clockDCB+SIZE[DCB]; clockSpareDCB↑ ← [DCBnil,high,white,0,0,LOOPHOLE[0,OrderedPOINTER],0]; hostDCB ← clockSpareDCB+SIZE[DCB]; hostDCB↑ ← [DCBnil,high,white,0,0,LOOPHOLE[0,OrderedPOINTER],0]; spacerDCB ← hostDCB+SIZE[DCB]; spacerDCB↑ ← [DCBnil,high,white,0,0,LOOPHOLE[0,OrderedPOINTER],0]; IF NXDefs.debug THEN RETURN; SetSystemDisplayWidth[16, 36*16]; displayLines ← 20; InitDisplay[80, displayLines, (displayLines*CharHeight['A]*36+255)/256, NIL]; StartCursor[]; END; Init[]; END.