<> <> <> <> <> <> <> DIRECTORY Basics USING [bitsPerWord, LongMult], ColorDisplayFace USING [ baseA, baseB, bplA, bplB, Connect, Disconnect, displayType, GetBlueMap, GetColor, GetGreenMap, GetRedMap, globalStateSize, HasMode, height, Initialize, InitializeCleanup, Mode, PagesForMode, pixelsPerInch, SetBlueMap, SetColor, SetGreenMap, SetRedMap, Show, TurnOff, TurnOn, width], DisplayFace USING [ Connect, cursorPosition, Disconnect, GetBitBltTable, globalStateSize, hasBorder, hasBuffer, height, Initialize, InitializeCleanup, pagesForBitmap, pixelsPerInch, SetBackground, SetBorderPattern, SetCursorPattern, TurnOff, TurnOn, width], KeyboardFace USING [keyboard], Keys USING [KeyBits], MouseFace USING [position, SetPosition], PrincOps USING [BBTable, BBTableSpace, BitAddress, BitBltTablePtr], PrincOpsUtils USING [AlignedBBTable, AllocateNakedCondition, BITBLT], Process USING [ Detach, EnableAborts, GetPriority, MsecToTicks, Pause, Priority, priorityForeground, SetPriority, Ticks], Terminal USING [ BitmapState, BWBackground, BWBorder, BWCursorBitmap, ChannelsVisible, ChannelValue, Color, ColorCursorBitmap, ColorCursorBitmapState, ColorCursorPresentation, ColorMode, Object, Position, SetBWCursorPosition, SetMousePosition, SwapAction, SwapNotifier, Virtual], TerminalExtras USING [], VM USING [ AddressForPageNumber, Allocate, CantAllocate, Free, Interval, lowCore, nullInterval, Pin, Unpin], VMSideDoor USING [AssignSpecialRealMemory, ReleaseSpecialRealMemory]; TerminalImpl: CEDAR MONITOR LOCKS terminalLock IMPORTS Basics, ColorDisplayFace, DisplayFace, KeyboardFace, MouseFace, PrincOpsUtils, Process, Terminal, VM, VMSideDoor EXPORTS Terminal, TerminalExtras SHARES Terminal = BEGIN <> <<>> Virtual: TYPE = Terminal.Virtual; TerminalList: TYPE = LIST OF Virtual; VirtualImpl: TYPE = REF VirtualImplObject; VirtualImplObject: TYPE = RECORD [ keyboard: Keys.KeyBits _ ALL[up], mouse: Terminal.Position _ [0, 0], <> bwCursor: Terminal.Position _ [0, 0], bwPattern: Terminal.BWCursorBitmap _ ALL[0], <> bwBitmapState: Terminal.BitmapState _ none, bwBackground: Terminal.BWBackground _ white, bwBorderOdd: Terminal.BWBorder _ 0, bwBorderEven: Terminal.BWBorder _ 0, bwBitmap: VM.Interval _ NULL, <> colorCursor: Terminal.Position _ [0, 0], colorPattern: Terminal.ColorCursorBitmap _ ALL[0], colorCursorPresentation: Terminal.ColorCursorPresentation _ onesAreBlack, colorCursorState: Terminal.ColorCursorBitmapState _ visible, colorCursorDisplayed: BOOL _ FALSE, colorFrameLocked: BOOL _ FALSE, xmin, ymin, xmax, ymax: NAT _ 0, colorCursorSourceA, colorCursorSourceB: LONG POINTER _ NIL, colorCursorBackupA, colorCursorBackupB: LONG POINTER _ NIL, colorCursorVM: VM.Interval _ NULL, <> colorBitmapState: Terminal.BitmapState _ none, colorVisibility: Terminal.ChannelsVisible _ none, colorVM: VM.Interval _ NULL, notifiers: Notifier _ NIL ]; Notifier: TYPE = REF NotifierItem; NotifierItem: TYPE = RECORD [ next, prev: Notifier, proc: Terminal.SwapNotifier, clientData: REF ANY ]; priorityDuringSelect: Process.Priority = Process.priorityForeground; blinkTime: Process.Ticks = Process.MsecToTicks[100]; <<>> <<>> <> <<>> terminalLock: PUBLIC MONITORLOCK; terminals: TerminalList; current: Virtual _ NIL; watcherDisableCount: NAT _ 0; terminalChanging: BOOL _ FALSE; <<'terminalChanging' synchronizes 'Select' with long-running operations that can't afford to hold the monitor lock throughout (including 'Select' itself).>> terminalStable: CONDITION _ [timeout: 0]; bwRetrace: LONG POINTER TO CONDITION; meFirst: BOOL _ TRUE; verticalRetrace: CONDITION _ [timeout: 0]; colorTerminal: Virtual _ NIL; <> <> <> <<>> CantDoIt: PUBLIC ERROR = CODE; Create: PUBLIC PROC RETURNS [vt: Virtual] = { AddToList: ENTRY PROC [vt: Virtual] = INLINE { ENABLE UNWIND => NULL; terminals _ CONS[vt, terminals]; }; AddToList[vt _ NewVirtual[]]; }; Select: PUBLIC PROC [vt: Virtual _ NIL] = { old: Virtual; new: Virtual _ vt; DoNotifiers: PROC [vt: Virtual, action: Terminal.SwapAction] = { impl: VirtualImpl = NARROW[vt.impl]; head: Notifier = impl.notifiers; n: Notifier _ impl.notifiers; IF head = NIL THEN RETURN; DO n.proc[vt, action, n.clientData]; IF (n _ IF action = coming THEN n.next ELSE n.prev) = head THEN EXIT; ENDLOOP; }; FlipTerminal: ENTRY PROC [old, new: Virtual] = INLINE { ENABLE UNWIND => NULL; UnloadTerminal[old]; current _ new; LoadTerminal[new]; }; FindNextTerminal: ENTRY PROC [old: Virtual] RETURNS [new: Virtual] = INLINE { ENABLE UNWIND => NULL; FOR t: TerminalList _ terminals, t.rest UNTIL t = NIL DO IF t.first = old THEN RETURN[(IF t.rest = NIL THEN terminals ELSE t.rest).first]; REPEAT FINISHED => ERROR; ENDLOOP; }; AcquireAndMarkTerminalUnstable[]; old _ current; IF new = NIL THEN new _ FindNextTerminal[old]; IF old ~= new THEN { priority: Process.Priority = Process.GetPriority[]; IF priority < priorityDuringSelect THEN TRUSTED {Process.SetPriority[priorityDuringSelect]}; DoNotifiers[old, going]; DoNotifiers[new, coming]; FlipTerminal[old: old, new: new]; DoNotifiers[old, gone]; DoNotifiers[new, here]; IF priority < priorityDuringSelect THEN TRUSTED {Process.SetPriority[priority]}; }; MarkTerminalStable[]; }; Current: PUBLIC ENTRY PROC RETURNS [vt: Virtual] = { ENABLE UNWIND => NULL; WHILE terminalChanging DO WAIT terminalStable; ENDLOOP; vt _ current; }; RegisterNotifier: PUBLIC ENTRY PROC [ vt: Virtual, notifier: Terminal.SwapNotifier, clientData: REF ANY _ NIL] = { ENABLE UNWIND => NULL; impl: VirtualImpl = NARROW[vt.impl]; n: Notifier = NEW[NotifierItem _ [next: NIL, prev: NIL, proc: notifier, clientData: clientData]]; head: Notifier = impl.notifiers; IF head = NIL THEN n.next _ n.prev _ n ELSE {n.next _ head; n.prev _ head.prev; head.prev.next _ n; head.prev _ n}; impl.notifiers _ n; }; UnregisterNotifier: PUBLIC ENTRY PROC [ vt: Virtual, notifier: Terminal.SwapNotifier, clientData: REF ANY _ NIL] = { ENABLE UNWIND => NULL; impl: VirtualImpl = NARROW[vt.impl]; head: Notifier = impl.notifiers; n: Notifier _ impl.notifiers; IF head ~= NIL THEN DO IF n.proc = notifier AND n.clientData = clientData THEN { n.prev.next _ n.next; n.next.prev _ n.prev; IF n = head THEN impl.notifiers _ IF n.next = n THEN NIL ELSE n.next; EXIT }; IF (n _ n.next) = head THEN EXIT; ENDLOOP; }; DisableKeyboardWatcher: PUBLIC ENTRY PROC = { ENABLE UNWIND => NULL; watcherDisableCount _ watcherDisableCount.SUCC; }; EnableKeyboardWatcher: PUBLIC ENTRY PROC = { ENABLE UNWIND => NULL; IF watcherDisableCount > 0 THEN watcherDisableCount _ watcherDisableCount.PRED; }; <> SetMousePosition: PUBLIC ENTRY PROC [vt: Virtual, position: Terminal.Position] = { ENABLE UNWIND => NULL; impl: VirtualImpl = NARROW[vt.impl]; IF current = vt THEN MouseFace.SetPosition[LOOPHOLE[position]] ELSE impl.mouse _ position; }; <<>> <> <<>> GetBWCursorPattern: PUBLIC ENTRY PROC [vt: Virtual] RETURNS [pattern: Terminal.BWCursorBitmap] = { ENABLE UNWIND => NULL; impl: VirtualImpl = NARROW[vt.impl]; RETURN[impl.bwPattern] }; SetBWCursorPattern: PUBLIC ENTRY PROC [vt: Virtual, pattern: Terminal.BWCursorBitmap] = { ENABLE UNWIND => NULL; impl: VirtualImpl = NARROW[vt.impl]; impl.bwPattern _ pattern; IF current = vt THEN TRUSTED {DisplayFace.SetCursorPattern[LOOPHOLE[LONG[@pattern]]]}; }; <<>> <> GetBWBitmapState: PUBLIC ENTRY PROC [vt: Virtual] RETURNS [Terminal.BitmapState] = { ENABLE UNWIND => NULL; impl: VirtualImpl = NARROW[vt.impl]; RETURN [impl.bwBitmapState] }; SetBWBitmapState: PUBLIC PROC [vt: Virtual, new: Terminal.BitmapState] RETURNS [old: Terminal.BitmapState] = { impl: VirtualImpl = NARROW[vt.impl]; SetBWBitmapStateInner: ENTRY PROC = { ENABLE UNWIND => NULL; IF (old _ impl.bwBitmapState) = new THEN RETURN; IF old = none THEN { impl.bwBitmap _ AllocateBWBitmap[]; IF current = vt THEN DisplayFace.Connect[impl.bwBitmap.page]; IF (impl.bwBitmapState _ new) = allocated THEN RETURN; }; SELECT new FROM displayed => IF current = vt THEN { IF DisplayFace.hasBuffer THEN VMSideDoor.AssignSpecialRealMemory[impl.bwBitmap] ELSE VM.Pin[impl.bwBitmap]; DisplayFace.TurnOn[]; }; allocated => IF current = vt THEN TurnOff[impl]; none => { IF current = vt THEN {TurnOff[impl]; DisplayFace.Disconnect[]}; TRUSTED {VM.Free[impl.bwBitmap]}; }; ENDCASE; impl.bwBitmapState _ new; }; <> --AcquireAndMarkTerminalUnstable[]; SetBWBitmapStateInner[]; --MarkTerminalStable[]; }; GetBWBackground: PUBLIC ENTRY PROC [vt: Virtual] RETURNS [Terminal.BWBackground] = { ENABLE UNWIND => NULL; impl: VirtualImpl = NARROW[vt.impl]; RETURN [impl.bwBackground] }; SetBWBackground: PUBLIC ENTRY PROC [vt: Virtual, new: Terminal.BWBackground] RETURNS [old: Terminal.BWBackground] = { ENABLE UNWIND => NULL; impl: VirtualImpl = NARROW[vt.impl]; IF (old _ impl.bwBackground) = new THEN RETURN; impl.bwBackground _ new; IF vt = current THEN DisplayFace.SetBackground[IF new = white THEN white ELSE black]; }; GetBWBorder: PUBLIC ENTRY PROC [vt: Virtual] RETURNS [oddPairs, evenPairs: Terminal.BWBorder] = { ENABLE UNWIND => NULL; impl: VirtualImpl = NARROW[vt.impl]; RETURN [impl.bwBorderOdd, impl.bwBorderEven] }; SetBWBorder: PUBLIC ENTRY PROC [vt: Virtual, oddPairs, evenPairs: Terminal.BWBorder] = { ENABLE UNWIND => NULL; impl: VirtualImpl = NARROW[vt.impl]; impl.bwBorderOdd _ oddPairs; impl.bwBorderEven _ evenPairs; IF DisplayFace.hasBorder AND vt = current THEN DisplayFace.SetBorderPattern[oddPairs: oddPairs, evenPairs: evenPairs]; }; GetBitBltTable: PUBLIC ENTRY UNSAFE PROC [vt: Virtual] RETURNS [bbt: PrincOps.BBTable] = { ENABLE UNWIND => NULL; impl: VirtualImpl = NARROW[vt.impl]; bbt _ DisplayFace.GetBitBltTable[]; TRUSTED{ bbt.dst _ bbt.src _ [ word: IF impl.bwBitmapState = none THEN NIL ELSE VM.AddressForPageNumber[impl.bwBitmap.page], bit: 0 ]; }; bbt.width _ vt.bwWidth; bbt.height _ vt.bwHeight; }; WaitForBWVerticalRetrace: PUBLIC ENTRY PROC [vt: Virtual] = { ENABLE UNWIND => NULL; WaitUntilSelected[vt]; InternalWaitForBWVerticalRetrace[]; }; BlinkBWDisplay: PUBLIC PROC [vt: Virtual] = { background: Terminal.BWBackground; AcquireAndMarkTerminalUnstable[]; IF vt = current THEN { background _ NARROW[vt.impl, VirtualImpl].bwBackground; DisplayFace.SetBackground[IF background = white THEN black ELSE white]; Process.Pause[blinkTime]; DisplayFace.SetBackground[IF background = white THEN white ELSE black]; }; MarkTerminalStable[]; }; <> nullColorFaceMode: ColorDisplayFace.Mode ~ [full: FALSE, useA: FALSE, useB: FALSE, lgBitsPerPixelA: 0, lgBitsPerPixelB: 0]; ColorFaceMode: PROC[mode: Terminal.ColorMode] RETURNS[fmode: ColorDisplayFace.Mode _ nullColorFaceMode] = { illegal: BOOL _ FALSE; IF mode.full THEN fmode.full _ TRUE ELSE { IF (fmode.useA _ mode.bitsPerPixelChannelA>0) THEN SELECT mode.bitsPerPixelChannelA FROM 1 => fmode.lgBitsPerPixelA _ 0; 2 => fmode.lgBitsPerPixelA _ 1; 4 => fmode.lgBitsPerPixelA _ 2; 8 => fmode.lgBitsPerPixelA _ 3; ENDCASE => illegal _ TRUE; IF (fmode.useB _ mode.bitsPerPixelChannelB>0) THEN SELECT mode.bitsPerPixelChannelB FROM 1 => fmode.lgBitsPerPixelB _ 0; 2 => fmode.lgBitsPerPixelB _ 1; 4 => fmode.lgBitsPerPixelB _ 2; 8 => fmode.lgBitsPerPixelB _ 3; ENDCASE => illegal _ TRUE; }; IF illegal THEN fmode _ nullColorFaceMode; }; LegalColorFaceMode: PROC[fmode: ColorDisplayFace.Mode] RETURNS[BOOL] = { IF fmode=nullColorFaceMode THEN RETURN[FALSE] ELSE TRUSTED { RETURN[ColorDisplayFace.HasMode[fmode]] }; }; GetColorBitmapState: PUBLIC ENTRY PROC [vt: Virtual] RETURNS [Terminal.BitmapState] = { ENABLE UNWIND => NULL; impl: VirtualImpl = NARROW[vt.impl]; RETURN [impl.colorBitmapState] }; SetColorBitmapState: PUBLIC PROC [vt: Virtual, newState: Terminal.BitmapState, newMode: Terminal.ColorMode, newVisibility: Terminal.ChannelsVisible ] RETURNS [ oldState: Terminal.BitmapState, oldMode: Terminal.ColorMode, oldVisibility: Terminal.ChannelsVisible ] = { impl: VirtualImpl = NARROW[vt.impl]; SetColorBitmapStateInner: ENTRY PROC = { ENABLE UNWIND => NULL; Connect: INTERNAL PROC[fmode: ColorDisplayFace.Mode] = TRUSTED { impl.colorVM _ AllocateColorVM[fmode]; ColorDisplayFace.Connect[mode: fmode, firstPage: impl.colorVM.page, nPages: impl.colorVM.count]; vt.colorWidth _ ColorDisplayFace.width; vt.colorHeight _ ColorDisplayFace.height; vt.colorBitmapA _ ColorDisplayFace.baseA; vt.colorBitmapB _ ColorDisplayFace.baseB; IF (ColorDisplayFace.bplA MOD Basics.bitsPerWord)=0 THEN vt.colorWordsPerLineA _ ColorDisplayFace.bplA/Basics.bitsPerWord ELSE ERROR; IF (ColorDisplayFace.bplB MOD Basics.bitsPerWord)=0 THEN vt.colorWordsPerLineB _ ColorDisplayFace.bplB/Basics.bitsPerWord ELSE ERROR; impl.colorCursorVM _ VM.Allocate[3]; VM.Pin[impl.colorCursorVM]; impl.colorCursorSourceA _ VM.AddressForPageNumber[impl.colorCursorVM.page]; --page 1 impl.colorCursorBackupA _ impl.colorCursorSourceA+256; --page 2 impl.colorCursorSourceB _ impl.colorCursorBackupA+256; --first half of page 3 impl.colorCursorBackupB _ impl.colorCursorSourceB+128; --second half of page 3 ExpandColorCursorPattern[vt, impl]; }; Disconnect: INTERNAL PROC = TRUSTED { vt.colorBitmapA _ vt.colorBitmapB _ NIL; vt.colorWordsPerLineA _ vt.colorWordsPerLineB _ 0; ColorDisplayFace.Disconnect[]; VM.Free[impl.colorVM]; impl.colorVM _ VM.nullInterval; impl.colorBitmapState _ none; impl.colorCursorSourceA _ impl.colorCursorBackupA _ NIL; impl.colorCursorSourceB _ impl.colorCursorBackupB _ NIL; VM.Free[impl.colorCursorVM]; impl.colorCursorVM _ VM.nullInterval; }; TurnOn: INTERNAL PROC = { IF current=vt THEN { VM.Pin[impl.colorVM]; TRUSTED{ColorDisplayFace.TurnOn[]}; }; }; TurnOff: INTERNAL PROC = { IF current=vt THEN { TRUSTED{ColorDisplayFace.TurnOff[]}; VM.Unpin[impl.colorVM]; }; }; oldMode _ vt.colorMode; oldState _ impl.colorBitmapState; oldVisibility _ impl.colorVisibility; IF newMode#oldMode THEN { fmode: ColorDisplayFace.Mode ~ ColorFaceMode[newMode]; IF LegalColorFaceMode[fmode] THEN vt.colorMode _ newMode ELSE ERROR CantDoIt; IF oldState#none THEN { IF oldState=displayed THEN TurnOff[]; Disconnect[]; }; IF newState#none THEN { Connect[fmode]; IF newState=displayed THEN TurnOn[]; }; } ELSE IF newState#oldState THEN { IF oldState=displayed THEN TurnOff[]; IF newState=none THEN Disconnect[]; IF oldState=none THEN Connect[ColorFaceMode[vt.colorMode]]; IF newState=displayed THEN TurnOn[]; }; impl.colorBitmapState _ newState; IF newVisibility#oldVisibility THEN { impl.colorVisibility _ newVisibility; IF vt=current THEN SELECT newVisibility FROM none => TRUSTED{ColorDisplayFace.Show[a: FALSE, b: FALSE]}; aOnly => TRUSTED{ColorDisplayFace.Show[a: TRUE, b: FALSE]}; bOnly => TRUSTED{ColorDisplayFace.Show[a: FALSE, b: TRUE]}; all => TRUSTED{ColorDisplayFace.Show[a: TRUE, b: TRUE]}; ENDCASE => ERROR; }; }; <> --AcquireAndMarkTerminalUnstable[]; SetColorBitmapStateInner[]; --MarkTerminalStable[]; }; LegalColorMode: PUBLIC PROC[vt: Virtual, mode: Terminal.ColorMode] RETURNS[BOOL] = { IF vt.hasColorDisplay THEN RETURN[LegalColorFaceMode[ColorFaceMode[mode]]] ELSE RETURN[FALSE]; }; GetVisibility: PUBLIC ENTRY PROC [vt: Virtual] RETURNS [Terminal.ChannelsVisible] = { ENABLE UNWIND => NULL; impl: VirtualImpl = NARROW[vt.impl]; RETURN [impl.colorVisibility]; }; <> Color: TYPE = Terminal.Color; GetRedMap: PUBLIC ENTRY PROC [vt: Virtual, in: Color] RETURNS [Color] = { impl: VirtualImpl = NARROW[vt.impl]; IF vt.hasColorDisplay AND impl.colorBitmapState#none AND vt.colorMode.full THEN TRUSTED{RETURN[ColorDisplayFace.GetRedMap[in]]} ELSE RETURN[0]; }; GetGreenMap: PUBLIC ENTRY PROC [vt: Virtual, in: Color] RETURNS [Color] = { impl: VirtualImpl = NARROW[vt.impl]; IF vt.hasColorDisplay AND impl.colorBitmapState#none AND vt.colorMode.full THEN TRUSTED{RETURN[ColorDisplayFace.GetGreenMap[in]]} ELSE RETURN[0]; }; GetBlueMap: PUBLIC ENTRY PROC [vt: Virtual, in: Color] RETURNS [Color] = { impl: VirtualImpl = NARROW[vt.impl]; IF vt.hasColorDisplay AND impl.colorBitmapState#none AND vt.colorMode.full THEN TRUSTED{RETURN[ColorDisplayFace.GetBlueMap[in]]} ELSE RETURN[0]; }; SetRedMap: PUBLIC ENTRY PROC [vt: Virtual, in: Color, out: Color] = { impl: VirtualImpl = NARROW[vt.impl]; IF vt.hasColorDisplay AND impl.colorBitmapState#none AND vt.colorMode.full THEN TRUSTED{ColorDisplayFace.SetRedMap[in: in, out: out]}; }; SetGreenMap: PUBLIC ENTRY PROC [vt: Virtual, in: Color, out: Color] = { impl: VirtualImpl = NARROW[vt.impl]; IF vt.hasColorDisplay AND impl.colorBitmapState#none AND vt.colorMode.full THEN TRUSTED{ColorDisplayFace.SetGreenMap[in: in, out: out]}; }; SetBlueMap: PUBLIC ENTRY PROC [vt: Virtual, in: Color, out: Color] = { impl: VirtualImpl = NARROW[vt.impl]; IF vt.hasColorDisplay AND impl.colorBitmapState#none AND vt.colorMode.full THEN TRUSTED{ColorDisplayFace.SetBlueMap[in: in, out: out]}; }; GetColor: PUBLIC ENTRY PROC [vt: Virtual, aChannelValue, bChannelValue: Terminal.ChannelValue _ 0] RETURNS [red, green, blue: Color] = { impl: VirtualImpl = NARROW[vt.impl]; IF vt.hasColorDisplay AND impl.colorBitmapState#none AND NOT vt.colorMode.full THEN TRUSTED{[r: red, g: green, b: blue] _ ColorDisplayFace.GetColor[ pixelA: aChannelValue, pixelB: bChannelValue]} ELSE red _ green _ blue _ 0; }; SetColor: PUBLIC ENTRY PROC [vt: Virtual, aChannelValue, bChannelValue: Terminal.ChannelValue _ 0, red, green, blue: Color] = { impl: VirtualImpl = NARROW[vt.impl]; IF vt.hasColorDisplay AND impl.colorBitmapState#none AND NOT vt.colorMode.full THEN TRUSTED{ColorDisplayFace.SetColor[pixelA: aChannelValue, pixelB: bChannelValue, r: red, g: green, b: blue]}; }; <<>> <<>> <> <<>> <> <> <<>> GetColorCursorPosition: PUBLIC ENTRY PROC [vt: Virtual] RETURNS [Terminal.Position] = { ENABLE UNWIND => NULL; impl: VirtualImpl = NARROW[vt.impl]; RETURN[impl.colorCursor]; }; SetColorCursorPosition: PUBLIC ENTRY PROC [vt: Virtual, position: Terminal.Position] = { ENABLE UNWIND => NULL; impl: VirtualImpl = NARROW[vt.impl]; IF NOT vt.hasColorDisplay THEN RETURN; IF impl.colorCursor=position THEN RETURN; -- no change IF impl.colorCursorDisplayed THEN HideColorCursor[vt, impl]; impl.colorCursor _ position; IF impl.colorCursorState=$visible AND NOT InhibitColorCursor[impl] THEN ShowColorCursor[vt, impl]; }; <> <> <<>> GetColorCursorPattern: PUBLIC ENTRY PROC [vt: Virtual] RETURNS [pattern: Terminal.ColorCursorBitmap] = { ENABLE UNWIND => NULL; impl: VirtualImpl = NARROW[vt.impl]; RETURN[impl.colorPattern]; }; SetColorCursorPattern: PUBLIC ENTRY PROC [vt: Virtual, pattern: Terminal.ColorCursorBitmap] = { ENABLE UNWIND => NULL; impl: VirtualImpl ~ NARROW[vt.impl]; displayed: BOOL ~ impl.colorCursorDisplayed; IF NOT vt.hasColorDisplay THEN RETURN; IF displayed THEN HideColorCursor[vt, impl]; impl.colorPattern _ pattern; IF impl.colorBitmapState#none THEN ExpandColorCursorPattern[vt, impl]; IF displayed THEN ShowColorCursor[vt, impl]; }; <<>> <> GetColorCursorPresentation: PUBLIC ENTRY PROC [vt: Virtual] RETURNS [Terminal.ColorCursorPresentation] = { ENABLE UNWIND => NULL; impl: VirtualImpl = NARROW[vt.impl]; RETURN[impl.colorCursorPresentation]; }; SetColorCursorPresentation: PUBLIC ENTRY PROC [vt: Virtual, new: Terminal.ColorCursorPresentation] RETURNS [old: Terminal.ColorCursorPresentation] = { ENABLE UNWIND => NULL; impl: VirtualImpl ~ NARROW[vt.impl]; displayed: BOOL ~ impl.colorCursorDisplayed; old _ impl.colorCursorPresentation; IF NOT vt.hasColorDisplay THEN RETURN; IF new=old THEN RETURN; -- no change IF displayed THEN HideColorCursor[vt, impl]; impl.colorCursorPresentation _ new; IF displayed THEN ShowColorCursor[vt, impl]; }; <<>> <<>> <> <> <<>> GetColorCursorState: PUBLIC ENTRY PROC [vt: Virtual] RETURNS [Terminal.ColorCursorBitmapState] = { ENABLE UNWIND => NULL; impl: VirtualImpl = NARROW[vt.impl]; RETURN[impl.colorCursorState]; }; SetColorCursorState: PUBLIC ENTRY PROC [vt: Virtual, new: Terminal.ColorCursorBitmapState] RETURNS [old: Terminal.ColorCursorBitmapState] = { ENABLE UNWIND => NULL; impl: VirtualImpl = NARROW[vt.impl]; old _ impl.colorCursorState; IF NOT vt.hasColorDisplay THEN RETURN; IF new=old THEN RETURN; IF impl.colorBitmapState#none THEN SELECT new FROM $invisible => IF impl.colorCursorDisplayed THEN HideColorCursor[vt, impl]; $visible => IF NOT InhibitColorCursor[impl] THEN ShowColorCursor[vt, impl]; ENDCASE; impl.colorCursorState _ new; }; LockColorFrame: PUBLIC ENTRY PROC[vt: Virtual, xmin, ymin: NAT _ 0, xmax, ymax: NAT _ NAT.LAST] = { ENABLE UNWIND => NULL; impl: VirtualImpl = NARROW[vt.impl]; impl.xmin _ xmin; impl.ymin _ ymin; impl.xmax _ xmax; impl.ymax _ ymax; impl.colorFrameLocked _ TRUE; IF impl.colorCursorDisplayed AND InhibitColorCursor[impl] THEN HideColorCursor[vt, impl]; }; UnlockColorFrame: PUBLIC ENTRY PROC[vt: Virtual] = { ENABLE UNWIND => NULL; impl: VirtualImpl = NARROW[vt.impl]; impl.colorFrameLocked _ FALSE; IF impl.colorBitmapState#none AND impl.colorCursorState=$visible AND NOT impl.colorCursorDisplayed THEN ShowColorCursor[vt, impl]; }; <<>> InhibitColorCursor: INTERNAL PROC[impl: VirtualImpl] RETURNS[BOOL] = INLINE { RETURN[impl.colorFrameLocked AND ColorCursorIntersectsFrame[impl]]; }; ColorCursorIntersectsFrame: INTERNAL PROC[impl: VirtualImpl] RETURNS[BOOL] = { x: INTEGER ~ impl.colorCursor.x; y: INTEGER ~ impl.colorCursor.y; w: INTEGER ~ 16; h: INTEGER ~ 16; RETURN[ximpl.xmin AND (y+h)>impl.ymin]; }; colorCursorWplSrcA: NAT ~ 16; colorCursorWplSrcB: NAT ~ 8; ExpandColorCursorPattern: INTERNAL PROC[vt: Virtual, impl: VirtualImpl] = { ExpandBitmap: PROC[buffer: LONG POINTER, wpl: CARDINAL, bpp: NAT] = TRUSTED { AddOne: PROC[address: PrincOps.BitAddress] RETURNS[PrincOps.BitAddress] = TRUSTED { IF address.bit<15 THEN address.bit _ address.bit+1 ELSE {address.bit _ 0; address.word _ address.word+1}; RETURN[address]; }; ppw: NAT ~ 16/bpp; bbSpace: PrincOps.BBTableSpace; bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbSpace]; bb^ _ [dst: [word: NIL, bit: 0], dstBpl: 0, src: [word: NIL, bit: 0], srcDesc: [srcBpl[0]], width: 0, height: 0, flags: [disjoint: TRUE, gray: FALSE, srcFunc: null, dstFunc: null]]; bb.src.word _ @impl.colorPattern; bb.srcDesc.srcBpl _ 16; bb.dst.word _ buffer; bb.dstBpl _ wpl*16; bb.width _ 1; bb.height _ 16; FOR i: NAT IN [0..16) DO FOR j: NAT IN [0..bpp) DO PrincOpsUtils.BITBLT[bb]; --write one column bb.dst _ AddOne[bb.dst]; ENDLOOP; bb.src _ AddOne[bb.src]; ENDLOOP; }; IF impl.colorBitmapState=none THEN RETURN; IF vt.colorMode.full THEN { ExpandBitmap[impl.colorCursorSourceA, colorCursorWplSrcA, 16]; ExpandBitmap[impl.colorCursorSourceB, colorCursorWplSrcB, 8]; } ELSE IF vt.colorMode.bitsPerPixelChannelA>0 THEN { ExpandBitmap[impl.colorCursorSourceA, colorCursorWplSrcA, vt.colorMode.bitsPerPixelChannelA]; }; }; HideColorCursor: INTERNAL PROC[vt: Virtual, impl: VirtualImpl] = TRUSTED { xMax: INTEGER ~ vt.colorWidth; yMax: INTEGER ~ vt.colorHeight; x: INTEGER ~ impl.colorCursor.x; y: INTEGER ~ impl.colorCursor.y; w: INTEGER ~ 16; h: INTEGER ~ 16; IF (x+w)>0 AND (y+h)>0 AND x0) THEN { bpp: NAT ~ IF vt.colorMode.full THEN 16 ELSE vt.colorMode.bitsPerPixelChannelA; ppw: NAT ~ 16/bpp; bltX, bltY, bltW, bltH: INTEGER; xoff, yoff: INTEGER _ 0; bbSpace: PrincOps.BBTableSpace; bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbSpace]; bb^ _ [dst: [word: NIL, bit: 0], dstBpl: 0, src: [word: NIL, bit: 0], srcDesc: [srcBpl[0]], width: 0, height: 0, flags: [disjoint: TRUE, gray: FALSE, srcFunc: null, dstFunc: null]]; bltX _ x; bltY _ y; bltW _ w; bltH _ h; IF x<0 THEN {xoff _ ABS[x]; bltW _ w-xoff; bltX _ 0}; IF y<0 THEN {yoff _ ABS[y]; bltH _ h-yoff; bltY _ 0}; IF x>(xMax-w) THEN bltW _ xMax-x; IF y>(yMax-h) THEN bltH _ yMax-y; bb.dst.word _ vt.colorBitmapA + Basics.LongMult[bltY,vt.colorWordsPerLineA] + bltX/ppw; bb.dst.bit _ (bltX MOD ppw)*bpp; bb.dstBpl _ vt.colorWordsPerLineA*16; bb.src.word _ impl.colorCursorBackupA; bb.src.bit _ 0; bb.srcDesc.srcBpl _ colorCursorWplSrcA*16; bb.width _ bltW*bpp; bb.height _ bltH; PrincOpsUtils.BITBLT[bb]; -- restore the bits under the cursor IF vt.colorMode.full THEN { bb.dst.word _ vt.colorBitmapB + Basics.LongMult[bltY,vt.colorWordsPerLineB] + bltX/2; bb.dst.bit _ (bltX MOD 2)*8; bb.dstBpl _ vt.colorWordsPerLineB*16; bb.src.word _ impl.colorCursorBackupB; bb.src.bit _ 0; bb.srcDesc.srcBpl _ colorCursorWplSrcB*16; bb.width _ bltW*8; bb.height _ bltH; PrincOpsUtils.BITBLT[bb]; -- restore the rest of the bits under the cursor }; }; impl.colorCursorDisplayed _ FALSE; }; ShowColorCursor: INTERNAL PROC[vt: Virtual, impl: VirtualImpl] = TRUSTED { xMax: INTEGER ~ vt.colorWidth; yMax: INTEGER ~ vt.colorHeight; x: INTEGER ~ impl.colorCursor.x; y: INTEGER ~ impl.colorCursor.y; w: INTEGER ~ 16; h: INTEGER ~ 16; xoff, yoff: INTEGER _ 0; IF (x+w)>0 AND (y+h)>0 AND x0) THEN { bpp: NAT ~ IF vt.colorMode.full THEN 16 ELSE vt.colorMode.bitsPerPixelChannelA; ppw: NAT ~ 16/bpp; bltX, bltY, bltW, bltH: INTEGER; xoff, yoff: INTEGER _ 0; bbSpace: PrincOps.BBTableSpace; bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbSpace]; bb^ _ [dst: [word: NIL, bit: 0], dstBpl: 0, src: [word: NIL, bit: 0], srcDesc: [srcBpl[0]], width: 0, height: 0, flags: [disjoint: TRUE, gray: FALSE, srcFunc: null, dstFunc: null]]; bltX _ x; bltY _ y; bltW _ w; bltH _ h; IF x<0 THEN {xoff _ ABS[x]; bltW _ w-xoff; bltX _ 0}; IF y<0 THEN {yoff _ ABS[y]; bltH _ h-yoff; bltY _ 0}; IF x>(xMax-w) THEN bltW _ xMax-x; IF y>(yMax-h) THEN bltH _ yMax-y; bb.dst _ [word: impl.colorCursorBackupA, bit: 0]; bb.dstBpl _ colorCursorWplSrcA*16; bb.src.word _ vt.colorBitmapA + Basics.LongMult[bltY,vt.colorWordsPerLineA] + bltX/ppw; bb.src.bit _ (bltX MOD ppw)*bpp; bb.srcDesc.srcBpl _ vt.colorWordsPerLineA*16; bb.width _ bltW*bpp; bb.height _ bltH; PrincOpsUtils.BITBLT[bb]; -- save the bits under the cursor IF vt.colorMode.full THEN { bb.src.word _ vt.colorBitmapB + Basics.LongMult[bltY,vt.colorWordsPerLineB] + bltX/2; bb.src.bit _ (bltX MOD 2)*8; bb.srcDesc.srcBpl _ vt.colorWordsPerLineB*16; bb.dst _ [word: impl.colorCursorBackupB, bit: 0]; bb.dstBpl _ colorCursorWplSrcB*16; bb.width _ bltW*8; bb.height _ bltH; PrincOpsUtils.BITBLT[bb]; -- save the rest of the bits under the cursor }; SELECT impl.colorCursorPresentation FROM $onesAreBlack => { bb.flags.srcFunc _ complement; bb.flags.dstFunc _ and }; $onesAreWhite => { bb.flags.srcFunc _ null; bb.flags.dstFunc _ or }; ENDCASE => ERROR; bb.dst.word _ vt.colorBitmapA + Basics.LongMult[bltY,vt.colorWordsPerLineA] + bltX/ppw; bb.dst.bit _ (bltX MOD ppw)*bpp; bb.dstBpl _ vt.colorWordsPerLineA*16; bb.src.word _ impl.colorCursorSourceA + yoff*colorCursorWplSrcA + xoff/ppw; bb.src.bit _ (xoff MOD ppw)*bpp; bb.srcDesc.srcBpl _ colorCursorWplSrcA*16; bb.width _ bltW*bpp; bb.height _ bltH; PrincOpsUtils.BITBLT[bb]; -- Put the cursor in IF vt.colorMode.full THEN { bb.dst.word _ vt.colorBitmapB + Basics.LongMult[bltY,vt.colorWordsPerLineB] + bltX/2; bb.dst.bit _ (bltX MOD 2)*8; bb.dstBpl _ vt.colorWordsPerLineB*16; bb.src.word _ impl.colorCursorSourceB + yoff*colorCursorWplSrcB + xoff/2; bb.src.bit _ (xoff MOD 2)*8; bb.srcDesc.srcBpl _ colorCursorWplSrcB*16; bb.width _ bltW*8; bb.height _ bltH; PrincOpsUtils.BITBLT[bb]; -- Put the rest of the cursor in }; }; impl.colorCursorDisplayed _ TRUE; }; <> WaitUntilSelected: INTERNAL PROC [vt: Virtual] = { UNTIL current = vt DO WAIT terminalStable; ENDLOOP; }; AcquireAndMarkTerminalUnstable: ENTRY PROC = { ENABLE UNWIND => NULL; WHILE terminalChanging DO WAIT terminalStable; ENDLOOP; terminalChanging _ TRUE; }; AcquireAndMarkSpecificTerminalUnstable: ENTRY PROC [vt: Virtual] = { ENABLE UNWIND => NULL; WHILE terminalChanging OR vt ~= current DO WAIT terminalStable; ENDLOOP; terminalChanging _ TRUE; }; MarkTerminalStable: ENTRY PROC = { ENABLE UNWIND => NULL; terminalChanging _ FALSE; BROADCAST terminalStable; }; InternalWaitForBWVerticalRetrace: INTERNAL PROC = { ENABLE UNWIND => NULL; IF meFirst THEN { meFirst _ FALSE; TRUSTED {WAIT bwRetrace^}; BROADCAST verticalRetrace; meFirst _ TRUE; } ELSE WAIT verticalRetrace; }; TurnOff: INTERNAL PROC[impl: VirtualImpl] = { DisplayFace.TurnOff[]; InternalWaitForBWVerticalRetrace[]; InternalWaitForBWVerticalRetrace[]; IF DisplayFace.hasBuffer THEN VMSideDoor.ReleaseSpecialRealMemory[impl.bwBitmap] ELSE VM.Unpin[impl.bwBitmap]; }; TurnOffColor: INTERNAL PROC[impl: VirtualImpl] = { TRUSTED{ColorDisplayFace.TurnOff[]}; VM.Unpin[impl.colorVM]; }; LoadTerminal: PROC [vt: Virtual] = TRUSTED { vtImpl: VirtualImpl = NARROW[vt.impl]; vt.keyboard _ LOOPHOLE[KeyboardFace.keyboard]; vt.mouse _ LOOPHOLE[MouseFace.position]; MouseFace.SetPosition[LOOPHOLE[vtImpl.mouse]]; vt.bwCursor _ LOOPHOLE[DisplayFace.cursorPosition]; vt.bwCursor^ _ LOOPHOLE[vtImpl.bwCursor]; DisplayFace.SetBackground[IF vtImpl.bwBackground = white THEN white ELSE black]; DisplayFace.SetBorderPattern[oddPairs: vtImpl.bwBorderOdd, evenPairs: vtImpl.bwBorderEven]; DisplayFace.SetCursorPattern[@vtImpl.bwPattern]; SELECT vtImpl.bwBitmapState FROM displayed => { DisplayFace.Connect[vtImpl.bwBitmap.page]; IF DisplayFace.hasBuffer THEN VMSideDoor.AssignSpecialRealMemory[vtImpl.bwBitmap] ELSE VM.Pin[vtImpl.bwBitmap]; DisplayFace.TurnOn[]; }; allocated => { DisplayFace.Connect[vtImpl.bwBitmap.page]; IF DisplayFace.hasBuffer THEN VMSideDoor.AssignSpecialRealMemory[vtImpl.bwBitmap]; }; none => NULL; ENDCASE; IF vtImpl.colorBitmapState=displayed THEN { VM.Pin[vtImpl.colorVM]; ColorDisplayFace.TurnOn[]; }; }; UnloadTerminal: INTERNAL PROC [vt: Virtual] = TRUSTED { vtImpl: VirtualImpl = NARROW[vt.impl]; vtImpl.keyboard _ LOOPHOLE[KeyboardFace.keyboard^]; vt.keyboard _ @vtImpl.keyboard; vtImpl.mouse _ LOOPHOLE[MouseFace.position^]; vt.mouse _ @vtImpl.mouse; vtImpl.bwCursor _ LOOPHOLE[DisplayFace.cursorPosition^]; vt.bwCursor _ @vtImpl.bwCursor; SELECT vtImpl.bwBitmapState FROM displayed => { TurnOff[vtImpl]; DisplayFace.Disconnect[]; }; allocated => { IF DisplayFace.hasBuffer THEN VMSideDoor.ReleaseSpecialRealMemory[vtImpl.bwBitmap]; DisplayFace.Disconnect[]; }; none => NULL; ENDCASE; IF vtImpl.colorBitmapState=displayed THEN { ColorDisplayFace.TurnOff[]; VM.Unpin[vtImpl.colorVM]; }; }; NewVirtual: PROC RETURNS [vt: Virtual] = { vtImpl: VirtualImpl = NEW[VirtualImplObject _ []]; TRUSTED { vt _ NEW[Terminal.Object _ [ keyboard: LOOPHOLE[@vtImpl.keyboard], mouse: LOOPHOLE[@vtImpl.mouse], hasBlackAndWhiteDisplay: TRUE, bwWidth: DisplayFace.width, bwHeight: DisplayFace.height, bwHasBorder: DisplayFace.hasBorder, bwPixelsPerInch: DisplayFace.pixelsPerInch, bwCursor: LOOPHOLE[@vtImpl.bwCursor], hasColorDisplay: FALSE, colorWidth: 0, colorHeight: 0, colorPixelsPerInch: 0, colorDisplayType: NULL, colorMode: [FALSE, 0, 0], colorBitmapA: NIL, colorBitmapB: NIL, colorWordsPerLineA: 0, colorWordsPerLineB: 0, impl: LOOPHOLE[vtImpl] ]]; }; }; AttachColorDisplay: PUBLIC ENTRY PROC[vt: Virtual] = { -- export to TerminalExtras ENABLE UNWIND => NULL; IF colorTerminal=NIL THEN colorTerminal _ vt ELSE IF colorTerminal=vt THEN NULL ELSE ERROR CantDoIt; IF ColorDisplayFace.displayType=none THEN RETURN; vt.colorPixelsPerInch _ ColorDisplayFace.pixelsPerInch; vt.colorDisplayType _ (SELECT ColorDisplayFace.displayType FROM ramtek525 => ramtek525, hitachi3619 => hitachi3619, ENDCASE => ramtek525); -- should be 'other' vt.hasColorDisplay _ TRUE; }; AllocateBWBitmap: PROC RETURNS [interval: VM.Interval] = { interval _ VM.Allocate[count: DisplayFace.pagesForBitmap, in64K: TRUE ! VM.CantAllocate => GO TO cant]; EXITS cant => ERROR CantDoIt; }; <<>> AllocateColorVM: PROC[fmode: ColorDisplayFace.Mode] RETURNS [interval: VM.Interval] = { pages: INT; TRUSTED { pages _ ColorDisplayFace.PagesForMode[fmode] }; interval _ VM.Allocate[count: pages ! VM.CantAllocate => GO TO cant]; EXITS cant => ERROR CantDoIt; }; <<>> <<>> KeyboardWatcher: PROC = TRUSTED { WatcherEnabled: ENTRY PROC RETURNS [BOOL] = TRUSTED INLINE { ENABLE UNWIND => NULL; RETURN[watcherDisableCount = 0] }; KeysRecord: TYPE = RECORD [ SELECT OVERLAID * FROM bits => [bits: Keys.KeyBits], words => [words: ARRAY [0..SIZE[Keys.KeyBits]) OF WORD], ENDCASE ]; keyboard: LONG POINTER TO KeysRecord = LOOPHOLE[KeyboardFace.keyboard]; waitTime: Process.Ticks = Process.MsecToTicks[300]; lastTime: KeysRecord _ keyboard^; <> magicCombination: KeysRecord _ [words[words: ALL[177777B]]]; magicCombination.bits[Ctrl] _ magicCombination.bits[LeftShift] _ magicCombination.bits[RightShift] _ down; Process.SetPriority[Process.priorityForeground]; DO Process.Pause[waitTime]; IF WatcherEnabled[] THEN { thisTime: KeysRecord = keyboard^; changed: BOOL _ FALSE; select: BOOL _ TRUE; FOR word: NAT IN [0..SIZE[KeysRecord]) DO thisWord: WORD = thisTime.words[word]; IF thisWord ~= lastTime.words[word] THEN changed _ TRUE; IF thisWord ~= magicCombination.words[word] THEN select _ FALSE; ENDLOOP; IF changed THEN { lastTime _ thisTime; IF select THEN Select[NIL]; }; }; ENDLOOP; }; <<>> <> <<>> Initialize: PROC = TRUSTED { WordSequence: TYPE = RECORD [SEQUENCE COMPUTED CARDINAL OF WORD]; headGlobalP: LONG POINTER = VM.lowCore.NEW[WordSequence[DisplayFace.globalStateSize]]; mask: WORD; vt: Virtual = NewVirtual[]; initialPosition: Terminal.Position; [bwRetrace, mask] _ PrincOpsUtils.AllocateNakedCondition[]; DisplayFace.Initialize[headGlobalP, mask]; DisplayFace.InitializeCleanup[]; IF ColorDisplayFace.displayType#none THEN { colorHeadGlobalP: LONG POINTER = VM.lowCore.NEW[WordSequence[ColorDisplayFace.globalStateSize]]; ColorDisplayFace.Initialize[colorHeadGlobalP]; ColorDisplayFace.InitializeCleanup[]; }; initialPosition _ [x: vt.bwWidth/2, y: vt.bwHeight/2]; Terminal.SetMousePosition[vt, initialPosition]; Terminal.SetBWCursorPosition[vt, initialPosition]; LoadTerminal[current _ vt]; terminals _ CONS[current, NIL]; Process.EnableAborts[@terminalStable]; Process.Detach[FORK KeyboardWatcher[]]; }; Initialize[]; END.