[PATCH] fixes: Pointer barriers
Soeren Sandmann
sandmann at cs.au.dk
Mon Feb 14 05:22:39 PST 2011
Adam Jackson <ajax at redhat.com> writes:
> This is pretty much a 'version 0' kind of thing, it looks right to me
> but reviews strongly needed.
A conceptual question I have is: What is supposed to happen on
diagonal movement? A possibility is to decompose such movement into a
horizontal and a vertical component, which is what it looks like this
patch is going for. That has the effect that in this situation:
*
\
\ |
\ |
\|
|
|\
| \
| \
| \
\
*
The cursor movement will be allowed even though geometrically, the
cursor is crossing a barrier. Also, in this situation:
* |
\ |
\ |
\ |
\
------ \
\
*
the movement will not be allowed. To me, both seem wrong.
The algorithm I'd suggest using is this:
- Write the mouse travel path as
t -> (ox, oy) * (1 - t) + t * (nx, ny), t in [0,1]
- Compute the attempted travel directions like the code does now
- For each barrier, if there is a t such that the path intersects
the barrier, then add (t, barrier) to a list.
- Sort that list from least to greatest t.
- For each (t, barrier) in sorted order, if the barrier does not
allow travel in one of the attempted directions, confine the
cursor according to that barrier and stop processing.
But it's probably the sort of thing that would have to be tried out to
be sure it works.
Comments on the code:
In CursorConstrainHarder():
- It looks to me like the barriers will contrain even if the pointer
is outside the barrier's extent: E.g., in this situation:
*------------* cursor
|
|
|
| barrier
the cursor will still be constrained by the barrier because this
code:
if (b->x1 == b->x2) {
if ((ox < b->x1 && *x > b->x1 && !(d & BarrierPositiveX)) ||
(ox > b->x1 && *x < b->x1 && !(d & BarrierNegativeX)))
{
...;
}
will trigger. Some check against the y coordinates seem to be
necessary - the exact nature of those checks depends on how the
conceptual issue described above is resolved.
- It seems there is some redundancy in if clauses. For example, if the
code detects a positive movement across a vertical barrier, it
confines if that movement is not both allowed and attempted. But we
already know that it *was* attempted because otherwise
(ox < b->x1 && *x > b->x1)
would not have been true. Hence, it is sufficient to check against
the allowed directions, and there is no need to compute the
attempted directions. (But this will be moot if barriers for
diagonal moves are implemented).
- In general, when checking against a barrier, the inequalities should
be < and >= (and not < and > ) if a barrier is to be considered
infinitely thin and residing between pixels.
- In this code:
if ((stuff->x1 != stuff->x2) || (stuff->y1 != stuff->y2))
return BadValue.
I think the "||" should be "&&". It may also be worthwhile checking
that the barrier is not a single point since if the diagonal
algorithm is used, there could be divide-by-zero issues.
Ie.,
if (stuff->x1 != stuff->x2 && stuff->y1 != stuff->y2)
return BadValue;
if (stuff->x1 == stuff->x2 && stuff->y1 == stuff->y2)
return BadValue;
- This comment:
/* This sure does need fixing */
is true of course.
Probably the list of devices should be stored per-barrier, and then
when a device is removed, it must be removed from all barriers. The
alternative would be to store a list of barriers in each
device. That would be slightly more efficient, but also probably
more complicated a barrier can apply to all devices, so it would
involve hooking device creation.
Soren
More information about the xorg-devel
mailing list