DIRECTORY Carets USING [ResumeCarets, SuspendCarets], CaretsExtras USING [DoWithoutCarets], CedarProcess USING [SetPriority], Icons USING [DrawIcon], Imager USING [black, ClipRectangleI, Color, Context, DoSaveAll, MakeGray, MaskRectangleI, SetColor, SetFont, SetXYI, ShowText, Trans, white], ImagerBackdoor USING [invert, MakeStipple, ViewClipRectangleI, ViewReset, ViewTranslateI], ImagerTerminal USING [BWContext, ColorContext, SetStandardColorMap], InterminalBackdoor USING [terminal], Menus USING [], Process USING [Detach, MsecToTicks, Pause, SecondsToTicks, Ticks], RefText USING [AppendRope, ObtainScratch, ReleaseScratch, TrustTextAsRope], Rope USING [Length, ROPE, Run], Terminal, VFonts USING [defaultFont, Font, StringWidth], ViewerClasses USING [PaintRectangle, Viewer], ViewerLocks USING [CallUnderWriteLock, Wedged], ViewerGroupLocks USING [CallRootUnderWriteLock], ViewerOps USING [ChangeColumn, FetchProp, PaintHint, SaveAllEdits, UserToScreenCoords], ViewerPrivate, ViewerSpecs, ViewerTools USING [GetSelectedViewer]; ViewerPaintImpl: CEDAR MONITOR IMPORTS Carets, CaretsExtras, CedarProcess, Icons, Imager, ImagerBackdoor, ImagerTerminal, InterminalBackdoor, Process, RefText, Rope, Terminal, VFonts, ViewerGroupLocks, ViewerLocks, ViewerOps, ViewerPrivate, ViewerSpecs, ViewerTools EXPORTS ViewerOps, ViewerPrivate SHARES Menus, ViewerClasses, ViewerLocks ~ BEGIN OPEN ViewerClasses, ViewerOps, ViewerSpecs; ContextCreatorProc: TYPE ~ ViewerPrivate.ContextCreatorProc; ROPE: TYPE ~ Rope.ROPE; DoWithScratchText: PROC[len: NAT, action: PROC[REF TEXT]] ~ { scratch: REF TEXT ~ RefText.ObtainScratch[len]; action[scratch ! UNWIND => RefText.ReleaseScratch[scratch]]; RefText.ReleaseScratch[scratch]; }; captionAscent: NAT _ 9; 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 { name: ROPE ~ viewer.name; nameLen: INT ~ Rope.Length[name]; file: ROPE ~ viewer.file; fileLen: INT ~ Rope.Length[file]; action: PROC[header: REF TEXT] ~ { font: VFonts.Font ~ VFonts.defaultFont; headerW: INTEGER _ 0; 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]"]; headerW _ VFonts.StringWidth[RefText.TrustTextAsRope[header], font]; headerW _ MIN[headerW, viewer.ww-wbs*2]; Imager.SetColor[context, Imager.black]; Imager.MaskRectangleI[context, 0, viewer.wh, viewer.ww, -captionHeight]; Imager.SetColor[context, Imager.white]; Imager.SetXYI[context, (viewer.ww-headerW)/2, viewer.wh-captionAscent]; Imager.SetFont[context, font]; Imager.ShowText[context, header]; }; DoWithScratchText[100, action]; }; }; 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 ~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; } 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 {PaintIcon[viewer, hint, whatChanged ! ABORTED => CONTINUE]; 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 ! ABORTED => CONTINUE; InvisiblePaint => CONTINUE ]; }; IF viewer = NIL OR viewer.destroyed OR viewer.paintingWedged THEN RETURN; ViewerGroupLocks.CallRootUnderWriteLock[LocalPaintViewer, viewer ! ViewerLocks.Wedged => {viewer.paintingWedged _ TRUE; CONTINUE}]; }; terminal: Terminal.Virtual _ InterminalBackdoor.terminal; Screen: TYPE ~ ViewerPrivate.Screen; CreateContext: PUBLIC PROC [screen: Screen] RETURNS [context: Imager.Context] ~ { RETURN [ContextCreator[screen]]; }; ContextCreator: PROC [screen: Screen] RETURNS [context: Imager.Context] _ DefaultCreateContext; DefaultCreateContext: PROC [screen: Screen] RETURNS [context: Imager.Context] ~ { SELECT screen FROM bw => context _ ImagerTerminal.BWContext[vt: terminal, pixelUnits: TRUE]; color => context _ ImagerTerminal.ColorContext[vt: terminal, pixelUnits: TRUE]; ENDCASE => ERROR; }; ContextList: TYPE ~ LIST OF Imager.Context; contextPool: ARRAY Screen OF ContextList _ ALL[NIL]; contextPoolOverflows: ARRAY Screen OF INT _ ALL[0]; Init: ENTRY PROC ~ { [] _ Terminal.SetBWBitmapState[terminal, allocated]; ViewerPrivate.SetBWScreenSize[w: terminal.bwWidth, h: terminal.bwHeight]; THROUGH [0..8) DO context: Imager.Context ~ CreateContext[bw]; contextPool[bw] _ CONS[context, contextPool[bw]]; ENDLOOP; }; AllocBWContexts: INTERNAL PROC ~ { contextPool[bw] _ NIL; THROUGH [0..8) DO context: Imager.Context ~ CreateContext[bw]; contextPool[bw] _ CONS[context, contextPool[bw]]; ENDLOOP; }; AllocColorContexts: INTERNAL PROC ~ { contextPool[color] _ NIL; THROUGH [0..4) DO context: Imager.Context ~ CreateContext[color]; contextPool[color] _ CONS[context, contextPool[color]]; ENDLOOP; }; SetCreator: PUBLIC PROC [creator: ContextCreatorProc] RETURNS [old: ContextCreatorProc] ~ { inner: ENTRY PROC ~ { old _ ContextCreator; ContextCreator _ IF creator=CreateContext OR creator=NIL THEN DefaultCreateContext ELSE creator; AllocBWContexts[]; IF colorEnabled THEN AllocColorContexts[]; }; DisablePainting[wait: TRUE]; inner[! UNWIND => EnablePainting[]]; EnablePainting[]; }; colorEnabled: BOOL _ FALSE; ColorModeFromBitsPerPixel: PROC [bitsPerPixel: NAT] RETURNS [Terminal.ColorMode] ~ { SELECT bitsPerPixel FROM IN[0..8] => RETURN[[bitsPerPixelChannelA: bitsPerPixel]]; 24 => RETURN[[full: TRUE]]; ENDCASE => RETURN[[FALSE, 0, 0]]; }; EnableColor: PUBLIC PROC [bitsPerPixel: NAT] RETURNS [ok: BOOL _ FALSE] ~ { inner: ENTRY PROC ~ { mode: Terminal.ColorMode ~ ColorModeFromBitsPerPixel[bitsPerPixel]; IF colorEnabled THEN RETURN; IF NOT Terminal.LegalColorMode[terminal, mode] THEN RETURN; [] _ Terminal.SetColorBitmapState[vt: terminal, newState: allocated, newMode: mode, newVisibility: all]; ViewerPrivate.SetColorScreenSize[w: terminal.colorWidth, h: terminal.colorHeight]; ImagerTerminal.SetStandardColorMap[terminal]; THROUGH [0..4) DO context: Imager.Context ~ CreateContext[color]; contextPool[color] _ CONS[context, contextPool[color]]; ENDLOOP; ok _ colorEnabled _ TRUE; }; DisablePainting[wait: TRUE]; inner[! UNWIND => EnablePainting[]]; EnablePainting[]; IF ok THEN { GreyScreen[color, 0, 0, 9999, 9999]; Terminal.TurnOnColorDisplay[terminal]; }; }; DisableColor: PUBLIC PROC ~ { inner: ENTRY PROC ~ { IF NOT colorEnabled THEN RETURN; [] _ Terminal.SetColorBitmapState[vt: terminal, newState: none, newMode: [FALSE, 0, 0], newVisibility: all]; THROUGH [0..3) DO contextPool[color] _ NIL; ENDLOOP; colorEnabled _ FALSE; }; DisablePainting[wait: TRUE]; inner[! UNWIND => EnablePainting[]]; 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>0 THEN paintingLock _ paintingLock-1; IF paintingLock=0 THEN BROADCAST PaintingEnabled; }; WaitForPaintingToFinish: PUBLIC ENTRY PROC ~ { WHILE paintingCount>0 DO WAIT FinishedPainting ENDLOOP; }; AcquireContext: ENTRY PROC [screen: Screen] RETURNS [Imager.Context] ~ { WHILE paintingLock>0 DO WAIT PaintingEnabled ENDLOOP; paintingCount _ paintingCount+1; FOR list: ContextList _ contextPool[screen], list.rest UNTIL list=NIL DO context: Imager.Context ~ list.first; IF context#NIL THEN { list.first _ NIL; RETURN[context] }; ENDLOOP; contextPoolOverflows[screen] _ contextPoolOverflows[screen]+1; RETURN[NIL]; }; ReleaseContext: ENTRY PROC [screen: Screen, context: Imager.Context] ~ { IF context#NIL THEN FOR list: ContextList _ contextPool[screen], list.rest UNTIL list=NIL DO IF list.first=NIL THEN { list.first _ context; EXIT }; ENDLOOP; paintingCount _ paintingCount-1; NOTIFY FinishedPainting; }; PaintScreen: PUBLIC PROC [screen: Screen, action: PROC [context: Imager.Context], suspendCarets: BOOL _ TRUE] ~ { acquired: Imager.Context ~ AcquireContext[screen]; context: Imager.Context _ acquired; saveAction: PROC ~ { ImagerBackdoor.ViewReset[context]; IF suspendCarets THEN Carets.SuspendCarets[]; action[context ! UNWIND => IF suspendCarets THEN Carets.ResumeCarets[]]; IF suspendCarets THEN Carets.ResumeCarets[]; }; IF context=NIL THEN context _ CreateContext[screen]; Imager.DoSaveAll[context, saveAction ! UNWIND => ReleaseContext[screen, acquired]]; ReleaseContext[screen, acquired]; }; 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; CaretsExtras.DoWithoutCarets[v.wx, v.wy, v.ww, v.wh, ViewerPrivate.ViewerScreen[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[ViewerPrivate.ViewerScreen[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[ViewerPrivate.ViewerScreen[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]; GreyScreen: PUBLIC PROC [screen: Screen, x, y, w, h: INTEGER] ~ { greyAction: PROC [context: Imager.Context] ~ { Imager.SetColor[context, IF screen=bw THEN desktopGrey ELSE uniformGrey]; IF screen=bw THEN Imager.SetColor[context, desktopGrey] ELSE Imager.SetColor[context, uniformGrey]; Imager.MaskRectangleI[context, x, y, w, h]; }; PaintScreen[screen, greyAction]; }; GreyWindow: PUBLIC PROC [viewer: Viewer] ~ { screen: Screen ~ ViewerPrivate.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]; IF screen=bw THEN Imager.SetColor[context, desktopGrey] ELSE Imager.SetColor[context, 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 ~ { Terminal.BlinkBWDisplay[terminal]; }; EmergencySaveAllEdits: PROC ~ { CedarProcess.SetPriority[foreground]; DO -- forever keys: Terminal.KeyBits ~ terminal.GetKeys[]; IF keys[LeftShift]=down AND keys[RightShift]=down AND keys[Spare3]=down THEN ViewerOps.SaveAllEdits[]; Process.Pause[Process.SecondsToTicks[1]]; ENDLOOP; }; Init[]; GreyScreen[bw, 0, 0, 9999, 9999]; [] _ Terminal.SetBWBitmapState[terminal, displayed]; Terminal.Select[terminal]; TRUSTED {Process.Detach[FORK EmergencySaveAllEdits[]]}; END. TViewerPaintImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Michael Plass, November 21, 1985 11:48:50 am PST Doug Wyatt, May 21, 1985 9:32:28 am PDT Russ Atkinson (RRA) July 1, 1985 6:49:06 pm PDT client-painted caption 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 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 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. Κ.– "Mesa" style˜codešœ™Kšœ Οmœ1™˜KKšœžœ žœ˜Kšœ ˜ Kšœžœ"˜.Kšœžœ˜-Kšœ žœ˜/Kšœžœ˜0Kšœ žœH˜WKšœ˜Kšœ ˜ Kšœ žœ˜&—K˜šΠblœžœž˜Kšžœγ˜κKšžœ˜ Kšžœ"˜(Kšœžœžœ'˜3—˜Kšœžœ$˜˜>—šœ˜Kšœ=˜=—šœ˜Kšœ;˜;—Kšžœ˜—šžœ žœž˜Kšœ:˜:—K˜KšœD˜DKšœ žœ˜(K˜'K˜HK˜'K˜GK˜Kšœ!˜!K˜—K˜Jšœ˜——J˜J˜—š  œžœ3žœ žœžœ˜|Kšžœ žœ˜0šžœžœ žœžœ˜*Jš œžœžœžœžœ˜=Jšœžœ˜Jšœžœ˜Jšœžœ$˜.Jšœžœ˜'šžœ žœžœ˜šžœžœ˜K˜'K˜+Kšœ˜—K˜'K˜8Kšœ˜—KšœB˜BK˜—Kšœ˜K˜—š   œžœ0žœžœžœ˜Qšœ žœ˜.šžœžœž˜šœ˜Kšœ@˜@—šœ˜Kšœžœžœ˜2Kšœžœ˜#Kšœ žœK˜Yšžœ ž˜Kšœ žœžœ˜6Kšœžœžœžœ˜:Kšžœ˜—Kšœ$˜$šžœ#žœ˜+Kšœ0˜0K˜Kšœž œ‘'˜CK˜š  œžœžœžœžœ˜4šœžœžœ˜Kšœ‘™‘K˜Kš žœžœžœžœžœžœ˜DKšœ˜—Kšœ˜Kšœ ˜ Kšœ˜Kšœ˜K˜—š œžœžœžœ˜%Kšžœžœ˜5Kšžœžœž œ˜1Kšœ˜K˜—š œžœžœžœ˜.Kšžœžœžœžœ˜7Kšœ˜K˜—š œžœžœžœ˜HKšžœžœžœžœ˜5Kšœ ˜ šžœ4žœžœž˜HKšœ%˜%Kš žœ žœžœžœžœ ˜:Kšžœ˜—K˜>Jšžœžœ˜ K˜K˜—š œžœžœ.˜Hšžœ žœž˜šžœ4žœžœž˜HKšžœ žœžœžœ˜6Kšžœ˜——Kšœ ˜ Kšžœ˜K˜K˜—K˜š   œžœžœžœ,žœžœ˜rKšœ2˜2Kšœ#˜#šœ žœ˜Kšœ"˜"Kšžœžœ˜-Kšœžœžœžœ˜HKšžœžœ˜,Kšœ˜—Kšžœ žœžœ!˜4Kšœ'žœ&˜SKšœ!˜!K˜K˜—š œžœžœ8˜rKšœžœ˜Kšœ˜Kšžœ žœžœžœ˜-Kšœ_˜_K˜K˜—š  œžœžœžœ˜Ušœžœ˜0Kšžœžœ#žœ˜NKšœ2žœ˜9Kšœ0˜0K˜—Kšœ>žœ˜EK˜K˜—š  œžœžœžœ˜UKšœ‘™‘šœžœ˜0Kšœ2žœ˜8Kšœ0˜0K˜—Kšžœžœžœ?žœ˜_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˜—š  œžœžœžœ˜Ašœ žœ˜.Kšœžœ žœ žœ˜IKšžœ ˜ Kšžœ&˜*Kšžœ'˜+K˜+K˜—Kšœ ˜ K˜K˜—š  œžœžœ˜,Kšœ4˜4šœ žœ˜.Kšœžœ˜Kšžœžœ#žœ˜NKšœ>žœ˜EKšžœ žœ&˜7Kšžœ'˜+Kšœ=˜=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šœ%˜%šžœ‘ ˜ Kšœ,˜,šžœžœžœž˜LK˜—K˜)Kšžœ˜—Kšœ˜—K˜K˜Kšœ!˜!K˜4K˜Kšžœžœ˜7K˜Kšžœ˜—…—M@hΒ