Copyright (C) 1992, Digital Equipment Corporation
All rights reserved.
See the file COPYRIGHT for a full description.
by Steve Glassman, Mark Manasse and Greg Nelson
Last modified on Tue Jan 31 09:06:40 PST 1995 by kalsow
modified on Fri Jul 8 17:10:22 PDT 1994 by msm
modified on Mon Nov 22 13:56:14 PST 1993 by steveg
modified on Mon Feb 24 13:59:46 PST 1992 by muller
<*PRAGMA LL*>
UNSAFE MODULE XMessenger;
IMPORT XClient, XClientF, TrestleClass, VBT, VBTClass, XEventQueue, X,
Thread, Split, TrestleComm, VBTRep, Ctypes, Word, Rect, XProperties,
Region, DpyFilter, TrestleOnX, MiscDetail, Text, Point, IntRefTbl;
TYPE
Closure = Thread.SizedClosure OBJECT
xcon: XClient.T
OVERRIDES
apply := Messenger
END;
PROCEDURE Start (trsl: XClient.T; stackSize := 20000) =
BEGIN
EVAL Thread.Fork(NEW(Closure, xcon := trsl, stackSize := stackSize));
END Start;
TYPE
Last = RECORD
x, y : INTEGER := 0;
root : X.Window := X.None;
time : X.Time := 0;
button := -1;
clickCount : CARDINAL := 0;
safetyRadius, doubleClickInterval: CARDINAL := 0;
keysym : X.KeySym := X.None;
xcompstatus := X.XComposeStatus{NIL, 0};
END;
last{x,y} = position of last mouseclick; lastRoot = root window of last
mouseclick; lastTime = time of last mouseClick; lastClickCount =
clickcount of last mouseclick, as defined in the VBT interface;
lastButton = button that last went up or down.
PROCEDURE Owns (ur: XClientF.Child; s: VBT.Selection): BOOLEAN =
BEGIN
RETURN s.sel < NUMBER(ur.owns^) AND ur.owns[s.sel]
END Owns;
PROCEDURE Messenger (self: Closure): REFANY RAISES {} =
VAR
evRec : X.XEvent;
ev := LOOPHOLE(ADR(evRec), X.XAnyEventStar);
ra : REFANY;
v : VBT.T;
ur : XClientF.Child;
last := Last{};
lost, takeFocus: BOOLEAN;
xcon := self.xcon;
<*FATAL XEventQueue.Exhausted*>
BEGIN
TRY
LOCK xcon DO XClientF.AdjustCoverage(xcon, 1) END;
LOOP
LOCK xcon DO
XClientF.AdjustCoverage(xcon, -1);
WHILE XEventQueue.IsEmpty(xcon.evq) AND NOT xcon.dead DO
Thread.Wait(xcon, xcon.evc)
END;
IF xcon.dead THEN EXIT END;
evRec := XEventQueue.Remove(xcon.evq);
IF ev.type = X.MappingNotify THEN
v := NIL;
ur := NIL;
WITH e = LOOPHOLE(ev, X.XMappingEventStar) DO
IF e.request # X.MappingPointer THEN
X.XRefreshKeyboardMapping(
LOOPHOLE(ADR(evRec), X.XMappingEventStar))
END
END;
XClientF.SetUngrabs(xcon)
ELSIF xcon.vbts.get(ev.window, ra) THEN
v := ra;
ur := v.upRef;
IF ur # NIL THEN
VAR
owns := Owns(ur, VBT.KBFocus);
ownsX := ur.isXFocus OR ur.inside AND ur.underXFocus;
BEGIN
lost := owns AND NOT ownsX;
takeFocus := NOT owns AND ownsX AND ur.recentlyOutside
END
ELSE
lost := FALSE;
takeFocus := FALSE
END;
last.safetyRadius := 3 (* xcon.params.safetyRadius*);
last.doubleClickInterval :=
500 (* xcon.params.doubleClickInterval*);
ELSE
v := NIL;
ur := NIL;
lost := FALSE;
takeFocus := FALSE
END
END;
XClientF.AdjustCoverage(xcon, 1);
IF ur # NIL
OR (ev.type = X.EnterNotify OR ev.type = X.MotionNotify)
AND ev.window = LOOPHOLE(ev, X.XMotionEventStar).root THEN
HandleEvent(v, xcon, ur, last, lost, takeFocus, ev)
END
END
EXCEPT
X.Error, TrestleComm.Failure => (* skip *)
END;
LOCK VBT.mu DO
VAR
vbts : REF ARRAY OF VBT.T;
iter: IntRefTbl.Iterator;
key, i: INTEGER;
val: REFANY;
BEGIN
LOCK xcon DO
vbts := NEW(REF ARRAY OF VBT.T, xcon.vbts.size());
iter := xcon.vbts.iterate();
i := 0;
WHILE iter.next(key, val) DO vbts[i] := val; INC(i); END;
END;
FOR i := 0 TO LAST(vbts^) DO
XClientF.Delete(xcon, vbts[i], vbts[i].upRef);
END
END
END;
RETURN NIL
END Messenger;
PROCEDURE HandleEvent ( v : VBT.T;
xcon : XClient.T;
ur : XClientF.Child;
VAR last : Last;
lost, takeFocus: BOOLEAN;
ev : X.XAnyEventStar )
RAISES {TrestleComm.Failure} =
VAR
width, height: CARDINAL;
junk : ARRAY [0 .. 0] OF Ctypes.char;
junkRef : REFANY;
BEGIN
LOCK VBT.mu DO
IF v = NIL OR v.upRef # NIL THEN
VBTRep.CoverRedisplay();
TRY
CASE ev.type OF
X.KeyPress, X.KeyRelease =>
WITH e = LOOPHOLE(ev, X.XKeyEventStar) DO
LOCK xcon DO
EVAL X.XLookupString(
e, ADR(junk[0]), NUMBER(junk), ADR(last.keysym),
ADR(last.xcompstatus))
END;
VAR state: INTEGER := e.state;
BEGIN
VBTClass.Key(
v, VBT.KeyRec{last.keysym, e.time, e.type = X.KeyPress,
LOOPHOLE(state, VBT.Modifiers)})
END
END
| X.ButtonPress, X.ButtonRelease =>
WITH e = LOOPHOLE(ev, X.XButtonEventStar) DO
ButtonEvent(v, xcon, ur, last, e)
END
| X.EnterNotify, X.LeaveNotify =>
WITH e = LOOPHOLE(ev, X.XCrossingEventStar) DO
EnterLeave(v, xcon, ur, lost, takeFocus, e)
END
| X.MotionNotify =>
(* WITH e = LOOPHOLE(ev, X.MotionEventStar) DO VAR cd:
VBT.PositionRec; BEGIN cd.time := e.time; cd.modifiers :=
LOOPHOLE(e.state, VBT.Modifiers); cd.cp.pt.h := ... *)
| X.FocusIn, X.FocusOut =>
IF lost THEN
LOCK xcon DO
XProperties.ExtendOwns(ur.owns, VBT.KBFocus);
XProperties.ExtendSel(xcon.sel, VBT.KBFocus);
ur.owns[VBT.KBFocus.sel] := FALSE;
IF xcon.sel[VBT.KBFocus.sel].v = v THEN
xcon.sel[VBT.KBFocus.sel].v := NIL
END
END;
VBTClass.Misc(
v, VBT.MiscRec{VBT.Lost, VBT.NullDetail, 0, VBT.KBFocus})
END
| X.Expose, X.GraphicsExpose => DeliverBadRegion(v, ur)
| X.DestroyNotify =>
IF ev.window = ur.w THEN
XClientF.Delete(xcon, v, ur)
ELSE
LOCK xcon DO EVAL xcon.vbts.delete(ev.window, junkRef) END
END
| X.ConfigureNotify =>
WITH e = LOOPHOLE(ev, X.XConfigureEventStar) DO
LOCK xcon DO XClientF.GetDomain(ur, width, height) END;
XClientF.Reshape(v, width, height, e.send_event # X.False)
END
| X.UnmapNotify, X.MapNotify =>
LOCK xcon DO XClientF.GetDomain(ur, width, height) END;
XClientF.Reshape(v, width, height)
| X.VisibilityNotify =>
WITH e = LOOPHOLE(ev, X.XVisibilityEventStar) DO
VBTClass.Misc(v, VBT.MiscRec{TrestleOnX.Visibility,
VBT.MiscCodeDetail{e.state, 0},
0, VBT.NilSel});
END
| X.SelectionClear =>
WITH e = LOOPHOLE(ev, X.XSelectionClearEventStar) DO
FOR s := FIRST(xcon.sel^) TO LAST(xcon.sel^) DO
IF xcon.sel[s].name = e.selection THEN
VAR mustDeliver: BOOLEAN;
BEGIN
LOCK xcon DO
XProperties.ExtendOwns(ur.owns, VBT.Selection{s});
mustDeliver := ur.owns[s];
ur.owns[s] := FALSE;
IF xcon.sel[s].v = v THEN xcon.sel[s].v := NIL END
END;
IF mustDeliver THEN
VBTClass.Misc(
v, VBT.MiscRec{VBT.Lost, VBT.NullDetail, e.time,
VBT.Selection{s}})
END
END
END
END
END
| X.ClientMessage =>
WITH e = LOOPHOLE(ev, X.XClientMessageEvent_l_star) DO
ClientMessage(v, xcon, ur, takeFocus, e)
END
ELSE
(* skip *)
END (* CASE *)
FINALLY
VBTRep.UncoverRedisplay()
END
END (* IF v.ur # NIL *)
END (* LOCK VBT.mu *)
END HandleEvent;
PROCEDURE ButtonEvent ( v : VBT.T;
xcon: XClient.T;
ur : XClientF.Child;
VAR last: Last;
e : X.XButtonEventStar)
RAISES {TrestleComm.Failure} =
VAR
cd: VBT.MouseRec;
mf := xcon.mouseFocus;
state : INTEGER := e.state;
CONST
NonButtons = VBT.Modifiers{FIRST(VBT.Modifier).. LAST(VBT.Modifier)}
- VBT.Buttons;
BEGIN
TRY
IF e.root = last.root
AND Word.Minus(e.time, last.time) <= last.doubleClickInterval
AND ABS(last.x - e.x) <= last.safetyRadius
AND ABS(last.y - e.y) <= last.safetyRadius
AND last.button = e.button THEN
INC(last.clickCount)
ELSE
last.clickCount := 0;
last.root := e.root;
last.x := e.x;
last.y := e.y;
last.button := e.button
END;
last.time := e.time;
cd.modifiers := LOOPHOLE(state, VBT.Modifiers);
cd.whatChanged := FIRST(VBT.Button);
INC(cd.whatChanged, e.button - X.Button1);
IF e.type = X.ButtonPress THEN
IF cd.modifiers <= NonButtons THEN
cd.clickType := VBT.ClickType.FirstDown;
xcon.mouseFocus := v;
xcon.mouseFocusRoot := ScreenNumber(xcon, e.root)
ELSE
cd.clickType := VBT.ClickType.OtherDown
END
ELSE
IF cd.modifiers <= NonButtons + VBT.Modifiers{cd.whatChanged} THEN
cd.clickType := VBT.ClickType.LastUp;
xcon.mouseFocus := NIL
ELSE
cd.clickType := VBT.ClickType.OtherUp
END
END;
cd.time := e.time;
cd.cp.pt.h := e.x;
cd.cp.pt.v := e.y;
cd.cp.offScreen := e.same_screen = X.False;
LOCK xcon DO
cd.cp.gone := cd.cp.offScreen OR e.subwindow # ur.w;
ur.cageCovered := TRUE;
END;
TRY
cd.cp.screen := ScreenNumber(xcon, e.root);
cd.clickCount := last.clickCount;
DeliverPosition(xcon, VBT.PositionRec{cd.cp, cd.time, cd.modifiers},
e.x_root, e.y_root, v, xcon.current, mf);
VBTClass.Mouse(v, cd);
FINALLY
LOCK xcon DO ur.cageCovered := FALSE END
END;
LOCK v DO xcon.setcage(v) END;
IF mf # NIL AND mf # v THEN
cd.cp.offScreen := e.root # xcon.mouseFocusRoot;
cd.cp.pt.h := e.x_root;
cd.cp.pt.v := e.y_root;
cd.cp.gone := TRUE;
IF NOT cd.cp.offScreen THEN
VAR mfur: XClientF.Child := mf.upRef;
BEGIN
TrestleOnX.Enter(xcon);
TRY
XClientF.ValidateNW(xcon, mfur, mf.st);
DEC(cd.cp.pt.h, mfur.nw.h);
DEC(cd.cp.pt.v, mfur.nw.v)
FINALLY
TrestleOnX.Exit(xcon)
END
END
END;
VBTClass.Mouse(mf, cd)
END;
TrestleOnX.Enter(xcon);
TRY
FOR s := FIRST(xcon.sel^) TO LAST(xcon.sel^) DO
WITH sr = xcon.sel[s] DO
IF s = VBT.KBFocus.sel THEN
IF sr.v = v AND ur.isXFocus THEN
X.XSetInputFocus(xcon.dpy, ur.w, X.RevertToParent, e.time);
sr.ts := e.time
END
ELSIF sr.v = v THEN
X.XSetSelectionOwner(xcon.dpy, sr.name, ur.w, e.time);
sr.ts := e.time
END
END
END
FINALLY
TrestleOnX.Exit(xcon)
END
EXCEPT X.Error => RAISE TrestleComm.Failure END;
END ButtonEvent;
PROCEDURE EnterLeave (v : VBT.T;
xcon : XClient.T;
ur : XClientF.Child;
lost, takeFocus: BOOLEAN;
e : X.XCrossingEventStar) =
VAR cd: VBT.PositionRec;
state: INTEGER := e.state;
BEGIN
cd.time := e.time;
cd.modifiers := LOOPHOLE(state, VBT.Modifiers);
cd.cp.pt.h := e.x;
cd.cp.pt.v := e.y;
cd.cp.gone := e.type = X.LeaveNotify;
cd.cp.offScreen := e.same_screen = X.False;
cd.cp.screen := ScreenNumber(xcon, e.root);
IF cd.cp.gone AND v = xcon.current THEN
xcon.current := NIL;
DeliverPosition(xcon, cd, e.x_root, e.y_root, v, xcon.mouseFocus)
ELSE
VAR oc := xcon.current;
BEGIN
IF NOT cd.cp.gone AND v # NIL THEN
xcon.current := v
ELSE
oc := NIL
END;
DeliverPosition(
xcon, cd, e.x_root, e.y_root, v, oc, xcon.mouseFocus)
END
END;
IF ur # NIL AND lost THEN
LOCK xcon DO
XProperties.ExtendOwns(ur.owns, VBT.KBFocus);
ur.owns[VBT.KBFocus.sel] := FALSE;
IF xcon.sel[VBT.KBFocus.sel].v = v THEN
xcon.sel[VBT.KBFocus.sel].v := NIL
END
END;
VBTClass.Misc(
v, VBT.MiscRec{VBT.Lost, VBT.NullDetail, 0, VBT.KBFocus})
ELSIF takeFocus THEN
LOCK xcon DO ur.recentlyOutside := FALSE END;
VBTClass.Misc(v, VBT.MiscRec{VBT.TakeSelection, VBT.NullDetail,
e.time, VBT.KBFocus})
END
END EnterLeave;
PROCEDURE ClientMessage (v : VBT.T;
xcon : XClient.T;
ur : XClientF.Child;
takeFocus: BOOLEAN;
e : X.XClientMessageEvent_l_star)
RAISES {TrestleComm.Failure} =
<* FATAL Split.NotAChild *>
BEGIN
WITH data = e.data DO
IF e.message_type = xcon.protocols THEN
IF data[0] = xcon.deleteWindow THEN
Split.Delete(xcon, v)
ELSIF data[0] = xcon.takeFocus THEN
LOCK xcon DO
XProperties.ExtendOwns(ur.owns, VBT.KBFocus);
takeFocus := NOT ur.owns[VBT.KBFocus.sel]
END;
IF takeFocus THEN
VAR
tsi: Ctypes.int := data[1];
ts := LOOPHOLE(tsi, Ctypes.unsigned_int);
BEGIN
VBTClass.Misc(
v, VBT.MiscRec{
VBT.TakeSelection, VBT.NullDetail, ts, VBT.KBFocus})
END
END
END
ELSIF e.message_type = xcon.decTakeFocus THEN
LOCK xcon DO
XProperties.ExtendOwns(ur.owns, VBT.KBFocus);
takeFocus := NOT ur.owns[VBT.KBFocus.sel]
END;
IF takeFocus THEN
VAR
tsi: Ctypes.int := data[0];
ts := LOOPHOLE(tsi, Ctypes.unsigned_int);
BEGIN
VBTClass.Misc(v, VBT.MiscRec{VBT.TakeSelection, VBT.NullDetail,
ts, VBT.KBFocus})
END
END
ELSIF e.message_type = xcon.paNewScreen
OR e.message_type = xcon.paNewDisplay
OR e.message_type = xcon.paAddDisplay THEN
NewScreen(v, xcon, ur, LOOPHOLE(e, X.XClientMessageEvent_s_star))
ELSIF e.message_type = xcon.miscAtom THEN
(* data[0] is an externalized MiscCodeType, data[2] is an
externalized Selection *)
data[0] := VBT.GetMiscCodeType(XClient.ToName(xcon, data[0])).typ;
data[2] := VBT.GetSelection(XClient.ToName(xcon, data[2])).sel;
VBTClass.Misc(
v, VBT.MiscRec{VBT.MiscCodeType{data[0]},
ARRAY [0 .. 1] OF INTEGER{data[3], data[4]},
data[1], VBT.Selection{data[2]}})
ELSIF e.message_type = xcon.wmMoved THEN
LOCK xcon DO ur.nwValid := FALSE END
END
END
END ClientMessage;
PROCEDURE NewScreen (v : VBT.T;
xcon: XClient.T;
ur : XClientF.Child;
e : X.XClientMessageEvent_s_star)
RAISES {TrestleComm.Failure} =
VAR
id := -1;
prop, type, type2 := X.None;
len, len2, remaining := 0;
format, format2: Ctypes.int := 0;
addr, addr2: Ctypes.unsigned_char_star;
hasprop2 := FALSE;
BEGIN
WITH shData = e.data DO
VAR
screen := shData[0];
x := shData[1];
y := shData[2];
width := shData[3];
height := shData[4];
hasprop := shData[5] # 0;
state := shData[6];
BEGIN
TRY
TRY
TrestleOnX.Enter(xcon);
TRY
IF hasprop
AND X.Success
# X.XGetWindowProperty(
xcon.dpy, ur.w, xcon.paNewScreen, 0,
X.XMaxRequestSize(xcon.dpy) - 50, X.True,
X.AnyPropertyType, ADR(type), ADR(format),
ADR(len), ADR(remaining), ADR(addr)) THEN
hasprop := FALSE
END;
IF (e.message_type = xcon.paNewDisplay
OR e.message_type = xcon.paAddDisplay)
AND X.Success
= X.XGetWindowProperty(
xcon.dpy, ur.w, e.message_type, 0,
MIN(4096, X.XMaxRequestSize(xcon.dpy) - 50),
X.True, X.AnyPropertyType, ADR(type2),
ADR(format2), ADR(len2), ADR(remaining),
ADR(addr2)) THEN
hasprop2 := TRUE;
IF format2 = 8 AND len2 > 0 THEN id := -2 END
ELSE
FOR i := FIRST(xcon.screens^) TO LAST(xcon.screens^) DO
IF xcon.screens[i].screenID = screen THEN id := i END
END
END
FINALLY
TrestleOnX.Exit(xcon)
END;
IF id >= 0 THEN
XClient.InnerOverlap(
xcon, v, id, Point.T{x, y}, TRUE,
iconic := state = X.IconicState, userPosition := TRUE,
prop := prop, type := type, len := len, format := format,
addr := addr)
ELSIF id = -2 THEN
VAR
nsp := NEW(XClientF.NewScreenProp);
m := NEW(DpyFilter.Message);
xx := MiscDetail.FromRef(m);
yy := MiscDetail.FromRef(NIL);
a := LOOPHOLE(
addr2, UNTRACED REF ARRAY [0 .. 4095] OF CHAR);
BEGIN
IF prop # X.None THEN
nsp.prop := prop;
nsp.type := type;
nsp.len := len;
nsp.format := format;
nsp.data :=
NEW(REF ARRAY OF Ctypes.char, len * format DIV 8);
nsp.data^ :=
SUBARRAY(LOOPHOLE(addr, UNTRACED REF
ARRAY [0 .. 4095] OF Ctypes.char)^,
0, NUMBER(nsp.data^));
yy := MiscDetail.FromRef(nsp)
END;
m.x := x;
m.y := y;
m.width := width;
m.height := height;
m.screen := screen;
m.iconic := state = X.IconicState;
m.status := TRUE;
ComputeHeads(a, m, len2);
IF e.message_type = xcon.paNewDisplay THEN
VBTClass.Misc(v, VBT.MiscRec{DpyFilter.ChangeDisplay,
VBT.MiscCodeDetail{xx, yy},
0, VBT.NilSel})
ELSE
VBTClass.Misc(v, VBT.MiscRec{DpyFilter.AddDisplay,
VBT.MiscCodeDetail{xx, yy},
0, VBT.NilSel})
END;
MiscDetail.Delete(xx);
MiscDetail.Delete(yy);
IF NOT m.status THEN
TrestleOnX.Enter(xcon);
TRY
X.XDeleteProperty(xcon.dpy, ur.w, xcon.paNewDisplay)
FINALLY
TrestleOnX.Exit(xcon)
END
END
END
END
FINALLY
IF hasprop THEN X.XFree(LOOPHOLE(addr, Ctypes.char_star)) END;
IF hasprop2 THEN X.XFree(LOOPHOLE(addr2, Ctypes.char_star)) END
END
EXCEPT
X.Error => RAISE TrestleComm.Failure
END;
END
END
END NewScreen;
PROCEDURE ComputeHeads (READONLY a : UNTRACED REF ARRAY [0..4095] OF CHAR;
m : DpyFilter.Message;
len2: INTEGER ) =
CONST NumDisplays = 20;
VAR
heads: ARRAY [0 .. NumDisplays] OF INTEGER;
cnt := 0;
tail := a[len2 - 1] = '\000';
BEGIN
heads[0] := 0;
FOR i := 0 TO len2 DO
IF a[i] = '\000' AND cnt < NumDisplays THEN
INC(cnt);
heads[cnt] := i + 1
END
END;
IF NOT tail AND cnt < NumDisplays THEN
INC(cnt);
heads[cnt] := len2 + 2
END;
IF cnt > 1 AND heads[2] > heads[1] + 1 THEN
m.oldAuth :=
Text.FromChars(SUBARRAY(a^, heads[1], heads[2] - heads[1] - 1))
ELSE
m.oldAuth := NIL
END;
IF cnt > 2 AND heads[3] > heads[2] + 1 THEN
m.newAuth :=
Text.FromChars(SUBARRAY(a^, heads[2], heads[3] - heads[2] - 1))
ELSE
m.newAuth := NIL
END;
m.newDisplay := NEW(REF ARRAY OF TEXT, MAX(1, cnt - 2));
m.newDisplay[0] :=
Text.FromChars(SUBARRAY(a^, heads[0], heads[1] - heads[0] - 1));
FOR i := 3 TO cnt - 1 DO
m.newDisplay[i - 2] :=
Text.FromChars(SUBARRAY(a^, heads[i], heads[i + 1] - heads[i] - 1))
END
END ComputeHeads;
PROCEDURE DeliverPosition ( t : XClient.T;
READONLY cd : VBT.PositionRec;
h, v : INTEGER;
w, s1, s2: VBT.T := NIL) =
<*FATAL Split.NotAChild*>
(* Deliver the position in cd to all the children of t, starting with s1,
including s2, and ending with w. *)
VAR
goneCd := cd;
others: BOOLEAN;
ch : VBT.T;
BEGIN
goneCd.cp.gone := TRUE;
LOCK t DO others := t.otherCages; t.otherCages := FALSE END;
IF s1 # NIL AND s1 # w THEN DoPosition(t, s1, goneCd, h, v) END;
IF others THEN
ch := Split.Succ(t, NIL);
WHILE ch # NIL DO
IF ch # s1 AND ch # w THEN DoPosition(t, ch, goneCd, h, v) END;
ch := Split.Succ(t, ch)
END
ELSIF s2 # NIL AND s2 # w AND s2 # s1 THEN
DoPosition(t, s2, goneCd, h, v)
END;
IF w # NIL THEN VBTClass.Position(w, cd) END
END DeliverPosition;
PROCEDURE ScreenNumber (t: XClient.T; w: X.Window): INTEGER =
BEGIN
IF t.screens = NIL THEN RETURN -1 END;
IF w = t.currentRootWindow THEN RETURN t.currentRoot END;
LOCK t DO
t.otherCages := TRUE;
FOR i := FIRST(t.screens^) TO LAST(t.screens^) DO
IF t.screens[i].root = w THEN
t.currentRootWindow := w;
t.currentRoot := t.screens[i].screenID;
RETURN t.currentRoot
END
END;
t.currentRootWindow := X.None;
t.currentRoot := -1;
RETURN -1
END
END ScreenNumber;
PROCEDURE DeliverBadRegion (v: VBT.T; ur: XClientF.Child) =
(* Join v's x-bad-region into v's child's ordinary bad region, call its
repaint method, and clear its x-bad-region. LL = VBT.mu. *)
BEGIN
LOCK v DO
LOCK v.parent DO
VBTClass.ForceRepaint(v, ur.badR, FALSE);
ur.badR := Region.Empty
END
END;
VBTClass.Repaint(v, Region.Empty)
END DeliverBadRegion;
PROCEDURE DoPosition (<*UNUSED*> t : XClient.T;
w : VBT.T;
VAR cd : VBT.PositionRec;
<*UNUSED*> h, v: INTEGER ) =
VAR cg := VBTClass.Cage(w);
BEGIN
IF (cg.screen = cd.cp.screen OR cg.screen = VBT.AllScreens)
AND TRUE IN cg.inOut THEN
IF Rect.Equal(cg.rect, Rect.Full) THEN RETURN END;
END
END DoPosition;
BEGIN
END XMessenger.