IdleImpl.mesa
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
Doug Wyatt, April 12, 1985 6:14:49 pm PST
Russ Atkinson (RRA) May 12, 1986 8:10:50 pm PDT
Spreitzer, March 21, 1986 11:09:07 am PST
DIRECTORY
Basics USING [BITAND, bitsPerWord, LongDivMod, LongMult, LowHalf],
BasicTime USING [GMT, Now, nullGMT, ToPupTime],
Booting USING [switches],
DebuggerSwap USING [EnableSwatWatcher],
Idle USING [BitmapRef, BitmapRep, IdleHandler, IdleReason, IdleRegistration, ImageProc],
IdleBackdoor USING [KeyFilter, KeyName, VTProc],
IO USING [PutRope, STREAM],
PrincOps USING [BBptr, BBTableSpace, BitAddress],
PrincOpsUtils USING [AlignedBBTable, BITBLT],
Process USING [Pause, SecondsToTicks, Ticks],
Rope USING [Length, ROPE],
SimpleTerminal USING [InputTimeout, SetInputTimeout, TurnOff, TurnOn],
Terminal USING [BWCursorBitmap, Create, Current, DisableKeyboardWatcher, EnableKeyboardWatcher, FrameBuffer, GetBWFrameBuffer, Select, SetBWBackground, SetBWBitmapState, SetBWCursorPosition, Virtual, WaitForBWVerticalRetrace],
TerminalDefs USING [KeyName],
TerminalFace USING [keyboard],
UserCredentials USING [Get, Login];
IdleImpl: CEDAR MONITOR
IMPORTS Basics, BasicTime, Booting, DebuggerSwap, IO, PrincOpsUtils, Process, Rope, SimpleTerminal, Terminal, TerminalFace, UserCredentials
EXPORTS Idle, IdleBackdoor
= BEGIN OPEN Idle, IdleBackdoor;
Global Variables (not exported)
vt: Terminal.Virtual = Terminal.Create[];
sleeping: BOOLFALSE;
napOver: CONDITION ← [timeout: 0];
Exports to IdleBackdoor
UseAlternateVT: PUBLIC PROC [vtProc: VTProc, logout: BOOLTRUE] RETURNS [wasAlreadyAlternate: BOOL] = {
NapNeeded: ENTRY PROC RETURNS [needed: BOOL] = INLINE {
IF (needed ← ~sleeping)
THEN sleeping ← TRUE
ELSE WHILE sleeping DO WAIT napOver ENDLOOP;
};
WakeUp: ENTRY PROC = {
sleeping ← FALSE;
BROADCAST napOver;
};
DoLogin: PROC RETURNS [wake: BOOLTRUE] = {
TerminalOn: PROC RETURNS [in, out: IO.STREAM] = {
[in, out] ← SimpleTerminal.TurnOn[];
out.PutRope["\NPlease login...\N"];
SimpleTerminal.SetInputTimeout[Process.SecondsToTicks[30]];
};
TerminalOff: PROC [in, out: IO.STREAM] = {
SimpleTerminal.SetInputTimeout[0];
SimpleTerminal.TurnOff[];
};
name, password: Rope.ROPE;
[name, password] ← UserCredentials.Get[];
IF password.Length[] = 0 THEN RETURN; -- wasn't previously logged in.
UserCredentials.Login[
startInteraction: TerminalOn,
endInteraction: TerminalOff,
options: [confirmCredentialsOverwrite: TRUE, alwaysInteract: TRUE]
! SimpleTerminal.InputTimeout => {wake ← FALSE; CONTINUE}];
};
currentVT: Terminal.Virtual;
IF wasAlreadyAlternate ← ~NapNeeded[] THEN RETURN;
IF logout THEN {
FOR each: IdleHandlerList ← CopyRegistry[], each.rest WHILE each # NIL DO
each.first.proc[each.first.data, becomingIdle];
ENDLOOP;
visiblyIdle ← TRUE;
DebuggerSwap.EnableSwatWatcher[Booting.switches[i]];
In the normal case, where the I switch is not used, the above call disables the swat watcher. If the I switch is used, the swat watcher is desired, even when the machine is in idle.
Terminal.DisableKeyboardWatcher[];
};
currentVT ← Terminal.Current[];
DO
vtProc[vt];
IF (NOT logout) OR DoLogin[] THEN EXIT;
ENDLOOP;
currentVT.Select[];
IF logout THEN {
Terminal.EnableKeyboardWatcher[];
DebuggerSwap.EnableSwatWatcher[TRUE];
};
WakeUp[];
IF logout THEN {
FOR each: IdleHandlerList ← CopyRegistry[], each.rest WHILE each # NIL DO
each.first.proc[each.first.data, becomingBusy];
ENDLOOP;
visiblyIdle ← FALSE;
};
};
KeyTyped: PUBLIC PROC [watch: KeyFilter] RETURNS [somethingWasDown: BOOL] = {
SomethingIsDown: PROC RETURNS [BOOLFALSE] = TRUSTED {
FOR k: KeyName IN [watch.first .. watch.last] DO
IF TerminalFace.keyboard[k]=down AND watch.pass[k] THEN RETURN[TRUE];
ENDLOOP;
};
IF (somethingWasDown ← SomethingIsDown[]) THEN
DO
vt.WaitForBWVerticalRetrace[];
IF ~SomethingIsDown[] THEN EXIT;
ENDLOOP;
};
defaultKeyFilter: PUBLIC KeyFilter ← [first: Five, last: Spare3, pass: ALL[TRUE]];
Idle Registry (exported to Idle)
IdleHandlerList: TYPE = LIST OF IdleHandlerRecord;
IdleHandlerRecord: TYPE = RECORD [proc: IdleHandler, data: REF];
idleRegistry: IdleHandlerList ← NIL;
visiblyIdle: BOOLFALSE;
IsIdle: PUBLIC PROC RETURNS [BOOL] = {
... returns TRUE iff the machine has entered the idle state.
RETURN [visiblyIdle];
};
RegisterIdleHandler: PUBLIC ENTRY PROC [handler: IdleHandler, data: REFNIL] RETURNS [IdleRegistration]= {
idleRegistry ← CONS[[handler, data], idleRegistry];
RETURN [idleRegistry];
};
UnregisterIdleHandler: PUBLIC ENTRY PROC [registration: IdleRegistration] = {
lag: IdleHandlerList ← NIL;
FOR each: IdleHandlerList ← idleRegistry, each.rest WHILE each # NIL DO
IF each = registration THEN {
IF lag = NIL THEN idleRegistry ← each.rest ELSE lag.rest ← each.rest;
EXIT;
};
lag ← each;
ENDLOOP;
};
CopyRegistry: ENTRY PROC RETURNS [head: IdleHandlerList ← NIL] = {
tail: IdleHandlerList ← NIL;
FOR each: IdleHandlerList ← idleRegistry, each.rest WHILE each # NIL DO
new: IdleHandlerList = LIST[each.first];
IF tail = NIL THEN head ← new ELSE tail.rest ← new;
tail ← new;
ENDLOOP;
};
Sleep stuff (exported to Idle)
Sleep: PUBLIC PROC [proc: Idle.ImageProc ← DefaultImageProc, powerOff: BasicTime.GMT ← BasicTime.nullGMT] = {
ticksPerSecond: Process.Ticks = Process.SecondsToTicks[1];
Bounce: PROC [vt: Terminal.Virtual] = TRUSTED {
frameBuffer: Terminal.FrameBuffer ← NIL;
bbTable: PrincOps.BBTableSpace;
bbt: PrincOps.BBptr = PrincOpsUtils.AlignedBBTable[@bbTable];
x: CARDINAL ← Random[] MOD vt.bwWidth;
y: CARDINAL ← Random[] MOD vt.bwHeight;
image: Idle.BitmapRef ← NIL;
org: PrincOps.BitAddress; -- origin of display bitmap
bpl: LONG CARDINAL; -- raster width of display bitmap
white: CARDINAL ← 0;
XYToBitAddress: PROC [x, y: CARDINAL] RETURNS [PrincOps.BitAddress] = TRUSTED {
q, r: CARDINAL;
[q, r] ← Basics.LongDivMod[org.bit + Basics.LongMult[y, bpl] + x, Basics.bitsPerWord];
RETURN[[word: org.word + q, bit: r]]
};
vt.Select[];
[] ← vt.SetBWBitmapState[$allocated];
frameBuffer ← vt.GetBWFrameBuffer[];
bbt^ ← [dst: NULL, dstBpl: NULL, src: NULL, srcDesc: NULL, width: 0, height: 0, flags: []];
bbt.dst ← org ← [word: frameBuffer.base, bit: 0];
bbt.dstBpl ← bpl ← frameBuffer.wordsPerLine*Basics.bitsPerWord;
bbt.width ← frameBuffer.width;
bbt.height ← frameBuffer.height;
blacken the entire bitmap (bbt.dst, bbt.height, and bbt.width are set up)
bbt.src ← [@white, 0, 0];
bbt.srcDesc ← [gray[[0, 0, 0, 0]]];
bbt.flags ← [gray: TRUE];
PrincOpsUtils.BITBLT[bbt];
[] ← vt.SetBWBitmapState[$displayed];
DO
w, h: CARDINAL;
x ← UpdateAndClip[x, vt.bwWidth, IF image = NIL THEN 0 ELSE image.width];
y ← UpdateAndClip[y, vt.bwHeight, IF image = NIL THEN 0 ELSE image.height];
w ← vt.bwWidth - x;
h ← vt.bwHeight - y;
IF image ~= NIL THEN {
unpaint old image
bbt.src ← [@white, 0, 0];
bbt.srcDesc ← [gray[[0, 0, 0, 0]]];
bbt.flags ← [gray: TRUE];
PrincOpsUtils.BITBLT[bbt];
};
image ← proc[w: w, h: h];
IF image ~= NIL THEN {
bbt.dst ← XYToBitAddress[x, y];
bbt.src ← [word: LOOPHOLE[image.base], bit: 0];
bbt.srcDesc ← [srcBpl[image.raster*Basics.bitsPerWord]];
bbt.width ← MIN[image.width, w];
bbt.height ← MIN[image.height, h];
bbt.flags ← [disjoint: TRUE];
PrincOpsUtils.BITBLT[bbt];
};
THROUGH [0..(((Random[] MOD 8) + 1) * ticksPerSecond) / 4) DO
IF KeyTyped[defaultKeyFilter] THEN GO TO keyTyped;
Process.Pause[1];
ENDLOOP;
REPEAT
keyTyped => NULL;
ENDLOOP;
[] ← vt.SetBWBitmapState[$none];
};
[] ← UseAlternateVT[Bounce, TRUE];
};
defaultBitmap: Idle.BitmapRef = NEW[Idle.BitmapRep ← [
base: NEW[Terminal.BWCursorBitmap ← [
002000B, 074000B, 140000B, 012767B, 012525B, 053566B, 111113B, 163100B,
000000B, 000000B, 154000B, 053520B, 062520B, 053360B, 155440B, 000140B
]],
raster: 1,
width: Basics.bitsPerWord,
height: Terminal.BWCursorBitmap.SIZE
]];
DefaultImageProc: PUBLIC Idle.ImageProc = {RETURN[defaultBitmap]};
nRandoms: CARDINAL = 20;
RandIndex: TYPE = [0..nRandoms);
randTable: ARRAY RandIndex OF CARDINAL ← [
30200, 27432, 62096, 39855, 17884, 58726, 55595, 20904, 28164, 27447,
34709, 35231, 33770, 31508, 40689, 1411, 20373, 3422, 62938, 40035];
randIndex: RandIndex ← Basics.LowHalf[BasicTime.ToPupTime[BasicTime.Now[]]] MOD nRandoms;
Random: PROC RETURNS [r: CARDINAL] = {
This algorithm is stolen from DMT.
i: RandIndex;
randIndex ← IF randIndex = LAST[RandIndex] THEN FIRST[RandIndex] ELSE SUCC[randIndex];
i ← (randIndex + 3) MOD nRandoms;
r ← randTable[i] ← randTable[randIndex] + randTable[i];
};
UpdateAndClip: PROC [v: CARDINAL, limit: CARDINAL, scale: CARDINAL ← 16]
RETURNS [newV: CARDINAL] = INLINE {
r: CARDINAL = Random[];
x: INTEGER ← v;
x ← x +
(SELECT TRUE FROM
Basics.BITAND[r, 100000B] ~= 0 => 0,
Basics.BITAND[r, 40000B] ~= 0 => scale,
ENDCASE => -scale);
RETURN [
SELECT x FROM
< 0 => limit - scale,
>= INTEGER[limit - scale] => 0,
ENDCASE => x
]
};
Initialization
defaultKeyFilter.pass[Lock] ← defaultKeyFilter.pass[Ctrl] ← defaultKeyFilter.pass[Spare3] ← defaultKeyFilter.pass[LeftShift] ← defaultKeyFilter.pass[RightShift] ← FALSE;
[] ← Terminal.SetBWBackground[vt, $black];
Terminal.SetBWCursorPosition[vt, [x: -SIZE[Terminal.BWCursorBitmap], y: -SIZE[Terminal.BWCursorBitmap]]];
END.