DIRECTORY Atom USING [GetProp], Carets USING [ResumeCarets, SuspendCarets], CedarProcess USING [SetPriority], Icons USING [DrawIcon], Imager USING [black, ClipRectangleI, Color, Context, DoSaveAll, MakeGray, MaskRectangleI, Rectangle, SetColor, SetFont, SetXYI, ShowText, Trans, white], ImagerBackdoor USING [GetBounds, invert, MakeStipple, ViewClipRectangleI, ViewReset, ViewTranslateI], KeyTypes, KeySymsKB, Process USING [Detach, MsecToTicks, Pause, SecondsToTicks, Ticks], Real USING [Round], RefText USING [AppendRope, New, TrustTextAsRope], Rope USING [Length, ROPE, Run], RuntimeError USING [Uncaught], UserInput, UserInputOps, VFonts USING [defaultFont, Font, StringWidth], ViewerClasses USING [PaintRectangle, Viewer], ViewerErrors USING [Query], ViewerLocks USING [CallUnderWriteLock, Wedged], ViewerOps USING [ChangeColumn, FetchProp, PaintHint, SaveAllEdits, UserToScreenCoords], ViewerPrivate, ViewerSpecs, ViewersWorld, ViewersWorldInstance, ViewersWorldRefType, ViewersWorldTypes, ViewerTools USING [GetSelectedViewer]; ViewerPaintImpl: CEDAR MONITOR IMPORTS Atom, Carets, CedarProcess, Icons, Imager, ImagerBackdoor, Process, Real, RefText, Rope, RuntimeError, UserInputOps, VFonts, ViewerErrors, ViewerLocks, ViewerOps, ViewerPrivate, ViewerSpecs, ViewersWorld, ViewersWorldInstance, ViewerTools EXPORTS ViewerOps, ViewerPrivate, ViewersWorldRefType SHARES ViewerClasses, ViewerErrors, ViewerLocks ~ BEGIN OPEN ViewerClasses, ViewerOps, ViewerSpecs; ContextCreatorProc: TYPE ~ ViewerPrivate.ContextCreatorProc; ContextList: TYPE = ViewersWorldTypes.ContextList; ROPE: TYPE ~ Rope.ROPE; ViewersWorldObj: PUBLIC TYPE = ViewersWorldTypes.ViewersWorldObj; captionAscent: NAT ¬ 9; FormatCaption: PROC [viewer: Viewer] RETURNS [REF TEXT] ~ { name: ROPE ~ viewer.name; nameLen: INT ~ Rope.Length[name]; file: ROPE ~ viewer.file; fileLen: INT ~ Rope.Length[file]; header: REF TEXT ¬ RefText.New[MAX[nameLen, fileLen] + 12]; header ¬ RefText.AppendRope[to: header, from: name]; IF fileLen>nameLen AND Rope.Run[s1: name, s2: file, case: FALSE]=nameLen THEN { header ¬ RefText.AppendRope[to: header, from: " ("]; header ¬ RefText.AppendRope[to: header, from: file, start: nameLen]; header ¬ RefText.AppendRope[to: header, from: ")"]; }; SELECT TRUE FROM viewer.saveInProgress => header ¬ RefText.AppendRope[to: header, from: " [Saving...]"]; viewer.newFile => header ¬ RefText.AppendRope[to: header, from: " [New File]"]; viewer.newVersion => header ¬ RefText.AppendRope[to: header, from: " [Edited]"]; ENDCASE; IF viewer.link#NIL THEN header ¬ RefText.AppendRope[to: header, from: " [Split]"]; RETURN [header]; }; PaintCaption: PROC [viewer: Viewer, context: Imager.Context] ~ { wbs: INTEGER ~ IF viewer.border THEN windowBorderSize ELSE 0; IF viewer.class.caption#NIL THEN { x: INTEGER ~ wbs; y: INTEGER ~ viewer.wh-captionHeight; w: INTEGER ~ viewer.ww-wbs*2; h: INTEGER ~ captionHeight-wbs; action: PROC ~ { Imager.SetXYI[context, x, y]; Imager.Trans[context]; Imager.ClipRectangleI[context, 0, 0, w, h]; viewer.class.caption[viewer, context]; }; Imager.DoSaveAll[context, action]; } ELSE { header: REF TEXT ~ FormatCaption[viewer]; font: VFonts.Font ~ VFonts.defaultFont; foreground: Imager.Color ~ CaptionColor[$foreground]; dropshadow: Imager.Color ~ CaptionColor[$dropshadow]; background: Imager.Color ~ CaptionColor[$background]; sidebar: Imager.Color ~ CaptionColor[$sidebar]; wbs: INTEGER ~ IF viewer.border THEN windowBorderSize ELSE 0; x: INTEGER ~ wbs; w: INTEGER ~ viewer.ww-wbs*2; captionLeft: INTEGER; headerW: INTEGER ¬ VFonts.StringWidth[RefText.TrustTextAsRope[header], font]; headerW ¬ MIN[headerW, viewer.ww-wbs*2]; Imager.SetColor[context, sidebar]; Imager.MaskRectangleI[context, x, viewer.wh, w, -captionHeight]; captionLeft ¬ (viewer.ww-headerW)/2; IF background # sidebar THEN { Imager.SetColor[context, background]; Imager.MaskRectangleI[context, captionLeft-2, viewer.wh, headerW+4, -captionHeight]; }; Imager.SetFont[context, font]; IF dropshadow # background THEN { Imager.SetColor[context, dropshadow]; Imager.SetXYI[context, captionLeft+1, viewer.wh-captionAscent]; Imager.ShowText[context, header]; Imager.SetXYI[context, captionLeft, viewer.wh-captionAscent-1]; Imager.ShowText[context, header]; }; Imager.SetColor[context, foreground]; Imager.SetXYI[context, captionLeft, viewer.wh-captionAscent]; Imager.ShowText[context, header]; }; }; CaptionColor: PROC [what: ATOM] RETURNS [Imager.Color] = { WITH Atom.GetProp[$ViewerCaptionColors, what] SELECT FROM color: Imager.Color => RETURN [color]; ENDCASE => RETURN [IF what = $foreground THEN Imager.white ELSE Imager.black]; }; PaintDocumentHeader: PROC [viewer: Viewer, context: Imager.Context, clear: BOOL, hint: PaintHint, whatChanged: REF ANY] = { IF hint#menu THEN PaintCaption[viewer, context]; IF hint#caption AND viewer.menu#NIL THEN { wbs: INTEGER ~ IF viewer.border THEN windowBorderSize ELSE 0; x: INTEGER ~ wbs; w: INTEGER ~ viewer.ww-wbs*2; h: INTEGER ~ viewer.menu.linesUsed*menuHeight; y: INTEGER ~ viewer.wh-captionHeight-h; IF whatChanged=NIL THEN { IF NOT clear THEN { Imager.SetColor[context, Imager.white]; Imager.MaskRectangleI[context, x, y, w, h]; }; Imager.SetColor[context, Imager.black]; Imager.MaskRectangleI[context, x, y, w, -menuBarHeight]; }; ViewerPrivate.DrawMenu[viewer.menu, context, x, y+h, whatChanged]; }; }; PaintIcon: PROC [viewer: Viewer, hint: PaintHint, whatChanged: REF ANY ¬ NIL] = { iconAction: PROC [context: Imager.Context] ~ { SELECT TRUE FROM viewer.icon=private => { [] ¬ viewer.class.paint[viewer, context, whatChanged, hint=all]; }; hint=all, hint=caption => { dirty: BOOL ~ viewer.newVersion OR viewer.newFile; label: ROPE ~ GetIconLabel[viewer]; drawIcon: PROC ~ { Icons.DrawIcon[flavor: viewer.icon, context: context, label: label] }; SELECT viewer.icon FROM document => IF dirty THEN viewer.icon ¬ dirtyDocument; dirtyDocument => IF NOT dirty THEN viewer.icon ¬ document; ENDCASE; Imager.DoSaveAll[context, drawIcon]; IF ViewerPrivate.selectedIcon=viewer THEN { Imager.SetColor[context, ImagerBackdoor.invert]; Imager.MaskRectangleI[context, 0, 0, iconWidth, iconHeight]; }; }; ENDCASE; }; IF viewer.parent=NIL THEN PaintWindow[viewer, iconAction]; }; GetIconLabel: PROC [viewer: Viewer] RETURNS [ROPE] = { IF viewer.label#NIL THEN RETURN [viewer.label]; WITH ViewerOps.FetchProp[viewer, $IconLabel] SELECT FROM label: ROPE => RETURN [label]; ENDCASE => RETURN [viewer.name]; }; InvisiblePaint: ERROR ~ CODE; RecursivelyPaintViewers: PROC [viewer: Viewer, hint: PaintHint, clearClient: BOOL, clear: BOOL, rect: PaintRectangle, whatChanged: REF] = { quit: BOOL ¬ FALSE; vx, vy: INTEGER; bitmapY: INTEGER ¬ 0; FOR v: Viewer ¬ viewer, v.parent UNTIL v=NIL DO -- visibility test IF v.parent#NIL THEN { IF (v.wy+v.wh < 0) OR (v.wy > v.parent.ch) THEN RETURN; IF (v.ww+v.ww < 0) OR (v.wx > v.parent.cw) THEN RETURN; } ELSE IF v.offDeskTop THEN RETURN; ENDLOOP; IF hint#client THEN { windowAction: PROC [context: Imager.Context] ~ { w: INTEGER ~ viewer.ww; h: INTEGER ~ viewer.wh; IF ~viewer.visible OR viewer.destroyed THEN ERROR InvisiblePaint; IF clearClient AND ~clear AND hint=all THEN { Imager.SetColor[context, Imager.white]; Imager.MaskRectangleI[context, 0, 0, w, h]; clear ¬ TRUE; }; IF viewer.border AND hint=all THEN { wbs: INTEGER ~ windowBorderSize; Imager.SetColor[context, Imager.black]; Imager.MaskRectangleI[context, 0, 0, windowBorderSize, h]; Imager.MaskRectangleI[context, w, 0, -windowBorderSize, h]; Imager.MaskRectangleI[context, 0, 0, w, windowBorderSize]; Imager.MaskRectangleI[context, 0, h, w, -windowBorderSize]; }; IF viewer.parent=NIL AND viewer.column#static THEN PaintDocumentHeader[viewer, context, clear, hint, whatChanged]; }; PaintWindow[viewer, windowAction]; }; IF hint=all OR hint=client THEN { clientAction: PROC [context: Imager.Context] ~ { IF ~viewer.visible OR viewer.destroyed THEN ERROR InvisiblePaint; IF rect#NIL AND viewer.class.bltH=none AND viewer.class.bltV=none THEN clearClient ¬ TRUE; -- if class doesn't care about blt, don't pass it a rectangle IF clearClient AND ~clear THEN { Imager.SetColor[context, Imager.white]; Imager.MaskRectangleI[context, 0, 0, viewer.cw, viewer.ch]; Imager.SetColor[context, Imager.black]; IF rect#NIL THEN whatChanged ¬ NIL; rect ¬ NIL; clear ¬ TRUE; }; IF viewer.class.paint#NIL THEN { quit ¬ viewer.class.paint[viewer, context, whatChanged, clear]; }; }; PaintClient[viewer, clientAction]; }; IF quit THEN RETURN; IF rect#NIL AND viewer.parent=NIL THEN { IF viewer.cx>=rect.x AND (viewer.cx+viewer.cw <= rect.x+rect.w) AND viewer.cy>=rect.y AND (viewer.cy+viewer.ch <= rect.y+rect.h) THEN RETURN; }; IF hint=all OR hint=client OR clear THEN FOR v: Viewer ¬ viewer.child, v.sibling UNTIL v=NIL DO IF rect # NIL THEN { IF viewer.class.topDownCoordSys THEN [vx, vy] ¬ ViewerOps.UserToScreenCoords[viewer, v.wx, viewer.ch-(v.wy+v.wh)] ELSE [vx, vy] ¬ ViewerOps.UserToScreenCoords[viewer, v.wx, v.wy]; IF vx >= rect.x AND (vx + v.ww <= rect.x + rect.w) AND vy >= rect.y AND (vy + v.wh <= rect.y + rect.h) THEN LOOP}; RecursivelyPaintViewers[v, all, FALSE, clear, rect, whatChanged]; ENDLOOP; }; PaintViewer: PUBLIC PROC [viewer: Viewer, hint: PaintHint ¬ client, clearClient: BOOL ¬ TRUE, whatChanged: REF ANY ¬ NIL] ~ { LocalPaintViewer: PROC ~ { rect: PaintRectangle ¬ NIL; IF (NOT viewer.visible) OR viewer.destroyed OR viewer.paintingWedged THEN RETURN; IF viewer.iconic THEN { IF ~viewer.offDeskTop THEN PaintIcon[viewer, hint, whatChanged]; RETURN }; WITH whatChanged SELECT FROM pr: PaintRectangle => rect ¬ pr; ENDCASE; RecursivelyPaintViewers[viewer: viewer, hint: hint, clearClient: clearClient AND ~(hint=menu OR hint=caption), clear: FALSE, rect: rect, whatChanged: whatChanged]; }; IF viewer = NIL OR viewer.destroyed OR viewer.paintingWedged THEN RETURN; ViewerLocks.CallUnderWriteLock[LocalPaintViewer, viewer ! ViewerLocks.Wedged => {viewer.paintingWedged ¬ TRUE; CONTINUE}; ABORTED => CONTINUE; InvisiblePaint => CONTINUE; RuntimeError.Uncaught => IF ViewerErrors.Query[signal].continue THEN CONTINUE; ]; }; Screen: TYPE ~ ViewerPrivate.Screen; CreateContext: PUBLIC PROC [screen: Screen] RETURNS [context: Imager.Context] ~ { vWorld: ViewersWorld.Ref ¬ ViewersWorldInstance.GetWorld[]; RETURN [vWorld.class.creator[vWorld.screenServerData, screen]]; }; AllocScreenContexts: PROC [screen: Screen, count: NAT ¬ 8] ~ { cl: LIST OF Imager.Context ¬ NIL; vWorld: ViewersWorld.Ref ¬ ViewersWorldInstance.GetWorld[]; vWorld.contextPool[screen] ¬ NIL; THROUGH [0..count) DO context: Imager.Context ~ vWorld.class.creator[vWorld.screenServerData, screen]; cl ¬ CONS[context, cl]; ENDLOOP; vWorld.contextPool[screen] ¬ cl; }; AllocColorContexts: INTERNAL PROC ~ { AllocScreenContexts[color, 4]; }; SetCreator: PUBLIC PROC [creator: ContextCreatorProc, screen: Screen ¬ main] RETURNS [old: ContextCreatorProc] ~ { inner: ENTRY PROC ~ { old ¬ vWorld.class.creator; vWorld.class.creator ¬ creator; AllocScreenContexts[screen, 8]; IF colorEnabled THEN AllocColorContexts[]; }; vWorld: ViewersWorld.Ref ¬ ViewersWorldInstance.GetWorld[]; DisablePainting[wait: TRUE]; inner[]; EnablePainting[]; }; SetCreatorScreen: PUBLIC PROC [creator: ContextCreatorProc ¬ NIL, screen: Screen] ~ { inner: ENTRY PROC ~ { vWorld.class.creator ¬ creator; }; vWorld: ViewersWorld.Ref ¬ ViewersWorldInstance.GetWorld[]; DisablePainting[wait: TRUE]; inner[]; AllocScreenContexts[screen, 8 ! UNWIND => EnablePainting[]; RuntimeError.Uncaught => IF ViewerErrors.Query[signal].continue THEN CONTINUE; ]; EnablePainting[]; }; GetCreatorScreen: PUBLIC PROC [screen: Screen] RETURNS [old: ContextCreatorProc] = { vWorld: ViewersWorld.Ref ¬ ViewersWorldInstance.GetWorld[]; old ¬ vWorld.class.creator; }; ViewerScreen: PUBLIC PROC [viewer: Viewer] RETURNS [Screen] ~ { RETURN [InlineViewerScreen[viewer]] }; InlineViewerScreen: PROC [viewer: Viewer] RETURNS [Screen] ~ { RETURN [IF viewer.column=color AND NOT viewer.iconic THEN color ELSE main] }; colorEnabled: BOOL ¬ FALSE; EnableColor: PUBLIC PROC [bitsPerPixel: NAT] RETURNS [ok: BOOL ¬ FALSE] ~ { inner: ENTRY PROC ~ { bounds: Imager.Rectangle ¬ [0, 0, 0, 0]; IF colorEnabled THEN RETURN; -- ViewerPrivate.SetColorScreenSize[w: vWorld.terminal.colorWidth, h: vWorld.terminal.colorHeight]; THROUGH [0..4) DO context: Imager.Context ~ CreateContext[color ! UNWIND => GOTO oops; RuntimeError.Uncaught => IF ViewerErrors.Query[signal].continue THEN GOTO oops; ]; IF context = NIL THEN RETURN; -- something wrong; bail out now. vWorld.contextPool[color] ¬ CONS[context, vWorld.contextPool[color]]; ENDLOOP; bounds ¬ ImagerBackdoor.GetBounds[vWorld.contextPool[color].first]; IF bounds.w > 0 THEN ViewerPrivate.SetColorScreenSize[w: Real.Round[bounds.w], h: Real.Round[bounds.h]]; colorEnabled ¬ ok ¬ TRUE; EXITS oops => {}; }; vWorld: ViewersWorld.Ref ¬ ViewersWorldInstance.GetWorld[]; DisablePainting[wait: TRUE]; inner[]; EnablePainting[]; IF ok THEN { GreyScreen[color, 0, 0, 9999, 9999]; }; }; DisableColor: PUBLIC PROC ~ { inner: ENTRY PROC ~ { vWorld.contextPool[color] ¬ NIL; colorEnabled ¬ FALSE; }; vWorld: ViewersWorld.Ref ¬ ViewersWorldInstance.GetWorld[]; DisablePainting[wait: TRUE]; inner[]; EnablePainting[]; }; paintingCount: CARDINAL ¬ 0; -- number of paints in progress FinishedPainting: CONDITION; -- notified when a process finishes painting paintingLock: CARDINAL ¬ 0; -- incremented to disable painting PaintingEnabled: CONDITION; -- wait here for painting to be enabled DisablePainting: PUBLIC PROC [wait: BOOL ¬ TRUE] = { locked: ENTRY PROC ~ { paintingLock ¬ paintingLock+1; IF wait THEN WHILE paintingCount>0 DO WAIT FinishedPainting ENDLOOP; }; Carets.SuspendCarets[]; locked[]; Carets.ResumeCarets[]; }; EnablePainting: PUBLIC ENTRY PROC ~ { IF paintingLock>1 THEN paintingLock ¬ paintingLock-1 ELSE {paintingLock ¬ 0; BROADCAST PaintingEnabled}; }; WaitForPaintingToFinish: PUBLIC ENTRY PROC ~ { WHILE paintingCount>0 DO WAIT FinishedPainting ENDLOOP; }; AcquireContext: ENTRY PROC [screen: Screen] RETURNS [Imager.Context, ContextList] ~ { list: ContextList; vWorld: ViewersWorld.Ref ¬ ViewersWorldInstance.GetWorld[]; WHILE paintingLock>0 DO WAIT PaintingEnabled ENDLOOP; paintingCount ¬ paintingCount+1; list ¬ vWorld.contextPool[screen]; FOR tail: ContextList ¬ list, tail.rest UNTIL tail=NIL DO context: Imager.Context ~ tail.first; IF context#NIL THEN { tail.first ¬ NIL; RETURN[context, list] }; ENDLOOP; vWorld.contextPoolOverflows[screen] ¬ vWorld.contextPoolOverflows[screen]+1; RETURN[NIL, NIL]; }; ReleaseContext: ENTRY PROC [context: Imager.Context, contextList: ContextList] ~ { IF context#NIL THEN FOR list: ContextList ¬ contextList, list.rest UNTIL list=NIL DO IF list.first=NIL THEN { list.first ¬ context; EXIT }; ENDLOOP; paintingCount ¬ paintingCount-1; IF paintingCount = 0 THEN BROADCAST FinishedPainting; }; PaintScreen: PUBLIC PROC [screen: Screen, action: PROC [context: Imager.Context], suspendCarets: BOOL ¬ TRUE] ~ { acquired, context: Imager.Context; list: ContextList; mustResumeCarets: BOOL ¬ FALSE; saveAction: PROC ~ { ImagerBackdoor.ViewReset[context]; IF suspendCarets THEN { Carets.SuspendCarets[]; mustResumeCarets ¬ TRUE; action[context]; mustResumeCarets ¬ FALSE; Carets.ResumeCarets[]; } ELSE action[context]; }; [acquired, list] ¬ AcquireContext[screen]; context ¬ acquired; IF context=NIL THEN context ¬ CreateContext[screen]; IF context#NIL THEN { Imager.DoSaveAll[context, saveAction ! UNWIND => { IF mustResumeCarets THEN Carets.ResumeCarets[]; ReleaseContext[acquired, list]; }; RuntimeError.Uncaught => IF ViewerErrors.Query[signal].continue THEN CONTINUE ]; }; ReleaseContext[acquired, list]; }; DoWithoutCaretsVisible: PROC [viewer: Viewer, action: PROC [context: Imager.Context], context: Imager.Context] ~ { proc: PROC ~ {action[context]}; v: Viewer ¬ viewer; UNTIL v.parent = NIL DO v ¬ v.parent ENDLOOP; ViewerPrivate.DoWithoutCarets[v.wx, v.wy, v.ww, v.wh, InlineViewerScreen[viewer], proc]; }; PaintWindow: PUBLIC PROC [viewer: Viewer, action: PROC [context: Imager.Context]] ~ { windowAction: PROC [context: Imager.Context] ~ { IF viewer.iconic AND (viewer.wy+viewer.wh)>openBottomY THEN ClipIcon[context]; SetView[context: context, viewer: viewer, client: FALSE]; DoWithoutCaretsVisible[viewer, action, context]; }; PaintScreen[InlineViewerScreen[viewer], windowAction, FALSE]; }; PaintClient: PUBLIC PROC [viewer: Viewer, action: PROC [context: Imager.Context]] ~ { clientAction: PROC [context: Imager.Context] ~ { SetView[context: context, viewer: viewer, client: TRUE]; DoWithoutCaretsVisible[viewer, action, context]; }; IF NOT viewer.iconic THEN PaintScreen[InlineViewerScreen[viewer], clientAction, FALSE]; }; SetView: PROC [context: Imager.Context, viewer: Viewer, client: BOOL] ~ { wx, wy: INTEGER; [wx, wy] ¬ ClipView[context, viewer, client]; ImagerBackdoor.ViewTranslateI[context, wx, wy]; }; ClipView: PROC [context: Imager.Context, viewer: Viewer, client: BOOL] RETURNS [wx, wy: INTEGER] ~ { parent: Viewer ~ viewer.parent; topDown: BOOL ~ (parent#NIL AND parent.class.topDownCoordSys); ww: INTEGER ¬ viewer.ww; wh: INTEGER ¬ viewer.wh; wx ¬ viewer.wx; wy ¬ IF topDown THEN parent.ch-(viewer.wy+wh) ELSE viewer.wy; IF parent # NIL THEN SetView[context: context, viewer: parent, client: TRUE]; IF client THEN { wx ¬ wx + viewer.cx; wy ¬ wy + viewer.cy; ww ¬ viewer.cw; wh ¬ viewer.ch; }; ImagerBackdoor.ViewClipRectangleI[context, wx, wy, ww, wh]; }; ClipIcon: PROC [context: Imager.Context] ~ { y: NAT ~ ViewerSpecs.openBottomY; h: NAT ~ ViewerSpecs.openTopY-y; Exclude: PROC [x, w: NAT] ~ { ImagerBackdoor.ViewClipRectangleI[context: context, x: x, y: y, w: w, h: h, exclude: TRUE]; }; IF ViewerPrivate.rootViewerTree[left]#NIL THEN Exclude[ViewerSpecs.openLeftLeftX, ViewerSpecs.openLeftWidth]; IF ViewerPrivate.rootViewerTree[right]#NIL THEN Exclude[ViewerSpecs.openRightLeftX, ViewerSpecs.openRightWidth]; }; desktopGrey: Imager.Color ¬ ImagerBackdoor.MakeStipple[104042B]; uniformGrey: Imager.Color ¬ Imager.MakeGray[0.4]; ColorScreen: PUBLIC PROC [screen: Screen, color: Imager.Color] = { colorAction: PROC [context: Imager.Context] ~ { Imager.SetColor[context, color]; Imager.MaskRectangleI[context, 0, 0, 9999, 9999]; }; PaintScreen[screen, colorAction]; }; GreyScreen: PUBLIC PROC [screen: Screen, x, y, w, h: INTEGER] ~ { greyAction: PROC [context: Imager.Context] ~ { Imager.SetColor[context, IF screen=main THEN desktopGrey ELSE uniformGrey]; Imager.MaskRectangleI[context, x, y, w, h]; }; PaintScreen[screen, greyAction]; }; GreyWindow: PUBLIC PROC [viewer: Viewer] ~ { screen: Screen ~ ViewerScreen[viewer]; greyAction: PROC [context: Imager.Context] ~ { wx, wy: INTEGER; IF viewer.iconic AND (viewer.wy+viewer.wh)>openBottomY THEN ClipIcon[context]; [wx, wy] ¬ ClipView[context: context, viewer: viewer, client: FALSE]; Imager.SetColor[context, IF screen=main THEN desktopGrey ELSE uniformGrey]; Imager.MaskRectangleI[context, wx, wy, viewer.ww, viewer.wh]; }; PaintScreen[screen, greyAction]; }; InvertForMenus: PUBLIC PROC [viewer: Viewer, x, y, w, h: INTEGER] = { invertAction: PROC [context: Imager.Context] ~ { Imager.SetColor[context, ImagerBackdoor.invert]; Imager.MaskRectangleI[context, x, y, w, h]; }; PaintWindow[viewer, invertAction]; }; BlinkOnce: PROC [viewer: Viewer, duration: Process.Ticks] ~ { LockedBlinkOnce: PROC ~ { blinkAction: PROC [context: Imager.Context] ~ { Imager.SetColor[context, ImagerBackdoor.invert]; Imager.MaskRectangleI[context, 0, 0, viewer.ww, viewer.wh]; Process.Pause[duration]; Imager.MaskRectangleI[context, 0, 0, viewer.ww, viewer.wh]; }; IF NOT viewer.visible OR viewer.destroyed THEN RETURN; PaintWindow[viewer, blinkAction]; }; ViewerLocks.CallUnderWriteLock[LockedBlinkOnce, viewer ! ViewerLocks.Wedged => CONTINUE]; }; BlinkViewer: PUBLIC PROC [viewer: Viewer, milliseconds: NAT ¬ 400] ~ { BlinkOnce[viewer, Process.MsecToTicks[milliseconds]]; }; BlinkIcon: PUBLIC PROC [viewer: Viewer, count: INT ¬ 1, secondsBetweenBlinks: NAT ¬ 2, millisecondsPerBlink: NAT ¬ 400] ~ { IF viewer.offDeskTop THEN ViewerOps.ChangeColumn[viewer, left]; TRUSTED { Process.Detach[ FORK BlinkProcess[viewer, count, secondsBetweenBlinks, millisecondsPerBlink]]; }; }; BlinkProcess: PROC [viewer: Viewer, count: INT, secondsBetweenBlinks, millisecondsPerBlink: NAT] ~ { ticksPerHalfSecond: Process.Ticks ~ Process.MsecToTicks[500]; ticksPerBlink: Process.Ticks ~ Process.MsecToTicks[millisecondsPerBlink]; DO BlinkOnce[viewer, ticksPerBlink]; IF count = 1 THEN RETURN; IF count > 0 THEN count ¬ count - 1; FOR i: NAT IN [0..2*secondsBetweenBlinks) DO -- check every half second. Process.Pause[ticksPerHalfSecond]; IF viewer.destroyed OR NOT viewer.iconic OR viewer=ViewerTools.GetSelectedViewer[] THEN RETURN; ENDLOOP; ENDLOOP; }; BlinkDisplay: PUBLIC PROC ~ { ViewersWorld.BlinkViewersWorld[ViewersWorldInstance.GetWorld[]]; }; lastKey: REF ¬ NIL; EmergencySaveAllEdits: PROC [key: REF] ~ { oneSecond: Process.Ticks ~ Process.SecondsToTicks[1]; CedarProcess.SetPriority[foreground]; lastKey ¬ key; WHILE key=lastKey DO vWorld: ViewersWorld.Ref; Process.Pause[oneSecond]; vWorld ¬ ViewersWorldInstance.GetWorld[]; IF vWorld # NIL THEN { handle: UserInput.Handle ~ ViewersWorld.GetInputHandle[vWorld]; IF handle # NIL THEN { Down: PROC [keySym: KeyTypes.KeySym] RETURNS [BOOL] ~ INLINE { RETURN [UserInputOps.GetLatestKeySymState[handle, keySym] = down]; }; IF Down[KeySymsKB.LeftShift] AND Down[KeySymsKB.RightShift] AND Down[KeySymsKB.R15] THEN { ViewerOps.SaveAllEdits[]; }; }; }; ENDLOOP; }; CheckForEmergencySaveAllEdits: PUBLIC PROC [] = { TRUSTED {Process.Detach[FORK EmergencySaveAllEdits[NEW[INT]]]}; }; END.  ViewerPaintImpl.mesa Copyright Σ 1985, 1986, 1987, 1988, 1989, 1991, 1992 by Xerox Corporation. All rights reserved. Michael Plass, March 15, 1992 5:03 pm PST Russ Atkinson (RRA) March 2, 1987 6:57:18 pm PST Doug Wyatt, June 27, 1988 1:29:35 pm PDT Bier, September 11, 1990 3:26 pm PDT Christian Jacobi, July 1, 1992 11:57 am PDT Willie-s, November 21, 1991 1:26 pm PST The intent of this crock is to show the file version for $Text viewers: if name is a prefix of file, show the remainder of file (presumably "!n") in parentheses client-painted caption Put a hook here for icon selection? -mfp  do we need to paint any of the children? recursively paint children these guys should be painted in reverse order for correct overlaps don't paint if it is completely within the blt map to the coodinate system that rect uses Protective stuff that is not required to be locked Used to call ViewerGroupLocks.CallRootUnderWriteLock but now ViewerLocks.CallUnderWriteLock is the same ChJ Returns the current context creator that is being used for the named screen. Note that bitsPerPixel is no longer used. EnableScreen: PUBLIC PROC [screen: Screen] RETURNS [ok: BOOL _ FALSE] ~ { inner: ENTRY PROC ~ { bounds: Imager.Rectangle _ [0, 0, 0, 0]; IF colorEnabled THEN RETURN; -- we need a per-screen bit here ViewerPrivate.SetScreenSize[w: vWorld.terminal.colorWidth, h: vWorld.terminal.colorHeight]; -- need per screen width and height THROUGH [0..8) DO context: Imager.Context ~ CreateContext[screen ! UNWIND, RuntimeError.Uncaught => ...]; IF context = NIL THEN RETURN; -- something wrong; bail out now. vWorld.contextPool[screen] _ CONS[context, vWorld.contextPool[screen]]; ENDLOOP; bounds _ ImagerBackdoor.GetBounds[vWorld.contextPool[screen].first]; IF bounds.w > 0 THEN ViewerPrivate.SetScreenSize[w: Real.Round[bounds.w], h: Real.Round[bounds.h], screen]; colorEnabled _ ok _ TRUE; }; vWorld: ViewersWorld.Ref _ ViewersWorldInstance.GetWorld[]; DisablePainting[wait: TRUE]; inner[! UNWIND, RuntimeError.Uncaught => EnablePainting[]]; EnablePainting[]; IF ok THEN GreyScreen[screen, 0, 0, 9999, 9999]; }; If we did this with carets running, we would run the risk of deadlock, since we need to AcquireContext to paint the caret, and paint procs might insist on touching the caret before they finish. Of course, we can still get in trouble if a paint proc calls PaintViewer . . . Caution: we assume that we have the viewer locked, yet PaintClient is exported to ViewerPrivate. The locking is now the caller's responsibility. Color the entire screen with the given color. Κ“–"cedarcode" style•NewlineDelimiter ™codešœ™Kšœ ΟeœU™`K™)K™0K™(K™$K™+K™'K™—šΟk ˜ Kšœžœ ˜Kšœžœ˜+Kšœ žœ˜!Kšœžœ ˜KšœžœŒ˜˜KšœžœQ˜eK˜ Kšœ ˜ Kšœžœ5˜BKšœžœ ˜Kšœžœ$˜1Kšœžœ žœ˜Kšœ žœ ˜K˜ K˜ Kšœžœ"˜.Kšœžœ˜-Kšœ žœ ˜Kšœ žœ˜/Kšœ žœH˜WKšœ˜Kšœ ˜ K˜ K˜Kšœ˜K˜Kšœ žœ˜&—K˜šΠblœžœž˜Kšžœο˜φKšžœ.˜5Kšžœ)˜/Kšœžœžœ'˜3—˜Kšœžœ$˜˜>—šœ˜Kšœ=˜=—šœ˜Kšœ;˜;—Kšžœ˜—šžœ žœž˜Kšœ:˜:—Kšžœ ˜K˜K˜—š  œžœ.˜@Kš œžœžœžœžœ˜=šžœž˜šžœ˜Kšœ™Kšœžœ˜Kšœžœ˜%Kšœžœ˜Kšœžœ˜šœžœ˜K˜K˜K˜+K˜&Kšœ˜—K˜"Kšœ˜—šžœ˜Kšœžœžœ˜)K˜'Kšœ5˜5Kšœ5˜5Kšœ5˜5Kšœ/˜/Kš œžœžœžœžœ˜=Kšœžœ˜Kšœžœ˜Kšœ žœ˜Kšœ žœ=˜MKšœ žœ˜(Kšœ"˜"K˜@Kšœ$˜$šžœžœ˜Kšœ%˜%KšœT˜TKšœ˜—K˜šžœžœ˜!Kšœ%˜%Kšœ?˜?Kšœ!˜!Kšœ?˜?Kšœ!˜!Kšœ˜—Kšœ%˜%Kšœ=˜=Kšœ!˜!Kšœ˜——K˜K˜—š  œžœžœžœ˜:šžœ*žœž˜9Kšœžœ ˜&Kš žœžœžœžœžœ˜N—Kšœ˜K˜—š  œžœ3žœ žœžœ˜|Kšžœ žœ˜0šžœžœ žœžœ˜*Kš œžœžœžœžœ˜=Kšœžœ˜Kšœžœ˜Kšœžœ$˜.Kšœžœ˜'šžœ žœžœ˜šžœžœžœ˜K˜'K˜+Kšœ˜—K˜'K˜8Kšœ˜—KšœB˜BK˜—Kšœ˜K˜—š   œžœ0žœžœžœ˜Qšœ žœ˜.KšΟtœ#‘™+šžœžœž˜šœ˜Kšœ@˜@K˜—šœ˜Kšœžœžœ˜2Kšœžœ˜#Kšœ žœK˜Yšžœ ž˜Kšœ žœžœ˜6Kšœžœžœžœ˜:Kšžœ˜—Kšœ$˜$šžœ#žœ˜+Kšœ0˜0K˜Kšœžœžœžœ˜!K˜;Kšœžœ˜!šžœ ž˜KšœP˜PKšœžœ˜Kšžœ˜—Kšœ ˜ Kšœ˜K˜—š œžœžœ˜%Kšœ˜Kšœ˜K˜—š  œžœžœ6žœ˜ršœžœžœ˜Kšœ˜Kšœ˜Kšœ˜Kšžœžœ˜*K˜—K˜;Kšœžœ˜Kšœ˜Kšœ˜Kšœ˜K˜—š œžœžœ žœ˜Ušœžœžœ˜Kšœ˜K˜—K˜;Kšœžœ˜Kšœ˜˜ Kšžœœ˜Kšœžœ%žœžœ˜NK˜—Kšœ˜Kšœ˜K˜—š œžœžœžœ˜TK™LK˜;Kšœ˜K˜K˜—š  œžœžœžœ ˜?Kšžœ˜#Kšœ˜K˜—š œžœžœ ˜>Kš žœžœžœžœžœžœ˜JKšœ˜K˜—Kšœžœžœ˜K˜š  œžœžœžœžœžœžœ˜KKšœ)™)šœžœžœ˜K˜(Kšžœžœžœ˜Kšœ.Πbfœ £œ˜cšžœž˜˜0Kšžœžœœ˜Kšœžœ%žœžœ˜OK˜—Kš žœ žœžœžœ’!˜?Kšœžœ%˜EKšžœ˜—KšœC˜CKšžœžœT˜hKšœžœ˜Kšžœ ˜K˜—K˜;Kšœžœ˜Kšœ˜Kšœ˜šžœžœ˜ Kšœ$˜$K˜—Kšœ˜K˜—š   œžœžœžœžœžœ™Išœžœžœ™K™(Kšžœžœžœ"™=Kšœ\’#™šžœž™K™WKš žœ žœžœžœ’!™?Kšœžœ&™GKšžœ™—KšœD™DKšžœžœW™kKšœžœ™K™—Kšœ;™;Kšœžœ™Kšœžžžœ+™;Kšœ™Kšžœžœ&™0Kšœ™K™—š  œžœžœ˜šœžœžœ˜Kšœžœ˜ Kšœžœ˜K˜—K˜;Kšœžœ˜Kšœ˜Kšœ˜Kšœ˜K˜—Kšœžœ’˜Kšœž œ’'˜CK˜š  œžœžœžœžœ˜4šœžœžœ˜Kšœ‘™‘K˜Kš žœžœžœžœžœžœ˜DKšœ˜—Kšœ˜Kšœ ˜ Kšœ˜Kšœ˜K˜—š œžœžœžœ˜%šžœ˜Kšžœ˜"Kšžœž œ˜3—Kšœ˜K˜—š œžœžœžœ˜.Kšžœžœžœžœ˜7Kšœ˜K˜—š œžœžœžœ"˜UKšœ˜K˜;Kšžœžœžœžœ˜5Kšœ ˜ Kšœ"˜"šžœ%žœžœž˜9Kšœ%˜%Kš žœ žœžœžœžœ˜@Kšžœ˜—KšœL˜LKšžœžœžœ˜K˜K˜—š œžœžœ8˜Ršžœ žœž˜šžœ,žœžœž˜@Kšžœ žœžœžœ˜6Kšžœ˜——Kšœ ˜ Kšžœžœž œ˜5K˜—K˜š   œžœžœžœ,žœžœ˜rKšœ"˜"Kšœ˜Kšœžœžœ˜šœ žœ˜Kšœ"˜"šžœ˜šžœ˜Kšœ˜Kšœžœ˜K˜Kšœžœ˜Kšœ˜Kšœ˜—Kšžœ˜—Kšœ˜—Kšœ*˜*Kšœ˜Kšžœ žœžœ!˜4šžœ žœžœ˜˜'šžœ˜ Kšžœžœ˜0K˜K˜—Kšœžœ%žœž˜MK˜—K˜—Kšœ˜K˜K˜—š œžœžœ8˜rKšœžœ˜Kšœ˜Kšžœ žœžœžœ˜-KšœX˜XK˜K˜—š  œžœžœžœ˜Ušœžœ˜0Kšžœžœ#žœ˜NKšœ2žœ˜9Kšœ0˜0K˜—Kšœ6žœ˜=K˜K˜—š  œžœžœžœ˜UKšœ‘™‘šœžœ˜0Kšœ2žœ˜8Kšœ0˜0K˜—šžœžœž˜Kšœ6žœ˜=—K˜K˜—š œžœ3žœ˜IKšœžœ˜Kšœ-˜-Kšœ/˜/Kšœ˜K˜—š  œžœ3žœžœ žœ˜dK˜Kšœ žœ žœžœ˜>Kšœžœ ˜Kšœžœ ˜Kšœ˜Kšœžœ žœžœ ˜=Kšžœ žœžœ3žœ˜Mšžœžœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜—Kšœ;˜;Kšœ˜K˜—š œžœ˜,Kšœžœ˜!Kšœžœ˜ š œžœžœ˜KšœUžœ˜[Kšœ˜—šžœ$žœž˜.Kšœ>˜>—šžœ%žœž˜/Kšœ@˜@—Kšœ˜K˜—Kšœ@˜@šœ1˜1K˜—š  œžœžœ*˜BK™-šœ žœ˜/Kšœ ˜ K˜1K˜—Kšœ!˜!K˜K˜—š  œžœžœžœ˜Ašœ žœ˜.Kšœžœ žœ žœ˜KK˜+K˜—Kšœ ˜ K˜K˜—š  œžœžœ˜,Kšœ&˜&šœ žœ˜.Kšœžœ˜Kšžœžœ#žœ˜NKšœ>žœ˜EKšœžœ žœ žœ˜KKšœ=˜=K˜—Kšœ ˜ K˜—K˜š œžœžœžœ˜Ešœžœ˜0Kšœ0˜0Kšœ+˜+K˜—K˜"Kšœ˜K˜—š  œžœ.˜=š œžœ˜šœ žœ˜/Kšœ0˜0K˜;Kšœ˜K˜;K˜—Kš žœžœžœžœžœ˜6K˜!K˜—šœ6˜6Kšœžœ˜"—Kšœ˜K˜—š  œžœžœ žœ ˜FKšœ5˜5Kšœ˜K˜—š   œžœžœžœžœžœ ˜|Kšžœžœ&˜?šžœ˜ šœ˜KšžœJ˜N—Kšœ˜—Kšœ˜K˜—š  œžœžœ/žœ˜eKšœ=˜=KšœI˜Išž˜Kšœ!˜!Kšžœ žœžœ˜Kšžœ žœ˜$š žœžœžœžœ’˜HKšœ"˜"šžœžœžœ˜)Kšžœ(žœžœ˜6—Kšžœ˜—Kšžœ˜—Kšœ˜K˜—K˜š  œžœžœ˜K˜@K˜K˜—Kšœ žœžœ˜š œžœžœ˜*K˜5Kšœ%˜%K˜šžœ ž˜K˜K˜K˜)šžœ žœžœ˜K˜?šžœ žœžœ˜š  œžœžœžœžœ˜>Kšžœ<˜BK˜—š žœžœžœžœžœ˜ZK˜K˜—K˜—K˜—Kšžœ˜—Kšœ˜K˜—š œžœžœ˜1Kšžœžœžœžœ˜?˜K˜——Kšžœ˜—…—T΄y]