diff options
author | Peter Hutterer <peter.hutterer@who-t.net> | 2012-08-08 11:34:32 +1000 |
---|---|---|
committer | Peter Hutterer <peter.hutterer@who-t.net> | 2012-08-21 07:54:07 +1000 |
commit | bafbd99080be49a17be97d2cc758fbe623369945 (patch) | |
tree | afbd1a80abd99272b85d1e9855ae1ae4d558ac22 | |
parent | 1ebba43052d68d874148e63c9ae38489ddfc5ec1 (diff) |
dix: work around scaling issues during WarpPointer (#53037)
In WarpPointer calls, we get input in screen coordinates. They must be
scaled to device coordinates, and then back to screen coordinates for screen
crossing and root coordinates in events.
The rounding errors introduced (and clipping in core/XI 1.x events) can lead
to the actual position being different to the requested input coordinates.
e.g. 200 scales to 199.9999, truncated to 199 in the event.
Avoid this by simply overwriting the scaled screen coordinates with the
input coordinates for the POINTER_SCREEN case.
X.Org Bug 53037 <http://bugs.freedesktop.org/show_bug.cgi?id=53037>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Keith Packard <keithp@keithp.com>
-rw-r--r-- | dix/getevents.c | 18 |
1 files changed, 17 insertions, 1 deletions
diff --git a/dix/getevents.c b/dix/getevents.c index b3bb162ae..4e62507aa 100644 --- a/dix/getevents.c +++ b/dix/getevents.c @@ -1327,6 +1327,7 @@ fill_pointer_events(InternalEvent *events, DeviceIntPtr pDev, int type, RawDeviceEvent *raw; double screenx = 0.0, screeny = 0.0; /* desktop coordinate system */ double devx = 0.0, devy = 0.0; /* desktop-wide in device coords */ + int sx, sy; /* for POINTER_SCREEN */ ValuatorMask mask; ScreenPtr scr; @@ -1369,8 +1370,11 @@ fill_pointer_events(InternalEvent *events, DeviceIntPtr pDev, int type, /* valuators are in driver-native format (rel or abs) */ if (flags & POINTER_ABSOLUTE) { - if (flags & POINTER_SCREEN) /* valuators are in screen coords */ + if (flags & POINTER_SCREEN) { /* valuators are in screen coords */ + sx = valuator_mask_get(&mask, 0); + sy = valuator_mask_get(&mask, 1); scale_from_screen(pDev, &mask); + } transformAbsolute(pDev, &mask); clipAbsolute(pDev, &mask); @@ -1388,6 +1392,18 @@ fill_pointer_events(InternalEvent *events, DeviceIntPtr pDev, int type, /* valuators are in device coordinate system in absolute coordinates */ scale_to_desktop(pDev, &mask, &devx, &devy, &screenx, &screeny); + + /* #53037 XWarpPointer's scaling back and forth between screen and + device may leave us with rounding errors. End result is that the + pointer doesn't end up on the pixel it should. + Avoid this by forcing screenx/screeny back to what the input + coordinates were. + */ + if (flags & POINTER_SCREEN) { + screenx = sx; + screeny = sy; + } + scr = positionSprite(pDev, (flags & POINTER_ABSOLUTE) ? Absolute : Relative, &mask, &devx, &devy, &screenx, &screeny); |