DIRECTORY Carets USING [ResumeCarets, SuspendCarets], Imager USING [black, Color, Context, MaskRectangleI, SetColor, white], ImagerBackdoor USING [MoveViewRectangle], Menus USING [ChangeNumberOfLines], ViewerBLT USING [], ViewerClasses USING [Column, HBltRule, PaintProc, PaintRectangle, PaintRectangleRec, VBltRule, Viewer], ViewerForkers USING [ForkCall, ForkPaint], ViewerLocks USING [CallUnderWriteLock], ViewerOps USING [EstablishViewerPosition, FetchViewerClass, PaintViewer, UserToScreenCoords], ViewerPrivate USING [GreyScreen, PaintScreen, rootViewerTree, Screen, ViewerScreen], ViewerSpecs USING [captionHeight, colorScreenHeight, colorScreenWidth, openBottomY, openLeftLeftX, openLeftWidth, openRightLeftX, openRightWidth, openTopY, windowBorderSize]; ViewerBLTImpl: CEDAR PROGRAM IMPORTS Carets, Imager, ImagerBackdoor, Menus, ViewerForkers, ViewerLocks, ViewerOps, ViewerPrivate, ViewerSpecs EXPORTS ViewerBLT SHARES Menus, ViewerOps, ViewerClasses = BEGIN OPEN ViewerClasses, ViewerSpecs; disable: BOOL _ FALSE; ChangeNumberOfLines: PUBLIC PROC[viewer: Viewer, newLines: [0..5)] = { LockedChangeLines: PROC = { oldBox, newBox: Box; IF viewer.menu = NIL THEN RETURN; oldBox _ [viewer.wx+viewer.cx, viewer.wy+viewer.cy, viewer.cw, viewer.ch]; Menus.ChangeNumberOfLines[viewer.menu, newLines]; ViewerOps.EstablishViewerPosition[viewer, viewer.wx, viewer.wy, viewer.ww, viewer.wh]; newBox _ [viewer.wx+viewer.cx, viewer.wy+viewer.cy, viewer.cw, viewer.ch]; BLTViewer[viewer, oldBox, newBox]; }; ViewerLocks.CallUnderWriteLock[LockedChangeLines, viewer]; }; InternalPaintColumn: PUBLIC PROC [column: Column, paintIcons: BOOL _ TRUE] = { oldIndex: CARDINAL; oldSnapshot: ColumnSnapshot; newSnapshot: ColumnSnapshot; invalidTop, invalidBottom: INTEGER; IF column = static THEN { FOR v: Viewer _ ViewerPrivate.rootViewerTree[column], v.sibling UNTIL v=NIL DO IF ~v.offDeskTop THEN ForkPaintViewerAll[v]; ENDLOOP; RETURN }; Carets.SuspendCarets[]; { ENABLE UNWIND => Carets.ResumeCarets[]; IF ViewerPrivate.rootViewerTree[column] = NIL THEN { height, leftX, width, bottomY: INTEGER; [height, leftX, width, bottomY, ] _ ColumnInfo[column]; ViewerPrivate.GreyScreen[IF column=color THEN color ELSE bw, leftX, bottomY, width, height]; ClearSnapshot[snapshots[column].before]; IF paintIcons AND column # color THEN -- paint newly visible icons FOR v: Viewer _ ViewerPrivate.rootViewerTree[static], v.sibling UNTIL v=NIL DO IF ~v.iconic OR v.offDeskTop THEN LOOP; IF v.wy + v.wh < bottomY THEN LOOP; IF v.wx + v.ww < leftX THEN LOOP; IF v.wx > leftX + width THEN LOOP; ForkPaintViewerAll[v]; ENDLOOP; GO TO done; }; oldSnapshot _ snapshots[column].before; newSnapshot _ SnapshotColumn[column]; snapshots[column].before _ newSnapshot; snapshots[column].after _ oldSnapshot; IF oldSnapshot = NIL OR disable THEN { FOR v: Viewer _ ViewerPrivate.rootViewerTree[column], v.sibling UNTIL v=NIL DO ForkPaintViewerAll[v]; ENDLOOP; GO TO done; }; invalidTop _ -1; -- top of section that has been blitted over invalidBottom _ 1000; -- bottom of section that has been blitted over FOR i: CARDINAL IN [0..newSnapshot.size) DO IF newSnapshot[i].viewer = NIL THEN EXIT; oldIndex _ GetIndex[oldSnapshot, newSnapshot[i].viewer]; IF oldIndex = oldSnapshot.size THEN LOOP; -- a new viewer IF oldSnapshot[oldIndex].box.y + oldSnapshot[oldIndex].box.h > invalidBottom AND oldSnapshot[oldIndex].box.y < invalidTop THEN LOOP; IF newSnapshot[i].box.y + newSnapshot[i].box.h > oldSnapshot[oldIndex].box.y + oldSnapshot[oldIndex].box.h THEN LOOP; IF newSnapshot[i].box # oldSnapshot[oldIndex].box THEN { BLTViewer[newSnapshot[i].viewer, oldSnapshot[oldIndex].box, newSnapshot[i].box]; invalidTop _ MAX[invalidTop, newSnapshot[i].box.y + newSnapshot[i].box.h]; invalidBottom _ MIN[invalidBottom, newSnapshot[i].box.y]; }; newSnapshot[i].painted _ TRUE; ENDLOOP; FOR i: CARDINAL DECREASING IN [0..newSnapshot.size) DO IF newSnapshot[i].viewer = NIL THEN LOOP; IF newSnapshot[i].painted THEN LOOP; oldIndex _ GetIndex[oldSnapshot, newSnapshot[i].viewer]; IF oldIndex = oldSnapshot.size THEN LOOP; -- a new viewer IF oldSnapshot[oldIndex].box.y + oldSnapshot[oldIndex].box.h > invalidBottom AND oldSnapshot[oldIndex].box.y < invalidTop THEN LOOP; IF newSnapshot[1].viewer # NIL AND -- more than one viewer in column newSnapshot[i].box.y < oldSnapshot[oldIndex].box.y THEN LOOP; IF newSnapshot[i].box # oldSnapshot[oldIndex].box THEN { BLTViewer[newSnapshot[i].viewer, oldSnapshot[oldIndex].box, newSnapshot[i].box]; invalidTop _ MAX[invalidTop, newSnapshot[i].box.y + newSnapshot[i].box.h]; invalidBottom _ MIN[invalidBottom, newSnapshot[i].box.y]; }; newSnapshot[i].painted _ TRUE; ENDLOOP; FOR i: CARDINAL IN [0..newSnapshot.size) DO IF newSnapshot[i].viewer = NIL THEN EXIT; IF ~newSnapshot[i].painted THEN ForkPaintViewerAll[newSnapshot[i].viewer]; ENDLOOP; EXITS done => {}; }; Carets.ResumeCarets[]; }; BLTViewer: PROC [viewer: Viewer, oldBox, newBox: Box] = { rect: PaintRectangle; hBLT: HBltRule; vBLT: VBltRule; w, h, header: INTEGER; fromX, fromY, toX, toY: INTEGER; wbs: INTEGER _ IF viewer.border THEN windowBorderSize ELSE 0; header _ viewer.wh - (viewer.cy + viewer.ch); w _ MIN[oldBox.w, newBox.w]; h _ MIN[oldBox.h, newBox.h]; hBLT _ IF oldBox.w = newBox.w THEN left ELSE viewer.class.bltH; SELECT hBLT FROM left, center, right => { IF oldBox.w # newBox.w THEN w _ w - wbs; -- don't include right border toX _ newBox.x; fromX _ oldBox.x; }; ENDCASE => {ForkPaintViewerAll[viewer]; RETURN}; vBLT _ IF oldBox.h = newBox.h THEN top ELSE viewer.class.bltV; SELECT vBLT FROM top => { IF oldBox.h # newBox.h THEN h _ h - wbs; -- don't include bottom border fromY _ oldBox.y + oldBox.h - h; toY _ newBox.y + newBox.h - h; }; bottom => { h _ h - header; -- don't include top header fromY _ oldBox.y; toY _ newBox.y; }; center => { fromY _ oldBox.y + wbs + oldBox.h/2 - h/2; toY _ newBox.y + wbs + newBox.h/2 - h/2; h _ h - header - wbs; -- don't include top or bottom }; ENDCASE => {ForkPaintViewerAll[viewer]; RETURN}; { OPEN viewer; action: PROC [context: Imager.Context] ~ { rect _ NEW[PaintRectangleRec _ [x: toX, y: toY, w: w, h: h]]; IF fromX # toX OR fromY # toY AND w >=0 AND h >= 0 THEN ImagerBackdoor.MoveViewRectangle[context: context, width: w, height: h, fromX: fromX, fromY: fromY, toX: toX, toY: toY]; Imager.SetColor[context, Imager.white]; IF wy < rect.y THEN -- some on the bottom Imager.MaskRectangleI[context, wx, wy, ww, rect.y - wy]; IF rect.h >=0 AND wy+wh > rect.y+rect.h THEN -- some on the top Imager.MaskRectangleI[context, wx, rect.y+rect.h, ww, (wy+wh) - (rect.y+rect.h)]; IF wx < rect.x THEN -- some on the left Imager.MaskRectangleI[context, wx, wy, rect.x - wx, wh]; IF rect.w >=0 AND wx+ww > rect.x+rect.w THEN -- some on the right Imager.MaskRectangleI[context, rect.x+rect.w, wy, (wx+ww) - (rect.x+rect.w), wh]; Imager.SetColor[context, Imager.black]; IF viewer.border AND (oldBox.w # newBox.w OR oldBox.h # newBox.h) THEN { Imager.MaskRectangleI[context, wx, wy, ww, wbs]; Imager.MaskRectangleI[context, wx, wy, wbs, wh]; Imager.MaskRectangleI[context, wx+ww-wbs, wy, wbs, wh]; Imager.MaskRectangleI[context, wx, wy+wh-wbs, ww, wbs]; }; }; ViewerPrivate.PaintScreen[ViewerPrivate.ViewerScreen[viewer], action]; }; IF viewer.wx < rect.x OR (viewer.wx + viewer.ww > rect.x + rect.w) OR (viewer.wy + viewer.wh - header) < rect.y OR (viewer.wy + viewer.wh > rect.y + rect.h) THEN { ViewerOps.PaintViewer[viewer, caption, FALSE]; ViewerOps.PaintViewer[viewer, menu, FALSE]; }; IF viewer.menu # NIL THEN { viewer.menu.x _ wbs; viewer.menu.y _ viewer.wh-captionHeight; }; ViewerForkers.ForkCall[viewer, RepaintViewer, NEW[RepaintActionData _ [viewer: viewer, xChanged: oldBox.w # newBox.w, yChanged: oldBox.h # newBox.h, rect: rect]]]; }; RepaintActionData: TYPE = RECORD [ viewer: Viewer, xChanged: BOOL, yChanged: BOOL, rect: PaintRectangle]; RepaintViewer: PROC [data: REF] = { WITH data SELECT FROM mine: REF RepaintActionData => { viewer: Viewer _ mine.viewer; ViewerOps.PaintViewer[viewer, client, FALSE, mine.rect]; IF ContainerPaint = NIL THEN ContainerPaint _ ViewerOps.FetchViewerClass[$Container].paint; IF viewer.class.paint = ContainerPaint THEN RepaintBoundViewers[viewer, mine.rect, mine.xChanged, mine.yChanged]; }; ENDCASE; }; RepaintBoundViewers: PROC[viewer: Viewer, rect: PaintRectangle, xChanged, yChanged: BOOL] = { xBound: LIST OF Viewer _ NARROW[viewer.class.get[viewer, $XBound]]; yBound: LIST OF Viewer _ NARROW[viewer.class.get[viewer, $YBound]]; IF xChanged THEN { FOR list: LIST OF Viewer _ xBound, list.rest WHILE list # NIL DO v: Viewer _ list.first; IF v.class.flavor = $Text OR v.class.flavor = $Typescript THEN {ViewerOps.PaintViewer[v, all]; LOOP}; ViewerOps.PaintViewer[v, all, FALSE, rect]; IF v.class.paint = ContainerPaint THEN { doubleBounded: BOOL _ FALSE; IF yChanged THEN FOR l: LIST OF Viewer _ yBound, l.rest WHILE l # NIL DO IF l.first = v THEN {doubleBounded _ TRUE; EXIT}; ENDLOOP; RepaintBoundViewers[v, rect, TRUE, doubleBounded]}; ENDLOOP; }; IF yChanged THEN { FOR list: LIST OF Viewer _ yBound, list.rest WHILE list # NIL DO v: Viewer _ list.first; painted: BOOL _ FALSE; FOR list: LIST OF Viewer _ xBound, list.rest WHILE list # NIL DO IF list.first = v THEN {painted _ TRUE; EXIT}; ENDLOOP; IF painted THEN LOOP; ViewerOps.PaintViewer[v, all, FALSE, rect]; IF v.class.paint = ContainerPaint THEN RepaintBoundViewers[v, rect, FALSE, TRUE]; ENDLOOP; }; }; WithinRect: PROC[v: Viewer, rect: PaintRectangle] RETURNS[BOOL] = { vx, vy: INTEGER; IF v.parent.class.topDownCoordSys THEN [vx, vy] _ ViewerOps.UserToScreenCoords[v.parent, v.wx, v.wy+v.wh] ELSE [vx, vy] _ ViewerOps.UserToScreenCoords[v.parent, v.wx, v.wy]; RETURN[vx >= rect.x AND (vx + v.ww <= rect.x + rect.w) AND vy >= rect.y AND (vy + v.wh <= rect.y + rect.h)]; }; ContainerPaint: ViewerClasses.PaintProc _ NIL; ColumnInfo: PROC[column: Column] RETURNS[totalSpace, leftX, width, bottomY, nextY: INTEGER] = INLINE { SELECT column FROM left => { totalSpace _ openTopY-openBottomY; bottomY _ nextY _ openBottomY; leftX _ openLeftLeftX; width _ openLeftWidth; }; right => { totalSpace _ openTopY-openBottomY; bottomY _ nextY _ openBottomY; leftX _ openRightLeftX; width _ openRightWidth; }; color => { totalSpace _ colorScreenHeight; bottomY _ nextY _ 0; leftX _ 0; width _ colorScreenWidth; }; ENDCASE => ERROR; }; ColumnSnapshot: TYPE ~ REF ColumnSequence; ColumnSequence: TYPE ~ RECORD[SEQUENCE size: NAT OF ColumnRec]; ColumnRec: TYPE ~ RECORD[viewer: Viewer, box: Box, painted: BOOL _ FALSE]; Box: TYPE = RECORD[x, y, w, h: INTEGER]; snapshots: ARRAY Column OF RECORD[before, after: ColumnSnapshot]; SnapshotColumn: PROC[column: Column] RETURNS[snapshot: ColumnSnapshot] = { length: CARDINAL _ 0; snapshot _ snapshots[column].after; IF snapshot = NIL THEN snapshot _ NEW[ColumnSequence[10]]; ClearSnapshot[snapshot]; FOR v: Viewer _ ViewerPrivate.rootViewerTree[column], v.sibling UNTIL v = NIL DO IF length = snapshot.size THEN { -- make a bigger snapshot temp: ColumnSnapshot _ NEW[ColumnSequence[snapshot.size + 10]]; FOR i: CARDINAL IN [0..snapshot.size) DO temp[i] _ snapshot[i]; ENDLOOP; snapshot _ temp; }; snapshot[length] _ [v, [v.wx, v.wy, v.ww, v.wh]]; length _ length + 1; ENDLOOP; }; ClearSnapshot: PROC[snapshot: ColumnSnapshot] = { IF snapshot = NIL THEN RETURN; FOR i: CARDINAL IN [0..snapshot.size) DO snapshot[i].viewer _ NIL; ENDLOOP; }; GetIndex: PROC[snapshot: ColumnSnapshot, viewer: Viewer] RETURNS[CARDINAL] = { FOR i: CARDINAL IN [0..snapshot.size) DO IF snapshot[i].viewer = NIL THEN EXIT; IF snapshot[i].viewer = viewer THEN RETURN[i]; ENDLOOP; RETURN[snapshot.size]; }; Invalidate: PUBLIC PROC = { ClearSnapshot[snapshots[left].before]; ClearSnapshot[snapshots[right].before]; ClearSnapshot[snapshots[color].before]; }; ForkPaintViewerAll: PROC [viewer: Viewer] = TRUSTED { ViewerForkers.ForkPaint[viewer, all]; }; END. ฤViewerBLTImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Doug Wyatt, April 24, 1985 10:48:26 pm PST Russ Atkinson (RRA) June 10, 1985 8:13:36 pm PDT try to save cycles by BLTing bit maps around. this algorithm assumes that the column is almost in the same order as it was before, except for creating, deleting, or moving at most one viewer. the algorithm should never blt an invalid bitmap. iterate from bottom to top of column, BLTing bit maps if the space is free check to see if the bitmap is invalid check to see if BLTing would wipe out a bitmap above now do it from top to bottom, catching the ones we couldn't do before check to see if the bitmap is invalid check to see if BLTing would wipe out a bitmap below assume that the menu is the same for before and after later we will distinguish between left, right and center -- erase remainder repaint header reset cached position call RepaintViewer even if the shape didn't change Private contract between RepaintViewer & BLTViewer. if this is a container, repaint the sub-viewers that were x and y bound. we cannot use the class name because the viewer may be a subclass of $Container. repaint x bound IF WithinRect[v, rect] THEN { repaint y bound IF WithinRect[v, rect] THEN { Glitch: PUBLIC PROC [viewer: Viewer, nLines: INTEGER] = { dY, sY, vY, vX: INTEGER; w: INTEGER _ viewer.cw; h: INTEGER _ viewer.ch-ABS[nLines]; dc: Graphics.Context _ ViewerOps.AcquireContext[NIL]; [vX, vY] _ ViewerOps.UserToScreenCoords[viewer, 0, IF viewer.class.coordSys=top THEN 0 ELSE viewer.ch]; dY _ IF nLines>0 THEN vY ELSE vY-nLines; sY _ IF nLines>0 THEN vY-nLines ELSE vY; Graphics.SetCP[dc, vX, dY]; GraphicsOps.DrawBitmap[ self: dc, bitmap: GraphicsOps.ScreenBitmap[], w: w, h: h, x: vX, y: ViewerSpecs.screenH-sY, xorigin: vX, yorigin: ViewerSpecs.screenH-sY ]; ViewerOps.ReleaseContext[dc]; }; VBLT: PUBLIC PROC [src: VPlace, dest: VPlace, srcw, srch: INTEGER] = { ERROR; -- not yet implemented }; ส)– "Mesa" style˜codešœ™Kšœ ฯmœ1™šžœž˜šœ˜Kšžœžœก˜GKšœ!˜!Kšœ˜Kšœ˜—šœ ˜ Kšœก˜+Kšœ˜Kšœ˜Kšœ˜—˜ K˜*K˜(Kšœก˜4Kšœ˜—Kšžœ!žœ˜0K˜—šœžœ˜šœžœ˜*Kšœžœ3˜=Kšžœ žœ žœžœ˜3Kšžœz˜~Kšœ™Kšœ'˜'šžœ žœก˜*Kšœ8˜8—šžœ žœžœก˜@KšœQ˜Q—šžœ žœก˜(Kšœ8˜8—šžœ žœžœก˜BKšœQ˜Q—Kšœ(˜(šžœžœžœžœ˜IKšœ0˜0Kšœ0˜0Kšœ7˜7Kšœ7˜7K˜—K˜—KšœF˜FKšœ˜—K˜š žœžœ*žœ*žœ+žœ˜ฃKšœ™Kšœ'žœ˜.Kšœ$žœ˜+Kšœ˜—šžœžœžœ˜Kšœ™Kšœ˜Kšœ(˜(Kšœ˜—Kšœ2™2Kšœ.žœr˜ฃKšœ˜K˜—šœžœžœ˜"Kšœ3™3Kšœžœ žœ˜FK˜—š  œžœžœ˜#šžœžœž˜šœžœ˜ Kšœ˜Kšœ&žœ ˜8K™HK™Pšžœžœž˜Kšœ>˜>—šžœ%ž˜+KšœE˜E—K˜—Kšžœ˜—K˜K˜—š œžœ;žœ˜]Kšœžœžœ žœ$˜CKšœžœžœ žœ%˜Dšžœ žœ˜Kšœ™š žœžœžœžœžœž˜@K˜Kšžœžœžœ!žœ˜eKšœ™Kšœžœ˜+šžœ žœ˜(Kšœžœžœ˜šžœ žœžœžœžœžœžœž˜HKšžœ žœžœžœ˜1Kšžœ˜—Kšœžœ˜3—Kšžœ˜—Kšœ˜—šžœ žœ˜Kšœ™š žœžœžœžœžœž˜@K˜Kšœ žœžœ˜š žœžœžœžœžœž˜@Kšžœžœ žœžœ˜.Kšžœ˜—Kšžœ žœžœ˜Kšœ™Kšœžœ˜+Kšžœ žœžœžœ˜QKšžœ˜—Kšœ˜—Kšœ˜K˜—š  œžœ"žœžœ˜CKšœžœ˜šžœ˜!KšžœC˜GKšžœ?˜C—šžœžœ ž˜:Kšœ žœ!˜1—Kšœ˜K˜—Kšœ*žœ˜.K˜š   œžœžœ+žœžœ˜fšžœž˜šœ ˜ K˜"K˜K˜Kšœ˜Kšœ˜—šœ ˜ K˜"K˜K˜Kšœ˜Kšœ˜—šœ ˜ Kšœ˜Kšœ˜Kšœ ˜ Kšœ˜Kšœ˜—Kšžœžœ˜—Kšœ˜—K˜Kšœžœžœ˜*Kš œžœžœžœžœžœ ˜?Kš œ žœžœ$žœžœ˜JKšœžœžœ žœ˜(K˜šœ žœžœžœ ˜AK˜—š œžœžœ˜JKšœžœ˜Kšœ#˜#Kšžœ žœžœ žœ˜;Kšœ˜šžœ=žœžœž˜Pšžœžœก˜:Kšœžœ%˜?šžœžœžœž˜(Kšœ˜Kšžœ˜—K˜K˜—Kšœ1˜1Kšœ˜Kšžœ˜—Kšœ˜K˜—š  œžœ˜1Kšžœ žœžœžœ˜Kš žœžœžœžœžœžœ˜KKšœ˜K˜—š œžœ+žœžœ˜Nšžœžœžœž˜(Kšžœžœžœžœ˜&Kšžœžœžœ˜.Kšžœ˜—Kšžœ˜Kšœ˜K˜—š  œžœžœ˜Kšœ&˜&Kšœ'˜'Kšœ'˜'Kšœ˜K˜—š œžœžœ˜5Kšœ%˜%K˜K˜—šžœ˜K™šœ9™9Kšœ™Kšœ™Kšœ#™#Kšœ5™5šœ2™2Kšœ4™4—Kšœ)™)Kšœ)™)K™™K™ K™#K™K™K™K™K™ K™K™—K™Kšœ™K™—šœF™FKšœ™Kšœ™K™———…—.šE‡