-- 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.