<> <> 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: BOOLEAN _ FALSE; 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: 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}]; IF ~name.Equal[UserCredentials.Get[].name, FALSE] THEN <> 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; <> 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 _ 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 [BOOL _ FALSE] = { 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] = { <> 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.