TerminalImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Levin on: December 15, 1983 4:31 pm
Birrell, November 16, 1983 11:24 am
Russ Atkinson (RRA) July 23, 1985 0:28:18 am PDT
Doug Wyatt, May 2, 1985 3:26:52 pm PDT
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];
Global variables protected by the monitor lock
TerminalList: TYPE ~ LIST OF Virtual;
terminals: TerminalList ← NIL;
current: Virtual ← NIL;
watcherDisableCount: NAT ← 0;
terminalChanging: BOOLFALSE;
'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: BOOLTRUE;
verticalRetrace: CONDITION ← [timeout: 0];
Internal Procedures
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];
RRA: this goodie is here to cache the frame buffer for the B&W display. It is the only way for a small-memory Dolphin to get off the ground (I think).
NewFrameBuffer: PROC [width, height, bitsPerPixel: NAT, in64K: BOOLFALSE]
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 POINTERNIL;
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
]];
};
Exports to Terminal
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 ANYNIL] = {
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 ANYNIL] = {
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;
};
Keyboard and Mouse
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 };
};
Black-and-White Cursor
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];
};
Black-and-White Display
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;
};
Acquire/Release replaced by ENTRY on inner proc to prevent deadlock in notifier stuff. This is probably not a good fix, since it may keep the monitor locked for a long time while allocating the bitmap
AcquireAndMarkTerminalUnstable[];
SetBWBitmapStateInner[];
MarkTerminalStable[];
};
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[];
};
Color Display
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];
};
Color maps
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] };
};
Color Cursor
GetColorCursorPosition returns the position of the virtual cursor associated with the color display on the specified virtual terminal. This position changes only as a result of calls on SetColorCursorPosition.
SetColorCursorPosition sets the cursor position of the specified virtual terminal to the indicated value. This position will be reflected on the screen when the virtual terminal is next selected (or, if it is presently selected, immediately). It is the responsibility of the client to clip the position, if desired, to ensure that the cursor remains on the visible area of the display.
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: NATNAT.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: NATNAT.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[x<impl.xmax AND y<impl.ymax AND (x+w)>impl.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 x<xMax AND y<yMax
AND (impl.colorMode.full OR impl.colorMode.bitsPerPixelChannelA>0) 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 x<xMax AND y<yMax
AND (impl.colorMode.full OR impl.colorMode.bitsPerPixelChannelA>0) 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;
};
Sound generator
Beep: PUBLIC PROC [vt: Virtual, frequency, duration: CARDINAL] ~ {
IF vt.hasSoundGenerator AND vt=current THEN TerminalFace.Beep[frequency, duration];
};
Keyboard watcher process
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: BOOLFALSE;
select: BOOLTRUE;
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;
};
Initialization
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.