<<>> <> <> <> <> <> <> <> <> <<>> DIRECTORY BasicTime, Buttons, EndOps, Idle, Process, Rope, RuntimeError, UserProfile, ViewerClasses, ViewerPrivate; EndOpsImpl: CEDAR MONITOR IMPORTS BasicTime, Buttons, Idle, Process, RuntimeError, UserProfile 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; }; <> autoIdleTimeout: INT--seconds-- ¬ 20*60; <> neverEnableAutoIdle: BOOL ¬ FALSE; <> sampleTimer: CONDITION; checkpointing: INT ¬ 0; lastInput: BasicTime.GMT ¬ BasicTime.Now[]; NoteAutoIdleChange: ENTRY UserProfile.ProfileChangedProc = TRUSTED { <<[reason: UserProfile.ProfileChangeReason]>> ENABLE UNWIND => NULL; minutes: INT ¬ UserProfile.Number["Viewers.AutoIdleTimeout", 20]; IF neverEnableAutoIdle OR NOT minutes IN (0 .. 40) THEN minutes ¬ 0; autoIdleTimeout ¬ minutes*60; RETURN}; < NULL; now: BasicTime.GMT; DO ENABLE ABORTED => LOOP; WAIT sampleTimer; now ¬ BasicTime.Now[]; IF TerminalActivity.hadInput THEN { TerminalActivity.hadInput ¬ FALSE; lastInput ¬ now; } ELSE { IF autoIdleTimeout>0 AND BasicTime.Period[from: lastInput, to: now] >= autoIdleTimeout AND NOT (checkpointing>0 OR Idle.IsIdle[]) THEN Process.Detach[FORK IdleMother[NIL]]; }; ENDLOOP; }; >> < NULL; checkpointing ¬ checkpointing + 1; }; OnRollback: ENTRY PROC [clientData: REF ANY] --Booting.RollbackProc-- ~ { ENABLE UNWIND => NULL; IF (checkpointing ¬ checkpointing - 1) = 0 THEN lastInput ¬ BasicTime.Now[]; }; OnBoot: PROC [clientData: REF ANY] RETURNS [rejection: Rope.ROPE ¬ NIL] --Booting.CheckpointProc-- ~ { dirty: INT ¬ 0; CheckDirty: ViewerOps.EnumProc = { IF v.newVersion OR v.newFile THEN dirty ¬ dirty+1; }; ViewerOps.EnumerateViewers[CheckDirty]; IF dirty#0 THEN IF NOT MessageWindow.Confirm["Confirm ignoring unsaved viewers"] THEN rejection ¬ "There are unsaved viewers."; };>> IdleMother: Buttons.ButtonProc = { IF NOT Idle.IsIdle[] THEN { Idle.Sleep[]; }; }; CreateIdleButton: PUBLIC PROC [] = { [] ¬ Buttons.Create[ info: [name: "Idle"], proc: IdleMother, fork: TRUE, documentation: "Hide desktop pending user login"]; }; Init: PROC = TRUSTED { Process.SetTimeout[@sampleTimer, Process.SecondsToTicks[30]]; }; Init[]; <> <> <> UserProfile.CallWhenProfileChanges[NoteAutoIdleChange]; END.