DIRECTORY Atom USING [GetPropFromList, PutPropOnList], Carets USING [ResumeCarets, SuspendCarets], InputFocus USING [GetInputFocus, SetInputFocus], List USING [CompareProc, Sort], Menus USING [CopyMenu, Menu], MessageWindow USING [Append, Blink, Clear], Rope USING [ROPE], ViewerBLT USING [InternalPaintColumn], ViewerClasses USING [Column, Viewer, ViewerClass, ViewerFlavor, ViewerRec], ViewerEvents USING [EventProc, ProcessEvent, RegisterEventProc], ViewerForkers USING [ForkPaint], ViewerLocks USING [CallUnderColumnLock, CallUnderColumnLocks, CallUnderViewerTreeLock, CallUnderWriteLock, Wedged], ViewerOps USING [AddProp, BottomViewer, CloseViewer, ComputeColumn, EnumerateChildren, EnumerateViewers, EnumProc, FetchProp, FetchViewerClass, OpenIcon, PaintViewer, ViewerColumn], ViewerPrivate, ViewerSpecs, WindowManager USING [colorDisplayOn]; ViewerOpsImplA: CEDAR PROGRAM IMPORTS Atom, Carets, InputFocus, List, Menus, MessageWindow, ViewerBLT, ViewerEvents, ViewerForkers, ViewerLocks, ViewerOps, ViewerPrivate, ViewerSpecs, WindowManager EXPORTS ViewerOps, ViewerPrivate SHARES Menus, ViewerClasses, ViewerEvents, ViewerOps, ViewerLocks = BEGIN OPEN ViewerClasses, ViewerSpecs, ViewerOps, WindowManager; fatalViewersError: ERROR = CODE; rootViewerTree: PUBLIC ARRAY Column OF Viewer _ ALL[NIL]; AddProp: PUBLIC PROC [viewer: Viewer, prop: ATOM, val: REF ANY] = { viewer.props _ Atom.PutPropOnList[viewer.props, prop, val] }; FetchProp: PUBLIC PROC [viewer: Viewer, prop: ATOM] RETURNS [val: REF ANY] = { RETURN[Atom.GetPropFromList[viewer.props, prop]] }; CreateViewer: PUBLIC PROC [flavor: ViewerFlavor, info: ViewerRec _ [], paint: BOOL _ TRUE] RETURNS [new: Viewer] = { ENABLE UNWIND => NULL; topLevel: BOOL; defaultPosition: BOOL; LockedCreateViewer: PROC = { class: ViewerClasses.ViewerClass = FetchViewerClass[flavor]; IF class=NIL THEN ERROR fatalViewersError; -- class not implemented defaultPosition _ (new.wx=0) AND (new.wy=0) AND (new.ww=0) AND (new.wh=0); IF new.parent=NIL AND new.column#static THEN defaultPosition _ TRUE; -- insist new.class _ class; topLevel _ (new.parent=NIL); IF topLevel THEN new.border _ TRUE; IF topLevel AND new.column#static THEN new.caption _ TRUE; IF class.scroll=NIL THEN new.scrollable _ FALSE; IF class.hscroll=NIL THEN new.hscrollable _ FALSE; IF new.tipTable=NIL THEN new.tipTable _ class.tipTable; IF new.icon=unInit THEN new.icon _ class.icon; IF topLevel THEN { IF new.column=static THEN new.iconic _ FALSE; IF NOT iconSlotsUsed NULL; IF viewer.destroyed THEN RETURN; -- already destroyed; nop IF viewer=NIL THEN ERROR fatalViewersError; InternalDestroyViewer[viewer, paint, FALSE]; }; InternalDestroyViewer: PROC [viewer: Viewer, paint, replace: BOOL] = { parent: Viewer; x,y,w,h: INTEGER; onlyLink: Viewer; -- set only if the only link paintParent, paintColumn: BOOL _ FALSE; LockedDestroyViewer: PROC = { parent _ viewer.parent; -- copy parent; smashed below x _ viewer.wx; y _ viewer.wy; w _ viewer.ww; h _ viewer.wh; KillInputFocus[viewer]; IF viewer.iconic THEN ViewerPrivate.GreyWindow[viewer]; -- erase the icon BottomUpRecursivelyDestroyViewerAndChildren[viewer]; IF viewer.link#NIL THEN { IF viewer.link.link=viewer THEN { viewer.link.link _ NIL; IF viewer.link.parent=NIL THEN onlyLink _ viewer.link; } ELSE FOR v: Viewer _ viewer.link.link, v.link UNTIL v.link=viewer DO REPEAT FINISHED => v.link _ viewer.link; ENDLOOP; viewer.link _ NIL; }; SELECT TRUE FROM parent # NIL => { SELECT TRUE FROM parent.child=viewer => parent.child _ viewer.sibling; viewer.sibling#NIL OR parent#viewer => FOR test: Viewer _ parent.child, test.sibling UNTIL test=NIL DO IF test.sibling#NIL AND test.sibling=viewer THEN test.sibling _ test.sibling.sibling; ENDLOOP; ENDCASE; viewer.sibling _ NIL; paintParent _ paint; }; viewer.iconic => { IF replace THEN RETURN; RemoveIcon[icon: viewer, fillSlot: TRUE]; }; ENDCASE => InternalComputeColumn[viewer.column, paint]; }; IF ViewerEvents.ProcessEvent[destroy, viewer, TRUE] THEN RETURN; KillInputFocus[viewer]; IF viewer.parent=NIL THEN { column: Column ~ IF viewer.iconic THEN static ELSE viewer.column; ViewerLocks.CallUnderColumnLock[LockedDestroyViewer, column]; } ELSE ViewerLocks.CallUnderWriteLock[LockedDestroyViewer, viewer.parent]; IF paintParent THEN ViewerOps.PaintViewer[parent, all]; IF onlyLink#NIL THEN ViewerOps.PaintViewer[onlyLink, caption]; [] _ ViewerEvents.ProcessEvent[destroy, viewer, FALSE]; }; BottomUpRecursivelyDestroyViewerAndChildren: PROC [viewer: Viewer] = { LockedBottomUpEtc: PROC = { child, next: Viewer; viewer.visible _ FALSE; viewer.destroyed _ TRUE; IF viewer.class.destroy#NIL THEN viewer.class.destroy[viewer]; child _ viewer.child; WHILE child # NIL DO [] _ ViewerEvents.ProcessEvent[destroy, child, TRUE]; -- what would abort mean? BottomUpRecursivelyDestroyViewerAndChildren[child]; [] _ ViewerEvents.ProcessEvent[destroy, child, FALSE]; next _ child.sibling; child.sibling _ NIL; child _ next; ENDLOOP; IF viewer.parent=NIL THEN UnlinkViewer[viewer]; viewer.parent _ NIL; viewer.name _ NIL; viewer.file _ NIL; viewer.menu _ NIL; viewer.props _ NIL; viewer.child _ NIL; viewer.data _ NIL; }; ViewerLocks.CallUnderWriteLock[LockedBottomUpEtc, viewer]; }; TopViewer: PUBLIC PROC [viewer: Viewer, paint: BOOL _ TRUE] = { LockedTopViewer: PROC = { IF viewer.parent#NIL THEN RETURN; -- top level viewers only SELECT viewer.column FROM left, right => IF (viewer.wy+viewer.wh)=ViewerSpecs.openTopY THEN RETURN; color => IF (viewer.wy+viewer.wh)=ViewerSpecs.colorScreenHeight THEN RETURN; ENDCASE => RETURN; -- not a sequenced column UnlinkViewer[viewer]; LinkViewer[viewer, FALSE]; InternalComputeColumn[viewer.column, paint]; }; IF viewer.offDeskTop THEN ChangeColumn[viewer, left]; ViewerLocks.CallUnderColumnLock[LockedTopViewer, viewer.column]; }; BottomViewer: PUBLIC PROC [viewer: Viewer, paint: BOOL _ TRUE] = { LockedBottomViewer: PROC = { IF viewer.parent#NIL THEN RETURN; -- top level viewers only SELECT viewer.column FROM left, right => IF viewer.wy=ViewerSpecs.openBottomY THEN RETURN; color => IF viewer.wy=0 THEN RETURN; ENDCASE => RETURN; -- not a sequenced column UnlinkViewer[viewer]; LinkViewer[viewer, TRUE]; InternalComputeColumn[viewer.column, paint]; }; IF viewer.offDeskTop THEN ChangeColumn[viewer, left]; ViewerLocks.CallUnderColumnLock[LockedBottomViewer, viewer.column]; }; MoveAboveViewer: PUBLIC PROC [altered, static: Viewer, paint: BOOL _ TRUE] = { LockedMoveAboveViewer: PROC = { IF altered.parent#NIL OR static.parent#NIL THEN RETURN; IF altered.column#static.column OR static.iconic THEN RETURN; UnlinkViewer[altered]; altered.sibling _ static.sibling; static.sibling _ altered; InternalComputeColumn[altered.column, paint]; }; IF static.offDeskTop THEN ChangeColumn[static, left]; IF altered.offDeskTop THEN ChangeColumn[altered, left]; ViewerLocks.CallUnderColumnLock[LockedMoveAboveViewer, altered.column]; }; MoveBelowViewer: PUBLIC PROC [altered, static: Viewer, paint: BOOL _ TRUE] = { LockedMoveBelowViewer: PROC = { IF altered.parent#NIL OR static.parent#NIL THEN RETURN; IF altered.column#static.column OR static.iconic THEN RETURN; IF altered.destroyed OR static.destroyed THEN RETURN; -- DKW: until locking is right UnlinkViewer[altered]; IF static=rootViewerTree[altered.column] THEN { altered.sibling _ static; rootViewerTree[altered.column] _ altered; } ELSE { inFront: Viewer; FOR v: Viewer _ rootViewerTree[altered.column], v.sibling UNTIL v.sibling=static DO REPEAT FINISHED => inFront _ v; ENDLOOP; altered.sibling _ static; inFront.sibling _ altered; }; InternalComputeColumn[altered.column, paint]; }; IF static.offDeskTop THEN ChangeColumn[static, left]; IF altered.offDeskTop THEN ChangeColumn[altered, left]; ViewerLocks.CallUnderColumnLock[LockedMoveBelowViewer, altered.column]; }; ReplaceViewer: PUBLIC PROC [new, old: Viewer] = { LockedReplaceViewer: PROC = { IF old.parent#NIL OR new.parent#NIL OR new.column#old.column THEN RETURN WITH ERROR fatalViewersError; -- must be same level and column KillInputFocus[old]; UnlinkViewer[new]; new.sibling _ old.sibling; old.sibling _ new; new.iconic _ old.iconic; new.position _ old.position; new.openHeight _ old.openHeight; new.column _ old.column; new.offDeskTop _ old.offDeskTop; new.visible _ old.visible; SetViewerPosition[new, old.wx, old.wy, old.ww, old.wh]; InternalDestroyViewer[old, FALSE, TRUE]; -- doesn't free the icon slot IF ~new.iconic THEN InternalComputeColumn[new.column]; }; KillInputFocus[old]; IF old.offDeskTop THEN ChangeColumn[old, left]; IF new.offDeskTop THEN ChangeColumn[new, left]; ViewerLocks.CallUnderColumnLock[LockedReplaceViewer, ViewerColumn[old]]; IF new.iconic THEN ViewerOps.PaintViewer[new, all]; }; MoveBoundary: PUBLIC PROC [newLeftWidth, newBottomY: INTEGER] = { LockedMoveBoundary: PROC = { oldBottomY: INTEGER ~ ViewerSpecs.openBottomY; oldLeftWidth: INTEGER ~ ViewerSpecs.openLeftWidth; ViewerPrivate.SetOpenLeftWidth[newLeftWidth]; ViewerPrivate.SetOpenBottomY[newBottomY]; IF ViewerSpecs.openLeftWidth > oldLeftWidth THEN { InternalComputeColumn[right, TRUE, FALSE]; InternalComputeColumn[left, TRUE, FALSE]; } ELSE { InternalComputeColumn[left, TRUE, FALSE]; InternalComputeColumn[right, TRUE, FALSE]; }; IF ViewerSpecs.openBottomY#oldBottomY THEN { -- repaint icons ViewerPrivate.GreyScreen[bw, 0, 0, ViewerSpecs.bwScreenWidth, ViewerSpecs.openBottomY]; FOR v: Viewer _ rootViewerTree[static], v.sibling UNTIL v = NIL DO IF v.offDeskTop OR NOT v.iconic THEN LOOP; ForkPaintViewerAll[v]; ENDLOOP; }; }; inner: PROC = { ViewerLocks.CallUnderViewerTreeLock[LockedMoveBoundary]; ViewerPrivate.WaitForPaintingToFinish[]; }; WithCaretsOff[inner]; }; ChangeColumn: PUBLIC PROC [viewer: Viewer, newColumn: Column] = { oldColumn: Column; paint: BOOL = TRUE; paintIcon: BOOL _ FALSE; LockedChangeColumn: PROC = { SetColumn: EnumProc = {v.column _ viewer.column}; oldColumn _ viewer.column; IF oldColumn = newColumn THEN RETURN; IF newColumn = static AND ~viewer.iconic THEN CloseViewer[viewer]; IF viewer.iconic THEN { IF oldColumn # static THEN { RemoveIcon[viewer]; ViewerPrivate.GreyWindow[viewer]; }; viewer.column _ newColumn; IF newColumn # static THEN {PositionIcon[viewer]; paintIcon _ TRUE}; }; IF ~viewer.iconic THEN { UnlinkViewer[viewer]; viewer.column _ newColumn; LinkViewer[viewer]; InternalComputeColumn[oldColumn, paint]; InternalComputeColumn[newColumn, paint]; }; IF oldColumn = static THEN viewer.offDeskTop _ FALSE; IF newColumn = static THEN { SetViewerPosition[viewer, 2000, 2000, 10, 10]; viewer.offDeskTop _ TRUE; }; EnumerateChildren[viewer, SetColumn]; }; inner: PROC = { IF ViewerPrivate.ColumnWedged[newColumn].wedged THEN { newColumn _ UnWedgedColumn[]; IF newColumn = static THEN RETURN; }; ViewerLocks.CallUnderColumnLocks[LockedChangeColumn, ViewerColumn[viewer], newColumn]; IF paintIcon THEN ViewerOps.PaintViewer[viewer, all]; }; IF ViewerEvents.ProcessEvent[changeColumn, viewer, TRUE].abort THEN RETURN; WithCaretsOff[inner]; [] _ ViewerEvents.ProcessEvent[changeColumn, viewer, FALSE]; }; OpenIcon: PUBLIC PROC [icon: Viewer, closeOthers: BOOL _ FALSE, bottom: BOOL _ TRUE, paint: BOOL _ TRUE] = { LockedOpenIcon: PROC = { ENABLE UNWIND => NULL; SetOpen: EnumProc = {v.visible _ TRUE}; IF ~icon.iconic THEN {paint _ closeOthers _ FALSE; RETURN}; KillInputFocus[icon]; closeOthers _ (closeOthers AND (CountViewers[icon.column]#0)); ViewerPrivate.GreyWindow[icon]; UnlinkViewer[icon]; icon.iconic _ FALSE; LinkViewer[icon, bottom]; EnumerateChildren[icon, SetOpen]; RemoveIcon[icon: icon, fillSlot: NOT closeOthers]; icon.position _ 0; IF closeOthers THEN GrowViewer[icon, paint]; InternalComputeColumn[icon.column, paint]; IF paint THEN MessageWindow.Clear[]; -- flush old messages }; inner: PROC = { IF ViewerPrivate.ColumnWedged[icon.column].wedged THEN { column: Column _ UnWedgedColumn[]; IF column # static THEN icon.column _ column; }; KillInputFocus[icon]; IF icon.offDeskTop THEN ChangeColumn[icon, left]; ViewerLocks.CallUnderColumnLocks[LockedOpenIcon, icon.column, static]; }; IF ViewerEvents.ProcessEvent[open, icon, TRUE].abort THEN RETURN; WithCaretsOff[inner ! ViewerLocks.Wedged => GO TO ignore]; [] _ ViewerEvents.ProcessEvent[open, icon, FALSE]; EXITS ignore => {}; }; CloseViewer: PUBLIC PROC [viewer: Viewer, paint: BOOL _ TRUE] = { ENABLE UNWIND => NULL; LockedCloseViewer: PROC = { SetClosed: EnumProc = {v.visible _ FALSE}; IF viewer.iconic OR viewer.column=static THEN RETURN; IF NOT iconSlotsUsed NARROW[ref2, Viewer].wy THEN less ELSE greater]}; ListColumn: ViewerOps.EnumProc = { IF ~v.iconic AND v.column=viewer.column THEN inThisColumn _ CONS[v, inThisColumn]; }; IF before THEN { ViewerOps.EnumerateViewers[ListColumn]; TRUSTED {inThisColumn _ LOOPHOLE[List.Sort[LOOPHOLE[inThisColumn], compare]]}; ViewerOps.AddProp[viewer, $InThisColumn, inThisColumn]; IF event = grow THEN RETURN; }; closedViewers _ NARROW[ViewerOps.FetchProp[viewer, $ClosedViewers]]; inThisColumn _ NARROW[ViewerOps.FetchProp[viewer, $InThisColumn]]; ViewerOps.AddProp[viewer, $ClosedViewers, inThisColumn]; ViewerOps.AddProp[viewer, $InThisColumn, NIL]; IF inThisColumn = NIL OR inThisColumn.rest # NIL THEN RETURN; -- first grow FOR v: LIST OF Viewer _ closedViewers, v.rest WHILE v # NIL DO SELECT TRUE FROM v.first.destroyed => {}; v.first = viewer => ViewerOps.BottomViewer[viewer: viewer, paint: FALSE]; v.first.iconic AND v.first.column = viewer.column => ViewerOps.OpenIcon[icon: v.first, paint: FALSE]; ENDCASE; ENDLOOP; ViewerOps.ComputeColumn[viewer.column]; }; inner: PROC = { ViewerLocks.CallUnderColumnLocks[LockedGrowExtra, viewer.column, static]; }; IF event = destroy AND viewer.parent # NIL THEN RETURN; IF event = destroy AND (viewer.iconic OR viewer.column = static) THEN RETURN; WithCaretsOff[inner]; }; ComputeColumn: PUBLIC PROC [column: Column, paint: BOOL _ TRUE] = { ENABLE UNWIND => NULL; LockedComputeColumn: PROC = { InternalComputeColumn[column, paint]; }; inner: PROC = { ViewerLocks.CallUnderColumnLock[LockedComputeColumn, column]; }; WithCaretsOff[inner]; }; InternalComputeColumn: PROC [column: Column, paint, icons: BOOL _ TRUE] = { force: BOOL _ FALSE; largestViewer: Viewer; totalRequested, requests: INTEGER _ 0; minHeight: INTEGER ~ captionHeight; leftX, width, bottomY, nextY: INTEGER; openViewers: INTEGER = CountViewers[column]; normalHeight, extra, default, totalSpace: INTEGER _ 0; DesiredHeight: PROC [v: Viewer] RETURNS [INTEGER] = INLINE { RETURN[--IF v.position#0 THEN v.position ELSE-- v.openHeight]; }; AddUpRequests: PROC [cutoff: INTEGER] = { largestHeight: INTEGER _ 0; totalRequested _ requests _ 0; FOR v: Viewer _ rootViewerTree[column], v.sibling UNTIL v=NIL DO IF DesiredHeight[v] > largestHeight THEN { largestHeight _ DesiredHeight[v]; largestViewer _ v; }; IF DesiredHeight[v]#0 AND DesiredHeight[v] <= cutoff THEN { totalRequested _ totalRequested + DesiredHeight[v]; requests _ requests + 1; }; ENDLOOP; }; IF column # static AND openViewers # 0 THEN { [x: leftX, w: width, y: bottomY, h: totalSpace] _ ColumnInfo[column]; nextY _ bottomY; normalHeight _ totalSpace/openViewers; AddUpRequests[LAST[INTEGER]/2]; IF totalRequested+((openViewers-requests)*minHeight) > totalSpace THEN { force _ TRUE; AddUpRequests[normalHeight]; }; IF openViewers=requests THEN extra _ totalSpace-totalRequested ELSE { default _ (totalSpace-totalRequested)/(openViewers-requests); extra _ (totalSpace-totalRequested) MOD (openViewers-requests); }; FOR v: Viewer _ rootViewerTree[column], v.sibling UNTIL v=NIL DO height: INTEGER _ SELECT TRUE FROM DesiredHeight[v]=0 => default, force AND DesiredHeight[v] > normalHeight => default, ENDCASE => DesiredHeight[v]; IF openViewers = requests AND largestViewer # NIL THEN {IF v = largestViewer THEN height _ height + extra} ELSE {IF nextY=bottomY THEN height _ height + extra}; SetViewerPosition[v, leftX, nextY, width, height]; nextY _ nextY + v.wh; ENDLOOP; }; IF paint THEN ViewerBLT.InternalPaintColumn[column, icons]; }; ColumnInfo: PROC[column: Column] RETURNS[x, y, w, h: INTEGER] = { SELECT column FROM left => RETURN[ x: ViewerSpecs.openLeftLeftX, w: ViewerSpecs.openLeftWidth, y: ViewerSpecs.openBottomY, h: ViewerSpecs.openTopY-ViewerSpecs.openBottomY ]; right => RETURN[ x: ViewerSpecs.openRightLeftX, w: ViewerSpecs.openRightWidth, y: ViewerSpecs.openBottomY, h: ViewerSpecs.openTopY-ViewerSpecs.openBottomY ]; color => RETURN[ x: 0, w: ViewerSpecs.colorScreenWidth, y: 0, h: ViewerSpecs.colorScreenHeight ]; ENDCASE => ERROR; }; maxIcons: NAT ~ 12*16; IconSlotsArray: TYPE ~ PACKED ARRAY [0..maxIcons) OF BOOL; iconSlotsArray: REF IconSlotsArray _ NEW[IconSlotsArray _ ALL[FALSE]]; iconSlotsUsed: [0..maxIcons] _ 0; RemoveIcon: PROC [icon: Viewer, fillSlot: BOOL _ FALSE] = { rows: NAT ~ ViewerSpecs.iconRows; columns: NAT ~ ViewerSpecs.iconColumns; filler: Viewer; slot: INTEGER _ 0; FindSlotIcon: ViewerOps.EnumProc = { IF v.offDeskTop THEN RETURN; IF v.iconic AND v.position=slot THEN { filler _ v; RETURN[FALSE] }; }; IF icon.offDeskTop THEN RETURN; iconSlotsUsed _ iconSlotsUsed-1; iconSlotsArray[icon.position] _ FALSE; IF NOT fillSlot THEN RETURN; FOR m: NAT DECREASING IN ((icon.position/columns)..rows) DO IF icon.column = right THEN FOR n: NAT DECREASING IN [0..columns) DO slot _ m*columns + n; IF iconSlotsArray[slot] THEN EXIT; ENDLOOP ELSE FOR n: NAT IN [0..columns) DO slot _ m*columns + n; IF iconSlotsArray[slot] THEN EXIT; ENDLOOP; ENDLOOP; IF slot = 0 OR NOT iconSlotsArray[slot] THEN RETURN; ViewerOps.EnumerateViewers[FindSlotIcon]; IF filler = NIL THEN RETURN; ViewerPrivate.GreyWindow[filler]; iconSlotsArray[filler.position] _ FALSE; filler.position _ icon.position; iconSlotsArray[filler.position] _ TRUE; SetIconPosition[filler]; ForkPaintViewerAll[filler]; }; PositionIcon: PROC [viewer: Viewer, slot: INTEGER _ 0] = { rows: NAT ~ ViewerSpecs.iconRows; columns: NAT ~ ViewerSpecs.iconColumns; slotIcon: Viewer; FindSlotIcon: ViewerOps.EnumProc = { IF v.offDeskTop THEN RETURN; IF v.iconic AND v.position=slot THEN {slotIcon _ v; RETURN[FALSE]}; }; FindIconSlot: PROC [side: Column] RETURNS [slot: CARDINAL] = { FOR m: CARDINAL IN [0..rows) DO IF side=right THEN FOR n: CARDINAL DECREASING IN [0..columns) DO slot _ m*columns+n; IF NOT iconSlotsArray[slot] THEN RETURN; ENDLOOP ELSE FOR n: CARDINAL IN [0..columns) DO slot _ m*columns+n; IF NOT iconSlotsArray[slot] THEN RETURN; ENDLOOP; ENDLOOP; }; IF slot # 0 AND iconSlotsArray[slot] THEN { -- move the icon in the slot ViewerOps.EnumerateViewers[FindSlotIcon]; slotIcon.position _ FindIconSlot[slotIcon.column]; iconSlotsArray[slotIcon.position] _ TRUE; SetIconPosition[slotIcon]; }; viewer.position _ IF slot # 0 THEN slot ELSE FindIconSlot[viewer.column]; iconSlotsArray[viewer.position] _ TRUE; iconSlotsUsed _ iconSlotsUsed+1; SetIconPosition[viewer]; }; SetIconPosition: PROC [icon: Viewer] = { columns: NAT ~ ViewerSpecs.iconColumns; position: NAT ~ icon.position; r: NAT ~ position/columns; c: NAT ~ position MOD columns; x: INTEGER ~ ViewerSpecs.iconLeftX+c*ViewerSpecs.iconColumnWidth; y: INTEGER ~ ViewerSpecs.iconBottomY+r*ViewerSpecs.iconRowHeight; SetViewerPosition[icon, x, y, iconWidth, iconHeight]; }; MoveViewer: PUBLIC PROC [viewer: Viewer, x, y, w, h: INTEGER, paint: BOOL _ TRUE] ~ { parent: Viewer ~ viewer.parent; LockedMoveViewer: PROC = { IF paint AND parent=NIL THEN ViewerPrivate.GreyWindow[viewer]; SetViewerPosition[viewer, x, y, w, h]; }; inner: PROC = { ViewerLocks.CallUnderWriteLock[LockedMoveViewer, viewer]; IF paint THEN ViewerOps.PaintViewer[IF parent=NIL THEN viewer ELSE parent, all]; }; WithCaretsOff[inner]; }; EstablishViewerPosition: PUBLIC PROC [viewer: Viewer, x, y, w, h: INTEGER] ~ { LockedEstablishViewerPosition: PROC = { SetViewerPosition[viewer, x, y, w, h]; }; inner: PROC = { ViewerLocks.CallUnderWriteLock[LockedEstablishViewerPosition, viewer]; }; WithCaretsOff[inner]; }; SetViewerPosition: PROC [viewer: Viewer, x, y, w, h: INTEGER] ~ { oldcw: INTEGER ~ viewer.cw; oldch: INTEGER ~ viewer.ch; IF w<0 THEN w _ 0; IF h<0 THEN h _ 0; viewer.wx _ x; viewer.wy _ y; viewer.ww _ w; viewer.wh _ h; IF viewer.iconic THEN { viewer.cx _ 0; viewer.cy _ 0; viewer.cw _ w; viewer.ch _ h; } ELSE { xmin: INTEGER _ 0; xmax: INTEGER _ w; ymin: INTEGER _ 0; ymax: INTEGER _ h; IF viewer.border THEN { size: INTEGER ~ ViewerSpecs.windowBorderSize; xmin _ xmin+size; xmax _ xmax-size; ymin _ ymin+size; ymax _ ymax-size; }; IF viewer.caption THEN ymax _ h-ViewerSpecs.captionHeight; IF viewer.menu#NIL THEN { lines: NAT ~ viewer.menu.linesUsed; ymax _ ymax-lines*ViewerSpecs.menuHeight; ymax _ ymax-ViewerSpecs.menuBarHeight; }; IF viewer.scrollable THEN xmin _ xmin+ViewerSpecs.scrollBarW; IF viewer.hscrollable THEN ymin _ ymin+ViewerSpecs.scrollBarW; IF xmax v.sibling _ new; ENDLOOP; }; UnlinkViewer: PROC [old: Viewer] = { column: Column ~ ViewerColumn[old]; IF old.parent = NIL THEN { root: Viewer _ rootViewerTree[column]; IF old=root THEN rootViewerTree[column] _ old.sibling ELSE FOR v: Viewer _ root, v.sibling WHILE v # NIL DO IF v.sibling = old THEN {v.sibling _ old.sibling; EXIT}; ENDLOOP; } ELSE { parent: Viewer _ old.parent; FOR v: Viewer _ parent, v.sibling WHILE v # NIL DO IF v.sibling = old THEN { IF parent.child = old THEN parent.child _ old.sibling; v.sibling _ old.sibling; EXIT}; ENDLOOP; }; old.sibling _ NIL; }; LinkChild: PROC [parent, child: Viewer, bottom: BOOL _ TRUE] = { IF parent.child=NIL OR bottom THEN { child.sibling _ parent.child; parent.child _ child; } ELSE FOR v: Viewer _ parent.child, v.sibling UNTIL v.sibling=NIL DO REPEAT FINISHED => v.sibling _ child; ENDLOOP; }; CountViewers: PROC [c: Column] RETURNS [count: INTEGER] = { count _ 0; FOR v: Viewer _ rootViewerTree[c], v.sibling UNTIL v=NIL DO count _ count+1; ENDLOOP; }; KillInputFocus: PROC [viewer: Viewer] = { focus: Viewer _ InputFocus.GetInputFocus[].owner; WHILE focus # NIL DO IF focus # viewer THEN focus _ focus.parent ELSE {InputFocus.SetInputFocus[]; EXIT}; ENDLOOP; }; UnWedgedColumn: PROC RETURNS[unwedged: Column] = { FOR unwedged IN Column DO IF unwedged = static THEN LOOP; -- save the static column for last IF unwedged = color AND ~WindowManager.colorDisplayOn THEN LOOP; IF NOT ViewerPrivate.ColumnWedged[unwedged].wedged THEN RETURN; ENDLOOP; RETURN[static]; }; ForkPaintViewerAll: PROC [viewer: Viewer] = TRUSTED { ViewerForkers.ForkPaint[viewer, all]; }; WithCaretsOff: PROC [inner: PROC] = { Carets.SuspendCarets[]; inner[ ! UNWIND => Carets.ResumeCarets[]]; Carets.ResumeCarets[]; }; [] _ ViewerEvents.RegisterEventProc[GrowExtra, grow, NIL, TRUE]; [] _ ViewerEvents.RegisterEventProc[GrowExtra, grow, NIL, FALSE]; [] _ ViewerEvents.RegisterEventProc[GrowExtra, destroy]; END. BViewerOpsImplA.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Plass, May 4, 1983 11:27 am Russ Atkinson (RRA) June 18, 1985 0:58:25 am PDT Doug Wyatt, April 18, 1985 4:14:24 pm PST rootViewerTree[column] is the bottom viewer in the column not locked, but these are not ordinary times! used by ReplaceViewer to prevent the slot from being reused the following are always painted because the caller isn't likely to know to repaint them help out the garbage collector (.sibling handled by caller and above) -- iconic case -- non iconic case -- hyperspace not locked, but these are not ordinary times! [viewer: Viewer, event: ViewerEvent, before: BOOL] cons up a list of viewers currently in the column monitored access to window chain If there are no requests, divide the column evenly among the viewers. If total requested > column height, ignore requests for more than average height. If total requested < column height AND requests = viewers, put extra on largest viewer. A top-level viewer, so a single chain terminated by NIL Child of a viewer (circular chain) ส#ฎ– "Mesa" style˜codešœ™Kšœ ฯmœ1™Kšœ-™-Kšœ"˜"Kšžœžœ˜,Kšœ˜K˜—šžœ ž˜šžœ˜Kšœžœ žœžœ ˜;Kšœ<˜K˜Kšœ0žœ˜7Kšœ˜K˜—š +œžœ˜Fš œžœ˜K˜Kšœžœ˜Kšœžœ˜Kšžœžœžœ˜>K˜K˜šžœ žœž˜Kšœ/žœก˜OKšœ3˜3Kšœ/žœ˜6K˜Kšœžœ˜K˜ Kšžœ˜K˜—Kšžœžœžœ˜/KšœE™EKšœžœžœžœ˜:Kšœžœžœžœ˜:Kšœžœ˜Kšœ˜K˜—Kšœ;˜;Kšœ˜—K˜š   œžœžœžœžœ˜?š œžœ˜Kš žœžœžœžœก˜;šžœž˜Kšœžœ,žœžœ˜IKšœ žœ5žœžœ˜LKšžœžœก˜,—K˜Kšœžœ˜Kšœ,˜,Kšœ˜—Kšžœžœ˜5Kšœ@˜@Kšœ˜K˜—š   œžœžœžœžœ˜Bš œžœ˜Kš žœžœžœžœก˜;šžœž˜Kšœžœ#žœžœ˜@Kšœ žœ žœžœ˜$Kšžœžœก˜,—K˜Kšœžœ˜Kšœ,˜,Kšœ˜—Kšžœžœ˜5KšœC˜CKšœ˜K˜—š  œžœžœ"žœžœ˜Nš œžœ˜Kš žœžœžœžœžœžœ˜7Kšžœžœžœžœ˜=K˜K˜!K˜K˜-Kšœ˜—Kšžœžœ˜5Kšžœžœ˜7KšœG˜GKšœ˜K˜—š  œžœžœ"žœžœ˜Nš œžœ˜Kš žœžœžœžœžœžœ˜7Kšžœžœžœžœ˜=Kš žœžœžœžœก˜TK˜šžœ'žœ˜/K˜Kšœ)˜)Kšœ˜—šžœ˜K˜šžœ7žœž˜SKšžœžœ˜Kšžœ˜—K˜K˜Kšœ˜—Kšœ-˜-Kšœ˜—Kšžœžœ˜5Kšžœžœ˜7KšœG˜GKšœ˜K˜—š  œžœžœ˜1š œžœ˜š žœ žœžœ žœžœž˜AKšžœžœžœก ˜E—K˜K˜K˜K˜K˜K˜K˜ K˜K˜ K˜K˜7Kšœžœžœก˜FKšžœ žœ#˜6K˜—K˜Kšžœžœ˜/Kšžœžœ˜/KšœH˜HKšžœ žœ!˜3Kšœ˜K˜—K˜š  œžœžœžœ˜Aš œžœ˜Kšœ žœ˜.Kšœžœ˜2Kšœ-˜-Kšœ)˜)šžœ*žœ˜2Kšœžœžœ˜*Kšœžœžœ˜)Kšœ˜—šžœ˜Kšœžœžœ˜)Kšœžœžœ˜*Kšœ˜—šžœ$žœก˜=KšœW˜Wšžœ/žœžœž˜BKš žœžœžœ žœžœ˜*Kšœ˜Kšžœ˜—Kšœ˜—K˜—šœžœ˜Kšœ8˜8K˜(K˜—K˜Kšœ˜K˜—š  œžœžœ(˜AK˜Kšœžœžœ˜Kšœ žœžœ˜š œžœ˜K˜1K˜Kšžœžœžœ˜%Kšžœžœžœ˜BK™šžœžœ˜šžœžœ˜Kšœ˜Kšœ!˜!Kšœ˜—Kšœ˜Kšžœžœ$žœ˜DKšœ˜—Kšก™šžœžœ˜K˜K˜K˜K˜(K˜(Kšœ˜—Kšœ ™ Kšžœžœžœ˜5šžœžœ˜K˜.Kšœžœ˜Kšœ˜K˜—K˜%K˜—šœžœ˜šžœ.žœ˜6K˜Kšžœžœžœ˜"Kšœ˜—KšœV˜VKšžœ žœ$˜5K˜—Kšžœ1žœžœžœ˜KK˜Kšœ5žœ˜Kšœ˜Kšœ˜Kšœžœ˜K˜K˜!Kšœ!žœ˜2K˜Kšžœ žœ˜,Kšœ*˜*Kšžœžœก˜:Kšœ˜—šœžœ˜šžœ0žœ˜8Kšœ-™-K˜"Kšžœžœ˜-Kšœ˜—Kšœ˜Kšžœžœ˜1KšœF˜FK˜K˜—Kšžœ'žœžœžœ˜AK˜šœ,žœžœ ˜:K˜—Kšœ+žœ˜2Kšžœ˜Kšœ˜K˜—š   œžœžœžœžœ˜AKšžœžœžœ˜š œžœ˜Kšœ#žœ˜*Kšžœžœžœžœ˜5šžœžœžœ˜$KšœOžœ˜UK˜Kšžœ˜Kšœ˜—Kšœ˜K˜Kšœžœ˜K˜K˜%Kšœ˜K˜,K˜—šœžœ˜K˜Kšžœžœ˜5KšœK˜KKšžœžœ$˜1K˜K˜—Kšžœ*žœžœžœ˜DKšœ˜Kšœ.žœ˜5Kšœ˜K˜—š  œžœžœ#žœžœ˜Qšž˜Kšœ ˜ Kšœžœžœ˜šœžœ˜Kš žœžœžœ žœžœ˜LKšžœžœžœžœ˜1Kšœ˜Kšœ˜Kšœžœ˜#Kšœ"žœ˜)Kšœžœ˜Kšœ˜K˜—Kšžœžœžœžœ˜1Kšžœ(žœžœ˜6Kšžœ0žœžœ˜>Kšžœžœžœ˜8Kšœ5˜5Kšžœžœžœžœ˜Kšžœ˜—Kšœ˜K˜—š   œžœžœžœžœ˜@Kšœžœžœ˜Kš œžœ1˜Jš œžœ˜šžœ6žœžœž˜IKšžœ žœžœ˜8Kšžœ˜—Kšœ˜—šœžœ˜Kšžœžœ˜5KšœJ˜Jš žœžœžœžœžœž˜=Kšœžœก-˜UKšžœ˜ —šžœžœžœžœ˜&š žœžœžœžœžœž˜=Kšžœžœ%˜;Kšžœ˜—KšœD˜DKšœ˜—K˜—Kšžœžœžœ žœ˜HKšžœ)žœžœžœ˜CKšœ˜Kšœ-žœ˜4Kšœ˜K˜—š  œ˜&Kšœ2™2š œžœ˜Kšœžœžœ ก˜;Kšœžœžœ ก"˜@šœžœžœžœ˜AKšžœžœžœ ˜1—šœ"˜"šžœ žœž˜,Kšœžœ˜%—Kšœ˜K˜—šžœžœ˜Kšœ1™1Kšœ'˜'Kšžœžœ žœ˜NKšœ7˜7Kšžœžœžœ˜Kšœ˜Kšœ˜—Kšœžœ.˜DKšœžœ-˜BKšœ8˜8Kšœ)žœ˜.Kš žœžœžœžœžœžœก ˜KK˜š žœžœžœ žœžœž˜>šžœžœž˜Kšœ˜KšœBžœ˜Išœžœ"˜4Kšœ)žœ˜0—Kšžœ˜—Kšžœ˜—Kšœ'˜'Kšœ˜—šœžœ˜KšœI˜IK˜—Kš žœžœžœžœžœ˜7Kš žœžœžœžœžœ˜MKšœ˜Kšœ˜—K˜š   œžœžœžœžœ˜CKšžœžœžœ˜š œžœ˜Kšœ%˜%Kšœ˜—šœžœ˜Kšœ=˜=K˜—K˜Kšœ˜K˜—š œžœ žœžœ˜KKšœ ™ Kšœžœžœ˜K˜Kšœžœ˜&Kšœ žœ˜#Kšœžœ˜&Kšœ žœ˜,Kšœ*žœ˜6š   œžœ žœžœžœ˜Kšœ˜—š  œžœ žœ˜*Kšœžœ˜Kšœ˜šžœ/žœžœž˜@šžœ"žœ˜*Kšœ4˜4Kšœ˜—šžœžœžœ˜;K˜3K˜Kšœ˜—Kšžœ˜—Kšœ˜K˜—šžœžœžœ˜-KšœE™EKšœQ™QKšœY™YK˜EK˜Kšœ&˜&Kšœžœžœ˜šžœ@žœ˜HKšœžœ˜*Kšœ˜—šžœ˜Kšžœ#˜'šžœ˜Kšœ=˜=Kšœ$žœ˜?Kšœ˜——šžœ/žœžœž˜@šœžœžœžœž˜"Kšœ˜Kšœžœ,˜5Kšžœ˜—šžœžœžœ˜2Kšžœžœžœ˜8Kšžœžœžœ˜5—K˜2K˜Kšžœ˜—Kšœ˜—K˜Kšžœžœ.˜;Kšœ˜K˜—š  œžœžœ žœ˜Ašžœž˜šœžœ˜Kšœ;˜;KšœK˜KKšœ˜—šœ žœ˜Kšœ=˜=KšœK˜KKšœ˜—šœ žœ˜Kšœ&˜&Kšœ&˜&Kšœ˜—Kšžœžœ˜—Kšœ˜—K˜Kšœ žœ ˜Kš œžœžœžœžœžœ˜:K˜Kš œžœžœžœžœ˜Fšœ!˜!K˜—š  œžœžœžœ˜;Kšœžœ˜!Kšœ žœ˜'K˜Kšœžœ˜šœ$˜$Kšžœžœžœ˜Kš žœ žœžœžœžœ˜CKšœ˜—K˜Kšžœžœžœ˜Kšœ ˜ Kšœ žœ˜&Kšžœžœ žœžœ˜š žœžœž œžœ!ž˜;š žœžœžœžœž œžœž˜DKšœ˜Kšžœžœžœ˜"Kšž˜—š žœžœžœžœž˜"Kšœ˜Kšžœžœžœ˜"Kšžœ˜—Kšžœ˜—Kš žœ žœžœžœžœ˜4K˜)Kšžœ žœžœžœ˜Kšœ!˜!Kšœ"žœ˜(Kšœ ˜ Kšœ"žœ˜'Kšœ˜Kšœ˜Kšœ˜K˜—š  œžœžœ ˜:Kšœžœ˜!Kšœ žœ˜'K˜š  œ˜$Kšžœžœžœ˜Kš žœ žœžœžœžœ˜CKšœ˜—š  œžœžœžœ˜>šžœžœžœ ž˜š žœ žœžœžœž œžœž˜@Kšœ˜Kšžœžœžœžœ˜(Kšž˜—š žœžœžœžœž˜'Kšœ˜Kšžœžœžœžœ˜(Kšžœ˜—Kšžœ˜—Kšœ˜—K˜šžœ žœžœก˜HKšœ)˜)K˜2Kšœ$žœ˜)Kšœ˜Kšœ˜K˜—Kšœžœ žœžœ˜IKšœ"žœ˜'K˜ Kšœ˜Kšœ˜K˜—š œžœ˜(Kšœ žœ˜'Kšœ žœ˜Kšœžœ˜Kšœžœ žœ ˜Kšœžœ7˜AKšœžœ7˜AKšœ5˜5Kšœ˜—K˜š   œžœžœžœ žœžœ˜UK˜š œžœ˜Kšžœžœžœžœ"˜>Kšœ&˜&Kšœ˜—šœžœ˜Kšœ9˜9Kš žœžœžœžœžœžœ˜PK˜—K˜Kšœ˜K˜—š œžœžœžœ˜Nš œžœ˜'Kšœ&˜&Kšœ˜—šœžœ˜KšœF˜FK˜—K˜Kšœ˜K˜—š œžœžœ˜AKšœžœžœ ˜7Kšžœžœžœžœ˜%K˜K˜K˜K˜šžœ˜šžœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—šžœ˜Kšœžœ žœ˜%Kšœžœ žœ˜%šžœžœ˜Kšœžœ ˜-Kšœ#˜#Kšœ#˜#K˜—šžœž˜Kšœ#˜#—šžœ žœžœ˜Kšœžœ˜#Kšœ)˜)K˜&K˜—šžœž˜Kšœ#˜#—šžœž˜Kšœ#˜#—Kšžœ žœ˜"Kšžœ žœ˜"Kšœ(˜(Kšœ(˜(K˜——š žœžœžœžœž˜HKšœ!˜!—Kšœ˜—K˜š  œžœžœžœ˜7Kšœ#˜#šžœžœžœ˜'šžœ˜K˜%K˜Kšœ˜—š žœžœ/žœ žœž˜MKšžœžœ˜#Kšžœ˜——Kšœ˜K˜—š  œžœ˜$Kšœ#˜#šžœž˜šžœ˜Kšœ4ž™7Kšœ&˜&šžœ ˜ Kšžœ%˜)š žœžœžœžœž˜5Kšžœžœžœ˜8Kšžœ˜——K˜—šžœ˜K™"Kšœ˜šžœžœžœž˜2šžœžœ˜Kšžœžœ˜6Kšœ˜Kšžœ˜—Kšžœ˜—K˜——Kšœžœ˜Kšœ˜K˜—š  œžœ!žœžœ˜@šžœžœžœžœ˜$K˜K˜Kšœ˜—š žœžœ%žœ žœž˜CKšžœžœ˜%Kšžœ˜—Kšœ˜—K˜š  œžœ žœ žœ˜;K˜ šžœ*žœžœž˜;Kšœ˜Kšžœ˜—Kšœ˜K˜—š œžœ˜)Kšœ1˜1šžœ žœž˜šžœ˜Kšžœ˜Kšžœžœ˜(—Kšžœ˜—Kšœ˜K˜—š œžœžœ˜2šžœ žœž˜Kšžœžœžœก"˜BKšžœžœžœžœ˜@Kšžœžœ-žœžœ˜?Kšžœ˜—Kšžœ ˜Kšœ˜K˜—š œžœžœ˜5Kšœ%˜%K˜K˜—š  œžœ žœ˜%K˜Kšœ žœ˜*K˜K˜K˜—Kšœ5žœžœ˜@Kšœ5žœžœ˜AKšœ8˜8K˜Kšžœ˜—…—kR“B