enterleave.c vs the protocol

Keith Packard keithp at keithp.com
Tue Dec 16 00:29:37 PST 2008


(btw, thanks so much for the huge comment; I'm going to ignore the code
and focus on how the comment relates to the core spec)

My theory is that we compute the logical pointer source and destination
for each window in the system and deliver events to that window as if
the pointer made that logical move. 

I believe (without proof) that the only windows which should receive
events for any pointer motion are precisely the set of windows which
would have received events under the core protocol with only a single
pointer. That would mean that all we have to do is compute *which* event
each one of those windows receives.

Using (as Owen did) P(W) to represent the pointer window as seen by W,
we walk the set of windows that are to receive events, compute P(W) (the
old pointer window) and P'(W) (the new pointer window) and use those two
windows to construct the correct event to deliver to W.

Here's some deconstruction of your specific instructions:

(X..Y) windows from X to Y not including X or Y
[X..Y) windows from X to Y including X but not Y
(X..Y] windows from X to Y not including X but including Y
[X..Y] windows from X to Y including X and Y
 
 * EnterNotify(Virtual, B) means EnterNotify Event, detail Virtual, child = B.
 *
 * Pointer moves from A to B, nonlinear (CoreEnterLeaveNonLinear):
 * 1. a. if A has another pointer, goto 2.

The goto seems correct -- nothing changes for A or any inferior of A.

 *    b. otherwise, if A has a inferior with a pointer in it,
 *       LeaveNotify(Inferior) to A

This seems correct -- A sees the pointer move from A to inferior(A).

 *       LeaveNotify(Virtual) between A and inferior(A)

This seems wrong -- (A..inferior(A)) see the pointer remain in
inferior(A). I'd say that no event should be generated here. In
particular, LeaveNotify(Virtual) means that the focus is moving to an
ancestor (of A).

 * 2. Find common ancestor X between A and B.
 * 3. Find closest pointer window P between A and X.
 *    a. if P exists
 *       LeaveNotify(Ancestor) to A

This seems incomplete. If inferior(A) has a pointer, then A should see
that pointer through a LeaveNotify(Inferior) event (already delivered
above). Otherwise, A sees P's pointer.

 *       LeaveNotify(Virtual) between A and P

Again, this is incomplete -- if inferior(A) has a pointer, (A..P) should
see that pointer and receive no events. Note that parent(A) should
receive LeaveNotify(Virtual,A).

 *    b. otherwise, if P does not exist,
 *       LeaveNotify(NonLinear) to A

Incomplete -- if inferior(A) has a pointer, A should see it and will
have received a LeaveNotify(Inferior) above.

 *       LeaveNotify(NonLinearVirtual) between A and X.

Incomplete -- if inferior(A) has a pointer, then (A..X) should see it. X
will also see other pointers, so precisely which windows X believes
holds the pointer is a matter of pointer priority. Note that parent(A)
should receive LeaveNotify(NonLinear, A).

 * 4. If X does not have a pointer, EnterNotify(NonLinearVirtual, B) to X.

This seems wrong -- X shouldn't receive any event (This is window C in
the non-linear case described in the protocol spec).

 * 5. Find closest pointer window Q between X and B.
 *    a. if Q exists, EnterNotify(NonLinearVirtual) between X and Q

I think this is incorrect; (X..Q] continue to see the pointer in Q and
should receive no events. 

If B and inferior(B) do not contain a pointer, then (Q..B] see the
pointer move from Q to B and should receive EnterNotify(Virtual) events,
parent(B) should receive EnterNotify(Virtual,B) and B should receive
EnterNotify(Ancestor).

If B or inferior(b) do contain a pointer, then (Q..B] see the pointer
move from inferior(B) to B. (Q..B) receive no events, while B receives
an EnterNotify(Inferior). If inferior(B) is a child of B, then B
receives EnterNotify(Inferior,inferior(B)) instead.

 *    b. otherwise, EnterNotify(NonLinearVirtual) between X and B

This is correct if B and inferior(B) do not contain a pointer. Note that
parent(B) gets the child field set to B.

If B or inferior(B) do contain a pointer, then (X..B) get no events.

 * 5. a. if B has another pointer in it, finish.

Yup.

 *    b. otherwise, if B has a inferior with a pointer in it
 *       LeaveNotify(Virtual) between inferior(B) and B.

Again, I think this is a mistake; LeaveNotify(Virtual) means the pointer
is moving past the window to an ancestor. In this case, the pointer
isn't moving at all as these windows see the pointer in inferior(B).

 *       EnterNotify(Inferior) to B.

Yes.

 *    c. otherwise, EnterNotify(NonLinear) to B.

Incomplete -- if Q exists, then B receives EnterNotify(Ancestor) instead.


(why did you do the non-linear case first? It's the hardest...)

 * --------------------------------------------------------------------------
 *
 * Pointer moves from A to B, A is an ancestor of B (CoreEnterLeaveToDescendant):
 * 1. a. If A has another pointer, goto 2.

yes.

 *    b. Otherwise, LeaveNotify(Inferior) to A.

yes.

 * 2. Find highest window X that has a pointer inferior that is not an inferior of B.

I assume that X is a member of (A..B).

 *    a. if X exists, EnterNotify(Virtual, B) between A and X,

No. (A..X) already see X containing a pointer. No events should be delivered.

 *       EnterNotify(Virtual, B) to X (if X has no pointer).

X sees the pointer move from inferior(X) to B, so it should receive no event.

 *    b. otherwise, EnterNotify(Virtual, B) between A and B.

Yes, but with only parent(B) receiving EnterNotify(Virtual,B), the other
windows receive EnterNotify(Virtual).

 *
 * 3. a. if B has another pointer, finish

Yes.

 *    b. otherwise, if B has an inferior with a pointer in it,
 *       LeaveNotify(Virtual, inferior(B)) between inferior(B) and B.

No, (B..inferior(B)) see no pointer window change and should receive no event.

 *       EnterNotify(Inferior, child(B)) to B.

No, B has a pointer and should receive EnterNotify(Ancestor) only.

 *    c. otherwise, EnterNotify(Ancestor) to B.

Yes.

 *
 * --------------------------------------------------------------------------
 *
 * Pointer moves from A to B, A is a child of B (CoreEnterLeaveToAncestor):
 * 1. a. If A has another pointer, goto 2.

Right.

 *    b. Otherwise, if A has a inferior with a pointer in it.
 *       LeaveNotify(Inferior, inferior(A)) to A.

Right, except it gets LeaveNotify(Inferior) unless inferior(A) is a
child of A.

 *       EnterNotify(Virtual, inferior(A)) between A and inferior(A).
 *       Skip to 3.

No, (A..inferior(A)] see no pointer change and should receive no event.

 * 2. Find closest pointer window P between A and B.
 *    If P does not exist, P is B.
 *           LeaveNotify(Ancestor) to A.

yes.

 *           LeaveNotify(Virtual, A) between A and P.

Yes, except only parent(A) receives LeaveNotify(Virtual, A), the rest
get LeaveNotify(Virtual).

[P..B] receive no event, which is right.

 * 3. a. If B has another pointer, finish.

right.

 *    b. otherwise, EnterNotify(Inferior) to B.

Right.

 */

-- 
keith.packard at intel.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 189 bytes
Desc: This is a digitally signed message part
URL: <http://lists.x.org/archives/xorg/attachments/20081216/28d72629/attachment.pgp>


More information about the xorg mailing list