IdleImpl.mesa
last edited by Levin on December 12, 1983 4:00 pm
DIRECTORY
Basics USING [BITAND, bitsPerWord, LongDivMod, LongMult, LowHalf],
BasicTime USING [GMT, Now, nullGMT, Period, ToPupTime],
DebuggerSwap USING [EnableSwatWatcher],
Idle USING [BitmapRef, BitmapRep, ImageProc],
IO USING [PutRope, STREAM],
KeyboardFace USING [KeyBits, KeyStation],
Keys USING [KeyBits, KeyName],
PrincOps USING [BBptr, BBTableSpace, BitAddress],
PrincOpsUtils USING [AlignedBBTable, BITBLT],
Process USING [Pause, SecondsToTicks, Ticks],
ProcessorFace USING [PowerOff],
Rope USING [Equal, Length, ROPE],
SimpleTerminal USING [InputTimeout, SetInputTimeout, TurnOff, TurnOn],
Terminal USING [
BWCursorBitmap, Create, Current, DisableKeyboardWatcher, EnableKeyboardWatcher, GetBitBltTable, GetKeys, Select, SetBWBackground, SetBWBitmapState, SetBWCursorPosition, Virtual, WaitForBWVerticalRetrace],
UserCredentials USING [Get, Login],
UserProfile USING [ProfileChanged];
IdleImpl: CEDAR MONITOR
IMPORTS
Basics, BasicTime, DebuggerSwap, IO, PrincOpsUtils, Process, ProcessorFace, Rope, SimpleTerminal, Terminal, UserCredentials, UserProfile
EXPORTS Idle =
BEGIN
ActionProc: TYPE = PROC RETURNS [wake: BOOL];
-- Global Variables (not exported) --
vt: Terminal.Virtual = Terminal.Create[];
sleeping: BOOLEANFALSE;
napOver: CONDITION ← [timeout: 0];
-- Exports to Idle --
Sleep: PUBLIC PROC [
proc: Idle.ImageProc ← DefaultImageProc, powerOff: BasicTime.GMT ← BasicTime.nullGMT] = {
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}];
IF ~name.Equal[UserCredentials.Get[].name, FALSE] THEN
The user name isn't what it was before we went to sleep, so we notify anyone who might care.
UserProfile.ProfileChanged[$rollBack];
};
currentVT: Terminal.Virtual;
IF ~NapNeeded[] THEN RETURN;
DebuggerSwap.EnableSwatWatcher[FALSE];
Terminal.DisableKeyboardWatcher[];
currentVT ← Terminal.Current[];
SleepInternal[proc, DoLogin, powerOff];
currentVT.Select[];
Terminal.EnableKeyboardWatcher[];
DebuggerSwap.EnableSwatWatcher[TRUE];
WakeUp[];
};
-- Sleep stuff --
SleepInternal: PROC [
imageProc: Idle.ImageProc, actionProc: ActionProc, powerOff: BasicTime.GMT] = TRUSTED {
ticksPerSecond: Process.Ticks = Process.SecondsToTicks[1];
DO -- loops only if actionProc returns FALSE
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];
bbt^ ← vt.GetBitBltTable[];
org ← bbt.dst;
bpl ← bbt.dstBpl;
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 ← imageProc[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[] THEN GO TO keyTyped;
Process.Pause[1];
ENDLOOP;
IF powerOff ~= BasicTime.nullGMT AND
BasicTime.Period[from: BasicTime.Now[], to: powerOff] >= 0 THEN
ProcessorFace.PowerOff[];
REPEAT
keyTyped => NULL;
ENDLOOP;
[] ← vt.SetBWBitmapState[$none];
IF actionProc[] THEN EXIT;
ENDLOOP;
};
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]};
KeyTyped: PROC RETURNS [somethingWasDown: BOOL] = {
KeyArray: TYPE = MACHINE DEPENDENT RECORD [
SELECT OVERLAID * FROM
nb => [namedBits: Keys.KeyBits],
ub => [unnamedBits: KeyboardFace.KeyBits],
wds => [words: ARRAY [0..SIZE[Keys.KeyBits]) OF WORD],
ENDCASE
];
SomethingIsDown: PROC RETURNS [BOOLFALSE] = {
InterestingKeys: TYPE = KeyboardFace.KeyStation[16..77];
up: KeyArray = [nb[namedBits: ALL[$up]]];
keys: KeyArray = [nb[namedBits: vt.GetKeys[]]];
FOR i: NAT IN [0..SIZE[KeyArray]) DO
IF keys.words[i] ~= up.words[i] THEN
FOR k: KeyboardFace.KeyStation IN [i*Basics.bitsPerWord..(i+1)*Basics.bitsPerWord) DO
IF k ~= Keys.KeyName[$Lock].ORD AND k IN InterestingKeys AND keys.unnamedBits[k] = $down THEN RETURN[TRUE];
ENDLOOP;
ENDLOOP;
};
IF (somethingWasDown ← SomethingIsDown[]) THEN
DO
vt.WaitForBWVerticalRetrace[];
IF ~SomethingIsDown[] THEN EXIT;
ENDLOOP;
};
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
]
};
-- ***************** --
-- *** Main Body *** --
-- ***************** --
[] ← vt.SetBWBackground[$black];
vt.SetBWCursorPosition[[x: -SIZE[Terminal.BWCursorBitmap], y: -SIZE[Terminal.BWCursorBitmap]]];
END.