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:
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];
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:
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
]];
};
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
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;
};
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: 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[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: 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;
};
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.