[PATCH v2.1] dix: fix device scaling to use a [min,max[ range.

Peter Hutterer peter.hutterer at who-t.net
Wed May 1 17:10:40 PDT 2013


defmin/defmax are screen coords and thus use a min-inclusive, max-exclusive
range. device axes ranges are inclusive, so bump the max up by one to get the
scaling right.

This fixes off-by-one coordinate errors if the coordinate matrix is used to
bind the device to a fraction of the screen. It introduces an off-by-one
scaling error in the device coordinate range, but since most devices have a
higher resolution than the screen (e.g. a Wacom I4 has 5080 dpi) the effect
of this should be limited.

This error manifests when we have numScreens > 1, as the scaling from
desktop size back to screen size drops one device unit.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
Changes to v2:
- comment added explaining where the valuators are off now

afaict, we can't win here anyway, and off by one device unit is the least
amount of pain.

 dix/devices.c   |  4 ++--
 dix/getevents.c | 14 ++++++++++----
 2 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/dix/devices.c b/dix/devices.c
index fa94a94..7b423de 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -112,8 +112,8 @@ DeviceSetTransform(DeviceIntPtr dev, float *transform_data)
      *  Transform is the user supplied (affine) transform
      *  InvScale scales coordinates back up into their native range
      */
-    sx = dev->valuator->axes[0].max_value - dev->valuator->axes[0].min_value;
-    sy = dev->valuator->axes[1].max_value - dev->valuator->axes[1].min_value;
+    sx = dev->valuator->axes[0].max_value - dev->valuator->axes[0].min_value + 1;
+    sy = dev->valuator->axes[1].max_value - dev->valuator->axes[1].min_value + 1;
 
     /* invscale */
     pixman_f_transform_init_scale(&scale, sx, sy);
diff --git a/dix/getevents.c b/dix/getevents.c
index a4f192c..1438625 100644
--- a/dix/getevents.c
+++ b/dix/getevents.c
@@ -297,11 +297,11 @@ rescaleValuatorAxis(double coord, AxisInfoPtr from, AxisInfoPtr to,
 
     if (from && from->min_value < from->max_value) {
         fmin = from->min_value;
-        fmax = from->max_value;
+        fmax = from->max_value + 1;
     }
     if (to && to->min_value < to->max_value) {
         tmin = to->min_value;
-        tmax = to->max_value;
+        tmax = to->max_value + 1;
     }
 
     if (fmin == tmin && fmax == tmax)
@@ -913,9 +913,9 @@ scale_to_desktop(DeviceIntPtr dev, ValuatorMask *mask,
 
     /* scale x&y to desktop coordinates */
     *screenx = rescaleValuatorAxis(x, dev->valuator->axes + 0, NULL,
-                                   screenInfo.x, screenInfo.width - 1);
+                                   screenInfo.x, screenInfo.width);
     *screeny = rescaleValuatorAxis(y, dev->valuator->axes + 1, NULL,
-                                   screenInfo.y, screenInfo.height - 1);
+                                   screenInfo.y, screenInfo.height);
 
     *devx = x;
     *devy = y;
@@ -1355,6 +1355,12 @@ QueuePointerEvents(DeviceIntPtr device, int type,
  * is the last coordinate on the first screen and must be rescaled for the
  * event to be m. XI2 clients that do their own coordinate mapping would
  * otherwise interpret the position of the device elsewere to the cursor.
+ * However, this scaling leads to losses:
+ * if we have two ScreenRecs we scale from e.g. [0..44704]  (Wacom I4) to
+ * [0..2048[. that gives us 2047.954 as desktop coord, or the per-screen
+ * coordinate 1023.954. Scaling that back into the device coordinate range
+ * gives us 44703. So off by one device unit. It's a bug, but we'll have to
+ * live with it because with all this scaling, we just cannot win.
  *
  * @return the number of events written into events.
  */
-- 
1.8.1.4



More information about the xorg-devel mailing list