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] = { 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. ึIdleImpl.mesa Copyright c 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 Global Variables (not exported) Exports to IdleBackdoor 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. Idle Registry (exported to Idle) ... returns TRUE iff the machine has entered the idle state. Sleep stuff (exported to Idle) blacken the entire bitmap (bbt.dst, bbt.height, and bbt.width are set up) unpaint old image This algorithm is stolen from DMT. Initialization ส ถ– "Cedar" style˜codešœ ™ Kšœ ฯmœ7™BK™)K™/K™)—˜šฯk ˜ Kšœžœžœ.˜BKšœ žœžœ˜/Kšœžœ ˜Kšœ žœ˜'KšœžœN˜XKšœ žœ˜0Kšžœžœ žœ˜Kšœ žœ#˜1Kšœžœžœ˜-Kšœžœ ˜-Kšœžœ žœ˜Kšœžœ2˜FKšœ žœิ˜โKšœ žœ ˜Kšœ žœ ˜Kšœžœ˜#K˜——šฯnœžœž˜Kšžœ+žœW˜‹Kšžœ˜Kšœžœžœ˜ K˜—šœ™K˜Kšœ)˜)K˜Kšœ žœžœ˜Kšœ ž œ˜"K˜—šœ™K˜šŸœžœžœžœžœžœžœ˜iš Ÿ œžœžœžœ žœžœ˜7šžœ˜Kšžœ ž˜Kš žœžœ žœžœ žœ˜,—K˜—šŸœžœžœ˜Kšœ žœ˜Kšž œ ˜Kšœ˜—š Ÿœžœžœžœžœ˜-š Ÿ œžœžœ žœžœ˜1Kšœ$˜$K˜#Kšœ;˜;Kšœ˜—šŸ œžœ žœžœ˜*K˜"Kšœ˜Kšœ˜—Kšœžœ˜K˜)Kšžœžœžœฯc˜Fšœ˜Kšœ˜Kšœ˜Kšœ'žœžœ˜BKšœ)žœžœ˜;—K˜—K˜Kšžœ$žœžœ˜2šžœžœ˜šžœ3žœžœž˜IKšœ/˜/Kšžœ˜—Kšœžœ˜šœ4˜4Kšœถ™ถ—Kšœ"˜"K˜—K˜šž˜Kšœ ˜ Kš žœžœ žœ žœžœ˜'Kšžœ˜—K˜šžœžœ˜Kšœ!˜!Kšœžœ˜%K˜—K˜ šžœžœ˜šžœ3žœžœž˜IKšœ/˜/Kšžœ˜—Kšœžœ˜K˜—K˜K˜—š Ÿœžœžœžœžœ˜Mš Ÿœžœžœžœžœžœ˜8šžœ žœž˜0Kš žœžœžœžœžœ˜EKšžœ˜—K˜—šžœ(ž˜.šž˜K˜Kšžœžœžœ˜ Kšžœ˜——K˜K˜—Kšœžœ/žœžœ˜RK˜—šœ ™ K˜Kšœžœžœžœ˜2Kšœžœžœžœ˜@Kšœ žœ˜$Kšœ žœžœ˜K˜š Ÿœžœžœžœžœ˜&Kšœ<™