<> <> <> <> <> <> DIRECTORY Basics USING [bitsPerWord, LongMult, RawWords], ColorDisplayFace, CountedVM USING [Allocate, Free, Handle, SimpleAllocate], PrincOps USING [BBTable, BBTableSpace, BitAddress, BitBltTablePtr], PrincOpsUtils USING [AlignedBBTable, AllocateNakedCondition, BITBLT], Process USING [Detach, EnableAborts, GetPriority, MsecToTicks, Pause, Priority, priorityForeground, SetPriority, Ticks], SystemVersion USING [machineType], Terminal USING [BitmapState, BWBackground, BWBorder, ChannelsVisible, ChannelValue, ColorCursorBitmapState, ColorCursorPresentation, ColorMode, ColorValue, FrameBuffer, FrameBufferRep, SwapAction, SwapNotifier, Virtual, VirtualRep], TerminalDefs USING [Cursor, KeyBits, KeyState, Position], TerminalFace USING [Beep, Connect, Disconnect, GetCursorPosition, GetKeyboard, GetMousePosition, globalStateSize, hasBorder, hasBuffer, hasSoundGenerator, height, Initialize, InitializeCleanup, pixelsPerInch, SetBackground, SetBorderPattern, SetCursorPattern, SetCursorPosition, SetMousePosition, TurnOff, TurnOn, width, wordsPerLine], TerminalPrivate USING [Notifier, NotifierItem, VirtualImpl, VirtualImplRep], VM USING [CantAllocate, lowCore, Pin, Unpin], VMSideDoor USING [AssignSpecialRealMemory, ReleaseSpecialRealMemory]; TerminalImpl: CEDAR MONITOR IMPORTS Basics, ColorDisplayFace, CountedVM, PrincOpsUtils, Process, SystemVersion, TerminalFace, VM, VMSideDoor EXPORTS Terminal ~ BEGIN OPEN TerminalPrivate, Terminal, TerminalDefs; VirtualImpl: TYPE ~ TerminalPrivate.VirtualImpl; VirtualImplRep: PUBLIC TYPE ~ TerminalPrivate.VirtualImplRep; Notifier: TYPE ~ TerminalPrivate.Notifier; NotifierItem: TYPE ~ TerminalPrivate.NotifierItem; priorityDuringSelect: Process.Priority = Process.priorityForeground; blinkTime: Process.Ticks = Process.MsecToTicks[100]; <<>> <> <<>> TerminalList: TYPE ~ LIST OF Virtual; terminals: TerminalList _ NIL; 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]; <<>> <> 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; }; MarkTerminalStable: ENTRY PROC = { ENABLE UNWIND => NULL; terminalChanging _ FALSE; BROADCAST terminalStable; }; AcquireColorDisplay: ENTRY PROC [vt: Virtual] ~ { ENABLE UNWIND => NULL; impl: VirtualImpl ~ vt.impl; WHILE impl.colorDisplayChanging DO WAIT impl.colorDisplayStable ENDLOOP; impl.colorDisplayChanging _ TRUE; }; ReleaseColorDisplay: ENTRY PROC [vt: Virtual] ~ { ENABLE UNWIND => NULL; impl: VirtualImpl ~ vt.impl; impl.colorDisplayChanging _ FALSE; BROADCAST impl.colorDisplayStable; }; InternalWaitForBWVerticalRetrace: INTERNAL PROC = { ENABLE UNWIND => NULL; IF meFirst THEN { meFirst _ FALSE; TRUSTED {WAIT bwRetrace^}; BROADCAST verticalRetrace; meFirst _ TRUE; } ELSE WAIT verticalRetrace; }; bitsPerWord: NAT ~ Basics.bitsPerWord; need64K: BOOL _ SystemVersion.machineType # dolphin; cachedBuffer: FrameBuffer _ NewFrameBuffer[ width: TerminalFace.width, height: TerminalFace.height, bitsPerPixel: 1, in64K: need64K]; <> NewFrameBuffer: PROC [width, height, bitsPerPixel: NAT, in64K: BOOL _ FALSE] RETURNS [FrameBuffer] ~ { wordsPerLine: NAT ~ (bitsPerPixel*width)/bitsPerWord; words: INT ~ INT[wordsPerLine]*INT[height]; vm: CountedVM.Handle ~ CountedVM.Allocate[words: words, in64K: in64K ! VM.CantAllocate => GO TO cant]; RETURN[NEW[FrameBufferRep _ [vm: vm, base: vm.pointer, wordsPerLine: wordsPerLine, bitsPerPixel: bitsPerPixel, width: width, height: height]]]; EXITS cant => ERROR CantDoIt; }; <<>> BWAllocate: INTERNAL PROC [impl: VirtualImpl] ~ { width: NAT ~ TerminalFace.width; height: NAT ~ TerminalFace.height; wordsPerLine: NAT ~ TerminalFace.wordsPerLine; IF (wordsPerLine*bitsPerWord)#width THEN ERROR; IF cachedBuffer # NIL THEN { impl.bwFrameBuffer _ cachedBuffer; cachedBuffer _ NIL; RETURN; }; impl.bwFrameBuffer _ NewFrameBuffer[ width: width, height: height, bitsPerPixel: 1, in64K: need64K]; }; BWFree: INTERNAL PROC [impl: VirtualImpl] ~ { IF cachedBuffer = NIL THEN cachedBuffer _ impl.bwFrameBuffer; impl.bwFrameBuffer _ NIL; }; BWConnect: INTERNAL PROC [impl: VirtualImpl] ~ { IF TerminalFace.hasBuffer THEN VMSideDoor.AssignSpecialRealMemory[impl.bwFrameBuffer.vm.interval]; TRUSTED { TerminalFace.Connect[impl.bwFrameBuffer.base] }; }; BWDisconnect: INTERNAL PROC [impl: VirtualImpl] ~ { TerminalFace.Disconnect[]; IF TerminalFace.hasBuffer THEN VMSideDoor.ReleaseSpecialRealMemory[impl.bwFrameBuffer.vm.interval]; }; BWTurnOn: INTERNAL PROC [impl: VirtualImpl] ~ TRUSTED { IF NOT TerminalFace.hasBuffer THEN VM.Pin[impl.bwFrameBuffer.vm.interval]; TerminalFace.TurnOn[]; }; BWTurnOff: INTERNAL PROC [impl: VirtualImpl] ~ { TerminalFace.TurnOff[]; InternalWaitForBWVerticalRetrace[]; InternalWaitForBWVerticalRetrace[]; IF NOT TerminalFace.hasBuffer THEN VM.Unpin[impl.bwFrameBuffer.vm.interval]; }; ColorAllocate: PROC [impl: VirtualImpl] ~ { mode: ColorMode ~ impl.colorMode; width: NAT ~ ColorDisplayFace.width; height: NAT ~ ColorDisplayFace.height; IF NOT ColorDisplayFace.HasMode[mode] THEN ERROR CantDoIt; IF mode.full THEN { impl.colorFrameBufferA _ NewFrameBuffer[ width: width, height: height, bitsPerPixel: 16]; impl.colorFrameBufferB _ NewFrameBuffer[ width: width, height: height, bitsPerPixel: 8]; } ELSE { IF mode.bitsPerPixelChannelA#0 THEN impl.colorFrameBufferA _ NewFrameBuffer[ width: width, height: height, bitsPerPixel: mode.bitsPerPixelChannelA]; IF mode.bitsPerPixelChannelB#0 THEN impl.colorFrameBufferB _ NewFrameBuffer[ width: width, height: height, bitsPerPixel: mode.bitsPerPixelChannelB]; }; impl.colorMapVM _ CountedVM.SimpleAllocate[ColorDisplayFace.wordsForColorMap]; TRUSTED { impl.colorMap _ ColorDisplayFace.InitializeColorMap[ mode: mode, pointer: impl.colorMapVM.pointer] }; IF impl.colorCursorVM=NIL THEN TRUSTED { vm: CountedVM.Handle ~ CountedVM.SimpleAllocate[words: 3*256]; impl.colorCursorVM _ vm; impl.colorCursorSourceA _ vm.pointer; --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 VM.Pin[vm.interval]; }; }; ColorFree: PROC [impl: VirtualImpl] ~ { impl.colorFrameBufferA _ NIL; impl.colorFrameBufferB _ NIL; TRUSTED { CountedVM.Free[impl.colorMapVM] }; impl.colorMap _ NIL; impl.colorMapVM _ NIL; }; ColorConnect: PROC [impl: VirtualImpl] ~ TRUSTED { mode: ColorMode ~ impl.colorMode; baseA, baseB: LONG POINTER _ NIL; IF impl.colorFrameBufferA#NIL THEN baseA _ impl.colorFrameBufferA.base; IF impl.colorFrameBufferB#NIL THEN baseB _ impl.colorFrameBufferB.base; ColorDisplayFace.Connect[mode: mode, baseA: baseA, baseB: baseB, map: impl.colorMap]; ExpandColorCursorPattern[impl]; }; ColorDisconnect: PROC [impl: VirtualImpl] ~ TRUSTED { ColorDisplayFace.Disconnect[]; }; ColorTurnOn: PROC [impl: VirtualImpl] ~ TRUSTED { mode: ColorMode ~ impl.colorMode; IF impl.colorFrameBufferA#NIL THEN VM.Pin[impl.colorFrameBufferA.vm.interval]; IF impl.colorFrameBufferB#NIL THEN VM.Pin[impl.colorFrameBufferB.vm.interval]; VM.Pin[impl.colorMapVM.interval]; ColorDisplayFace.TurnOn[]; }; ColorTurnOff: PROC [impl: VirtualImpl] ~ TRUSTED { mode: ColorMode ~ impl.colorMode; ColorDisplayFace.TurnOff[]; IF impl.colorFrameBufferA#NIL THEN VM.Unpin[impl.colorFrameBufferA.vm.interval]; IF impl.colorFrameBufferB#NIL THEN VM.Unpin[impl.colorFrameBufferB.vm.interval]; VM.Unpin[impl.colorMapVM.interval]; }; LoadTerminal: INTERNAL PROC[vt: Virtual] ~ { impl: VirtualImpl ~ vt.impl; TerminalFace.SetMousePosition[impl.mouse]; TerminalFace.SetCursorPosition[impl.bwCursorPosition]; TerminalFace.SetCursorPattern[impl.bwCursorPattern]; TerminalFace.SetBackground[impl.bwBackground]; TerminalFace.SetBorderPattern[oddPairs: impl.bwBorderOdd, evenPairs: impl.bwBorderEven]; IF impl.bwBitmapState#none THEN BWConnect[impl]; IF impl.bwBitmapState=displayed THEN BWTurnOn[impl]; ColorDisplayFace.SetVisibility[impl.colorVisibility]; IF impl.colorBitmapState#none THEN ColorConnect[impl]; IF impl.colorBitmapState=displayed THEN ColorTurnOn[impl]; }; UnloadTerminal: INTERNAL PROC[vt: Virtual] ~ { impl: VirtualImpl ~ vt.impl; impl.keyboard _ TerminalFace.GetKeyboard[]; impl.mouse _ TerminalFace.GetMousePosition[]; impl.bwCursorPosition _ TerminalFace.GetCursorPosition[]; IF impl.bwBitmapState=displayed THEN BWTurnOff[impl]; IF impl.bwBitmapState#none THEN BWDisconnect[impl]; IF impl.colorBitmapState=displayed THEN ColorTurnOff[impl]; IF impl.colorBitmapState#none THEN ColorDisconnect[impl]; }; NewVirtual: PROC RETURNS[vt: Virtual] = { impl: VirtualImpl = NEW[VirtualImplRep _ []]; vt _ NEW[Terminal.VirtualRep _ [ hasBlackAndWhiteDisplay: TRUE, bwWidth: TerminalFace.width, bwHeight: TerminalFace.height, bwHasBorder: TerminalFace.hasBorder, bwPixelsPerInch: TerminalFace.pixelsPerInch, hasColorDisplay: ColorDisplayFace.displayType#none, colorWidth: 0, colorHeight: 0, colorPixelsPerInch: ColorDisplayFace.pixelsPerInch, hasSoundGenerator: TerminalFace.hasSoundGenerator, impl: impl ]]; }; <<>> <> <<>> 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 = 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] = { ENABLE UNWIND => NULL; UnloadTerminal[old]; current _ new; LoadTerminal[new]; }; FindNextTerminal: ENTRY PROC [old: Virtual] RETURNS [new: Virtual] = { 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]; AcquireColorDisplay[old]; AcquireColorDisplay[new]; FlipTerminal[old: old, new: new]; ReleaseColorDisplay[old]; ReleaseColorDisplay[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; }; DisableKeyboardWatcher: PUBLIC ENTRY PROC = { ENABLE UNWIND => NULL; watcherDisableCount _ watcherDisableCount.SUCC; }; EnableKeyboardWatcher: PUBLIC ENTRY PROC = { ENABLE UNWIND => NULL; IF watcherDisableCount > 0 THEN watcherDisableCount _ watcherDisableCount.PRED; }; RegisterNotifier: PUBLIC ENTRY PROC[vt: Virtual, notifier: Terminal.SwapNotifier, clientData: REF ANY _ NIL] = { ENABLE UNWIND => NULL; impl: VirtualImpl = 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 = 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; }; <> GetKeys: PUBLIC ENTRY PROC[vt: Virtual] RETURNS[KeyBits] ~ { ENABLE UNWIND => NULL; IF vt=current THEN RETURN[TerminalFace.GetKeyboard[]] ELSE { impl: VirtualImpl ~ vt.impl; RETURN[impl.keyboard] }; }; <<>> GetMousePosition: PUBLIC ENTRY PROC[vt: Virtual] RETURNS[Position] ~ { ENABLE UNWIND => NULL; IF vt=current THEN RETURN[TerminalFace.GetMousePosition[]] ELSE { impl: VirtualImpl ~ vt.impl; RETURN[impl.mouse] }; }; <<>> SetMousePosition: PUBLIC ENTRY PROC[vt: Virtual, position: Position] ~ { ENABLE UNWIND => NULL; IF vt=current THEN TerminalFace.SetMousePosition[position] ELSE { impl: VirtualImpl ~ vt.impl; impl.mouse _ position }; }; <<>> <> <<>> SetBWCursorPosition: PUBLIC ENTRY PROC[vt: Virtual, position: Position] ~ { ENABLE UNWIND => NULL; IF vt=current THEN TerminalFace.SetCursorPosition[position] ELSE { impl: VirtualImpl ~ vt.impl; impl.bwCursorPosition _ position }; }; <<>> GetBWCursorPosition: PUBLIC ENTRY PROC[vt: Virtual] RETURNS[Position] ~ { ENABLE UNWIND => NULL; IF vt=current THEN RETURN[TerminalFace.GetCursorPosition[]] ELSE { impl: VirtualImpl ~ vt.impl; RETURN[impl.bwCursorPosition] }; }; <<>> SetBWCursorPattern: PUBLIC ENTRY PROC[vt: Virtual, pattern: Cursor] = { ENABLE UNWIND => NULL; impl: VirtualImpl ~ vt.impl; impl.bwCursorPattern _ pattern; IF vt=current THEN TerminalFace.SetCursorPattern[pattern]; }; GetBWCursorPattern: PUBLIC ENTRY PROC[vt: Virtual] RETURNS[pattern: Cursor] ~ { ENABLE UNWIND => NULL; impl: VirtualImpl ~ vt.impl; RETURN[impl.bwCursorPattern]; }; <<>> <> GetBWBitmapState: PUBLIC ENTRY PROC[vt: Virtual] RETURNS[BitmapState] ~ { ENABLE UNWIND => NULL; impl: VirtualImpl ~ vt.impl; RETURN[impl.bwBitmapState] }; SetBWBitmapState: PUBLIC PROC[vt: Virtual, new: BitmapState] RETURNS[old: BitmapState] ~ { SetBWBitmapStateInner: ENTRY PROC ~ { ENABLE UNWIND => NULL; impl: VirtualImpl ~ vt.impl; old _ impl.bwBitmapState; IF new=old THEN RETURN; IF old=none THEN BWAllocate[impl]; IF current=vt THEN { IF old=none THEN BWConnect[impl]; IF new=displayed THEN BWTurnOn[impl]; IF old=displayed THEN BWTurnOff[impl]; IF new=none THEN BWDisconnect[impl]; }; IF new=none THEN BWFree[impl]; impl.bwBitmapState _ new; }; <> <> SetBWBitmapStateInner[]; <> }; GetBWFrameBuffer: PUBLIC ENTRY PROC[vt: Virtual] RETURNS[FrameBuffer] ~ { ENABLE UNWIND => NULL; impl: VirtualImpl ~ vt.impl; RETURN[impl.bwFrameBuffer]; }; GetBWBackground: PUBLIC ENTRY PROC[vt: Virtual] RETURNS[BWBackground] ~ { ENABLE UNWIND => NULL; impl: VirtualImpl ~ vt.impl; RETURN[impl.bwBackground]; }; SetBWBackground: PUBLIC ENTRY PROC[vt: Virtual, new: BWBackground] RETURNS[old: BWBackground] ~ { ENABLE UNWIND => NULL; impl: VirtualImpl ~ vt.impl; old _ impl.bwBackground; IF old=new THEN RETURN; impl.bwBackground _ new; IF vt=current THEN TerminalFace.SetBackground[IF new=white THEN white ELSE black]; }; GetBWBorder: PUBLIC ENTRY PROC[vt: Virtual] RETURNS[oddPairs, evenPairs: BWBorder] ~ { ENABLE UNWIND => NULL; impl: VirtualImpl ~ vt.impl; RETURN[impl.bwBorderOdd, impl.bwBorderEven]; }; SetBWBorder: PUBLIC ENTRY PROC[vt: Virtual, oddPairs, evenPairs: BWBorder] ~ { ENABLE UNWIND => NULL; impl: VirtualImpl ~ vt.impl; impl.bwBorderOdd _ oddPairs; impl.bwBorderEven _ evenPairs; IF vt=current AND TerminalFace.hasBorder THEN TerminalFace.SetBorderPattern[oddPairs: oddPairs, evenPairs: evenPairs]; }; WaitForBWVerticalRetrace: PUBLIC ENTRY PROC[vt: Virtual] = { ENABLE UNWIND => NULL; WaitUntilSelected[vt]; InternalWaitForBWVerticalRetrace[]; }; BlinkBWDisplay: PUBLIC PROC[vt: Virtual] = { impl: VirtualImpl ~ vt.impl; AcquireAndMarkTerminalUnstable[]; IF vt=current THEN { impl: VirtualImpl ~ vt.impl; background: BWBackground ~ impl.bwBackground; TerminalFace.SetBackground[IF background=white THEN black ELSE white]; Process.Pause[blinkTime]; TerminalFace.SetBackground[IF background=white THEN white ELSE black]; }; MarkTerminalStable[]; }; <> MinimumBitmapState: PROC [state1, state2: BitmapState] RETURNS [BitmapState] ~ { IF state1=none OR state2=none THEN RETURN[none]; IF state1=allocated OR state2=allocated THEN RETURN[allocated]; RETURN[displayed]; }; GetColorBitmapState: PUBLIC ENTRY PROC [vt: Virtual] RETURNS [BitmapState] ~ { ENABLE UNWIND => NULL; impl: VirtualImpl ~ vt.impl; WHILE impl.colorDisplayChanging DO WAIT impl.colorDisplayStable ENDLOOP; RETURN [impl.colorBitmapState] }; SetColorBitmapState: PUBLIC PROC[vt: Virtual, newState: BitmapState, newMode: ColorMode, newVisibility: ChannelsVisible ] RETURNS [ oldState: BitmapState, oldMode: ColorMode, oldVisibility: ChannelsVisible ] ~ { SetColorBitmapStateInner: PROC ~ { impl: VirtualImpl ~ vt.impl; midState: BitmapState _ none; oldState _ impl.colorBitmapState; oldMode _ impl.colorMode; oldVisibility _ impl.colorVisibility; IF newMode=oldMode THEN midState _ MinimumBitmapState[oldState, newState]; IF current=vt AND oldState#midState THEN { IF oldState=displayed THEN ColorTurnOff[impl]; IF midState=none THEN ColorDisconnect[impl]; }; IF oldState#none AND midState=none THEN { vt.colorWidth _ 0; vt.colorHeight _ 0; ColorFree[impl]; }; impl.colorBitmapState _ midState; impl.colorMode _ newMode; impl.colorVisibility _ newVisibility; IF current=vt THEN ColorDisplayFace.SetVisibility[newVisibility]; IF midState=none AND newState#none THEN { ColorAllocate[impl]; -- may raise CantDoIt vt.colorWidth _ ColorDisplayFace.width; vt.colorHeight _ ColorDisplayFace.height; }; IF current=vt AND midState#newState THEN { IF midState=none THEN ColorConnect[impl]; IF newState=displayed THEN ColorTurnOn[impl]; }; impl.colorBitmapState _ newState; }; AcquireColorDisplay[vt]; SetColorBitmapStateInner[! UNWIND => ReleaseColorDisplay[vt]]; ReleaseColorDisplay[vt]; }; GetColorFrameBufferA: PUBLIC ENTRY PROC[vt: Virtual] RETURNS[FrameBuffer] ~ { ENABLE UNWIND => NULL; impl: VirtualImpl ~ vt.impl; WHILE impl.colorDisplayChanging DO WAIT impl.colorDisplayStable ENDLOOP; RETURN[impl.colorFrameBufferA]; }; GetColorFrameBufferB: PUBLIC ENTRY PROC[vt: Virtual] RETURNS[FrameBuffer] ~ { ENABLE UNWIND => NULL; impl: VirtualImpl ~ vt.impl; WHILE impl.colorDisplayChanging DO WAIT impl.colorDisplayStable ENDLOOP; RETURN[impl.colorFrameBufferB]; }; LegalColorMode: PUBLIC PROC[vt: Virtual, mode: ColorMode] RETURNS[BOOL] = { RETURN[ColorDisplayFace.HasMode[mode]]; }; GetColorMode: PUBLIC ENTRY PROC [vt: Virtual] RETURNS [ColorMode] ~ { ENABLE UNWIND => NULL; impl: VirtualImpl ~ vt.impl; WHILE impl.colorDisplayChanging DO WAIT impl.colorDisplayStable ENDLOOP; RETURN[impl.colorMode]; }; SetColorMode: PUBLIC PROC [vt: Virtual, new: ColorMode] RETURNS [old: ColorMode] ~ { RETURN[SetColorBitmapState[vt, allocated, new, all].oldMode]; }; TurnOnColorDisplay: PUBLIC PROC [vt: Virtual] ~ { impl: VirtualImpl ~ vt.impl; [] _ SetColorBitmapState[vt, displayed, impl.colorMode, all]; }; <<>> TurnOffColorDisplay: PUBLIC PROC [vt: Virtual] ~ { impl: VirtualImpl ~ vt.impl; [] _ SetColorBitmapState[vt, allocated, impl.colorMode, all]; }; <<>> GetVisibility: PUBLIC ENTRY PROC[vt: Virtual] RETURNS[ChannelsVisible] ~ { ENABLE UNWIND => NULL; impl: VirtualImpl ~ vt.impl; WHILE impl.colorDisplayChanging DO WAIT impl.colorDisplayStable ENDLOOP; RETURN[impl.colorVisibility]; }; SetVisibility: PUBLIC ENTRY PROC[vt: Virtual, visibility: ChannelsVisible] ~ { ENABLE UNWIND => NULL; impl: VirtualImpl ~ vt.impl; WHILE impl.colorDisplayChanging DO WAIT impl.colorDisplayStable ENDLOOP; impl.colorVisibility _ visibility; IF vt=current THEN ColorDisplayFace.SetVisibility[visibility]; }; <> GetColor: PUBLIC ENTRY PROC [vt: Virtual, aChannelValue, bChannelValue: ChannelValue ] RETURNS [red, green, blue: ColorValue _ 0] ~ { ENABLE UNWIND => NULL; impl: VirtualImpl ~ vt.impl; WHILE impl.colorDisplayChanging DO WAIT impl.colorDisplayStable ENDLOOP; IF impl.colorMap#NIL THEN [r: red, g: green, b: blue] _ ColorDisplayFace.GetColor[ map: impl.colorMap, pixelA: aChannelValue, pixelB: bChannelValue]; }; SetColor: PUBLIC ENTRY PROC [vt: Virtual, aChannelValue, bChannelValue: ChannelValue, red, green, blue: ColorValue] ~ { ENABLE UNWIND => NULL; impl: VirtualImpl ~ vt.impl; WHILE impl.colorDisplayChanging DO WAIT impl.colorDisplayStable ENDLOOP; IF impl.colorMap#NIL THEN TRUSTED { ColorDisplayFace.SetColor[map: impl.colorMap, pixelA: aChannelValue, pixelB: bChannelValue, r: red, g: green, b: blue] }; }; <<>> GetRedMap: PUBLIC ENTRY PROC[vt: Virtual, in: ChannelValue] RETURNS [ColorValue] ~ { ENABLE UNWIND => NULL; impl: VirtualImpl ~ vt.impl; WHILE impl.colorDisplayChanging DO WAIT impl.colorDisplayStable ENDLOOP; IF impl.colorMap#NIL THEN RETURN[ColorDisplayFace.GetR[map: impl.colorMap, in: in]] ELSE RETURN[0]; }; GetGreenMap: PUBLIC ENTRY PROC [vt: Virtual, in: ChannelValue] RETURNS [ColorValue] ~ { ENABLE UNWIND => NULL; impl: VirtualImpl ~ vt.impl; WHILE impl.colorDisplayChanging DO WAIT impl.colorDisplayStable ENDLOOP; IF impl.colorMap#NIL THEN RETURN[ColorDisplayFace.GetG[map: impl.colorMap, in: in]] ELSE RETURN[0]; }; GetBlueMap: PUBLIC ENTRY PROC [vt: Virtual, in: ChannelValue] RETURNS [ColorValue] ~ { ENABLE UNWIND => NULL; impl: VirtualImpl ~ vt.impl; WHILE impl.colorDisplayChanging DO WAIT impl.colorDisplayStable ENDLOOP; IF impl.colorMap#NIL THEN RETURN[ColorDisplayFace.GetB[map: impl.colorMap, in: in]] ELSE RETURN[0]; }; SetRedMap: PUBLIC ENTRY PROC [vt: Virtual, in: ChannelValue, out: ColorValue] ~ { ENABLE UNWIND => NULL; impl: VirtualImpl ~ vt.impl; WHILE impl.colorDisplayChanging DO WAIT impl.colorDisplayStable ENDLOOP; IF impl.colorMap#NIL THEN TRUSTED { ColorDisplayFace.SetR[map: impl.colorMap, in: in, out: out] }; }; SetGreenMap: PUBLIC ENTRY PROC [vt: Virtual, in: ChannelValue, out: ColorValue] ~ { ENABLE UNWIND => NULL; impl: VirtualImpl ~ vt.impl; WHILE impl.colorDisplayChanging DO WAIT impl.colorDisplayStable ENDLOOP; IF impl.colorMap#NIL THEN TRUSTED { ColorDisplayFace.SetG[map: impl.colorMap, in: in, out: out] }; }; SetBlueMap: PUBLIC ENTRY PROC [vt: Virtual, in: ChannelValue, out: ColorValue] ~ { ENABLE UNWIND => NULL; impl: VirtualImpl ~ vt.impl; WHILE impl.colorDisplayChanging DO WAIT impl.colorDisplayStable ENDLOOP; IF impl.colorMap#NIL THEN TRUSTED { ColorDisplayFace.SetB[map: impl.colorMap, in: in, out: out] }; }; <> <<>> <> <> <<>> GetColorCursorPosition: PUBLIC ENTRY PROC [vt: Virtual] RETURNS [Position] = { ENABLE UNWIND => NULL; impl: VirtualImpl = vt.impl; WHILE impl.colorDisplayChanging DO WAIT impl.colorDisplayStable ENDLOOP; RETURN[impl.colorCursorPosition]; }; SetColorCursorPosition: PUBLIC ENTRY PROC [vt: Virtual, position: Position] = { ENABLE UNWIND => NULL; impl: VirtualImpl = vt.impl; IF NOT vt.hasColorDisplay THEN RETURN; WHILE impl.colorDisplayChanging DO WAIT impl.colorDisplayStable ENDLOOP; IF impl.colorCursorPosition=position THEN RETURN; -- no change IF impl.colorCursorDisplayed THEN HideColorCursor[vt, impl]; impl.colorCursorPosition _ position; IF impl.colorCursorState=$visible AND NOT InhibitColorCursor[impl] THEN ShowColorCursor[vt, impl]; }; GetColorCursorPattern: PUBLIC ENTRY PROC [vt: Virtual] RETURNS [Cursor] = { ENABLE UNWIND => NULL; impl: VirtualImpl = vt.impl; WHILE impl.colorDisplayChanging DO WAIT impl.colorDisplayStable ENDLOOP; RETURN[impl.colorCursorPattern]; }; SetColorCursorPattern: PUBLIC ENTRY PROC [vt: Virtual, pattern: Cursor] = { ENABLE UNWIND => NULL; impl: VirtualImpl ~ vt.impl; displayed: BOOL ~ impl.colorCursorDisplayed; IF NOT vt.hasColorDisplay THEN RETURN; WHILE impl.colorDisplayChanging DO WAIT impl.colorDisplayStable ENDLOOP; IF displayed THEN HideColorCursor[vt, impl]; impl.colorCursorPattern _ pattern; IF impl.colorBitmapState#none THEN ExpandColorCursorPattern[impl]; IF displayed THEN ShowColorCursor[vt, impl]; }; GetColorCursorPresentation: PUBLIC ENTRY PROC [vt: Virtual] RETURNS [ColorCursorPresentation] = { ENABLE UNWIND => NULL; impl: VirtualImpl = vt.impl; WHILE impl.colorDisplayChanging DO WAIT impl.colorDisplayStable ENDLOOP; RETURN[impl.colorCursorPresentation]; }; SetColorCursorPresentation: PUBLIC ENTRY PROC [vt: Virtual, new: ColorCursorPresentation] RETURNS [old: ColorCursorPresentation] = { ENABLE UNWIND => NULL; impl: VirtualImpl ~ vt.impl; displayed: BOOL ~ impl.colorCursorDisplayed; WHILE impl.colorDisplayChanging DO WAIT impl.colorDisplayStable ENDLOOP; 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 [ColorCursorBitmapState] = { ENABLE UNWIND => NULL; impl: VirtualImpl = vt.impl; WHILE impl.colorDisplayChanging DO WAIT impl.colorDisplayStable ENDLOOP; RETURN[impl.colorCursorState]; }; SetColorCursorState: PUBLIC ENTRY PROC [vt: Virtual, new: ColorCursorBitmapState] RETURNS [old: ColorCursorBitmapState] = { ENABLE UNWIND => NULL; impl: VirtualImpl = vt.impl; WHILE impl.colorDisplayChanging DO WAIT impl.colorDisplayStable ENDLOOP; 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: PROC[vt: Virtual, xmin, ymin: NAT _ 0, xmax, ymax: NAT _ NAT.LAST] = { impl: VirtualImpl = vt.impl; AcquireColorDisplay[vt]; 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: PROC[vt: Virtual] = { impl: VirtualImpl = vt.impl; impl.colorFrameLocked _ FALSE; IF impl.colorBitmapState#none AND impl.colorCursorState=$visible AND NOT impl.colorCursorDisplayed THEN ShowColorCursor[vt, impl]; ReleaseColorDisplay[vt]; }; ModifyColorFrame: PUBLIC PROC [vt: Virtual, action: PROC, xmin, ymin: NAT _ 0, xmax, ymax: NAT _ NAT.LAST] ~ { LockColorFrame[vt, xmin, ymin, xmax, ymax]; action[! UNWIND => UnlockColorFrame[vt]]; UnlockColorFrame[vt]; }; InhibitColorCursor: PROC[impl: VirtualImpl] RETURNS[BOOL] = INLINE { RETURN[impl.colorFrameLocked AND ColorCursorIntersectsFrame[impl]]; }; ColorCursorIntersectsFrame: PROC[impl: VirtualImpl] RETURNS[BOOL] = { x: INTEGER ~ impl.colorCursorPosition.x; y: INTEGER ~ impl.colorCursorPosition.y; w: INTEGER ~ 16; h: INTEGER ~ 16; RETURN[ximpl.xmin AND (y+h)>impl.ymin]; }; colorCursorWplSrcA: NAT ~ 16; colorCursorWplSrcB: NAT ~ 8; ExpandColorCursorPattern: PROC[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.colorCursorPattern; 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 impl.colorMode.full THEN { ExpandBitmap[impl.colorCursorSourceA, colorCursorWplSrcA, 16]; ExpandBitmap[impl.colorCursorSourceB, colorCursorWplSrcB, 8]; } ELSE IF impl.colorMode.bitsPerPixelChannelA>0 THEN { ExpandBitmap[impl.colorCursorSourceA, colorCursorWplSrcA, impl.colorMode.bitsPerPixelChannelA]; }; }; HideColorCursor: PROC[vt: Virtual, impl: VirtualImpl] = TRUSTED { xMax: INTEGER ~ vt.colorWidth; yMax: INTEGER ~ vt.colorHeight; x: INTEGER ~ impl.colorCursorPosition.x; y: INTEGER ~ impl.colorCursorPosition.y; w: INTEGER ~ 16; h: INTEGER ~ 16; IF (x+w)>0 AND (y+h)>0 AND x0) THEN { bpp: NAT ~ IF impl.colorMode.full THEN 16 ELSE impl.colorMode.bitsPerPixelChannelA; ppw: NAT ~ 16/bpp; frameA: FrameBuffer ~ impl.colorFrameBufferA; frameB: FrameBuffer ~ impl.colorFrameBufferB; 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 _ frameA.base + Basics.LongMult[bltY, frameA.wordsPerLine] + bltX/ppw; bb.dst.bit _ (bltX MOD ppw)*bpp; bb.dstBpl _ frameA.wordsPerLine*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 impl.colorMode.full THEN { bb.dst.word _ frameB.base + Basics.LongMult[bltY, frameB.wordsPerLine] + bltX/2; bb.dst.bit _ (bltX MOD 2)*8; bb.dstBpl _ frameB.wordsPerLine*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: PROC[vt: Virtual, impl: VirtualImpl] = TRUSTED { xMax: INTEGER ~ vt.colorWidth; yMax: INTEGER ~ vt.colorHeight; x: INTEGER ~ impl.colorCursorPosition.x; y: INTEGER ~ impl.colorCursorPosition.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 impl.colorMode.full THEN 16 ELSE impl.colorMode.bitsPerPixelChannelA; ppw: NAT ~ 16/bpp; frameA: FrameBuffer ~ impl.colorFrameBufferA; frameB: FrameBuffer ~ impl.colorFrameBufferB; 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 _ frameA.base + Basics.LongMult[bltY, frameA.wordsPerLine] + bltX/ppw; bb.src.bit _ (bltX MOD ppw)*bpp; bb.srcDesc.srcBpl _ frameA.wordsPerLine*16; bb.width _ bltW*bpp; bb.height _ bltH; PrincOpsUtils.BITBLT[bb]; -- save the bits under the cursor IF impl.colorMode.full THEN { bb.src.word _ frameB.base + Basics.LongMult[bltY, frameB.wordsPerLine] + bltX/2; bb.src.bit _ (bltX MOD 2)*8; bb.srcDesc.srcBpl _ frameB.wordsPerLine*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 _ frameA.base + Basics.LongMult[bltY, frameA.wordsPerLine] + bltX/ppw; bb.dst.bit _ (bltX MOD ppw)*bpp; bb.dstBpl _ frameA.wordsPerLine*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 impl.colorMode.full THEN { bb.dst.word _ frameB.base + Basics.LongMult[bltY, frameB.wordsPerLine] + bltX/2; bb.dst.bit _ (bltX MOD 2)*8; bb.dstBpl _ frameB.wordsPerLine*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; }; <> Beep: PUBLIC PROC [vt: Virtual, frequency, duration: CARDINAL] ~ { IF vt.hasSoundGenerator AND vt=current THEN TerminalFace.Beep[frequency, duration]; }; <<>> <> <<>> WatcherEnabled: ENTRY PROC RETURNS [BOOL] = INLINE { ENABLE UNWIND => NULL; RETURN[watcherDisableCount = 0] }; KeyboardWatcher: PROC = TRUSTED { lastTime, thisTime, magicCombination: KeyState _ [bits[ALL[up]]]; waitTime: Process.Ticks = Process.MsecToTicks[300]; Process.SetPriority[Process.priorityForeground]; magicCombination.bits _ [Ctrl: down, LeftShift: down, RightShift: down]; lastTime.bits _ TerminalFace.GetKeyboard[]; DO Process.Pause[waitTime]; IF WatcherEnabled[] THEN { changed: BOOL _ FALSE; select: BOOL _ TRUE; thisTime.bits _ TerminalFace.GetKeyboard[]; FOR word: NAT IN[0..SIZE[KeyState]) 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; }; <<>> <> <<>> AllocateGlobalState: PROC[size: NAT] RETURNS[LONG POINTER] ~ TRUSTED { RETURN[IF size=0 THEN NIL ELSE VM.lowCore.NEW[Basics.RawWords[size]]]; }; Initialize: ENTRY PROC ~ TRUSTED { vt: Virtual = NewVirtual[]; mask: WORD _ 0; initialPosition: Position; [bwRetrace, mask] _ PrincOpsUtils.AllocateNakedCondition[]; TerminalFace.Initialize[AllocateGlobalState[TerminalFace.globalStateSize], mask]; TerminalFace.InitializeCleanup[]; IF ColorDisplayFace.displayType#none THEN { ColorDisplayFace.Initialize[AllocateGlobalState[ColorDisplayFace.globalStateSize]]; ColorDisplayFace.InitializeCleanup[]; }; initialPosition _ [x: TerminalFace.width/2, y: TerminalFace.height/2]; TerminalFace.SetMousePosition[initialPosition]; TerminalFace.SetCursorPosition[initialPosition]; LoadTerminal[current _ vt]; terminals _ CONS[current, NIL]; Process.EnableAborts[@terminalStable]; Process.Detach[FORK KeyboardWatcher[]]; }; Initialize[]; END.