<> <> <<>> DIRECTORY Carets USING [ResumeCarets, SuspendCarets], Cursors USING [InvertCursor], InputFocus USING [GetInputFocus, SetInputFocus], Menus USING [CopyMenu, Menu], Process USING [GetPriority, Priority, priorityForeground, SetPriority], RefTab USING [Create, Fetch, Ref, Store], Rope USING [Compare, ROPE], RTOS USING [GetCurrent, RegisterCedarProcess, UnregisterCedarProcess], TIPUser USING [TIPScreenCoords], ViewerEvents USING [ProcessEvent], ViewerOps, ViewerLocks, ViewerClasses, ViewerSpecs, WindowManager USING [colorDisplayOn], WindowManagerPrivate; ViewerOpsImplB: CEDAR PROGRAM IMPORTS Carets, Cursors, InputFocus, Menus, Process, RefTab, Rope, RTOS, ViewerEvents, ViewerLocks, ViewerOps, WindowManager, WindowManagerPrivate EXPORTS ViewerOps SHARES Menus, ViewerEvents = BEGIN OPEN ViewerClasses, ViewerSpecs, ViewerOps, WindowManager; classTable: RefTab.Ref _ RefTab.Create[mod:50]; -- hold viewer classes RegisterViewerClass: PUBLIC PROC [flavor: ViewerFlavor, class: ViewerClass] = { class.flavor _ flavor; [] _ RefTab.Store[classTable, flavor, class]}; <> FetchViewerClass: PUBLIC PROC [flavor: ViewerFlavor] RETURNS [ViewerClass] = {IF flavor = $TypeScript THEN flavor _ $Typescript; RETURN[NARROW[RefTab.Fetch[classTable, flavor].val]]}; <> <<>> EnumerateViewers: PUBLIC PROC [enum: EnumProc] = BEGIN <> FOR c: Column DECREASING IN Column DO -- decreasing so will try static viewers last v: Viewer _ WindowManagerPrivate.rootViewerTree[c]; next: Viewer; UNTIL v=NIL DO next _ v.sibling; IF ~enum[v] THEN RETURN; v _ next; ENDLOOP; ENDLOOP; END; EnumerateChildren: PUBLIC PROC [viewer: Viewer, enum: EnumProc] = BEGIN v: Viewer _ viewer.child; next: Viewer; WHILE v#NIL DO next _ v.sibling; EnumerateChildren[v, enum]; IF ~enum[v] THEN RETURN; v _ next; ENDLOOP; END; FindViewer: PUBLIC PROC [name: Rope.ROPE] RETURNS [viewer: Viewer] = BEGIN MatchName: EnumProc = BEGIN IF Rope.Compare[name, v.name, FALSE]=equal THEN BEGIN viewer _ v; RETURN[FALSE]; END ELSE RETURN[TRUE]; END; EnumerateViewers[MatchName]; END; <<>> SaveViewer: PUBLIC PROC [viewer: Viewer] = BEGIN list: LIST OF Viewer; LockedStart: PROC = { FOR v: Viewer _ viewer, v.link DO v.saveInProgress _ TRUE; PaintViewer[v, caption, FALSE]; list _ CONS[v, list]; IF v.link = NIL OR v.link = viewer THEN EXIT; ENDLOOP}; LockedStop: PROC = { FOR saved: LIST OF Viewer _ list, saved.rest UNTIL saved = NIL DO v: Viewer = saved.first; IF v.destroyed THEN LOOP; v.newVersion _ v.newFile _ v.saveInProgress _ FALSE; PaintViewer[v, caption, FALSE]; [] _ ViewerEvents.ProcessEvent[save, v, FALSE]; ENDLOOP}; FOR v: Viewer _ viewer, v.link DO IF ViewerEvents.ProcessEvent[save, v, TRUE].abort THEN RETURN; IF v.link = NIL OR v.link = viewer THEN EXIT; ENDLOOP; <> LockedStart[]; IF viewer.class.save#NIL THEN viewer.class.save[viewer]; LockedStop[]; END; RestoreViewer: PUBLIC PROC [viewer: Viewer] = BEGIN DoOne: PROC [v: Viewer] = INLINE BEGIN KillInputFocus[v]; IF v.class.init # NIL THEN v.class.init[v]; v.newVersion _ v.newFile _ FALSE; PaintViewer[v, all]; END; DoOne[viewer]; IF viewer.link#NIL THEN FOR v: Viewer _ viewer.link, v.link UNTIL v=viewer DO DoOne[v]; ENDLOOP; END; KillInputFocus: PROC [viewer: Viewer] = BEGIN focus: Viewer _ InputFocus.GetInputFocus[].owner; WHILE focus # NIL DO IF focus # viewer THEN focus _ focus.parent ELSE {InputFocus.SetInputFocus[]; EXIT}; ENDLOOP; END; SetMenu: PUBLIC PROC [viewer: Viewer, menu: Menus.Menu, paint: BOOL _ TRUE] = BEGIN sameSize: BOOL = (menu#NIL AND viewer.menu#NIL AND viewer.menu.linesUsed=menu.linesUsed); IF viewer.iconic THEN paint _ FALSE; IF viewer.parent#NIL THEN ERROR; viewer.menu _ IF menu=NIL THEN NIL ELSE Menus.CopyMenu[menu]; IF ~sameSize AND paint THEN EstablishViewerPosition[viewer, viewer.wx, viewer.wy, viewer.ww, viewer.wh]; IF paint THEN PaintViewer[viewer, IF sameSize THEN menu ELSE all]; END; IndicateNewVersion: PUBLIC PROC [viewer: Viewer] = BEGIN link1, link2: Viewer; LockedNewVersion: PROC = { FOR v: Viewer _ viewer, v.link DO v.newVersion _ TRUE; PaintViewer[v, caption]; [] _ ViewerEvents.ProcessEvent[edit, v, FALSE]; IF v.link = NIL OR v.link = viewer THEN EXIT; ENDLOOP}; FOR v: Viewer _ viewer, v.link DO IF ViewerEvents.ProcessEvent[edit, v, TRUE].abort THEN RETURN; IF v.link = NIL OR v.link = viewer THEN EXIT; ENDLOOP; IF viewer # NIL THEN link1 _ viewer.link; IF link1 # NIL THEN link2 _ link1.link; ViewerLocks.CallUnderReadLocks[LockedNewVersion, viewer, link1, link2]; END; SetNewFile: PUBLIC PROC [viewer: Viewer] = BEGIN DoOne: PROC [v: Viewer] = BEGIN v.newFile _ TRUE; PaintViewer[v, caption]; END; DoOne[viewer]; IF viewer.link#NIL THEN FOR v: Viewer _ viewer.link, v.link UNTIL v=viewer DO DoOne[v]; ENDLOOP; END; SetOpenHeight: PUBLIC PROC [viewer: Viewer, clientHeight: INTEGER] = BEGIN overhead: INTEGER _ captionHeight + (IF viewer.border THEN windowBorderSize ELSE 0); IF viewer.menu#NIL THEN overhead _ overhead+(viewer.menu.linesUsed*menuHeight)+menuBarHeight; viewer.openHeight _ clientHeight+overhead; END; SaveAllEdits: PUBLIC PROC = BEGIN <> old: Process.Priority = Process.GetPriority[]; Save: EnumProc = BEGIN Cursors.InvertCursor[]; IF (v.newVersion OR v.newFile) AND v.class.save # NIL THEN v.class.save[v, TRUE ! ANY => CONTINUE]; v.newVersion _ v.newFile _ FALSE; IF v.icon=dirtyDocument THEN v.icon _ document; IF v.link#NIL THEN FOR t: Viewer _ v.link, t.link UNTIL t=v DO t.newVersion _ t.newFile _ FALSE; ENDLOOP; Cursors.InvertCursor[]; RETURN[TRUE]; END; IF old>Process.priorityForeground THEN TRUSTED BEGIN -- called from CoPilot Process.SetPriority[Process.priorityForeground]; RTOS.RegisterCedarProcess[RTOS.GetCurrent[]]; END; EnumerateViewers[Save]; IF old>Process.priorityForeground THEN TRUSTED BEGIN -- called from CoPilot RTOS.UnregisterCedarProcess[RTOS.GetCurrent[]]; Process.SetPriority[old]; END; END; PaintEverything: PUBLIC PROC = BEGIN OPEN Process; ResetPaintCache[]; Carets.SuspendCarets[]; GreyScreen[0, 0, 9999, 9999, FALSE, FALSE]; ComputeColumn[static]; ComputeColumn[left]; ComputeColumn[right]; IF WindowManager.colorDisplayOn THEN ComputeColumn[color]; WaitForPaintingToFinish[]; Carets.ResumeCarets[]; END; UserToScreenCoords: PUBLIC PROC [self: Viewer, vx, vy: INTEGER _ 0] RETURNS [sx, sy: INTEGER] = BEGIN invert: BOOL; UNTIL self=NIL DO -- compute enclosing viewer offsets invert _ IF self.parent=NIL THEN self.class.coordSys=top ELSE self.class.coordSys#self.parent.class.coordSys; vx _ vx + self.cx; IF invert THEN vy _ Top2Bottom[self, vy]; vy _ vy + self.cy; self _ self.parent; ENDLOOP; RETURN [vx, vy]; END; MouseInViewer: PUBLIC PROC [tsc: TIPUser.TIPScreenCoords] RETURNS [viewer: Viewer, client: BOOL] = BEGIN ENABLE UNWIND => NULL; x: INTEGER _ tsc.mouseX; y: INTEGER _ tsc.mouseY; invert: BOOL; TopLevelHit: PROC RETURNS [Viewer] = BEGIN FOR c: Column DECREASING IN Column DO FOR v: Viewer _ WindowManagerPrivate.rootViewerTree[c], v.sibling UNTIL v=NIL DO IF ViewerHit[v] THEN RETURN[v]; ENDLOOP; REPEAT FINISHED => RETURN[NIL]; ENDLOOP; END; ViewerHit: PROC [v: Viewer] RETURNS [BOOL] = INLINE {RETURN[x IN [v.wx..v.wx+v.ww) AND y IN [v.wy..v.wy+v.wh) AND (IF tsc.color THEN (v.column=color AND ~v.iconic) ELSE (v.column#color OR v.iconic))]}; Client: PROC RETURNS [BOOL] = INLINE {RETURN[y IN [viewer.cy..viewer.cy+viewer.ch) AND x IN [viewer.cx..viewer.cx+viewer.cw)]}; CheckViewersChildren: PROC [v: Viewer] RETURNS [BOOL] = BEGIN ex, ey: INTEGER; EmbeddedViewerHit: PROC [v: Viewer] RETURNS [BOOL] = INLINE {RETURN[ex IN [v.wx..v.wx+v.ww) AND ey IN [v.wy..v.wy+v.wh)]}; ex _ x - v.cx; ey _ y - v.cy; invert _ IF v.parent=NIL THEN v.class.coordSys=top ELSE v.class.coordSys#v.parent.class.coordSys; IF invert THEN ey _ Bottom2Top[v, ey]; FOR v _ v.child, v.sibling UNTIL v=NIL DO IF EmbeddedViewerHit[v] THEN BEGIN <> x _ ex; y _ ey; viewer _ v; RETURN[TRUE]; END; ENDLOOP; RETURN[FALSE]; END; IF (viewer _ TopLevelHit[]) = NIL THEN RETURN [NIL, FALSE]; IF viewer.child#NIL AND ~viewer.iconic AND Client[] THEN WHILE viewer.child#NIL AND CheckViewersChildren[viewer] DO ENDLOOP; client _ Client[]; invert _ IF viewer.parent=NIL THEN client AND viewer.class.coordSys=top ELSE viewer.class.coordSys#viewer.parent.class.coordSys; <> tsc.mouseX _ x - (IF client THEN viewer.cx ELSE viewer.wx); y _ y - (IF client THEN viewer.cy ELSE viewer.wy); tsc.mouseY _ IF ~invert THEN y ELSE IF client THEN Top2Bottom[viewer, y] ELSE viewer.wh-y; END; END . . .