<> <> <> <> <> 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; <> vt: Terminal.Virtual = Terminal.Create[]; sleeping: BOOL _ FALSE; napOver: CONDITION _ [timeout: 0]; <> UseAlternateVT: PUBLIC PROC [vtProc: VTProc, logout: BOOL _ TRUE] 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: BOOL _ TRUE] = { 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]]; <> 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 [BOOL _ FALSE] = 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]]; <> IdleHandlerList: TYPE = LIST OF IdleHandlerRecord; IdleHandlerRecord: TYPE = RECORD [proc: IdleHandler, data: REF]; idleRegistry: IdleHandlerList _ NIL; visiblyIdle: BOOL _ FALSE; IsIdle: PUBLIC PROC RETURNS [BOOL] = { <<... returns TRUE iff the machine has entered the idle state.>> RETURN [visiblyIdle]; }; <<>> RegisterIdleHandler: PUBLIC ENTRY PROC [handler: IdleHandler, data: REF _ NIL] 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: 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; <> 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 { <> 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] = { <> 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 ] }; <> 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.