DIRECTORY Carets USING [pCaretViewer, ResumeCarets, sCaretViewer, StartCaret, SuspendCarets], ColorDisplay USING [height, width], Graphics USING [black, ClipBox, Context, DrawBox, SetColor, SetStipple, white], GraphicsColor USING [IntensityToColor], GraphicsOps USING [MoveDeviceRectangle], Menus, Process USING [Detach], ViewerBLT, ViewerClasses, ViewerLocks USING [CallUnderWriteLock], ViewerOps, ViewerSpecs, WindowManagerPrivate USING [rootViewerTree]; ViewerBLTImpl: CEDAR PROGRAM IMPORTS Carets, ColorDisplay, Graphics, GraphicsColor, GraphicsOps, Menus, Process, ViewerLocks, ViewerOps, ViewerSpecs, WindowManagerPrivate EXPORTS ViewerBLT, ViewerOps SHARES Menus, ViewerOps, ViewerClasses = BEGIN OPEN ViewerClasses, ViewerOps, ViewerSpecs, WindowManagerPrivate; ChangeNumberOfLines: PUBLIC PROC[viewer: Viewer, newLines: [0..5)] = BEGIN LockedChangeLines: PROC = BEGIN oldBox, newBox: Box; IF viewer.menu = NIL THEN RETURN; oldBox _ [viewer.cx, viewer.cy, viewer.cw, viewer.ch]; Menus.ChangeNumberOfLines[viewer.menu, newLines]; ViewerOps.EstablishViewerPosition[viewer, viewer.wx, viewer.wy, viewer.ww, viewer.wh]; newBox _ [viewer.cx, viewer.cy, viewer.cw, viewer.ch]; BLTViewer[viewer, oldBox, newBox]; END; ViewerLocks.CallUnderWriteLock[LockedChangeLines, viewer]; END; InternalPaintColumn: PUBLIC PROC [column: Column, paintIcons: BOOL _ TRUE] = BEGIN oldIndex: CARDINAL; oldSnapshot: ColumnSnapshot; newSnapshot: ColumnSnapshot; invalidTop, invalidBottom: INTEGER; IF column = static THEN { FOR v: Viewer _ rootViewerTree[column], v.sibling UNTIL v=NIL DO IF ~v.offDeskTop THEN TRUSTED {Process.Detach[FORK PaintViewer[v, all]]}; ENDLOOP; RETURN}; IF rootViewerTree[column] = NIL THEN { height, leftX, width, bottomY: INTEGER; [height, leftX, width, bottomY, ] _ ColumnInfo[column]; GreyScreen[leftX, bottomY, width, height, column=color, FALSE]; IF paintIcons AND column # color THEN -- paint newly visible icons FOR v: Viewer _ 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; TRUSTED {Process.Detach[FORK PaintViewer[v, all]]}; ENDLOOP; RETURN}; oldSnapshot _ snapshots[column].before; newSnapshot _ SnapshotColumn[column]; snapshots[column].before _ newSnapshot; snapshots[column].after _ oldSnapshot; IF oldSnapshot = NIL THEN { Carets.SuspendCarets[]; FOR v: Viewer _ rootViewerTree[column], v.sibling UNTIL v=NIL DO TRUSTED {Process.Detach[FORK PaintViewer[v, all]]}; ENDLOOP; WaitForPaintingToFinish[]; Carets.ResumeCarets[]; RETURN}; Carets.SuspendCarets[]; 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 TRUSTED { Process.Detach[FORK PaintViewer[newSnapshot[i].viewer, all]]}; ENDLOOP; Carets.StartCaret[Carets.pCaretViewer, -10000, -10000, primary]; -- reset the primary caret Carets.StartCaret[Carets.sCaretViewer, -10000, -10000, secondary]; -- reset the secondary caret WaitForPaintingToFinish[]; Carets.ResumeCarets[]; END; ScreenHeightForViewer: PROC[viewer: Viewer] RETURNS[INTEGER] = INLINE { RETURN[IF viewer.column=color THEN ColorDisplay.height ELSE ViewerSpecs.screenH] }; BLTViewer: PROC[viewer: Viewer, oldBox, newBox: Box] = BEGIN rect: PaintRectangle; hBLT, vBLT: BltRule; w, h, header: INTEGER; context: Graphics.Context; fromX, fromY, toX, toY: INTEGER; wbs: INTEGER _ IF viewer.border THEN windowBorderSize ELSE 0; screenH: INTEGER = ScreenHeightForViewer[viewer]; header _ (viewer.wy + viewer.wh) - (viewer.cy + viewer.ch); w _ MIN[oldBox.w, newBox.w]; h _ MIN[oldBox.h, newBox.h]; IF (viewer.class.flavor = $Text OR viewer.class.flavor = $Typescript) THEN vBLT _ none ELSE vBLT _ viewer.class.bltContents; IF oldBox.w = newBox.w THEN vBLT _ top; SELECT vBLT FROM top, bottom, center => { -- later we will distinguish between left, right and center IF oldBox.w # newBox.w THEN w _ w - wbs; -- don't include right border toX _ newBox.x; fromX _ oldBox.x}; ENDCASE => TRUSTED {Process.Detach[FORK PaintViewer[viewer, all]]; RETURN}; hBLT _ IF oldBox.h = newBox.h THEN top ELSE viewer.class.bltContents; SELECT hBLT 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 => TRUSTED {Process.Detach[FORK PaintViewer[viewer, all]]; RETURN}; BEGIN OPEN viewer; ENABLE UNWIND => IF context#NIL THEN ReleaseContext[context]; context _ AcquireContext[NIL, viewer.column=color]; rect _ NEW[PaintRectangleRec _ [blt, toX, toY, w, h]]; IF fromX # toX OR fromY # toY THEN GraphicsOps.MoveDeviceRectangle[ self: context, width: w, height: h, fromX: fromX, fromY: screenH - (fromY + h), toX: toX, toY: screenH - (toY + h)]; Graphics.SetColor[context, Graphics.white]; IF wy < rect.y THEN -- some on the bottom Graphics.DrawBox[context, XYWH2Box[wx, wy, ww, rect.y - wy]]; IF wy+wh > rect.y+rect.h THEN -- some on the top Graphics.DrawBox[context, XYWH2Box[wx, rect.y+rect.h, ww, (wy+wh) - (rect.y+rect.h)]]; IF wx < rect.x THEN -- some on the left Graphics.DrawBox[context, XYWH2Box[wx, wy, rect.x - wx, wh]]; IF wx+ww > rect.x+rect.w THEN -- some on the right Graphics.DrawBox[context, XYWH2Box[rect.x+rect.w, wy, (wx+ww) - (rect.x+rect.w), wh]]; Graphics.SetColor[context, Graphics.black]; IF viewer.border AND (oldBox.w # newBox.w OR oldBox.h # newBox.h) THEN { Graphics.DrawBox[context, XYWH2Box[wx, wy, ww, wbs]]; Graphics.DrawBox[context, XYWH2Box[wx, wy, wbs, wh]]; Graphics.DrawBox[context, XYWH2Box[wx+ww-wbs, wy, wbs, wh]]; Graphics.DrawBox[context, XYWH2Box[wx, wy+wh-wbs, ww, wbs]]}; ReleaseContext[context]; END; 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 { -- repaint header PaintViewer[viewer, caption, FALSE]; PaintViewer[viewer, menu, FALSE]}; IF oldBox.w # newBox.w OR oldBox.h # newBox.h -- shape has changed THEN TRUSTED {Process.Detach[FORK PaintViewer[viewer, client, FALSE, rect]]}; IF viewer.menu # NIL THEN { -- reset cached position viewer.menu.x _ viewer.wx + wbs; viewer.menu.y _ viewer.wy + viewer.wh - menuHeight - captionHeight}; END; ColumnInfo: PROC[column: Column] RETURNS[totalSpace, leftX, width, bottomY, nextY: INTEGER] = INLINE BEGIN SELECT column FROM left => { totalSpace _ openLeftTopY-openBottomY; bottomY _ nextY _ openBottomY; leftX _ openLeftLeftX; width _ openLeftWidth}; right => { totalSpace _ openRightTopY-openBottomY; bottomY _ nextY _ openBottomY; leftX _ openRightLeftX; width _ openRightWidth}; color => { totalSpace _ ColorDisplay.height; bottomY _ nextY _ 0; leftX _ 0; width _ ColorDisplay.width}; ENDCASE => ERROR; END; ColumnSnapshot: TYPE = REF ColumnSequence; ColumnSequence: TYPE = RECORD[SEQUENCE size: NAT OF 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] = BEGIN length: CARDINAL _ 0; snapshot _ snapshots[column].after; IF snapshot = NIL THEN snapshot _ NEW[ColumnSequence[10]]; ClearSnapshot[snapshot]; FOR v: Viewer _ 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; END; ClearSnapshot: PROC[snapshot: ColumnSnapshot] = INLINE BEGIN IF snapshot = NIL THEN RETURN; FOR i: CARDINAL IN [0..snapshot.size) DO snapshot[i].viewer _ NIL; ENDLOOP; END; GetIndex: PROC[snapshot: ColumnSnapshot, viewer: Viewer] RETURNS[CARDINAL] = BEGIN 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]; END; GreyScreen: PUBLIC PROC [x,y,w,h: INTEGER, color, icon: BOOL, stipple: CARDINAL _ 104042B] = BEGIN context: Graphics.Context _ AcquireContext[NIL, color]; IF icon AND y+h > openBottomY THEN ClipIcon[context]; IF color THEN Graphics.SetColor[context, GraphicsColor.IntensityToColor[.5]] ELSE Graphics.SetStipple[context, stipple]; Graphics.DrawBox[context, ViewerOps.XYWH2Box[x, y, w, h]]; ReleaseContext[context]; IF icon THEN RETURN; IF color THEN ClearSnapshot[snapshots[color].before] ELSE { IF x + w > openRightLeftX THEN ClearSnapshot[snapshots[right].before]; IF x < openLeftLeftX + openLeftWidth THEN ClearSnapshot[snapshots[left].before]}; END; ClipIcon: PROC [context: Graphics.Context] = BEGIN ClipOpenViewer: ViewerOps.EnumProc = BEGIN IF ~v.iconic AND (v.column=right OR v.column=left) THEN Graphics.ClipBox[context, [v.wx, v.wy, v.wx+v.ww, v.wy+v.wh], TRUE]; END; ViewerOps.EnumerateViewers[ClipOpenViewer]; END; END . . . Glitch: PUBLIC PROC [viewer: Viewer, nLines: INTEGER] = BEGIN 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]; END; VBLT: PUBLIC PROC [src: VPlace, dest: VPlace, srcw, srch: INTEGER] = BEGIN ERROR; -- not yet implemented END; END. ÒViewerBLTImpl.mesa; Last Edited by McGregor, May 31, 1983 11:18 am Last Edited by: Maxwell, May 24, 1983 11:53 am Last Edited by: Wyatt, September 15, 1983 10:40 am -- 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 reset caret below relies on special deal with CaretsImpl -- assume that the menu is the same for before and after -- erase remainder clips for overlapping top level windows given valid Context and Viewer Ê k– "Mesa" style˜JšÏc™Jš.™.Jšœ.™.Jšœ2™2J˜šÏk ˜ JšœžœG˜SJšœ žœ˜#Jšœ žœA˜OJšœžœ˜'Jšœ žœ˜(Jšœ˜Jšœžœ ˜J˜ Jšœ˜Jšœ žœ˜'Jšœ ˜ Jšœ ˜ Jšœžœ˜,J˜—šœž ˜Jšžœ†˜Jšžœ˜Jšžœ"˜(J˜—Jšžœžœ=˜GJ˜šÏnœžœžœ%ž˜JšŸœžœž˜Jšœ˜Jšžœžœžœžœ˜!J˜6J˜1J˜VJ˜6Jšœ"˜"Jšžœ˜—J˜Jšœ:˜:Jšžœ˜J˜—š Ÿœžœžœžœžœ˜MJšž˜Jšœ žœ˜Jšœ˜Jšœ˜Jšœžœ˜#J˜šžœžœ˜šžœ/žœžœž˜@Jšžœžœžœžœ˜IJšžœ˜—Jšžœ˜J˜—šžœžœžœ˜&Jšœžœ˜'Jšœ7˜7Jšœ8žœ˜?šžœ žœžœ˜Cšžœ/žœžœž˜@Jšžœ žœžœžœ˜'Jšžœžœžœ˜#Jšžœžœžœ˜!Jšžœžœžœ˜"Jšžœžœ˜3Jšžœ˜——Jšžœ˜J˜—Jšœ'˜'Jšœ%˜%Jšœ'˜'Jšœ&˜&J˜šžœžœžœ˜Jšœ˜šžœ/žœžœž˜@Jšžœžœ˜3Jšžœ˜—Jšœ˜Jšœ˜Jšžœ˜—J˜Jšœ˜J˜Jšœ1™1J™WJš?™?J™4J™Jšœ)˜=Jšœ/˜EJšœJ™Mšžœžœžœž˜+Jšžœžœžœžœ˜)J˜8Jšžœžœžœ˜9Jš(™(šžœJ˜LJšžœ*žœžœ˜7—Jš7™7šžœ/˜1Jšœ:žœžœ˜E—šœ2žœ˜8JšœP˜PJšœ žœ:˜JJšœžœ'˜:—Jšœžœ˜Jšžœ˜—J˜JšœE™Hš žœžœž œžœž˜6Jšžœžœžœžœ˜)Jšžœžœžœ˜$J˜8Jšžœžœžœ˜9Jš(™(šžœJ˜LJšžœ*žœžœ˜7—Jš7™7šžœžœžœ"˜EJšœ3žœžœ˜=—šœ2žœ˜8JšœP˜PJšœ žœ:˜JJšœžœ'˜:—Jšœžœ˜Jšžœ˜J˜—šžœžœžœž˜+Jšžœžœžœžœ˜)šžœžœžœ˜)Jšœžœ+˜>—Jšžœ˜—J˜Jšœ8™8JšœA˜[JšœC˜_Jšœ˜J˜Jšžœ˜—J˜š Ÿœžœžœžœžœ˜GJšžœžœžœžœ˜SJ˜—šŸ œžœ(ž˜Jšœ žœž˜$Jšœ+žœ ˜7Jšžœžœžœ˜5šžœžœ?˜LJšžœ'˜+—J˜:J˜Jšžœžœžœ˜šžœžœ(žœ˜;Jšžœžœ(˜FJšžœ#žœ(˜Q—Jšžœ˜J˜—šŸœžœž˜2JšF™Fšœ%ž˜*šžœ žœžœž˜7Jšœ>žœ˜D—Jšžœ˜—J˜+Jšžœ˜—J˜J˜Jšžœ˜ J˜š Ÿœžœžœžœž˜=Jšœžœ˜Jšœžœ ˜Jšœžœ žœ ˜#Jšœ0žœ˜5˜2Jšžœžœžœ ˜4—Jšœžœ žœžœ ˜)Jšœžœ žœ žœ˜)J˜˜J˜ J˜#J˜J˜J˜J˜J˜ J˜J˜—J˜Jšžœ˜J˜—š žœžœžœ)žœž˜JJšžœ˜Jšžœ˜J˜—Jšžœ˜J˜J˜—…—-À>ý