-- Copyright (C) 1982, 1983, 1984 by Xerox Corporation. All rights reserved. -- File: WindowImplB.mesa - last edit: -- Haynes.PA 31-Aug-84 14:24:11 -- Bruce, 20-Dec-82 15:52:11 -- Daniels 31-Oct-83 15:51:32 DIRECTORY BitBlt: TYPE USING [BitAddress, BITBLT], Display: TYPE USING [replaceFlags], Inline: TYPE USING [LongDiv, LongMult], RecOps: TYPE USING [ Alloc, Bite, Blt, ClipBox, Convert, ConvertBox, Copy, Free, FreeRecList, Intersect, RecList, ScreenToWindowBox, Shift], SpecialDisplay: TYPE USING [defaultContext, Special], Window: TYPE USING [ Box, EnumerateTree, Error, MouseTransformerProc, nullBox, Place, Stack, UnderChangedProc, ValidateTree], WindowExtra: TYPE USING [], WindowOps: TYPE USING [ AssertUnobscured, bbPtr, InvalidateTree, GetBpl, lock, Object, Offset, rootWindow, SpecialTimesWpl]; WindowImplB: MONITOR LOCKS WindowOps.lock IMPORTS BitBlt, Inline, RecOps, SpecialDisplay, Window, WindowOps EXPORTS Window, WindowExtra = BEGIN Handle: TYPE = LONG POINTER TO Object; Object: PUBLIC TYPE = WindowOps.Object; -- reading and writing fields in opaque record GetBox: PUBLIC PROC [w: Handle] RETURNS [Window.Box] = {RETURN[w.box]}; GetParent: PUBLIC PROC [w: Handle] RETURNS [Handle] = {RETURN[w.parent]}; GetSibling: PUBLIC PROC [w: Handle] RETURNS [Handle] = {RETURN[w.sibling]}; GetChild: PUBLIC PROC [w: Handle] RETURNS [Handle] = {RETURN[w.child]}; GetDisplayProc: PUBLIC PROC [w: Handle] RETURNS [PROC [Handle]] = { RETURN[w.display]}; GetClearingRequired: PUBLIC PROC [w: Handle] RETURNS [BOOLEAN] = { RETURN[w.clearingRequired]}; GetUseBadPhosphor: PUBLIC PROC [w: Handle] RETURNS [BOOLEAN] = { RETURN[w.useBadPhosphor]}; IsDescendantOfRoot: PUBLIC PROC [w: Handle] RETURNS [BOOLEAN] = { RETURN[w.inTree]}; SetParent: PUBLIC PROC [window, newParent: Handle] RETURNS [oldParent: Handle] = { IF window.inTree THEN ERROR Window.Error[windowInTree]; oldParent ← window.parent; window.parent ← newParent}; SetSibling: PUBLIC PROC [window, newSibling: Handle] RETURNS [oldSibling: Handle] = { IF window.inTree THEN ERROR Window.Error[windowInTree]; oldSibling ← window.sibling; window.sibling ← newSibling}; SetChild: PUBLIC PROC [window, newChild: Handle] RETURNS [oldChild: Handle] = { IF window.inTree THEN ERROR Window.Error[windowInTree]; oldChild ← window.child; window.child ← newChild}; SetDisplayProc: PUBLIC PROC [window: Handle, newProc: PROC [Handle]] RETURNS [oldProc: PROC [Handle]] = { oldProc ← window.display; window.display ← newProc}; SetClearingRequired: PUBLIC PROC [window: Handle, required: BOOLEAN] RETURNS [old: BOOLEAN] = { old ← window.clearingRequired; window.clearingRequired ← required}; SetUseBadPhosphor: PUBLIC ENTRY PROC [window: Handle, use: BOOLEAN] RETURNS [old: BOOLEAN] = { ENABLE UNWIND => NULL; old ← window.useBadPhosphor; window.useBadPhosphor ← use}; InitializeWindow: PUBLIC PROC [ window: Handle, display: PROC [Handle], box: Window.Box, parent: Handle ← WindowOps.rootWindow, sibling, child: Handle ← NIL, clearingRequired: BOOLEAN ← TRUE, under, cookieCutter: BOOLEAN ← FALSE] = { window↑ ← [ beingDisplayed: FALSE, useBadPhosphor: TRUE, cookieCutterVariant: cookieCutter, cookie: FALSE, underVariant: under, underNow: FALSE, clearingRequired: clearingRequired, inTree: FALSE, parent: parent, sibling: sibling, child: child, box: box, place: [0, 0], display: display, invalid: NIL, badPhosphor: NIL]}; -- bitmap under routines MinusLandBitmapUnder: PUBLIC TYPE = RECORD [ pointer: LONG POINTER, underChanged: Window.UnderChangedProc, -- ↑↑ called when bitmapunder changes if # NIL mouseTransformer: Window.MouseTransformerProc] ← TRASH; -- make Ed happy... -- ↑↑ called to convert a mouse position if # NIL WordsForBitmapUnder: PUBLIC PROC [window: Handle] RETURNS [CARDINAL] = { RETURN[ Inline.LongDiv[ Inline.LongMult[window.box.dims.w + 31, window.box.dims.h], 16]]}; GetBitmapUnder: PUBLIC PROC [window: Handle] RETURNS [LONG POINTER] = { minus: LONG POINTER TO MinusLandBitmapUnder; IF ~window.underVariant THEN RETURN[NIL]; IF ~window.underNow THEN RETURN[NIL]; minus ← LOOPHOLE[window - MinusLandBitmapUnder.SIZE]; RETURN[minus.pointer]}; SetBitmapUnder: PUBLIC PROC [ window: Handle, pointer: LONG POINTER ← NIL, underChanged: Window.UnderChangedProc ← NIL, mouseTransformer: Window.MouseTransformerProc ← NIL] RETURNS [oldPointer: LONG POINTER] = { shouldValidate: BOOLEAN ← FALSE; SetBitmapUnderLocked: ENTRY PROC = { ENABLE UNWIND => NULL; atbu: LONG POINTER TO MinusLandBitmapUnder ← LOOPHOLE[window, LONG POINTER] - MinusLandBitmapUnder.SIZE; IF ~window.underVariant THEN ERROR Window.Error[noUnderVariant]; oldPointer ← atbu.pointer; atbu↑ ← MinusLandBitmapUnder[ pointer: pointer, underChanged: underChanged, mouseTransformer: mouseTransformer]; window.underNow ← pointer # NIL; IF ~window.inTree OR ~window.underNow THEN RETURN; WindowOps.AssertUnobscured[window, illegalBitmap]; {bitsToInvalidate: RecOps.RecList = RecOps.Convert[window]; oldInvalidList: RecOps.RecList = window.invalid; window.invalid ← NIL; SetDst[bitsToInvalidate, window]; WindowOps.InvalidateTree[window.parent, window.sibling, bitsToInvalidate]; RecOps.FreeRecList[window.invalid]; window.invalid ← oldInvalidList}; shouldValidate ← TRUE}; IF pointer # NIL AND window.inTree THEN Window.Stack[window, window.parent.child]; SetBitmapUnderLocked[]; IF shouldValidate THEN Window.ValidateTree[]}; Float: PUBLIC PROC [ window, temp: Handle, proc: PROC [window: Handle] RETURNS [place: Window.Place, done: BOOLEAN]] = { done: BOOLEAN; newPlace: Window.Place; IF window.parent = NIL THEN ERROR Window.Error[illegalFloat]; IF ~window.inTree THEN ERROR Window.Error[illegalFloat]; IF temp.inTree THEN ERROR Window.Error[illegalFloat]; [newPlace, done] ← proc[window]; IF done THEN RETURN; Window.Stack[window, window.parent.child]; Window.ValidateTree[]; FloatLocked[window, temp, proc, newPlace]}; FloatLocked: ENTRY PROC [ window, temp: Handle, proc: PROC [window: Handle] RETURNS [place: Window.Place, done: BOOLEAN], newPlace: Window.Place] = { ENABLE UNWIND => NULL; ctx: SpecialDisplay.Special = SpecialDisplay.defaultContext; icon: LONG POINTER = GetBitmapUnder[temp]; iconBpl: CARDINAL = window.box.dims.w; done: BOOLEAN ← FALSE; IF icon = NIL THEN ERROR Window.Error[illegalFloat]; IF GetBitmapUnder[window] = NIL THEN ERROR Window.Error[illegalFloat]; IF temp.box.dims # window.box.dims THEN ERROR Window.Error[illegalFloat]; WindowOps.AssertUnobscured[window, illegalFloat]; WindowOps.bbPtr↑ ← [ dst: [word: icon, bit: 0], dstBpl: iconBpl, src: GetBitAddress[window.place, ctx], srcDesc: [srcBpl[ctx.bpl]], width: iconBpl, height: window.box.dims.h, flags: Display.replaceFlags]; BitBlt.BITBLT[WindowOps.bbPtr]; UNTIL done DO dx: INTEGER = newPlace.x - window.place.x; dy: INTEGER = newPlace.y - window.place.y; old: RecOps.RecList = RecOps.Convert[window]; new: RecOps.RecList = RecOps.Shift[RecOps.Copy[old], dx, dy]; list: RecOps.RecList; Slide: INTERNAL PROC [w: Handle] = { w.place.x ← w.place.x + dx; w.place.y ← w.place.y + dy}; list ← RecOps.Bite[list: RecOps.Copy[old], biter: RecOps.Copy[new]]; SetSrc[list, window]; RecOps.Blt[list, 0, 0]; -- place bits down from under ShiftUnder[window, old.box.left, old.box.top, dx, dy]; Window.EnumerateTree[window, Slide]; window.box.place.x ← window.box.place.x + dx; window.box.place.y ← window.box.place.y + dy; list ← RecOps.Bite[list: new, biter: old]; SetDst[list, window]; RecOps.Blt[list, 0, 0]; -- pick up new bits WindowOps.bbPtr↑ ← [ -- put back icon dst: GetBitAddress[window.place, ctx], dstBpl: ctx.bpl, src: [word: icon, bit: 0], srcDesc: [srcBpl[iconBpl]], width: iconBpl, height: window.box.dims.h, flags: Display.replaceFlags]; BitBlt.BITBLT[WindowOps.bbPtr]; [newPlace, done] ← proc[window]; ENDLOOP}; ShiftUnder: INTERNAL PROC [w: Handle, left, top, dx, dy: INTEGER] = { oldOffset: CARDINAL = CARDINAL[left]/16; underLeft: CARDINAL = oldOffset*16; myDx: INTEGER = (CARDINAL[left + dx]/16 - oldOffset)*16; old: RecOps.RecList = RecOps.Alloc[]; new: RecOps.RecList; old↑ ← [ box: [ left: underLeft, top: top, right: underLeft + WindowOps.GetBpl[w], bottom: top + w.box.dims.h], link: NIL, src: w, dst: w]; new ← RecOps.Shift[RecOps.Copy[old], myDx, dy]; RecOps.Blt[RecOps.Intersect[old, new], -myDx, -dy]; RecOps.FreeRecList[new]; RecOps.FreeRecList[old]}; SetSrc: PROC [list: RecOps.RecList, w: Handle] = INLINE { FOR r: RecOps.RecList ← list, r.link UNTIL r = NIL DO r.src ← w ENDLOOP}; SetDst: PROC [list: RecOps.RecList, w: Handle] = INLINE { FOR r: RecOps.RecList ← list, r.link UNTIL r = NIL DO r.dst ← w ENDLOOP}; GetBitAddress: PROC [place: Window.Place, ctx: SpecialDisplay.Special] RETURNS [BitBlt.BitAddress] = INLINE { offset, bit: INTEGER; [word: offset, bit: bit] ← WindowOps.Offset[place.x]; RETURN[[ word: ctx.bmAddress + WindowOps.SpecialTimesWpl[place.y, ctx] + offset, bit: bit]]}; -- utilities used only by Tajo BitmapPlace: PUBLIC PROC [window: Handle, place: Window.Place ← [0, 0]] RETURNS [pl: Window.Place] = { pl.x ← place.x + window.place.x; pl.y ← place.y + window.place.y}; BitmapPlaceToWindowAndPlace: PUBLIC PROC [bitmapPlace: Window.Place] RETURNS [window: Handle, place: Window.Place] = { w: Handle ← WindowOps.rootWindow; child: Handle; IF NOT w.inTree THEN RETURN [NIL, [0, 0]]; IF bitmapPlace.x NOT IN [w.box.place.x..w.box.place.x + w.box.dims.w) OR bitmapPlace.y NOT IN [w.box.place.y..w.box.place.y + w.box.dims.h) THEN RETURN[NIL, [0, 0]]; DO FOR child ← w.child, child.sibling UNTIL child = NIL DO IF bitmapPlace.x IN [child.place.x..child.place.x + child.box.dims.w) AND bitmapPlace.y IN [child.place.y..child.place.y + child.box.dims.h) THEN EXIT; ENDLOOP; IF child = NIL THEN RETURN[w, [bitmapPlace.x - w.place.x, bitmapPlace.y - w.place.y]]; w ← child; ENDLOOP}; BoxesAreDisjoint: PUBLIC PROC [a, b: Window.Box] RETURNS [BOOLEAN] = { RETURN[ (a.place.x + a.dims.w <= b.place.x) OR (a.place.x >= b.place.x + b.dims.w) OR (a.place.y + a.dims.h <= b.place.y) OR (a.place.y >= b.place.y + b.dims.h)]}; IntersectBoxes: PUBLIC PROC [b1, b2: Window.Box] RETURNS [box: Window.Box] = { left: INTEGER = MAX[b1.place.x, b2.place.x]; top: INTEGER = MAX[b1.place.y, b2.place.y]; right: INTEGER = MIN[b1.place.x + b1.dims.w, b2.place.x + b2.dims.w]; bottom: INTEGER = MIN[b1.place.y + b1.dims.h, b2.place.y + b2.dims.h]; box ← [[left, top], [right - left, bottom - top]]; IF box.dims.h <= 0 OR box.dims.w <= 0 THEN RETURN[Window.nullBox]}; IsPlaceInBox: PUBLIC PROC [place: Window.Place, box: Window.Box] RETURNS [BOOLEAN] = { RETURN[ place.x IN [box.place.x..box.place.x + box.dims.w) AND place.y IN [box.place.y..box.place.y + box.dims.h)]}; ObscuredBySibling: PUBLIC PROC [w: Handle] RETURNS [BOOLEAN] = { FOR sib: Handle ← w.parent.child, sib.sibling UNTIL sib = w DO IF ~BoxesAreDisjoint[sib.box, w.box] THEN RETURN[TRUE] ENDLOOP; RETURN[FALSE]}; TrimBoxStickouts: PUBLIC PROC [window: Handle, box: Window.Box] RETURNS [newBox: Window.Box] = { r: RecOps.RecList; IF ~window.inTree THEN RETURN[Window.nullBox]; r ← RecOps.ClipBox[window, RecOps.ConvertBox[window, box]].clippedBox; IF r.link # NIL THEN {ClipBoxBug: SIGNAL = CODE; SIGNAL ClipBoxBug}; newBox ← RecOps.ScreenToWindowBox[r.box]; newBox.place.x ← newBox.place.x - window.place.x; newBox.place.y ← newBox.place.y - window.place.y; RecOps.Free[r]}; END.