[PATCH] dix: Clip only into axis ranges if we're in absolute mode. (#26543)

Peter Hutterer peter.hutterer at who-t.net
Thu Feb 25 22:56:48 PST 2010

An absolute device in relative mode may provide valuators outside of the
axis range. Clipping back into the range prevents screen crossings in a
multi-screen (Xinerama) setup as the required screen edge for crossing is
never met: miPointerSetPosition crosses the screen conditional to the X
coordinate being equal to the screen width or _less than_ 0. While the
former can be met when clipping into the coordinate range and scaling, the
latter cannot, resulting in a mouse pointer that gets stuck on the rightmost

This patch only applies axis clipping for valuators in mode Absolute. If
relative, we allow the values to get above/below the axis ranges. Doesn't
matter, miPointerSetPosition will reset the values to the allowed range even
if no screen was crossed.
This leads to interesting values provided to clients, the valuator range of
the device resets once a screen is crossed and essentially reflects
the position of the cursor on the screen - scaled into the valuator range.
The values themselves are valid given the range though.

In theory, the XI1 specs require that a relative device has a min/max range
of 0/0. This doesn't really go well with devices that actually can switch
mode between relative and absolute since they would have to reset their axis
range when switching. If multiple XI clients are in use, we have no method
of notifying them about the changes, so other clients may continue to use
the wrong axis ranges (note: XI1 wasn't really designed to have multiple
clients use a device). Expecting all relative devices to have this min/max
of 0 is unrealistic at this point.

So pick what is possibly the lesser of all evils, pass the beer and despair.

X.Org Bug 26543 <http://bugs.freedesktop.org/show_bug.cgi?id=26543>

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
 dix/getevents.c |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/dix/getevents.c b/dix/getevents.c
index 82bb77b..197deb4 100644
--- a/dix/getevents.c
+++ b/dix/getevents.c
@@ -710,7 +710,7 @@ moveRelative(DeviceIntPtr dev, int *x, int *y,
     /* if attached, clip both x and y to the defined limits (usually
      * co-ord space limit). If it is attached, we need x/y to go over the
      * limits to be able to change screens. */
-    if(dev->u.master) {
+    if(dev->u.master && dev->valuator->mode == Absolute) {
         clipAxis(dev, 0, x);
         clipAxis(dev, 1, y);
@@ -720,7 +720,8 @@ moveRelative(DeviceIntPtr dev, int *x, int *y,
     for (; i < num; i++)
         dev->last.valuators[i + first] += valuators[i];
-        clipAxis(dev, i, &dev->last.valuators[i + first]);
+        if (dev->valuator->mode == Absolute)
+            clipAxis(dev, i, &dev->last.valuators[i + first]);
         valuators[i] = dev->last.valuators[i + first];

More information about the xorg-devel mailing list