ViewerOpsImplB.mesa; Written by Maxwell
Edited by Maxwell, May 18, 1983 9:19 am
Edited by Paul Rovner, June 16, 1983 9:46 am
Edited by Doug Wyatt, December 13, 1983 5:59 pm
DIRECTORY
Carets USING [ResumeCarets, SuspendCarets],
Cursors USING [InvertCursor],
InputFocus USING [GetInputFocus, SetInputFocus],
Menus USING [CopyMenu, Menu],
MessageWindow USING [Append, Blink],
Process USING [GetPriority, Priority, priorityForeground, SetPriority],
RefTab USING [Create, Fetch, Ref, Store],
Rope USING [Compare, ROPE],
TIPUser USING [TIPScreenCoords],
ViewerEvents USING [ProcessEvent],
ViewerOps,
ViewerLocks,
ViewerClasses,
ViewerClassesExtras USING [],
ViewerSpecs,
WindowManager USING [colorDisplayOn],
WindowManagerPrivate;
ViewerOpsImplB: CEDAR PROGRAM
IMPORTS Carets, Cursors, InputFocus, Menus, MessageWindow, Process, RefTab, Rope, ViewerEvents, ViewerLocks, ViewerOps, WindowManager, WindowManagerPrivate
EXPORTS ViewerOps, ViewerClassesExtras
SHARES Menus, ViewerEvents =
BEGIN OPEN ViewerClasses, ViewerSpecs, ViewerOps, WindowManager;
ROPE: TYPE = Rope.ROPE;
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]};
let the Viewer package know about a new class of viewer.
FetchViewerClass:
PUBLIC
PROC [flavor: ViewerFlavor]
RETURNS [ViewerClass] =
{IF flavor = $TypeScript THEN flavor ← $Typescript;
RETURN[NARROW[RefTab.Fetch[classTable, flavor].val]]};
class information from an existing viewer class.
EnumerateViewers:
PUBLIC
PROC [enum: EnumProc] =
BEGIN
Safe in that caller can move the enumerated viewer in the tree in which case all viewers get seen at least once
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;
SaveAborted: PUBLIC ERROR[error: ROPE] = CODE; -- exported to ViewerClassesExtras
SaveViewer:
PUBLIC
PROC [viewer: Viewer] =
BEGIN
list: LIST OF Viewer;
errorMessage: ROPE ← NIL;
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;
IF errorMessage=NIL THEN v.newVersion ← v.newFile ← FALSE;
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;
Not called under locks so viewers can be saved when the column is locked.
LockedStart[];
IF viewer.class.save=NIL THEN errorMessage ← "no save procedure in viewer class"
ELSE viewer.class.save[viewer ! SaveAborted => { errorMessage ← error; CONTINUE }];
IF errorMessage#
NIL
THEN {
MessageWindow.Append["Can't SAVE -- ", TRUE];
MessageWindow.Append[errorMessage];
MessageWindow.Blink[];
};
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
poor man's crash recovery
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];
END;
EnumerateViewers[Save];
IF old>Process.priorityForeground
THEN
TRUSTED BEGIN
-- called from CoPilot
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
embedded frames are client info relative
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;
overwrite screen coords record
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 . . .