<<>> <> <> <> <> <> DIRECTORY Draw2d, ForkOps, Imager, PreemptablePaintProcs, Process, ViewerClasses, ViewerOps; PreemptablePaintProcsImpl: CEDAR MONITOR LOCKS lc USING lc: LockedContext IMPORTS ForkOps, Process, ViewerOps, Draw2d EXPORTS PreemptablePaintProcs = BEGIN OPEN PreemptablePaintProcs; nilLockedContext: LockedContext = NEW[LockedContextRec]; NilLockedContext: PUBLIC PROC [] RETURNS [LockedContext] ~ {RETURN[nilLockedContext]}; AbortContext: PUBLIC ENTRY PROC [lc: LockedContext] ~ { ENABLE UNWIND => NULL; lc.abort ¬ TRUE; lc.suspend ¬ FALSE; NOTIFY lc.stateHasChanged; }; SuspendContext: PUBLIC ENTRY PROC [lc: LockedContext] ~ { ENABLE UNWIND => NULL; IF NOT lc.abort THEN lc.suspend ¬ TRUE; }; RestartContext: PUBLIC ENTRY PROC [lc: LockedContext] ~ { ENABLE UNWIND => NULL; lc.suspend ¬ FALSE; NOTIFY lc.stateHasChanged; }; DoUnderLock: PUBLIC ENTRY PROC [lc: LockedContext, Action: LockedContextActionProc] ~ { ENABLE UNWIND => NULL; WHILE lc.suspend DO WAIT lc.stateHasChanged ENDLOOP; IF lc.abort THEN ERROR ABORTED; Action[lc.context, lc.zip]; }; PaintWithoutLocks: PUBLIC PROC [self: ViewerClasses.Viewer, context: Imager.Context, whatChanged: REF, clear: BOOL, UnlockedPaint: UnlockedPaintProc, PauseWhilePaint: PauseProc ¬ DefaultPauseWhilePaint, PauseWhileIdle: PauseProc ¬ DefaultPauseWhileIdle] RETURNS [lc: LockedContext] ~ { { WITH whatChanged SELECT FROM lockedContext: LockedContext => { lc ¬ lockedContext; IF lc.abort THEN RETURN; lc.context ¬ context; lc.zip ¬ Draw2d.GetZip[context, lc.zip]; RestartContext[lc]; PauseWhilePaint[]; GOTO Suspend; }; ENDCASE => { lc ¬ NEW[LockedContextRec ¬ [ context: context, zip: Draw2d.GetZip[context], pauseWhileIdle: PauseWhileIdle, viewer: self ]]; TRUSTED{Process.Detach[FORK UnlockedPaint[self, lc, whatChanged, clear]]}; PauseWhilePaint[]; GOTO Suspend; }; EXITS Suspend => { SuspendContext[lc]; ForkOps.Fork[DelayThenContinuePaint, lc]; }; } }; DelayThenContinuePaint: PROC [data: REF] ~ { lc: LockedContext ~ NARROW[data]; IF lc.abort THEN RETURN; lc.pauseWhileIdle[]; IF lc.abort THEN RETURN; ViewerOps.PaintViewer[ viewer: lc.viewer, hint: client, clearClient: FALSE, whatChanged: lc ]; }; DefaultPauseWhilePaint: PUBLIC PROC[] ~ {Process.PauseMsec[1000]}; --1 seconds of paint DefaultPauseWhileIdle: PUBLIC PROC[] ~ {Process.PauseMsec[50]}; --1/25 second idle END.