TerminalImpl.mesa
last edited by: Levin on: December 15, 1983 4:31 pm
Last Edited by: Birrell, November 16, 1983 11:24 am
Last Edited by: Wyatt, December 21, 1983 1:19 pm
implement color display
Last Edited by: Russ Atkinson, December 21, 1983 5:17 pm
fix problems with ShowColorCursor & HideColorCursor
DIRECTORY
Basics USING [bitsPerWord, LongMult],
ColorDisplayFace
USING [
baseA, baseB, bplA, bplB, Connect, Disconnect, displayType, GetBlueMap, GetColor, GetGreenMap, GetRedMap, globalStateSize, HasMode, height, Initialize, InitializeCleanup, Mode, PagesForMode, pixelsPerInch, SetBlueMap, SetColor, SetGreenMap, SetRedMap, Show, TurnOff, TurnOn, width],
DisplayFace
USING [
Connect, cursorPosition, Disconnect, GetBitBltTable, globalStateSize, hasBorder, hasBuffer, height, Initialize, InitializeCleanup, pagesForBitmap, pixelsPerInch, SetBackground, SetBorderPattern, SetCursorPattern, TurnOff, TurnOn, width],
KeyboardFace USING [keyboard],
Keys USING [KeyBits],
MouseFace USING [position, SetPosition],
PrincOps USING [BBTable, BBTableSpace, BitAddress, BitBltTablePtr],
PrincOpsUtils USING [AlignedBBTable, AllocateNakedCondition, BITBLT],
Process
USING [
Detach, EnableAborts, GetPriority, MsecToTicks, Pause, Priority, priorityForeground, SetPriority, Ticks],
Terminal
USING [
BitmapState, BWBackground, BWBorder, BWCursorBitmap, ChannelsVisible, ChannelValue, Color, ColorCursorBitmap, ColorCursorBitmapState, ColorCursorPresentation, ColorMode, Object, Position, SetBWCursorPosition, SetMousePosition, SwapAction, SwapNotifier, Virtual],
TerminalExtras USING [],
VM
USING [
AddressForPageNumber, Allocate, CantAllocate, Free, Interval, lowCore, nullInterval, Pin, Unpin],
VMSideDoor USING [AssignSpecialRealMemory, ReleaseSpecialRealMemory];
TerminalImpl:
CEDAR
MONITOR
LOCKS terminalLock
IMPORTS
Basics, ColorDisplayFace, DisplayFace, KeyboardFace, MouseFace, PrincOpsUtils, Process, Terminal, VM, VMSideDoor
EXPORTS Terminal, TerminalExtras
SHARES Terminal =
BEGIN
Types
Virtual: TYPE = Terminal.Virtual;
TerminalList: TYPE = LIST OF Virtual;
VirtualImpl: TYPE = REF VirtualImplObject;
VirtualImplObject:
TYPE =
RECORD [
keyboard: Keys.KeyBits ← ALL[up],
mouse: Terminal.Position ← [0, 0],
black and white cursor
bwCursor: Terminal.Position ← [0, 0],
bwPattern: Terminal.BWCursorBitmap ← ALL[0],
black and white frame buffer
bwBitmapState: Terminal.BitmapState ← none,
bwBackground: Terminal.BWBackground ← white,
bwBorderOdd: Terminal.BWBorder ← 0,
bwBorderEven: Terminal.BWBorder ← 0,
bwBitmap: VM.Interval ← NULL,
color cursor
colorCursor: Terminal.Position ← [0, 0],
colorPattern: Terminal.ColorCursorBitmap ← ALL[0],
colorCursorPresentation: Terminal.ColorCursorPresentation ← onesAreBlack,
colorCursorState: Terminal.ColorCursorBitmapState ← visible,
colorCursorDisplayed: BOOL ← FALSE,
colorFrameLocked: BOOL ← FALSE,
xmin, ymin, xmax, ymax: NAT ← 0,
colorCursorSourceA, colorCursorSourceB: LONG POINTER ← NIL,
colorCursorBackupA, colorCursorBackupB: LONG POINTER ← NIL,
colorCursorVM: VM.Interval ← NULL,
color frame buffer
colorBitmapState: Terminal.BitmapState ← none,
colorVisibility: Terminal.ChannelsVisible ← none,
colorVM: VM.Interval ← NULL,
notifiers: Notifier ← NIL
];
Notifier: TYPE = REF NotifierItem;
NotifierItem:
TYPE =
RECORD [
next, prev: Notifier,
proc: Terminal.SwapNotifier,
clientData: REF ANY
];
priorityDuringSelect: Process.Priority = Process.priorityForeground;
blinkTime: Process.Ticks = Process.MsecToTicks[100];
Global variables protected by the monitor lock
terminalLock: PUBLIC MONITORLOCK;
terminals: TerminalList;
current: Virtual ← NIL;
watcherDisableCount: NAT ← 0;
terminalChanging:
BOOL ←
FALSE;
'terminalChanging' synchronizes 'Select' with long-running operations that can't afford to hold the monitor lock throughout (including 'Select' itself).
terminalStable: CONDITION ← [timeout: 0];
bwRetrace: LONG POINTER TO CONDITION;
meFirst: BOOL ← TRUE;
verticalRetrace: CONDITION ← [timeout: 0];
colorTerminal: Virtual ←
NIL;
For now, the color display can be attached to only one virtual terminal.
This should be fixed, but it requires some reworking of ColorDisplayFace.
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 = NARROW[vt.impl];
head: Notifier = impl.notifiers;
n: Notifier ← impl.notifiers;
IF head = NIL THEN RETURN;
DO
n.proc[vt, action, n.clientData];
IF (n ← IF action = coming THEN n.next ELSE n.prev) = head THEN EXIT;
ENDLOOP;
};
FlipTerminal:
ENTRY
PROC [old, new: Virtual] =
INLINE {
ENABLE UNWIND => NULL;
UnloadTerminal[old];
current ← new;
LoadTerminal[new];
};
FindNextTerminal:
ENTRY
PROC [old: Virtual]
RETURNS [new: Virtual] =
INLINE {
ENABLE UNWIND => NULL;
FOR t: TerminalList ← terminals, t.rest
UNTIL t =
NIL
DO
IF t.first = old THEN RETURN[(IF t.rest = NIL THEN terminals ELSE t.rest).first];
REPEAT
FINISHED => ERROR;
ENDLOOP;
};
AcquireAndMarkTerminalUnstable[];
old ← current;
IF new = NIL THEN new ← FindNextTerminal[old];
IF old ~= new
THEN {
priority: Process.Priority = Process.GetPriority[];
IF priority < priorityDuringSelect THEN TRUSTED {Process.SetPriority[priorityDuringSelect]};
DoNotifiers[old, going];
DoNotifiers[new, coming];
FlipTerminal[old: old, new: new];
DoNotifiers[old, gone];
DoNotifiers[new, here];
IF priority < priorityDuringSelect THEN TRUSTED {Process.SetPriority[priority]};
};
MarkTerminalStable[];
};
Current:
PUBLIC
ENTRY
PROC
RETURNS [vt: Virtual] = {
ENABLE UNWIND => NULL;
WHILE terminalChanging DO WAIT terminalStable; ENDLOOP;
vt ← current;
};
RegisterNotifier:
PUBLIC
ENTRY
PROC [
vt: Virtual, notifier: Terminal.SwapNotifier, clientData: REF ANY ← NIL] = {
ENABLE UNWIND => NULL;
impl: VirtualImpl = NARROW[vt.impl];
n: Notifier = NEW[NotifierItem ← [next: NIL, prev: NIL, proc: notifier, clientData: clientData]];
head: Notifier = impl.notifiers;
IF head = NIL THEN n.next ← n.prev ← n
ELSE {n.next ← head; n.prev ← head.prev; head.prev.next ← n; head.prev ← n};
impl.notifiers ← n;
};
UnregisterNotifier:
PUBLIC
ENTRY
PROC [
vt: Virtual, notifier: Terminal.SwapNotifier, clientData: REF ANY ← NIL] = {
ENABLE UNWIND => NULL;
impl: VirtualImpl = NARROW[vt.impl];
head: Notifier = impl.notifiers;
n: Notifier ← impl.notifiers;
IF head ~=
NIL
THEN
DO
IF n.proc = notifier
AND n.clientData = clientData
THEN {
n.prev.next ← n.next;
n.next.prev ← n.prev;
IF n = head THEN impl.notifiers ← IF n.next = n THEN NIL ELSE n.next;
EXIT
};
IF (n ← n.next) = head THEN EXIT;
ENDLOOP;
};
DisableKeyboardWatcher:
PUBLIC
ENTRY
PROC = {
ENABLE UNWIND => NULL;
watcherDisableCount ← watcherDisableCount.SUCC;
};
EnableKeyboardWatcher:
PUBLIC
ENTRY
PROC = {
ENABLE UNWIND => NULL;
IF watcherDisableCount > 0 THEN watcherDisableCount ← watcherDisableCount.PRED;
};
Mouse
SetMousePosition:
PUBLIC
ENTRY
PROC [vt: Virtual, position: Terminal.Position] = {
ENABLE UNWIND => NULL;
impl: VirtualImpl = NARROW[vt.impl];
IF current = vt THEN MouseFace.SetPosition[LOOPHOLE[position]]
ELSE impl.mouse ← position;
};
Black-and-White Cursor
GetBWCursorPattern:
PUBLIC ENTRY PROC [vt: Virtual]
RETURNS [pattern: Terminal.BWCursorBitmap] = {
ENABLE UNWIND => NULL;
impl: VirtualImpl = NARROW[vt.impl];
RETURN[impl.bwPattern]
};
SetBWCursorPattern:
PUBLIC ENTRY PROC [vt: Virtual, pattern: Terminal.BWCursorBitmap] = {
ENABLE UNWIND => NULL;
impl: VirtualImpl = NARROW[vt.impl];
impl.bwPattern ← pattern;
IF current = vt THEN TRUSTED {DisplayFace.SetCursorPattern[LOOPHOLE[LONG[@pattern]]]};
};
Black-and-White Display
GetBWBitmapState:
PUBLIC ENTRY PROC [vt: Virtual]
RETURNS [Terminal.BitmapState] = {
ENABLE UNWIND => NULL;
impl: VirtualImpl = NARROW[vt.impl];
RETURN [impl.bwBitmapState]
};
SetBWBitmapState:
PUBLIC PROC [vt: Virtual, new: Terminal.BitmapState]
RETURNS [old: Terminal.BitmapState] = {
impl: VirtualImpl = NARROW[vt.impl];
SetBWBitmapStateInner:
ENTRY
PROC = {
ENABLE UNWIND => NULL;
IF (old ← impl.bwBitmapState) = new THEN RETURN;
IF old = none
THEN {
impl.bwBitmap ← AllocateBWBitmap[];
IF current = vt THEN DisplayFace.Connect[impl.bwBitmap.page];
IF (impl.bwBitmapState ← new) = allocated THEN RETURN;
};
SELECT new
FROM
displayed =>
IF current = vt
THEN {
IF DisplayFace.hasBuffer THEN VMSideDoor.AssignSpecialRealMemory[impl.bwBitmap]
ELSE VM.Pin[impl.bwBitmap];
DisplayFace.TurnOn[];
};
allocated => IF current = vt THEN TurnOff[impl];
none => {
IF current = vt THEN {TurnOff[impl]; DisplayFace.Disconnect[]};
TRUSTED {VM.Free[impl.bwBitmap]};
};
ENDCASE;
impl.bwBitmapState ← new;
};
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[];
};
GetBWBackground:
PUBLIC
ENTRY
PROC [vt: Virtual]
RETURNS [Terminal.BWBackground] = {
ENABLE UNWIND => NULL;
impl: VirtualImpl = NARROW[vt.impl];
RETURN [impl.bwBackground]
};
SetBWBackground:
PUBLIC
ENTRY
PROC [vt: Virtual, new: Terminal.BWBackground]
RETURNS [old: Terminal.BWBackground] = {
ENABLE UNWIND => NULL;
impl: VirtualImpl = NARROW[vt.impl];
IF (old ← impl.bwBackground) = new THEN RETURN;
impl.bwBackground ← new;
IF vt = current
THEN
DisplayFace.SetBackground[IF new = white THEN white ELSE black];
};
GetBWBorder:
PUBLIC
ENTRY PROC [vt: Virtual]
RETURNS [oddPairs, evenPairs: Terminal.BWBorder] = {
ENABLE UNWIND => NULL;
impl: VirtualImpl = NARROW[vt.impl];
RETURN [impl.bwBorderOdd, impl.bwBorderEven]
};
SetBWBorder:
PUBLIC
ENTRY PROC [vt: Virtual, oddPairs, evenPairs: Terminal.BWBorder] = {
ENABLE UNWIND => NULL;
impl: VirtualImpl = NARROW[vt.impl];
impl.bwBorderOdd ← oddPairs;
impl.bwBorderEven ← evenPairs;
IF DisplayFace.hasBorder
AND vt = current
THEN
DisplayFace.SetBorderPattern[oddPairs: oddPairs, evenPairs: evenPairs];
};
GetBitBltTable:
PUBLIC
ENTRY
UNSAFE
PROC [vt: Virtual]
RETURNS [bbt: PrincOps.BBTable] = {
ENABLE UNWIND => NULL;
impl: VirtualImpl = NARROW[vt.impl];
bbt ← DisplayFace.GetBitBltTable[];
TRUSTED{
bbt.dst ← bbt.src ← [
word:
IF impl.bwBitmapState = none THEN NIL
ELSE VM.AddressForPageNumber[impl.bwBitmap.page],
bit: 0
];
};
bbt.width ← vt.bwWidth;
bbt.height ← vt.bwHeight;
};
WaitForBWVerticalRetrace:
PUBLIC
ENTRY
PROC [vt: Virtual] = {
ENABLE UNWIND => NULL;
WaitUntilSelected[vt];
InternalWaitForBWVerticalRetrace[];
};
BlinkBWDisplay:
PUBLIC PROC [vt: Virtual] = {
background: Terminal.BWBackground;
AcquireAndMarkTerminalUnstable[];
IF vt = current
THEN {
background ← NARROW[vt.impl, VirtualImpl].bwBackground;
DisplayFace.SetBackground[IF background = white THEN black ELSE white];
Process.Pause[blinkTime];
DisplayFace.SetBackground[IF background = white THEN white ELSE black];
};
MarkTerminalStable[];
};
Color Display
nullColorFaceMode: ColorDisplayFace.Mode ~
[full: FALSE, useA: FALSE, useB: FALSE, lgBitsPerPixelA: 0, lgBitsPerPixelB: 0];
ColorFaceMode:
PROC[mode: Terminal.ColorMode]
RETURNS[fmode: ColorDisplayFace.Mode ← nullColorFaceMode] = {
illegal: BOOL ← FALSE;
IF mode.full THEN fmode.full ← TRUE
ELSE {
IF (fmode.useA ← mode.bitsPerPixelChannelA>0)
THEN
SELECT mode.bitsPerPixelChannelA
FROM
1 => fmode.lgBitsPerPixelA ← 0;
2 => fmode.lgBitsPerPixelA ← 1;
4 => fmode.lgBitsPerPixelA ← 2;
8 => fmode.lgBitsPerPixelA ← 3;
ENDCASE => illegal ← TRUE;
IF (fmode.useB ← mode.bitsPerPixelChannelB>0)
THEN
SELECT mode.bitsPerPixelChannelB
FROM
1 => fmode.lgBitsPerPixelB ← 0;
2 => fmode.lgBitsPerPixelB ← 1;
4 => fmode.lgBitsPerPixelB ← 2;
8 => fmode.lgBitsPerPixelB ← 3;
ENDCASE => illegal ← TRUE;
};
IF illegal THEN fmode ← nullColorFaceMode;
};
LegalColorFaceMode:
PROC[fmode: ColorDisplayFace.Mode]
RETURNS[
BOOL] = {
IF fmode=nullColorFaceMode THEN RETURN[FALSE]
ELSE TRUSTED { RETURN[ColorDisplayFace.HasMode[fmode]] };
};
GetColorBitmapState:
PUBLIC ENTRY PROC [vt: Virtual]
RETURNS [Terminal.BitmapState] = {
ENABLE UNWIND => NULL;
impl: VirtualImpl = NARROW[vt.impl];
RETURN [impl.colorBitmapState]
};
SetColorBitmapState:
PUBLIC
PROC [vt: Virtual,
newState: Terminal.BitmapState,
newMode: Terminal.ColorMode, newVisibility: Terminal.ChannelsVisible
]
RETURNS [
oldState: Terminal.BitmapState,
oldMode: Terminal.ColorMode, oldVisibility: Terminal.ChannelsVisible
] = {
impl: VirtualImpl = NARROW[vt.impl];
SetColorBitmapStateInner:
ENTRY
PROC = {
ENABLE UNWIND => NULL;
Connect:
INTERNAL
PROC[fmode: ColorDisplayFace.Mode] =
TRUSTED {
impl.colorVM ← AllocateColorVM[fmode];
ColorDisplayFace.Connect[mode: fmode,
firstPage: impl.colorVM.page, nPages: impl.colorVM.count];
vt.colorWidth ← ColorDisplayFace.width;
vt.colorHeight ← ColorDisplayFace.height;
vt.colorBitmapA ← ColorDisplayFace.baseA;
vt.colorBitmapB ← ColorDisplayFace.baseB;
IF (ColorDisplayFace.bplA
MOD Basics.bitsPerWord)=0
THEN
vt.colorWordsPerLineA ← ColorDisplayFace.bplA/Basics.bitsPerWord
ELSE ERROR;
IF (ColorDisplayFace.bplB
MOD Basics.bitsPerWord)=0
THEN
vt.colorWordsPerLineB ← ColorDisplayFace.bplB/Basics.bitsPerWord
ELSE ERROR;
impl.colorCursorVM ← VM.Allocate[3];
VM.Pin[impl.colorCursorVM];
impl.colorCursorSourceA ← VM.AddressForPageNumber[impl.colorCursorVM.page]; --page 1
impl.colorCursorBackupA ← impl.colorCursorSourceA+256; --page 2
impl.colorCursorSourceB ← impl.colorCursorBackupA+256; --first half of page 3
impl.colorCursorBackupB ← impl.colorCursorSourceB+128; --second half of page 3
ExpandColorCursorPattern[vt, impl];
};
Disconnect:
INTERNAL
PROC =
TRUSTED {
vt.colorBitmapA ← vt.colorBitmapB ← NIL;
vt.colorWordsPerLineA ← vt.colorWordsPerLineB ← 0;
ColorDisplayFace.Disconnect[];
VM.Free[impl.colorVM];
impl.colorVM ← VM.nullInterval;
impl.colorBitmapState ← none;
impl.colorCursorSourceA ← impl.colorCursorBackupA ← NIL;
impl.colorCursorSourceB ← impl.colorCursorBackupB ← NIL;
VM.Free[impl.colorCursorVM];
impl.colorCursorVM ← VM.nullInterval;
};
TurnOn:
INTERNAL
PROC = {
IF current=vt
THEN {
VM.Pin[impl.colorVM];
TRUSTED{ColorDisplayFace.TurnOn[]};
};
};
TurnOff:
INTERNAL
PROC = {
IF current=vt
THEN {
TRUSTED{ColorDisplayFace.TurnOff[]};
VM.Unpin[impl.colorVM];
};
};
oldMode ← vt.colorMode;
oldState ← impl.colorBitmapState;
oldVisibility ← impl.colorVisibility;
IF newMode#oldMode
THEN {
fmode: ColorDisplayFace.Mode ~ ColorFaceMode[newMode];
IF LegalColorFaceMode[fmode] THEN vt.colorMode ← newMode ELSE ERROR CantDoIt;
IF oldState#none
THEN {
IF oldState=displayed THEN TurnOff[];
Disconnect[];
};
IF newState#none
THEN {
Connect[fmode];
IF newState=displayed THEN TurnOn[];
};
}
ELSE
IF newState#oldState
THEN {
IF oldState=displayed THEN TurnOff[];
IF newState=none THEN Disconnect[];
IF oldState=none THEN Connect[ColorFaceMode[vt.colorMode]];
IF newState=displayed THEN TurnOn[];
};
impl.colorBitmapState ← newState;
IF newVisibility#oldVisibility
THEN {
impl.colorVisibility ← newVisibility;
IF vt=current
THEN
SELECT newVisibility
FROM
none => TRUSTED{ColorDisplayFace.Show[a: FALSE, b: FALSE]};
aOnly => TRUSTED{ColorDisplayFace.Show[a: TRUE, b: FALSE]};
bOnly => TRUSTED{ColorDisplayFace.Show[a: FALSE, b: TRUE]};
all => TRUSTED{ColorDisplayFace.Show[a: TRUE, b: TRUE]};
ENDCASE => ERROR;
};
};
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[];
SetColorBitmapStateInner[];
--MarkTerminalStable[];
};
LegalColorMode:
PUBLIC
PROC[vt: Virtual, mode: Terminal.ColorMode]
RETURNS[
BOOL] = {
IF vt.hasColorDisplay THEN RETURN[LegalColorFaceMode[ColorFaceMode[mode]]]
ELSE RETURN[FALSE];
};
GetVisibility:
PUBLIC
ENTRY
PROC [vt: Virtual]
RETURNS [Terminal.ChannelsVisible] = {
ENABLE UNWIND => NULL;
impl: VirtualImpl = NARROW[vt.impl];
RETURN [impl.colorVisibility];
};
Colormaps
Color:
TYPE = Terminal.Color;
GetRedMap:
PUBLIC
ENTRY
PROC [vt: Virtual, in: Color]
RETURNS [Color] = {
impl: VirtualImpl = NARROW[vt.impl];
IF vt.hasColorDisplay
AND impl.colorBitmapState#none
AND vt.colorMode.full
THEN
TRUSTED{RETURN[ColorDisplayFace.GetRedMap[in]]}
ELSE RETURN[0];
};
GetGreenMap:
PUBLIC
ENTRY
PROC [vt: Virtual, in: Color]
RETURNS [Color] = {
impl: VirtualImpl = NARROW[vt.impl];
IF vt.hasColorDisplay
AND impl.colorBitmapState#none
AND vt.colorMode.full
THEN
TRUSTED{RETURN[ColorDisplayFace.GetGreenMap[in]]}
ELSE RETURN[0];
};
GetBlueMap:
PUBLIC
ENTRY
PROC [vt: Virtual, in: Color]
RETURNS [Color] = {
impl: VirtualImpl = NARROW[vt.impl];
IF vt.hasColorDisplay
AND impl.colorBitmapState#none
AND vt.colorMode.full
THEN
TRUSTED{RETURN[ColorDisplayFace.GetBlueMap[in]]}
ELSE RETURN[0];
};
SetRedMap:
PUBLIC
ENTRY
PROC [vt: Virtual, in: Color, out: Color] = {
impl: VirtualImpl = NARROW[vt.impl];
IF vt.hasColorDisplay
AND impl.colorBitmapState#none
AND vt.colorMode.full
THEN
TRUSTED{ColorDisplayFace.SetRedMap[in: in, out: out]};
};
SetGreenMap:
PUBLIC
ENTRY
PROC [vt: Virtual, in: Color, out: Color] = {
impl: VirtualImpl = NARROW[vt.impl];
IF vt.hasColorDisplay
AND impl.colorBitmapState#none
AND vt.colorMode.full
THEN
TRUSTED{ColorDisplayFace.SetGreenMap[in: in, out: out]};
};
SetBlueMap:
PUBLIC
ENTRY
PROC [vt: Virtual, in: Color, out: Color] = {
impl: VirtualImpl = NARROW[vt.impl];
IF vt.hasColorDisplay
AND impl.colorBitmapState#none
AND vt.colorMode.full
THEN
TRUSTED{ColorDisplayFace.SetBlueMap[in: in, out: out]};
};
GetColor:
PUBLIC
ENTRY
PROC [vt: Virtual,
aChannelValue, bChannelValue: Terminal.ChannelValue ← 0]
RETURNS [red, green, blue: Color] = {
impl: VirtualImpl = NARROW[vt.impl];
IF vt.hasColorDisplay
AND impl.colorBitmapState#none
AND
NOT vt.colorMode.full
THEN
TRUSTED{[r: red, g: green, b: blue] ← ColorDisplayFace.GetColor[
pixelA: aChannelValue, pixelB: bChannelValue]}
ELSE red ← green ← blue ← 0;
};
SetColor:
PUBLIC
ENTRY
PROC [vt: Virtual,
aChannelValue, bChannelValue: Terminal.ChannelValue ← 0,
red, green, blue: Color] = {
impl: VirtualImpl = NARROW[vt.impl];
IF vt.hasColorDisplay
AND impl.colorBitmapState#none
AND
NOT vt.colorMode.full
THEN
TRUSTED{ColorDisplayFace.SetColor[pixelA: aChannelValue, pixelB: bChannelValue,
r: red, g: green, b: blue]};
};
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 [Terminal.Position] = {
ENABLE UNWIND => NULL;
impl: VirtualImpl = NARROW[vt.impl];
RETURN[impl.colorCursor];
};
SetColorCursorPosition:
PUBLIC
ENTRY
PROC [vt: Virtual, position: Terminal.Position] = {
ENABLE UNWIND => NULL;
impl: VirtualImpl = NARROW[vt.impl];
IF NOT vt.hasColorDisplay THEN RETURN;
IF impl.colorCursor=position THEN RETURN; -- no change
IF impl.colorCursorDisplayed THEN HideColorCursor[vt, impl];
impl.colorCursor ← position;
IF impl.colorCursorState=$visible
AND
NOT InhibitColorCursor[impl]
THEN
ShowColorCursor[vt, impl];
};
GetColorCursorPattern returns the bitmap of the virtual cursor associated with the color display on the specified virtual terminal. This bitmap changes only as a result of calls on SetColorCursorPattern and/or SetColorCursorPresentation.
SetColorCursorPattern sets the cursor bitmap of the specified virtual terminal to the indicated value. This bitmap will be reflected on the screen when the virtual terminal is next selected (or, if it is presently selected, immediately).
GetColorCursorPattern:
PUBLIC
ENTRY
PROC [vt: Virtual]
RETURNS [pattern: Terminal.ColorCursorBitmap] = {
ENABLE UNWIND => NULL;
impl: VirtualImpl = NARROW[vt.impl];
RETURN[impl.colorPattern];
};
SetColorCursorPattern:
PUBLIC
ENTRY
PROC [vt: Virtual,
pattern: Terminal.ColorCursorBitmap] = {
ENABLE UNWIND => NULL;
impl: VirtualImpl ~ NARROW[vt.impl];
displayed: BOOL ~ impl.colorCursorDisplayed;
IF NOT vt.hasColorDisplay THEN RETURN;
IF displayed THEN HideColorCursor[vt, impl];
impl.colorPattern ← pattern;
IF impl.colorBitmapState#none THEN ExpandColorCursorPattern[vt, impl];
IF displayed THEN ShowColorCursor[vt, impl];
};
These procedures control the manner in which the cursor bitmap is presented on the color display. "onesAreWhite" means a one-bit in the ColorCursorBitmap is mapped to a color value of all ones (conventionally white) and a zero-bit is mapped to a color value of all zeros (conventionally black). "onesAreBlack" reverses this interpretation.
GetColorCursorPresentation:
PUBLIC
ENTRY
PROC [vt: Virtual]
RETURNS [Terminal.ColorCursorPresentation] = {
ENABLE UNWIND => NULL;
impl: VirtualImpl = NARROW[vt.impl];
RETURN[impl.colorCursorPresentation];
};
SetColorCursorPresentation:
PUBLIC
ENTRY
PROC [vt: Virtual,
new: Terminal.ColorCursorPresentation]
RETURNS [old: Terminal.ColorCursorPresentation] = {
ENABLE UNWIND => NULL;
impl: VirtualImpl ~ NARROW[vt.impl];
displayed: BOOL ~ impl.colorCursorDisplayed;
old ← impl.colorCursorPresentation;
IF NOT vt.hasColorDisplay THEN RETURN;
IF new=old THEN RETURN; -- no change
IF displayed THEN HideColorCursor[vt, impl];
impl.colorCursorPresentation ← new;
IF displayed THEN ShowColorCursor[vt, impl];
};
These procedures control the visibility of the cursor bitmap on the color display. When the state is "visible", the cursor bitmap (supplied by SetColorCursorPattern and influenced by SetColorCursorPresentation) is displayed at the position determined by SetColorCursorPosition. When the state is "invisible", no cursor appears on the color display. In the "visible" state, the cursor is merged into the color display bitmap by software, which caches the contents of the display bitmap that lie "under" the cursor. If the cursor moves (as a result of SetColorCursorPosition), the display bitmap is restored to the cached value. The procedures used to modify the display bitmap do not check to see if this cache should be invalidated. Therefore, if the client wants to change the display bitmap under the cursor, it must first flush the cache by setting the cursor state to "invisible".
The effect of these procedures can only be observed when vt is selected and GetColorBitmapState[vt] = displayed.
GetColorCursorState:
PUBLIC
ENTRY
PROC [vt: Virtual]
RETURNS [Terminal.ColorCursorBitmapState] = {
ENABLE UNWIND => NULL;
impl: VirtualImpl = NARROW[vt.impl];
RETURN[impl.colorCursorState];
};
SetColorCursorState:
PUBLIC
ENTRY
PROC [vt: Virtual, new: Terminal.ColorCursorBitmapState]
RETURNS [old: Terminal.ColorCursorBitmapState] = {
ENABLE UNWIND => NULL;
impl: VirtualImpl = NARROW[vt.impl];
old ← impl.colorCursorState;
IF NOT vt.hasColorDisplay THEN RETURN;
IF new=old THEN RETURN;
IF impl.colorBitmapState#none
THEN
SELECT new
FROM
$invisible => IF impl.colorCursorDisplayed THEN HideColorCursor[vt, impl];
$visible => IF NOT InhibitColorCursor[impl] THEN ShowColorCursor[vt, impl];
ENDCASE;
impl.colorCursorState ← new;
};
LockColorFrame:
PUBLIC
ENTRY
PROC[vt: Virtual,
xmin, ymin: NAT ← 0, xmax, ymax: NAT ← NAT.LAST] = {
ENABLE UNWIND => NULL;
impl: VirtualImpl = NARROW[vt.impl];
impl.xmin ← xmin; impl.ymin ← ymin;
impl.xmax ← xmax; impl.ymax ← ymax;
impl.colorFrameLocked ← TRUE;
IF impl.colorCursorDisplayed AND InhibitColorCursor[impl] THEN HideColorCursor[vt, impl];
};
UnlockColorFrame:
PUBLIC
ENTRY
PROC[vt: Virtual] = {
ENABLE UNWIND => NULL;
impl: VirtualImpl = NARROW[vt.impl];
impl.colorFrameLocked ← FALSE;
IF impl.colorBitmapState#none AND impl.colorCursorState=$visible AND NOT impl.colorCursorDisplayed THEN ShowColorCursor[vt, impl];
};
InhibitColorCursor:
INTERNAL
PROC[impl: VirtualImpl]
RETURNS[
BOOL] =
INLINE {
RETURN[impl.colorFrameLocked AND ColorCursorIntersectsFrame[impl]];
};
ColorCursorIntersectsFrame:
INTERNAL
PROC[impl: VirtualImpl]
RETURNS[
BOOL] = {
x: INTEGER ~ impl.colorCursor.x; y: INTEGER ~ impl.colorCursor.y;
w: INTEGER ~ 16; h: INTEGER ~ 16;
RETURN[x<impl.xmax AND y<impl.ymax AND (x+w)>impl.xmin AND (y+h)>impl.ymin];
};
colorCursorWplSrcA: NAT ~ 16;
colorCursorWplSrcB: NAT ~ 8;
ExpandColorCursorPattern:
INTERNAL
PROC[vt: Virtual, impl: VirtualImpl] = {
ExpandBitmap:
PROC[buffer:
LONG
POINTER, wpl:
CARDINAL, bpp:
NAT] =
TRUSTED {
AddOne:
PROC[address: PrincOps.BitAddress]
RETURNS[PrincOps.BitAddress] =
TRUSTED {
IF address.bit<15 THEN address.bit ← address.bit+1
ELSE {address.bit ← 0; address.word ← address.word+1};
RETURN[address];
};
ppw: NAT ~ 16/bpp;
bbSpace: PrincOps.BBTableSpace;
bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbSpace];
bb^ ← [dst: [word:
NIL, bit: 0], dstBpl: 0, src: [word:
NIL, bit: 0], srcDesc: [srcBpl[0]],
width: 0, height: 0, flags: [disjoint: TRUE, gray: FALSE, srcFunc: null, dstFunc: null]];
bb.src.word ← @impl.colorPattern;
bb.srcDesc.srcBpl ← 16;
bb.dst.word ← buffer;
bb.dstBpl ← wpl*16;
bb.width ← 1;
bb.height ← 16;
FOR i:
NAT
IN [0..16)
DO
FOR j:
NAT
IN [0..bpp)
DO
PrincOpsUtils.BITBLT[bb]; --write one column
bb.dst ← AddOne[bb.dst];
ENDLOOP;
bb.src ← AddOne[bb.src];
ENDLOOP;
};
IF impl.colorBitmapState=none THEN RETURN;
IF vt.colorMode.full
THEN {
ExpandBitmap[impl.colorCursorSourceA, colorCursorWplSrcA, 16];
ExpandBitmap[impl.colorCursorSourceB, colorCursorWplSrcB, 8];
}
ELSE
IF vt.colorMode.bitsPerPixelChannelA>0
THEN {
ExpandBitmap[impl.colorCursorSourceA, colorCursorWplSrcA,
vt.colorMode.bitsPerPixelChannelA];
};
};
HideColorCursor:
INTERNAL
PROC[vt: Virtual, impl: VirtualImpl] =
TRUSTED {
xMax: INTEGER ~ vt.colorWidth;
yMax: INTEGER ~ vt.colorHeight;
x: INTEGER ~ impl.colorCursor.x;
y: INTEGER ~ impl.colorCursor.y;
w: INTEGER ~ 16;
h: INTEGER ~ 16;
IF (x+w)>0 AND (y+h)>0 AND x<xMax AND y<yMax
AND (vt.colorMode.full
OR vt.colorMode.bitsPerPixelChannelA>0)
THEN {
bpp: NAT ~ IF vt.colorMode.full THEN 16 ELSE vt.colorMode.bitsPerPixelChannelA;
ppw: NAT ~ 16/bpp;
bltX, bltY, bltW, bltH: INTEGER;
xoff, yoff: INTEGER ← 0;
bbSpace: PrincOps.BBTableSpace;
bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbSpace];
bb^ ← [dst: [word:
NIL, bit: 0], dstBpl: 0, src: [word:
NIL, bit: 0], srcDesc: [srcBpl[0]],
width: 0, height: 0, flags: [disjoint: TRUE, gray: FALSE, srcFunc: null, dstFunc: null]];
bltX ← x; bltY ← y;
bltW ← w; bltH ← h;
IF x<0 THEN {xoff ← ABS[x]; bltW ← w-xoff; bltX ← 0};
IF y<0 THEN {yoff ← ABS[y]; bltH ← h-yoff; bltY ← 0};
IF x>(xMax-w) THEN bltW ← xMax-x;
IF y>(yMax-h) THEN bltH ← yMax-y;
bb.dst.word ← vt.colorBitmapA + Basics.LongMult[bltY,vt.colorWordsPerLineA] + bltX/ppw;
bb.dst.bit ← (bltX MOD ppw)*bpp;
bb.dstBpl ← vt.colorWordsPerLineA*16;
bb.src.word ← impl.colorCursorBackupA;
bb.src.bit ← 0;
bb.srcDesc.srcBpl ← colorCursorWplSrcA*16;
bb.width ← bltW*bpp;
bb.height ← bltH;
PrincOpsUtils.BITBLT[bb]; -- restore the bits under the cursor
IF vt.colorMode.full
THEN {
bb.dst.word ← vt.colorBitmapB + Basics.LongMult[bltY,vt.colorWordsPerLineB] + bltX/2;
bb.dst.bit ← (bltX MOD 2)*8;
bb.dstBpl ← vt.colorWordsPerLineB*16;
bb.src.word ← impl.colorCursorBackupB;
bb.src.bit ← 0;
bb.srcDesc.srcBpl ← colorCursorWplSrcB*16;
bb.width ← bltW*8;
bb.height ← bltH;
PrincOpsUtils.BITBLT[bb]; -- restore the rest of the bits under the cursor
};
};
impl.colorCursorDisplayed ← FALSE;
};
ShowColorCursor:
INTERNAL
PROC[vt: Virtual, impl: VirtualImpl] =
TRUSTED {
xMax: INTEGER ~ vt.colorWidth;
yMax: INTEGER ~ vt.colorHeight;
x: INTEGER ~ impl.colorCursor.x;
y: INTEGER ~ impl.colorCursor.y;
w: INTEGER ~ 16;
h: INTEGER ~ 16;
xoff, yoff: INTEGER ← 0;
IF (x+w)>0 AND (y+h)>0 AND x<xMax AND y<yMax
AND (vt.colorMode.full
OR vt.colorMode.bitsPerPixelChannelA>0)
THEN {
bpp: NAT ~ IF vt.colorMode.full THEN 16 ELSE vt.colorMode.bitsPerPixelChannelA;
ppw: NAT ~ 16/bpp;
bltX, bltY, bltW, bltH: INTEGER;
xoff, yoff: INTEGER ← 0;
bbSpace: PrincOps.BBTableSpace;
bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbSpace];
bb^ ← [dst: [word:
NIL, bit: 0], dstBpl: 0, src: [word:
NIL, bit: 0], srcDesc: [srcBpl[0]],
width: 0, height: 0, flags: [disjoint: TRUE, gray: FALSE, srcFunc: null, dstFunc: null]];
bltX ← x; bltY ← y;
bltW ← w; bltH ← h;
IF x<0 THEN {xoff ← ABS[x]; bltW ← w-xoff; bltX ← 0};
IF y<0 THEN {yoff ← ABS[y]; bltH ← h-yoff; bltY ← 0};
IF x>(xMax-w) THEN bltW ← xMax-x;
IF y>(yMax-h) THEN bltH ← yMax-y;
bb.dst ← [word: impl.colorCursorBackupA, bit: 0];
bb.dstBpl ← colorCursorWplSrcA*16;
bb.src.word ← vt.colorBitmapA + Basics.LongMult[bltY,vt.colorWordsPerLineA] + bltX/ppw;
bb.src.bit ← (bltX MOD ppw)*bpp;
bb.srcDesc.srcBpl ← vt.colorWordsPerLineA*16;
bb.width ← bltW*bpp;
bb.height ← bltH;
PrincOpsUtils.BITBLT[bb]; -- save the bits under the cursor
IF vt.colorMode.full
THEN {
bb.src.word ← vt.colorBitmapB + Basics.LongMult[bltY,vt.colorWordsPerLineB] + bltX/2;
bb.src.bit ← (bltX MOD 2)*8;
bb.srcDesc.srcBpl ← vt.colorWordsPerLineB*16;
bb.dst ← [word: impl.colorCursorBackupB, bit: 0];
bb.dstBpl ← colorCursorWplSrcB*16;
bb.width ← bltW*8;
bb.height ← bltH;
PrincOpsUtils.BITBLT[bb]; -- save the rest of the bits under the cursor
};
SELECT impl.colorCursorPresentation
FROM
$onesAreBlack => { bb.flags.srcFunc ← complement; bb.flags.dstFunc ← and };
$onesAreWhite => { bb.flags.srcFunc ← null; bb.flags.dstFunc ← or };
ENDCASE => ERROR;
bb.dst.word ← vt.colorBitmapA + Basics.LongMult[bltY,vt.colorWordsPerLineA] + bltX/ppw;
bb.dst.bit ← (bltX MOD ppw)*bpp;
bb.dstBpl ← vt.colorWordsPerLineA*16;
bb.src.word ← impl.colorCursorSourceA + yoff*colorCursorWplSrcA + xoff/ppw;
bb.src.bit ← (xoff MOD ppw)*bpp;
bb.srcDesc.srcBpl ← colorCursorWplSrcA*16;
bb.width ← bltW*bpp;
bb.height ← bltH;
PrincOpsUtils.BITBLT[bb]; -- Put the cursor in
IF vt.colorMode.full
THEN {
bb.dst.word ← vt.colorBitmapB + Basics.LongMult[bltY,vt.colorWordsPerLineB] + bltX/2;
bb.dst.bit ← (bltX MOD 2)*8;
bb.dstBpl ← vt.colorWordsPerLineB*16;
bb.src.word ← impl.colorCursorSourceB + yoff*colorCursorWplSrcB + xoff/2;
bb.src.bit ← (xoff MOD 2)*8;
bb.srcDesc.srcBpl ← colorCursorWplSrcB*16;
bb.width ← bltW*8;
bb.height ← bltH;
PrincOpsUtils.BITBLT[bb]; -- Put the rest of the cursor in
};
};
impl.colorCursorDisplayed ← TRUE;
};
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;
};
AcquireAndMarkSpecificTerminalUnstable:
ENTRY
PROC [vt: Virtual] = {
ENABLE UNWIND => NULL;
WHILE terminalChanging OR vt ~= current DO WAIT terminalStable; ENDLOOP;
terminalChanging ← TRUE;
};
MarkTerminalStable:
ENTRY
PROC = {
ENABLE UNWIND => NULL;
terminalChanging ← FALSE;
BROADCAST terminalStable;
};
InternalWaitForBWVerticalRetrace:
INTERNAL
PROC = {
ENABLE UNWIND => NULL;
IF meFirst
THEN {
meFirst ← FALSE;
TRUSTED {WAIT bwRetrace^};
BROADCAST verticalRetrace;
meFirst ← TRUE;
}
ELSE WAIT verticalRetrace;
};
TurnOff:
INTERNAL
PROC[impl: VirtualImpl] = {
DisplayFace.TurnOff[];
InternalWaitForBWVerticalRetrace[];
InternalWaitForBWVerticalRetrace[];
IF DisplayFace.hasBuffer THEN VMSideDoor.ReleaseSpecialRealMemory[impl.bwBitmap]
ELSE VM.Unpin[impl.bwBitmap];
};
TurnOffColor:
INTERNAL
PROC[impl: VirtualImpl] = {
TRUSTED{ColorDisplayFace.TurnOff[]};
VM.Unpin[impl.colorVM];
};
LoadTerminal:
PROC [vt: Virtual] =
TRUSTED {
vtImpl: VirtualImpl = NARROW[vt.impl];
vt.keyboard ← LOOPHOLE[KeyboardFace.keyboard];
vt.mouse ← LOOPHOLE[MouseFace.position];
MouseFace.SetPosition[LOOPHOLE[vtImpl.mouse]];
vt.bwCursor ← LOOPHOLE[DisplayFace.cursorPosition];
vt.bwCursor^ ← LOOPHOLE[vtImpl.bwCursor];
DisplayFace.SetBackground[IF vtImpl.bwBackground = white THEN white ELSE black];
DisplayFace.SetBorderPattern[oddPairs: vtImpl.bwBorderOdd, evenPairs: vtImpl.bwBorderEven];
DisplayFace.SetCursorPattern[@vtImpl.bwPattern];
SELECT vtImpl.bwBitmapState
FROM
displayed => {
DisplayFace.Connect[vtImpl.bwBitmap.page];
IF DisplayFace.hasBuffer THEN VMSideDoor.AssignSpecialRealMemory[vtImpl.bwBitmap]
ELSE VM.Pin[vtImpl.bwBitmap];
DisplayFace.TurnOn[];
};
allocated => {
DisplayFace.Connect[vtImpl.bwBitmap.page];
IF DisplayFace.hasBuffer THEN VMSideDoor.AssignSpecialRealMemory[vtImpl.bwBitmap];
};
none => NULL;
ENDCASE;
IF vtImpl.colorBitmapState=displayed
THEN {
VM.Pin[vtImpl.colorVM];
ColorDisplayFace.TurnOn[];
};
};
UnloadTerminal:
INTERNAL
PROC [vt: Virtual] =
TRUSTED {
vtImpl: VirtualImpl = NARROW[vt.impl];
vtImpl.keyboard ← LOOPHOLE[KeyboardFace.keyboard^];
vt.keyboard ← @vtImpl.keyboard;
vtImpl.mouse ← LOOPHOLE[MouseFace.position^];
vt.mouse ← @vtImpl.mouse;
vtImpl.bwCursor ← LOOPHOLE[DisplayFace.cursorPosition^];
vt.bwCursor ← @vtImpl.bwCursor;
SELECT vtImpl.bwBitmapState
FROM
displayed => {
TurnOff[vtImpl];
DisplayFace.Disconnect[];
};
allocated => {
IF DisplayFace.hasBuffer THEN VMSideDoor.ReleaseSpecialRealMemory[vtImpl.bwBitmap];
DisplayFace.Disconnect[];
};
none => NULL;
ENDCASE;
IF vtImpl.colorBitmapState=displayed
THEN {
ColorDisplayFace.TurnOff[];
VM.Unpin[vtImpl.colorVM];
};
};
NewVirtual:
PROC
RETURNS [vt: Virtual] = {
vtImpl: VirtualImpl = NEW[VirtualImplObject ← []];
TRUSTED {
vt ←
NEW[Terminal.Object ← [
keyboard: LOOPHOLE[@vtImpl.keyboard],
mouse: LOOPHOLE[@vtImpl.mouse],
hasBlackAndWhiteDisplay: TRUE,
bwWidth: DisplayFace.width,
bwHeight: DisplayFace.height,
bwHasBorder: DisplayFace.hasBorder,
bwPixelsPerInch: DisplayFace.pixelsPerInch,
bwCursor: LOOPHOLE[@vtImpl.bwCursor],
hasColorDisplay: FALSE,
colorWidth: 0,
colorHeight: 0,
colorPixelsPerInch: 0,
colorDisplayType: NULL,
colorMode: [FALSE, 0, 0],
colorBitmapA: NIL,
colorBitmapB: NIL,
colorWordsPerLineA: 0,
colorWordsPerLineB: 0,
impl: LOOPHOLE[vtImpl]
]];
};
};
AttachColorDisplay:
PUBLIC
ENTRY
PROC[vt: Virtual] = {
-- export to TerminalExtras
ENABLE UNWIND => NULL;
IF colorTerminal=NIL THEN colorTerminal ← vt
ELSE IF colorTerminal=vt THEN NULL
ELSE ERROR CantDoIt;
IF ColorDisplayFace.displayType=none THEN RETURN;
vt.colorPixelsPerInch ← ColorDisplayFace.pixelsPerInch;
vt.colorDisplayType ← (
SELECT ColorDisplayFace.displayType
FROM
ramtek525 => ramtek525, hitachi3619 => hitachi3619,
ENDCASE => ramtek525); -- should be 'other'
vt.hasColorDisplay ← TRUE;
};
AllocateBWBitmap:
PROC
RETURNS [interval:
VM.Interval] = {
interval ←
VM.Allocate[count: DisplayFace.pagesForBitmap, in64K:
TRUE
! VM.CantAllocate => GO TO cant];
EXITS
cant => ERROR CantDoIt;
};
AllocateColorVM:
PROC[fmode: ColorDisplayFace.Mode]
RETURNS [interval:
VM.Interval] = {
pages: INT;
TRUSTED { pages ← ColorDisplayFace.PagesForMode[fmode] };
interval ← VM.Allocate[count: pages ! VM.CantAllocate => GO TO cant];
EXITS
cant => ERROR CantDoIt;
};
KeyboardWatcher:
PROC =
TRUSTED {
WatcherEnabled:
ENTRY
PROC
RETURNS [
BOOL] =
TRUSTED INLINE {
ENABLE UNWIND => NULL;
RETURN[watcherDisableCount = 0]
};
KeysRecord:
TYPE =
RECORD [
SELECT
OVERLAID *
FROM
bits => [bits: Keys.KeyBits],
words => [words: ARRAY [0..SIZE[Keys.KeyBits]) OF WORD],
ENDCASE
];
keyboard: LONG POINTER TO KeysRecord = LOOPHOLE[KeyboardFace.keyboard];
waitTime: Process.Ticks = Process.MsecToTicks[300];
lastTime: KeysRecord ← keyboard^;
In the following, [bits[bits: ALL[up]]] doesn't quite work, since the number of bits in a Keys.KeyBits isn't evenly divisible by bitsPerWord, causing the excess bits in the last word not to be initialized. This leads to trouble in the word-oriented comparisons in the main loop.
magicCombination: KeysRecord ← [words[words: ALL[177777B]]];
magicCombination.bits[Ctrl] ← magicCombination.bits[LeftShift] ←
magicCombination.bits[RightShift] ← down;
Process.SetPriority[Process.priorityForeground];
DO
Process.Pause[waitTime];
IF WatcherEnabled[]
THEN {
thisTime: KeysRecord = keyboard^;
changed: BOOL ← FALSE;
select: BOOL ← TRUE;
FOR word:
NAT
IN [0..
SIZE[KeysRecord])
DO
thisWord: WORD = thisTime.words[word];
IF thisWord ~= lastTime.words[word] THEN changed ← TRUE;
IF thisWord ~= magicCombination.words[word] THEN select ← FALSE;
ENDLOOP;
IF changed
THEN {
lastTime ← thisTime;
IF select THEN Select[NIL];
};
};
ENDLOOP;
};
Initialization
Initialize:
PROC =
TRUSTED {
WordSequence: TYPE = RECORD [SEQUENCE COMPUTED CARDINAL OF WORD];
headGlobalP: LONG POINTER = VM.lowCore.NEW[WordSequence[DisplayFace.globalStateSize]];
mask: WORD;
vt: Virtual = NewVirtual[];
initialPosition: Terminal.Position;
[bwRetrace, mask] ← PrincOpsUtils.AllocateNakedCondition[];
DisplayFace.Initialize[headGlobalP, mask];
DisplayFace.InitializeCleanup[];
IF ColorDisplayFace.displayType#none
THEN {
colorHeadGlobalP: LONG POINTER = VM.lowCore.NEW[WordSequence[ColorDisplayFace.globalStateSize]];
ColorDisplayFace.Initialize[colorHeadGlobalP];
ColorDisplayFace.InitializeCleanup[];
};
initialPosition ← [x: vt.bwWidth/2, y: vt.bwHeight/2];
Terminal.SetMousePosition[vt, initialPosition];
Terminal.SetBWCursorPosition[vt, initialPosition];
LoadTerminal[current ← vt];
terminals ← CONS[current, NIL];
Process.EnableAborts[@terminalStable];
Process.Detach[FORK KeyboardWatcher[]];
};
Initialize[];
END.