<> <> <> <> <<>> DIRECTORY Buttons USING [ButtonProc, Create], ClassIncreek USING [ActionBody, GetAction, Increek, IncreekError, NewStdIncreek, SetAtLatest], EndOps USING [], Idle USING [IsIdle, Sleep], Process USING [Detach, DisableTimeout, GetCurrent, SecondsToTicks, SetTimeout], RuntimeError USING [UNCAUGHT], SystemVersion USING [machineType], UserProfile USING [CallWhenProfileChanges, Number, ProfileChangedProc], ViewerClasses USING [Viewer], ViewerOps USING [PaintEverything], ViewerPrivate USING []; EndOpsImpl: CEDAR MONITOR IMPORTS Buttons, ClassIncreek, Process, Idle, RuntimeError, SystemVersion, UserProfile, ViewerOps EXPORTS EndOps, ViewerPrivate = BEGIN <> ProcList: TYPE ~ LIST OF PROC; registerHead: ProcList _ NIL; registerTail: ProcList _ NIL; Register: PUBLIC ENTRY PROC [proc: PROC] = { prev: ProcList ~ registerTail; registerTail _ LIST[proc]; IF prev=NIL THEN registerHead _ registerTail ELSE prev.rest _ registerTail; }; ProcessEndOpsRegistry: PUBLIC PROC = { FOR list: ProcList _ registerHead, list.rest UNTIL list = NIL DO list.first[ ! RuntimeError.UNCAUGHT => CONTINUE]; ENDLOOP; }; <> idleProcess: PROCESS _ NIL; <> neverEnableAutoIdle: BOOL _ FALSE; <> autoIdleCond: CONDITION; <> NoteAutoIdleChange: ENTRY UserProfile.ProfileChangedProc = TRUSTED { <<[reason: UserProfile.ProfileChangeReason]>> ENABLE UNWIND => NULL; minutes: INT _ UserProfile.Number["Viewers.AutoIdleTimeout", 20]; IF neverEnableAutoIdle THEN minutes _ 0; SELECT minutes FROM <= 0, >= 40 => { Process.DisableTimeout[@autoIdleCond]; idleProcess _ NIL; BROADCAST autoIdleCond; }; ENDCASE => { Process.SetTimeout[@autoIdleCond, Process.SecondsToTicks[minutes*60]]; idleProcess _ FORK AutoIdle[]; BROADCAST autoIdleCond; }; }; AutoIdle: ENTRY PROC = TRUSTED { ENABLE UNWIND => NULL; increek: ClassIncreek.Increek _ ClassIncreek.NewStdIncreek[]; DO ClassIncreek.SetAtLatest[increek]; WAIT autoIdleCond; IF neverEnableAutoIdle THEN EXIT; IF Process.GetCurrent[] # idleProcess THEN EXIT ELSE { action: ClassIncreek.ActionBody _ ClassIncreek.GetAction[self: increek, waitMode: dontWait, acceptance: clicksAndMotion ! ClassIncreek.IncreekError => LOOP]; IF neverEnableAutoIdle THEN EXIT; IF Process.GetCurrent[] = idleProcess THEN WITH a: action SELECT FROM timedOut => IF IdleProc # NIL THEN { idleProcess _ NIL; Process.Detach[FORK IdleProc[NIL]]; <> RETURN; }; ENDCASE; }; ENDLOOP; }; useIdleCrock: BOOL _ TRUE; -- can be set to FALSE to provoke the bug IdleProcInit: Buttons.ButtonProc = { IF NOT Idle.IsIdle[] THEN { Idle.Sleep[]; IF useIdleCrock AND SystemVersion.machineType = dandelion THEN <> <> ViewerOps.PaintEverything[]; }; }; IdleProc: Buttons.ButtonProc _ IdleProcInit; [] _ Buttons.Create[ info: [name: "Idle"], proc: IdleProc, fork: TRUE, documentation: "Hide desktop pending user login"]; UserProfile.CallWhenProfileChanges[NoteAutoIdleChange]; END.